Merge Graph changes into Master branch

This commit is contained in:
Sam Xu 2018-08-08 10:18:01 -07:00
parent 35ec9180e1
commit 1b8d685dc7
156 changed files with 8948 additions and 1198 deletions

View file

@ -0,0 +1,23 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
namespace Microsoft.OpenApi.OData.Abstractions
{
/// <summary>
/// The <see cref="IAuthorization"/> provider interface.
/// </summary>
public interface IAuthorizationProvider
{
/// <summary>
/// Provide the <see cref="IAuthorization"/>.
/// </summary>
/// <returns>The <see cref="IAuthorization"/>.</returns>
//IEnumerable<IAuthorization> GetAuthorizations(IEdmModel model, IEdmVocabularyAnnotatable target);
}
}

View file

@ -0,0 +1,76 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// Complex type Org.OData.Core.V1.CustomParameter
/// </summary>
internal class CustomParameter
{
/// <summary>
/// The Name.
/// </summary>
public string Name { get; set; }
/// <summary>
/// The Description.
/// </summary>
public string Description { get; set; }
/// <summary>
/// The DocumentationURL.
/// </summary>
public string DocumentationURL { get; set; }
/// <summary>
/// The Required.
/// </summary>
public bool? Required { get; set; }
/// <summary>
/// The ExampleValues.
/// </summary>
public IEnumerable<Example> ExampleValues { get; set; }
/// <summary>
/// Init the <see cref="CustomParameter"/>
/// </summary>
/// <param name="record">The input record.</param>
public virtual void Init(IEdmRecordExpression record)
{
Utils.CheckArgumentNull(record, nameof(record));
// Name
Name = record.GetString("Name");
// Description
Description = record.GetString("Description");
// DocumentationURL
DocumentationURL = record.GetString("DocumentationURL");
// Required
Required = record.GetBoolean("Required");
// ExampleValues
ExampleValues = record.GetCollection("ExampleValues", r =>
{
IEdmRecordExpression itemRecord = r as IEdmRecordExpression;
if (itemRecord != null)
{
return Example.CreateExample(itemRecord);
}
return null;
});
}
}
}

View file

@ -0,0 +1,76 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// Org.OData.Core.V1.Example
/// </summary>
internal abstract class Example
{
/// <summary>
/// Description.
/// </summary>
public string Description { get; set; }
/// <summary>
/// Init the <see cref="Example"/>.
/// </summary>
/// <param name="record">The input record.</param>
public virtual void Init(IEdmRecordExpression record)
{
Utils.CheckArgumentNull(record, nameof(record));
// Description
Description = record.GetString("Description");
}
/// <summary>
/// Creat the corresponding example object.
/// </summary>
/// <param name="record">The input record.</param>
/// <returns>The created example object.</returns>
public static Example CreateExample(IEdmRecordExpression record)
{
if (record == null || record.DeclaredType == null)
{
return null;
}
IEdmComplexType complexType = record.DeclaredType.Definition as IEdmComplexType;
if (complexType == null)
{
return null;
}
Example example = null;
switch (complexType.FullTypeName())
{
case "Org.OData.Core.V1.ExternalExample":
example = new ExternalExample();
break;
case "Org.OData.Core.V1.InlineExample":
example = new InlineExample();
break;
default:
break;
}
if (example != null)
{
example.Init(record);
}
return example;
}
}
}

View file

@ -0,0 +1,33 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// Complex type Org.OData.Core.V1.ExternalExample
/// </summary>
internal class ExternalExample : Example
{
/// <summary>
/// ExternalValue
/// </summary>
public string ExternalValue { get; set; }
/// <summary>
/// Init the <see cref="ExternalExample"/>.
/// </summary>
/// <param name="record">The record.</param>
public override void Init(IEdmRecordExpression record)
{
base.Init(record);
// ExternalValue
ExternalValue = record.GetString("ExternalValue");
}
}
}

View file

@ -0,0 +1,84 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Authorizations;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// Org.OData.Core.V1.HttpRequest
/// </summary>
internal class HttpRequest
{
/// <summary>
/// The description.
/// </summary>
public string Description { get; set; }
/// <summary>
/// The MethodDescription.
/// </summary>
public string MethodDescription { get; set; }
/// <summary>
/// The MethodType.
/// </summary>
public string MethodType { get; set; }
/// <summary>
/// The Custom Query Options.
/// </summary>
public IList<CustomParameter> CustomQueryOptions { get; set; }
/// <summary>
/// The custom Headers.
/// </summary>
public IList<CustomParameter> CustomHeaders { get; set; }
/// <summary>
/// The http responses.
/// </summary>
public IList<HttpResponse> HttpResponses { get; set; }
/// <summary>
/// The security sechems.
/// </summary>
public IList<SecurityScheme> SecuritySchemes { get; set; }
/// <summary>
/// Init the <see cref="HttpRequest"/>.
/// </summary>
/// <param name="record">The input record.</param>
public virtual void Init(IEdmRecordExpression record)
{
Utils.CheckArgumentNull(record, nameof(record));
// Description.
Description = record.GetString("Description");
// MethodDescription.
MethodDescription = record.GetString("MethodDescription");
// MethodType.
MethodType = record.GetString("MethodType");
// CustomQueryOptions
CustomQueryOptions = record.GetCollection<CustomParameter>("CustomQueryOptions", (s, r) => s.Init(r as IEdmRecordExpression));
// CustomHeaders
CustomHeaders = record.GetCollection<CustomParameter>("CustomHeaders", (s, r) => s.Init(r as IEdmRecordExpression));
// HttpResponses
HttpResponses = record.GetCollection<HttpResponse>("HttpResponses", (s, r) => s.Init(r as IEdmRecordExpression));
// SecuritySchemes
SecuritySchemes = record.GetCollection<SecurityScheme>("SecuritySchemes", (s, r) => s.Init(r as IEdmRecordExpression));
}
}
}

View file

@ -0,0 +1,100 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// Org.OData.Core.V1.HttpRequests
/// </summary>
internal class HttpRequestsAnnotation
{
/// <summary>
/// The Term type name.
/// </summary>
public virtual string QualifiedName => "Org.OData.Core.V1.HttpRequests";
/// <summary>
/// Gets the http request array.
/// </summary>
public IList<HttpRequest> Requests { get; private set; }
/// <summary>
/// Gets the Edm mode.
/// </summary>
public IEdmModel Model { get; }
/// <summary>
/// Gets the vocabulary annotatble.
/// </summary>
public IEdmVocabularyAnnotatable Target { get; }
/// <summary>
/// Initializes a new instance of <see cref="HttpRequestsAnnotation"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="target">The Edm annotation target.</param>
public HttpRequestsAnnotation(IEdmModel model, IEdmVocabularyAnnotatable target)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));
Model = model;
Target = target;
Initialize();
}
public HttpRequest GetRequest(string method)
{
if (Requests == null)
{
return null;
}
return Requests.FirstOrDefault(e => string.Equals(e.MethodType, method, System.StringComparison.OrdinalIgnoreCase));
}
protected virtual void Initialize()
{
IEdmVocabularyAnnotation annotation = Model.GetVocabularyAnnotation(Target, QualifiedName);
if (annotation == null)
{
IEdmNavigationSource navigationSource = Target as IEdmNavigationSource;
// if not, search the entity type.
if (navigationSource != null)
{
IEdmEntityType entityType = navigationSource.EntityType();
annotation = Model.GetVocabularyAnnotation(entityType, QualifiedName);
}
}
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Collection)
{
return;
}
IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value;
Requests = new List<HttpRequest>();
foreach (var item in collection.Elements)
{
IEdmRecordExpression record = (IEdmRecordExpression)item;
HttpRequest request = new HttpRequest();
request.Init(record);
Requests.Add(request);
}
}
}
}

View file

@ -0,0 +1,154 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
#if false
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// Org.OData.Core.V1.HttpRequests
/// </summary>
internal class HttpRequestsHelper
{
/// <summary>
/// The Term type name.
/// </summary>
public virtual string QualifiedName => "Org.OData.Core.V1.HttpRequests";
public IEdmTerm Term { get; private set; }
/// <summary>
/// Gets the http request array.
/// </summary>
public IDictionary<IEdmVocabularyAnnotatable, IList<HttpRequest> > Requests { get; private set; }
/// <summary>
/// Gets the Edm mode.
/// </summary>
public IEdmModel Model { get; }
/// <summary>
/// Initializes a new instance of <see cref="HttpRequestsAnnotation"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
public HttpRequestsHelper(IEdmModel model)
{
Utils.CheckArgumentNull(model, nameof(model));
Term = model.FindTerm(QualifiedName);
Model = model;
}
public HttpRequest GetRequest(string method)
{
if (Requests == null)
{
return null;
}
return Requests.FirstOrDefault(e => string.Equals(e.MethodType, method, System.StringComparison.OrdinalIgnoreCase));
}
protected virtual HttpRequest FindRequest(IEdmVocabularyAnnotatable target, string method)
{
if (Requests == null)
{
Requests = new Dictionary<IEdmVocabularyAnnotatable, IList<HttpRequest>>();
}
IEdmVocabularyAnnotatable newTarget = target;
IEdmNavigationSource navigationSource = target as IEdmNavigationSource;
if (navigationSource != null)
{
newTarget = navigationSource.EntityType();
}
if (Requests.TryGetValue(newTarget, out IList<HttpRequest> values))
{
return values.FirstOrDefault(e => string.Equals(e.MethodType, method, System.StringComparison.OrdinalIgnoreCase));
}
var annotations = Model.FindVocabularyAnnotations<IEdmVocabularyAnnotation>(target, Term);
if (annotations != null && annotations.Any())
{
}
}
protected virtual void Initialize()
{
IEdmVocabularyAnnotation annotation = Model.GetVocabularyAnnotation(Target, QualifiedName);
if (annotation == null)
{
IEdmNavigationSource navigationSource = Target as IEdmNavigationSource;
// if not, search the entity type.
if (navigationSource != null)
{
IEdmEntityType entityType = navigationSource.EntityType();
annotation = Model.GetVocabularyAnnotation(entityType, QualifiedName);
}
}
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Collection)
{
return;
}
IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value;
Requests = new List<HttpRequest>();
foreach (var item in collection.Elements)
{
IEdmRecordExpression record = (IEdmRecordExpression)item;
HttpRequest request = new HttpRequest();
request.Init(record);
Requests.Add(request);
}
}
protected virtual void Initialize()
{
IEdmVocabularyAnnotation annotation = Model.GetVocabularyAnnotation(Target, QualifiedName);
if (annotation == null)
{
IEdmNavigationSource navigationSource = Target as IEdmNavigationSource;
// if not, search the entity type.
if (navigationSource != null)
{
IEdmEntityType entityType = navigationSource.EntityType();
annotation = Model.GetVocabularyAnnotation(entityType, QualifiedName);
}
}
if (annotation == null ||
annotation.Value == null ||
annotation.Value.ExpressionKind != EdmExpressionKind.Collection)
{
return;
}
IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value;
Requests = new List<HttpRequest>();
foreach (var item in collection.Elements)
{
IEdmRecordExpression record = (IEdmRecordExpression)item;
HttpRequest request = new HttpRequest();
request.Init(record);
Requests.Add(request);
}
}
}
}
#endif

View file

@ -0,0 +1,57 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// The Org.OData.Core.v1.HttpResponse
/// </summary>
internal class HttpResponse
{
/// <summary>
/// Description.
/// </summary>
public string Description { get; set; }
/// <summary>
/// ResponseCode
/// </summary>
public string ResponseCode { get; set; }
/// <summary>
/// Examples
/// </summary>
public IEnumerable<Example> Examples { get; set; }
/// <summary>
/// Int the <see cref="HttpResponse"/>.
/// </summary>
/// <param name="record">The input record.</param>
public void Init(IEdmRecordExpression record)
{
// ResponseCode
ResponseCode = record.GetString("ResponseCode");
// Description
Description = record.GetString("Description");
// Examples
Examples = record.GetCollection("Examples", r =>
{
IEdmRecordExpression itemRecord = r as IEdmRecordExpression;
if (itemRecord != null)
{
return Example.CreateExample(itemRecord);
}
return null;
});
}
}
}

View file

@ -0,0 +1,33 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Annotations
{
/// <summary>
/// Complex type Org.OData.Core.V1.InlineExample
/// </summary>
internal class InlineExample : Example
{
/// <summary>
/// InlineValue
/// </summary>
public string InlineValue { get; set; }
/// <summary>
/// Init the <see cref="InlineExample"/>.
/// </summary>
/// <param name="record">The record.</param>
public override void Init(IEdmRecordExpression record)
{
base.Init(record);
// InlineValue
InlineValue = record.GetString("InlineValue");
}
}
}

View file

@ -0,0 +1,69 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Enum type KeyLocation
/// </summary>
internal enum KeyLocation
{
/// <summary>
/// API Key is passed in the header.
/// </summary>
Header,
/// <summary>
/// API Key is passed as a query option.
/// </summary>
QueryOption,
/// <summary>
/// API Key is passed as a cookie.
/// </summary>
Cookie
}
/// <summary>
/// Complex type 'Org.OData.Core.V1.ApiKey'
/// </summary>
internal class ApiKey : Authorization
{
/// <summary>
/// The name of the header or query parameter.
/// </summary>
public string KeyName { get; set; }
/// <summary>
/// Whether the API Key is passed in the header or as a query option.
/// </summary>
public KeyLocation? Location { get; set; }
/// <summary>
/// Gets the security scheme type.
/// </summary>
public override SecuritySchemeType SchemeType => SecuritySchemeType.ApiKey;
/// <summary>
/// Init <see cref="ApiKey"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// KeyName.
KeyName = record.GetString("KeyName");
// Location.
Location = record.GetEnum<KeyLocation>("Location");
}
}
}

View file

@ -0,0 +1,114 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Properties;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Abstract complex type 'Org.OData.Core.V1.Authorization'
/// </summary>
internal abstract class Authorization
{
/// <summary>
/// Name that can be used to reference the authorization flow.
/// </summary>
public string Name { get; set; }
/// <summary>
/// Description of the authorization method.
/// </summary>
public string Description { get; set; }
/// <summary>
/// Gets the security scheme type.
/// </summary>
public abstract SecuritySchemeType SchemeType { get; }
/// <summary>
/// Init the <see cref="Authorization"/>.
/// </summary>
/// <param name="record">The corresponding record.</param>
public virtual void Init(IEdmRecordExpression record)
{
Utils.CheckArgumentNull(record, nameof(record));
// Name.
Name = record.GetString("Name");
// Description.
Description = record.GetString("Description");
}
/// <summary>
/// Create the corresponding Authorization object.
/// </summary>
/// <param name="record">The input record.</param>
/// <returns>The created <see cref="Authorization"/> object.</returns>
public static Authorization CreateAuthorization(IEdmRecordExpression record)
{
if (record == null || record.DeclaredType == null)
{
return null;
}
IEdmComplexType complexType = record.DeclaredType.Definition as IEdmComplexType;
if (complexType == null)
{
return null;
}
Authorization auth = null;
switch (complexType.FullTypeName())
{
case AuthorizationConstants.OpenIDConnect: // OpenIDConnect
auth = new OpenIDConnect();
break;
case AuthorizationConstants.Http: // Http
auth = new Http();
break;
case AuthorizationConstants.ApiKey: // ApiKey
auth = new ApiKey();
break;
case AuthorizationConstants.OAuth2ClientCredentials: // OAuth2ClientCredentials
auth = new OAuth2ClientCredentials();
break;
case AuthorizationConstants.OAuth2Implicit: // OAuth2Implicit
auth = new OAuth2Implicit();
break;
case AuthorizationConstants.OAuth2Password: // OAuth2Password
auth = new OAuth2Password();
break;
case AuthorizationConstants.OAuth2AuthCode: // OAuth2AuthCode
auth = new OAuth2AuthCode();
break;
case AuthorizationConstants.OAuthAuthorization: // OAuthAuthorization
default:
throw new OpenApiException(String.Format(SRResource.AuthorizationRecordTypeNameNotCorrect, complexType.FullTypeName()));
}
if (auth != null)
{
auth.Init(record);
}
return auth;
}
}
}

View file

@ -0,0 +1,68 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Constant values for Authorization Vocabulary
/// </summary>
internal class AuthorizationConstants
{
/// <summary>
/// The namespace of Authorization annotation.
/// </summary>
public const string Namespace = "Org.OData.Authorization.V1";
/// <summary>
/// Term Org.OData.Authorization.V1.Authorizations
/// </summary>
public const string Authorizations = Namespace + ".Authorizations";
/// <summary>
/// Term Org.OData.Authorization.V1.SecuritySchemes
/// </summary>
public const string SecuritySchemes = Namespace + ".SecuritySchemes";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.OpenIDConnect
/// </summary>
public const string OpenIDConnect = Namespace + ".OpenIDConnect";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.Http
/// </summary>
public const string Http = Namespace + ".Http";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.ApiKey
/// </summary>
public const string ApiKey = Namespace + ".ApiKey";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.OAuth2ClientCredentials
/// </summary>
public const string OAuth2ClientCredentials = Namespace + ".OAuth2ClientCredentials";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.OAuth2Implicit
/// </summary>
public const string OAuth2Implicit = Namespace + ".OAuth2Implicit";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.OAuth2Password
/// </summary>
public const string OAuth2Password = Namespace + ".OAuth2Password";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.OAuth2AuthCode
/// </summary>
public const string OAuth2AuthCode = Namespace + ".OAuth2AuthCode";
/// <summary>
/// Complex type: Org.OData.Authorization.V1.OAuthAuthorization
/// </summary>
public const string OAuthAuthorization = Namespace + ".OAuthAuthorization";
}
}

View file

@ -0,0 +1,61 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Abstractions;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// The default 'Org.OData.Core.V1.Authorization' provider.
/// </summary>
internal class AuthorizationProvider
{
/// <summary>
/// Gets the <see cref="IAuthorization"/> collections for a given target in the given Edm model.
/// </summary>
/// <returns>The <see cref="IAuthorization"/> collections.</returns>
public virtual IEnumerable<Authorization> GetAuthorizations(IEdmModel model, IEdmVocabularyAnnotatable target)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));
// Retrieve it every time when it needed. Don't want to cache the result.
return RetrieveAuthorizations(model, target);
}
/// <summary>
/// Create the corresponding Authorization object.
/// </summary>
/// <param name="record">The input record.</param>
/// <returns>The created <see cref="Authorization"/> object.</returns>
private IEnumerable<Authorization> RetrieveAuthorizations(IEdmModel model, IEdmVocabularyAnnotatable target)
{
IEdmVocabularyAnnotation annotation = model.GetVocabularyAnnotation(target, AuthorizationConstants.Authorizations);
if (annotation != null && annotation.Value != null && annotation.Value.ExpressionKind == EdmExpressionKind.Collection)
{
IEdmCollectionExpression collection = (IEdmCollectionExpression)annotation.Value;
foreach (var item in collection.Elements)
{
IEdmRecordExpression record = item as IEdmRecordExpression;
if (record == null || record.DeclaredType == null)
{
continue;
}
Authorization auth = Authorization.CreateAuthorization(record);
if (auth != null)
{
yield return auth;
}
}
}
}
}
}

View file

@ -0,0 +1,42 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type 'Org.OData.Core.V1.AuthorizationScope'
/// </summary>
internal class AuthorizationScope
{
/// <summary>
/// Scope name.
/// </summary>
public string Scope { get; set; }
/// <summary>
/// Description of the scope.
/// </summary>
public string Description { get; set; }
/// <summary>
/// Init the <see cref="AuthorizationScope"/>.
/// </summary>
/// <param name="record">The corresponding record.</param>
public virtual void Init(IEdmRecordExpression record)
{
Utils.CheckArgumentNull(record, nameof(record));
// Scope.
Scope = record.GetString("Scope");
// Description.
Description = record.GetString("Description");
}
}
}

View file

@ -0,0 +1,48 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type 'Org.OData.Core.V1.Http'
/// </summary>
internal class Http : Authorization
{
/// <summary>
/// HTTP Authorization scheme to be used in the Authorization header, as per RFC7235.
/// </summary>
public string Scheme { get; set; }
/// <summary>
/// Format of the bearer token.
/// </summary>
public string BearerFormat { get; set; }
/// <summary>
/// Gets the security scheme type.
/// </summary>
public override SecuritySchemeType SchemeType => SecuritySchemeType.Http;
/// <summary>
/// Init <see cref="Http"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// Scheme
Scheme = record.GetString("Scheme");
// BearerFormat
BearerFormat = record.GetString("BearerFormat");
}
}
}

View file

@ -0,0 +1,47 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type 'Org.OData.Core.V1.OAuth2AuthCode'.
/// </summary>
internal class OAuth2AuthCode : OAuthAuthorization
{
/// <summary>
/// Authorization URL.
/// </summary>
public string AuthorizationUrl { get; set; }
/// <summary>
/// Token Url.
/// </summary>
public string TokenUrl { get; set; }
/// <summary>
/// Gets the OAuth2 type.
/// </summary>
public override OAuth2Type OAuth2Type => OAuth2Type.AuthCode;
/// <summary>
/// Init <see cref="OAuth2AuthCode"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// AuthorizationUrl
AuthorizationUrl = record.GetString("AuthorizationUrl");
// TokenUrl
TokenUrl = record.GetString("TokenUrl");
}
}
}

View file

@ -0,0 +1,39 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type 'Org.OData.Core.V1.OAuth2ClientCredentials'
/// </summary>
internal class OAuth2ClientCredentials : OAuthAuthorization
{
/// <summary>
/// Token Url.
/// </summary>
public string TokenUrl { get; set; }
/// <summary>
/// Gets the OAuth2 type.
/// </summary>
public override OAuth2Type OAuth2Type => OAuth2Type.ClientCredentials;
/// <summary>
/// Init <see cref="OAuth2ClientCredentials"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// TokenUrl
TokenUrl = record.GetString("TokenUrl");
}
}
}

View file

@ -0,0 +1,39 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type 'Org.OData.Core.V1.OAuth2Implicit'
/// </summary>
internal class OAuth2Implicit : OAuthAuthorization
{
/// <summary>
/// Authorization URL.
/// </summary>
public string AuthorizationUrl { get; set; }
/// <summary>
/// Gets the OAuth2 type.
/// </summary>
public override OAuth2Type OAuth2Type => OAuth2Type.Implicit;
/// <summary>
/// Init <see cref="OAuth2Implicit"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// AuthorizationUrl
AuthorizationUrl = record.GetString("AuthorizationUrl");
}
}
}

View file

@ -0,0 +1,39 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type 'Org.OData.Core.V1.OAuth2Password'
/// </summary>
internal class OAuth2Password : OAuthAuthorization
{
/// <summary>
/// Token Url.
/// </summary>
public string TokenUrl { get; set; }
/// <summary>
/// Gets the OAuth2 type.
/// </summary>
public override OAuth2Type OAuth2Type => OAuth2Type.Pasword;
/// <summary>
/// Init <see cref="OAuth2Password"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// TokenUrl
TokenUrl = record.GetString("TokenUrl");
}
}
}

View file

@ -0,0 +1,80 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// OAuth2 type kind.
/// </summary>
internal enum OAuth2Type
{
/// <summary>
/// ClientCredentials
/// </summary>
ClientCredentials,
/// <summary>
/// Implicit
/// </summary>
Implicit,
/// <summary>
/// Pasword
/// </summary>
Pasword,
/// <summary>
/// AuthCode
/// </summary>
AuthCode
}
/// <summary>
/// Abstract complex type 'Org.OData.Core.V1.OAuthAuthorization'
/// </summary>
internal abstract class OAuthAuthorization : Authorization
{
/// <summary>
/// Available scopes.
/// </summary>
public IList<AuthorizationScope> Scopes { get; set; }
/// <summary>
/// Refresh Url
/// </summary>
public string RefreshUrl { get; set; }
/// <summary>
/// Gets the security scheme type.
/// </summary>
public override SecuritySchemeType SchemeType => SecuritySchemeType.OAuth2;
/// <summary>
/// Gets the OAuth2 type.
/// </summary>
public abstract OAuth2Type OAuth2Type { get; }
/// <summary>
/// Init <see cref="OAuthAuthorization"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// Scopes
Scopes = record.GetCollection<AuthorizationScope>("Scopes", (s, item) => s.Init(item as IEdmRecordExpression));
// RefreshUrl
RefreshUrl = record.GetString("RefreshUrl");
}
}
}

View file

@ -0,0 +1,41 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type 'Org.OData.Core.V1.OpenIDConnect'
/// </summary>
internal class OpenIDConnect : Authorization
{
/// <summary>
/// Issuer location for the OpenID Provider.
/// Configuration information can be obtained by appending `/.well-known/openid-configuration` to this Url.
/// </summary>
public string IssuerUrl { get; set; }
/// <summary>
/// Gets the security scheme type.
/// </summary>
public override SecuritySchemeType SchemeType => SecuritySchemeType.OpenIdConnect;
/// <summary>
/// Init <see cref="OpenIDConnect"/>.
/// </summary>
/// <param name="record">the input record.</param>
public override void Init(IEdmRecordExpression record)
{
// base checked.
base.Init(record);
// IssuerUrl
IssuerUrl = record.GetString("IssuerUrl");
}
}
}

View file

@ -0,0 +1,43 @@
// -----------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Authorizations
{
/// <summary>
/// Complex type Org.OData.Core.V1.SecurityScheme
/// </summary>
internal class SecurityScheme
{
/// <summary>
/// The name of a required authorization scheme.
/// </summary>
public string AuthorizationSchemeName { get; set; }
/// <summary>
/// The names of scopes required from this authorization scheme.
/// </summary>
public IList<string> RequiredScopes { get; set; }
/// <summary>
/// Init the <see cref="SecurityScheme"/>.
/// </summary>
/// <param name="record">The input record.</param>
public void Init(IEdmRecordExpression record)
{
Utils.CheckArgumentNull(record, nameof(record));
// AuthorizationSchemeName
AuthorizationSchemeName = record.GetString("AuthorizationSchemeName");
// RequiredScopes
RequiredScopes = record.GetCollection("RequiredScopes");
}
}
}

View file

@ -3,7 +3,7 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
namespace Microsoft.OpenApi.OData.Generator
namespace Microsoft.OpenApi.OData.Common
{
/// <summary>
/// Constant strings
@ -31,8 +31,28 @@ namespace Microsoft.OpenApi.OData.Generator
public static string StatusCode204 = "204";
/// <summary>
/// Status code: 204
/// Status code: default
/// </summary>
public static string StatusCodeDefault = "default";
/// <summary>
/// extension for toc (table of content) type
/// </summary>
public static string xMsTocType = "x-ms-docs-toc-type";
/// <summary>
/// extension for key type
/// </summary>
public static string xMsKeyType = "x-ms-docs-key-type";
/// <summary>
/// extension for operation type
/// </summary>
public static string xMsDosOperationType = "x-ms-docs-operation-type";
/// <summary>
/// extension for group type
/// </summary>
public static string xMsDosGroupPath = "x-ms-docs-grouped-path";
}
}

View file

@ -7,7 +7,7 @@ using System;
using System.Globalization;
using Microsoft.OpenApi.OData.Properties;
namespace Microsoft.OpenApi.OData
namespace Microsoft.OpenApi.OData.Common
{
/// <summary>
/// Utility class for creating and unwrapping <see cref="Exception"/> instances.
@ -80,6 +80,29 @@ namespace Microsoft.OpenApi.OData
return Error.Argument(parameterName, SRResource.ArgumentNullOrEmpty, parameterName);
}
/// <summary>
/// Creates an <see cref="InvalidOperationException"/>.
/// </summary>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static InvalidOperationException InvalidOperation(string messageFormat, params object[] messageArgs)
{
return new InvalidOperationException(Error.Format(messageFormat, messageArgs));
}
/// <summary>
/// Creates an <see cref="InvalidOperationException"/>.
/// </summary>
/// <param name="innerException">Inner exception</param>
/// <param name="messageFormat">A composite format string explaining the reason for the exception.</param>
/// <param name="messageArgs">An object array that contains zero or more objects to format.</param>
/// <returns>The logged <see cref="Exception"/>.</returns>
internal static InvalidOperationException InvalidOperation(Exception innerException, string messageFormat, params object[] messageArgs)
{
return new InvalidOperationException(Error.Format(messageFormat, messageArgs), innerException);
}
/// <summary>
/// Creates an <see cref="NotSupportedException"/>.
/// </summary>

View file

@ -12,6 +12,22 @@ namespace Microsoft.OpenApi.OData.Common
/// </summary>
public static class Utils
{
/// <summary>
/// Upper the first character of the string.
/// </summary>
/// <param name="input">The input string.</param>
/// <returns>The changed string.</returns>
public static string UpperFirstChar(string input)
{
if (input == null)
{
return input;
}
char first = Char.ToUpper(input[0]);
return first + input.Substring(1);
}
/// <summary>
/// Check the input argument whether its value is null or not.
/// </summary>
@ -28,5 +44,21 @@ namespace Microsoft.OpenApi.OData.Common
return value;
}
/// <summary>
/// Check the input string null or empty.
/// </summary>
/// <param name="value">The input string</param>
/// <param name="parameterName">The input parameter name.</param>
/// <returns>The input value.</returns>
internal static string CheckArgumentNullOrEmpty(string value, string parameterName)
{
if (String.IsNullOrEmpty(value))
{
throw Error.ArgumentNullOrEmpty(parameterName);
}
return value;
}
}
}

View file

@ -0,0 +1,150 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Extension methods for <see cref="IEdmModel"/>
/// </summary>
public static class EdmModelExtensions
{
/// <summary>
/// Gets the vocabulary annotation from a target annotatable.
/// </summary>
/// <param name="model">The model referenced to.</param>
/// <param name="target">The target Annotatable to find annotation</param>
/// <returns>The annotation or null.</returns>
public static IEdmVocabularyAnnotation GetVocabularyAnnotation(this IEdmModel model, IEdmVocabularyAnnotatable target, string qualifiedName)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));
Utils.CheckArgumentNull(qualifiedName, nameof(qualifiedName));
IEdmTerm term = model.FindTerm(qualifiedName);
if (term != null)
{
IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations<IEdmVocabularyAnnotation>(target, term).FirstOrDefault();
if (annotation != null)
{
return annotation;
}
}
return null;
}
/// <summary>
/// Gets the vocabulary annotation from a target annotatable.
/// </summary>
/// <param name="model">The model referenced to.</param>
/// <param name="target">The target Annotatable to find annotation</param>
/// <returns>The annotation or null.</returns>
public static IEdmVocabularyAnnotation GetVocabularyAnnotation(this IEdmModel model, IEdmVocabularyAnnotatable target, IEdmTerm term)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(target, nameof(target));
Utils.CheckArgumentNull(term, nameof(term));
IEdmVocabularyAnnotation annotation = model.FindVocabularyAnnotations<IEdmVocabularyAnnotation>(target, term).FirstOrDefault();
if (annotation != null)
{
return annotation;
}
return null;
}
/// <summary>
/// Checks if the <paramref name="baseType"/> is assignable to <paramref name="subtype"/>.
/// In other words, if <paramref name="subtype"/> is a subtype of <paramref name="baseType"/> or not.
/// </summary>
/// <param name="baseType">Type of the base type.</param>
/// <param name="subtype">Type of the sub type.</param>
/// <returns>true, if the <paramref name="baseType"/> is assignable to <paramref name="subtype"/>. Otherwise returns false.</returns>
public static bool IsAssignableFrom(this IEdmEntityType baseType, IEdmEntityType subtype)
{
Utils.CheckArgumentNull(baseType, nameof(baseType));
Utils.CheckArgumentNull(subtype, nameof(subtype));
if (baseType.TypeKind != subtype.TypeKind)
{
return false;
}
if (subtype.IsEquivalentTo(baseType))
{
return true;
}
IEdmStructuredType structuredSubType = subtype;
while (structuredSubType != null)
{
if (structuredSubType.IsEquivalentTo(baseType))
{
return true;
}
structuredSubType = structuredSubType.BaseType;
}
return false;
}
/// <summary>
/// Check whether the operaiton is overload in the model.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="operation">The test operations.</param>
/// <returns>True/false.</returns>
public static bool IsOperationOverload(this IEdmModel model, IEdmOperation operation)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(operation, nameof(operation));
return model.SchemaElements.OfType<IEdmOperation>()
.Where(o => o.IsBound == operation.IsBound && o.FullName() == operation.FullName() &&
o.Parameters.First().Type.Definition == operation.Parameters.First().Type.Definition
).Count() > 1;
}
public static bool IsOperationOverload(this IEdmModel model, IEdmOperationImport operationImport)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(operationImport, nameof(operationImport));
if (model.EntityContainer == null)
{
return false;
}
return model.EntityContainer.OperationImports()
.Where(o => o.Operation.IsBound == operationImport.Operation.IsBound && o.Name == operationImport.Name).Count() > 1;
}
public static bool IsNavigationTypeOverload(this IEdmModel model, IEdmEntityType entityType, IEdmNavigationProperty navigationProperty)
{
Utils.CheckArgumentNull(model, nameof(model));
Utils.CheckArgumentNull(entityType, nameof(entityType));
Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty));
int count = 0;
IEdmEntityType nvaEntityType = navigationProperty.ToEntityType();
foreach(var np in entityType.DeclaredNavigationProperties())
{
if (np.ToEntityType() == nvaEntityType)
{
count++;
}
}
return count == 0;
}
}
}

View file

@ -0,0 +1,236 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Abstractions;
using Microsoft.OpenApi.OData.Annotations;
using Microsoft.OpenApi.OData.Authorizations;
using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
using Microsoft.OpenApi.OData.Operation;
using Microsoft.OpenApi.OData.PathItem;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Context information for the <see cref="IEdmModel"/>, configuration, etc.
/// </summary>
internal class ODataContext
{
private IDictionary<IEdmTypeReference, IEdmOperation> _boundOperations;
private bool _keyAsSegmentSupported = false;
private IList<OpenApiTag> _tags = new List<OpenApiTag>();
private ODataPathHandler _pathHandler;
/// <summary>
/// Initializes a new instance of <see cref="ODataContext"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
public ODataContext(IEdmModel model)
: this(model, new OpenApiConvertSettings())
{
}
/// <summary>
/// Initializes a new instance of <see cref="ODataContext"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="settings">The convert setting.</param>
public ODataContext(IEdmModel model, OpenApiConvertSettings settings)
{
Model = model ?? throw Error.ArgumentNull(nameof(model));
Settings = settings ?? throw Error.ArgumentNull(nameof(settings));
EdmModelVisitor visitor = new EdmModelVisitor();
visitor.Visit(model);
IsSpatialTypeUsed = visitor.IsSpatialTypeUsed;
_keyAsSegmentSupported = settings.KeyAsSegment ?? model.GetKeyAsSegmentSupported();
_pathHandler = new ODataPathHandler(this);
OperationHanderProvider = new OperationHandlerProvider();
PathItemHanderProvider = new PathItemHandlerProvider();
AuthorizationProvider = new AuthorizationProvider();
}
public IPathItemHandlerProvider PathItemHanderProvider { get; }
public IOperationHandlerProvider OperationHanderProvider { get; }
/// <summary>
/// Gets the <see cref="IAuthorizationProvider"/> to provider the authorization.
/// </summary>
public AuthorizationProvider AuthorizationProvider { get; }
/// <summary>
/// Gets the Edm model.
/// </summary>
public IEdmModel Model { get; }
/// <summary>
/// Gets the Entity Container.
/// </summary>
public IEdmEntityContainer EntityContainer
{
get
{
return Model.EntityContainer;
}
}
/// <summary>
/// Gets the <see cref="ODataPath"/>s.
/// </summary>
public IList<ODataPath> Paths => _pathHandler.Paths;
/// <summary>
/// Gets the boolean value indicating to support key as segment.
/// </summary>
public bool KeyAsSegment => _keyAsSegmentSupported;
/// <summary>
/// Gets the value indicating the Edm spatial type used.
/// </summary>
public bool IsSpatialTypeUsed { get; private set; }
/// <summary>
/// Gets the convert settings.
/// </summary>
public OpenApiConvertSettings Settings { get; }
/// <summary>
/// Gets the bound operations (functions & actions).
/// </summary>
public IDictionary<IEdmTypeReference, IEdmOperation> BoundOperations
{
get
{
if (_boundOperations == null)
{
GenerateBoundOperations();
}
return _boundOperations;
}
}
/// <summary>
/// Finds the operations using the <see cref="IEdmEntityType"/>
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="entityType">The entity type.</param>
/// <param name="collection">The collection flag.</param>
/// <returns>The found operations.</returns>
public IEnumerable<Tuple<IEdmEntityType, IEdmOperation>> FindOperations(IEdmEntityType entityType, bool collection)
{
Utils.CheckArgumentNull(entityType, nameof(entityType));
string fullTypeName = collection ?
"Collection(" + entityType.FullName() + ")" :
entityType.FullName();
foreach (var item in BoundOperations)
{
IEdmEntityType operationBindingType;
if (collection)
{
if (!item.Key.IsCollection())
{
continue;
}
operationBindingType = item.Key.AsCollection().ElementType().AsEntity().EntityDefinition();
}
else
{
if (item.Key.IsCollection())
{
continue;
}
operationBindingType = item.Key.AsEntity().EntityDefinition();
}
if (entityType.IsAssignableFrom(operationBindingType))
{
yield return Tuple.Create(operationBindingType, item.Value);
}
}
}
private IDictionary<IEdmVocabularyAnnotatable, HttpRequestsAnnotation> _requests;
public HttpRequest FindRequest(IEdmVocabularyAnnotatable target, string method)
{
if (_requests == null)
{
_requests = new Dictionary<IEdmVocabularyAnnotatable, HttpRequestsAnnotation>();
}
if (!_requests.TryGetValue(target, out HttpRequestsAnnotation value))
{
value = new HttpRequestsAnnotation(Model, target);
_requests.Add(target, value);
}
return value.GetRequest(method);
}
private void GenerateBoundOperations()
{
if (_boundOperations != null)
{
return;
}
_boundOperations = new Dictionary<IEdmTypeReference, IEdmOperation>();
foreach (var edmOperation in Model.SchemaElements.OfType<IEdmOperation>().Where(e => e.IsBound))
{
IEdmOperationParameter bindingParameter = edmOperation.Parameters.First();
_boundOperations.Add(bindingParameter.Type, edmOperation);
}
}
public IList<OpenApiTag> Tags
{
get
{
return _tags;
}
}
public void AppendTag(OpenApiTag tagItem)
{
if (_tags.Any(c => c.Name == tagItem.Name))
{
return;
}
_tags.Add(tagItem);
}
private IDictionary<string, int> _cached1 = new Dictionary<string, int>();
public int GetIndex(string source)
{
if (_cached1.TryGetValue(source, out int value))
{
_cached1[source]++;
return _cached1[source];
}
else
{
_cached1[source] = 0;
return 0;
}
}
}
}

View file

@ -0,0 +1,53 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// The key segment.
/// </summary>
public class ODataKeySegment : ODataSegment
{
/// <summary>
/// Initializes a new instance of <see cref="ODataKeySegment"/> class.
/// </summary>
/// <param name="entityType">The entity type contains the keys.</param>
public ODataKeySegment(IEdmEntityType entityType)
{
EntityType = entityType ?? throw Error.ArgumentNull(nameof(entityType));
}
/// <inheritdoc />
public override IEdmEntityType EntityType { get; }
/// <inheritdoc />
public override string Name => throw new NotImplementedException();
/// <inheritdoc />
public override string ToString()
{
IList<IEdmStructuralProperty> keys = EntityType.Key().ToList();
if (keys.Count() == 1)
{
return "{" + keys.First().Name + "}";
}
else
{
IList<string> keyStrings = new List<string>();
foreach (var keyProperty in keys)
{
keyStrings.Add(keyProperty.Name + "={" + keyProperty.Name + "}");
}
return "{" + String.Join(",", keyStrings) + "}";
}
}
}
}

View file

@ -0,0 +1,42 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Navigation property segment.
/// </summary>
public class ODataNavigationPropertySegment : ODataSegment
{
/// <summary>
/// Initializes a new instance of <see cref="ODataNavigationPropertySegment"/> class.
/// </summary>
/// <param name="navigationProperty"></param>
public ODataNavigationPropertySegment(IEdmNavigationProperty navigationProperty)
{
NavigationProperty = navigationProperty ?? throw Error.ArgumentNull(nameof(navigationProperty));
}
/// <summary>
/// Gets the navigation property.
/// </summary>
public IEdmNavigationProperty NavigationProperty { get; }
/// <inheritdoc />
public override IEdmEntityType EntityType => NavigationProperty.ToEntityType();
/// <inheritdoc />
public override string Name => NavigationProperty.Name;
/// <inheritdoc />
public override string ToString()
{
return NavigationProperty.Name;
}
}
}

View file

@ -0,0 +1,42 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Navigation source (entity set or singleton) segment.
/// </summary>
public class ODataNavigationSourceSegment : ODataSegment
{
/// <summary>
/// Initializes a new instance of <see cref="ODataNavigationSourceSegment"/> class.
/// </summary>
/// <param name="navigaitonSource">The navigation source.</param>
public ODataNavigationSourceSegment(IEdmNavigationSource navigaitonSource)
{
NavigationSource = navigaitonSource ?? throw Error.ArgumentNull(nameof(navigaitonSource));
}
/// <summary>
/// Gets the navigation source.
/// </summary>
public IEdmNavigationSource NavigationSource { get; }
/// <inheritdoc />
public override IEdmEntityType EntityType => NavigationSource.EntityType();
/// <inheritdoc />
public override string Name => NavigationSource.Name;
/// <inheritdoc />
public override string ToString()
{
return NavigationSource.Name;
}
}
}

View file

@ -0,0 +1,42 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Operation import segment.
/// </summary>
public class ODataOperationImportSegment : ODataSegment
{
/// <summary>
/// Initializes a new instance of <see cref="ODataOperationImportSegment"/> class.
/// </summary>
/// <param name="operationImport">The operation import.</param>
public ODataOperationImportSegment(IEdmOperationImport operationImport)
{
OperationImport = operationImport ?? throw Error.ArgumentNull(nameof(operationImport));
}
/// <summary>
/// Gets the operation import.
/// </summary>
public IEdmOperationImport OperationImport { get; }
/// <inheritdoc />
public override IEdmEntityType EntityType => throw new System.NotImplementedException();
/// <inheritdoc />
public override string Name => OperationImport.Name;
/// <inheritdoc />
public override string ToString()
{
return OperationImport.Name;
}
}
}

View file

@ -0,0 +1,110 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Linq;
using System.Text;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Operation segment
/// </summary>
public class ODataOperationSegment : ODataSegment
{
/// <summary>
/// Initializes a new instance of <see cref="ODataOperationSegment"/> class.
/// </summary>
/// <param name="operation">The operation.</param>
public ODataOperationSegment(IEdmOperation operation)
: this(operation, true)
{ }
/// <summary>
/// Initializes a new instance of <see cref="ODataOperationSegment"/> class.
/// </summary>
/// <param name="operation">The operation.</param>
/// <param name="unqualifiedCall">The unqualified call.</param>
public ODataOperationSegment(IEdmOperation operation, bool unqualifiedCall)
{
Operation = operation ?? throw Error.ArgumentNull(nameof(operation));
UnqualifiedCall = unqualifiedCall;
}
/// <summary>
/// Gets the operation.
/// </summary>
public IEdmOperation Operation { get; }
/// <summary>
/// Gets the unqualified call.
/// </summary>
public bool UnqualifiedCall { get; }
/// <inheritdoc />
public override string Name => Operation.Name;
/// <inheritdoc />
public override IEdmEntityType EntityType => throw new NotImplementedException();
/// <inheritdoc />
public override string ToString()
{
if (Operation.IsFunction())
{
return FunctionName(Operation as IEdmFunction);
}
return ActionName(Operation as IEdmAction);
}
private string FunctionName(IEdmFunction function)
{
StringBuilder functionName = new StringBuilder();
if (UnqualifiedCall)
{
functionName.Append(function.Name);
}
else
{
functionName.Append(function.FullName());
}
functionName.Append("(");
// Structured or collection-valued parameters are represented as a parameter alias in the path template
// and the parameters array contains a Parameter Object for the parameter alias as a query option of type string.
int skip = function.IsBound ? 1 : 0;
functionName.Append(String.Join(",", function.Parameters.Skip(skip).Select(p =>
{
if (p.Type.IsStructured() || p.Type.IsCollection())
{
return p.Name + "=@" + p.Name;
}
else
{
return p.Name + "={" + p.Name + "}";
}
})));
functionName.Append(")");
return functionName.ToString();
}
private string ActionName(IEdmAction action)
{
if (UnqualifiedCall)
{
return action.Name;
}
else
{
return action.FullName();
}
}
}
}

View file

@ -0,0 +1,217 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Describes an OData path.
/// </summary>
public class ODataPath : IEnumerable<ODataSegment>
{
private ODataPathType? _pathType;
/// <summary>
/// Initializes a new instance of <see cref="ODataPath"/> class.
/// </summary>
/// <param name="segments">The segments.</param>
public ODataPath(IEnumerable<ODataSegment> segments)
{
Segments = segments.ToList();
if (Segments.Any(s => s == null))
{
throw Error.ArgumentNull("segments");
}
}
/// <summary>
/// Creates a new instance of <see cref="ODataPath"/> containing the given segments.
/// </summary>
/// <param name="segments">The segments that make up the path.</param>
/// <exception cref="ArgumentNullException">Throws if input segments is null.</exception>
public ODataPath(params ODataSegment[] segments)
: this((IEnumerable<ODataSegment>)segments)
{
}
/// <summary>
/// Gets the segments.
/// </summary>
public IList<ODataSegment> Segments { get; private set; }
/// <summary>
/// Pop the last segment.
/// </summary>
/// <returns>The pop last segment.</returns>
public ODataSegment Pop()
{
if (!Segments.Any())
{
throw Error.InvalidOperation("Pop a segment is invalid. The segments in the path is empty.");
}
ODataSegment segment = Segments.Last();
Segments.RemoveAt(Segments.Count - 1);
return segment;
}
/// <summary>
/// Push a segment to the last.
/// </summary>
/// <param name="segment">The pushed segment.</param>
/// <returns>The whole path object.</returns>
public ODataPath Push(ODataSegment segment)
{
if (Segments == null)
{
Segments = new List<ODataSegment>();
}
Segments.Add(segment);
return this;
}
/// <summary>
/// Gets the first segment in the path. Returns null if the path is empty.
/// </summary>
public ODataSegment FirstSegment
{
get
{
return this.Segments.Count == 0 ? null : this.Segments[0];
}
}
/// <summary>
/// Get the last segment in the path. Returns null if the path is empty.
/// </summary>
public ODataSegment LastSegment
{
get
{
return this.Segments.Count == 0 ? null : this.Segments[this.Segments.Count - 1];
}
}
/// <summary>
/// Get the number of segments in this path.
/// </summary>
public int Count
{
get { return this.Segments.Count; }
}
/// <summary>
/// Get the segments enumerator
/// </summary>
/// <returns>The segments enumerator</returns>
public IEnumerator<ODataSegment> GetEnumerator()
{
return this.Segments.GetEnumerator();
}
/// <summary>
/// Get the segments enumerator
/// </summary>
/// <returns>The segments enumerator.</returns>
IEnumerator IEnumerable.GetEnumerator()
{
return this.GetEnumerator();
}
/// <summary>
/// Clone a new ODataPath object.
/// </summary>
/// <returns>The new ODataPath.</returns>
public ODataPath Clone()
{
return new ODataPath(Segments);
}
/// <summary>
/// Get the segment count.
/// </summary>
/// <param name="keySegmentAsDepth">A bool value indicating whether to count key segment or not.</param>
/// <returns>The count.</returns>
public int GetCount(bool keySegmentAsDepth)
{
return Segments.Count(c => keySegmentAsDepth ? true : !(c is ODataKeySegment));
}
/// <summary>
/// Output the path string.
/// </summary>
/// <returns>The string.</returns>
public override string ToString()
{
return "/" + String.Join("/", Segments);
}
internal ODataPathType PathType
{
get
{
if (_pathType == null)
{
CalcPathType();
}
return _pathType.Value;
}
}
private void CalcPathType()
{
if (Segments.Any(c => c is ODataNavigationPropertySegment))
{
_pathType = ODataPathType.NavigationProperty;
return;
}
else if (Segments.Any(c => c is ODataOperationImportSegment))
{
_pathType = ODataPathType.OperationImport;
return;
}
else if (Segments.Any(c => c is ODataOperationSegment))
{
_pathType = ODataPathType.Operation;
return;
}
if (Segments.Count == 1)
{
ODataNavigationSourceSegment segment = Segments[0] as ODataNavigationSourceSegment;
if (segment == null)
{
throw Error.ArgumentNull("segment");
}
if (segment.NavigationSource is IEdmSingleton)
{
_pathType = ODataPathType.Singleton;
}
else
{
_pathType = ODataPathType.EntitySet;
}
}
else
{
if (Segments.Count != 2)
{
throw Error.InvalidOperation("Calc the path type wrong!");
}
_pathType = ODataPathType.Entity;
}
}
}
}

View file

@ -0,0 +1,269 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Helper class for <see cref="ODataPath"/> generating.
/// </summary>
internal class ODataPathHandler
{
private IList<ODataPath> _paths = null;
/// <summary>
/// Gets the OData Context
/// </summary>
public ODataContext Context { get; }
/// <summary>
/// Gets the <see cref="ODataPath"/>s.
/// </summary>
public IList<ODataPath> Paths => GeneratePaths();
/// <summary>
/// Initializes a new instance of <see cref="ODataPathHandler"/> class.
/// </summary>
/// <param name="context">The OData context.</param>
public ODataPathHandler(ODataContext context)
{
Context = context ?? throw Error.ArgumentNull(nameof(context));
}
/// <summary>
/// Generate the <see cref="ODataPath"/> from <see cref="IEdmModel"/> and <see cref="OpenApiConvertSettings"/>.
/// </summary>
/// <returns>The generated paths.</returns>
private IList<ODataPath> GeneratePaths()
{
if (_paths != null)
{
return _paths;
}
_paths = new List<ODataPath>();
if (Context.Model.EntityContainer == null)
{
return _paths;
}
// entity set
foreach (IEdmEntitySet entitySet in Context.Model.EntityContainer.EntitySets())
{
RetrieveNavigationSourcePaths(entitySet);
if (Context.Settings.EnableOperationPath)
{
RetrieveOperationPaths(entitySet);
}
}
// singleton
foreach (IEdmSingleton singleton in Context.Model.EntityContainer.Singletons())
{
RetrieveNavigationSourcePaths(singleton);
if (Context.Settings.EnableOperationPath)
{
RetrieveOperationPaths(singleton);
}
}
// operation import
if (Context.Settings.EnableOperationImportPath)
{
foreach (IEdmOperationImport import in Context.Model.EntityContainer.OperationImports())
{
_paths.Add(new ODataPath(new ODataOperationImportSegment(import)));
}
}
return _paths;
}
/// <summary>
/// Retrieve the path for <see cref="IEdmNavigationSource"/>.
/// </summary>
/// <param name="navigationSource">The navigation source.</param>
private void RetrieveNavigationSourcePaths(IEdmNavigationSource navigationSource)
{
Debug.Assert(navigationSource != null);
// navigation source itself
ODataPath path = new ODataPath();
path.Push(new ODataNavigationSourceSegment(navigationSource));
_paths.Add(path.Clone());
IEdmEntitySet entitySet = navigationSource as IEdmEntitySet;
IEdmEntityType entityType = navigationSource.EntityType();
// for entity set, create a path with key
if (entitySet != null)
{
path.Push(new ODataKeySegment(entityType));
_paths.Add(path.Clone());
}
// navigation property
if (Context.Settings.EnableNavigationPropertyPath)
{
foreach (IEdmNavigationProperty np in entityType.DeclaredNavigationProperties())
{
RetrieveNavigationPropertyPaths(np, path);
}
}
if (entitySet != null)
{
path.Pop(); // end of entity
}
path.Pop(); // end of navigation source.
Debug.Assert(path.Any() == false);
}
/// <summary>
/// Retrieve the path for <see cref="IEdmNavigationProperty"/>.
/// </summary>
/// <param name="navigationProperty">The navigation property.</param>
/// <param name="currentPath">The current OData path.</param>
private void RetrieveNavigationPropertyPaths(IEdmNavigationProperty navigationProperty, ODataPath currentPath)
{
Debug.Assert(navigationProperty != null);
Debug.Assert(currentPath != null);
int count = currentPath.GetCount(Context.Settings.CountKeySegmentAsDepth);
if (count > Context.Settings.NavigationPropertyDepth)
{
return;
}
bool shouldExpand = ShouldExpandNavigationProperty(navigationProperty, currentPath);
// append a navigation property.
currentPath.Push(new ODataNavigationPropertySegment(navigationProperty));
_paths.Add(currentPath.Clone());
// append a navigation property key.
IEdmEntityType navEntityType = navigationProperty.ToEntityType();
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
currentPath.Push(new ODataKeySegment(navEntityType));
_paths.Add(currentPath.Clone());
}
if (shouldExpand)
{
foreach (IEdmNavigationProperty subNavProperty in navEntityType.DeclaredNavigationProperties())
{
RetrieveNavigationPropertyPaths(subNavProperty, currentPath);
}
}
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
currentPath.Pop();
}
currentPath.Pop();
}
/// <summary>
/// Retrieve the <see cref="IEdmOperation"/> path for <see cref="IEdmNavigationSource"/>.
/// </summary>
/// <param name="navigationSource">The navigation source.</param>
private void RetrieveOperationPaths(IEdmNavigationSource navigationSource)
{
Debug.Assert(navigationSource != null);
IEnumerable<Tuple<IEdmEntityType, IEdmOperation>> operations;
IEdmEntitySet entitySet = navigationSource as IEdmEntitySet;
ODataPath path = new ODataPath(new ODataNavigationSourceSegment(navigationSource));
if (entitySet != null)
{
operations = Context.FindOperations(navigationSource.EntityType(), collection: true);
foreach (var operation in operations)
{
// Append the type cast
if (!operation.Item1.IsEquivalentTo(navigationSource.EntityType()))
{
path.Push(new ODataTypeCastSegment(operation.Item1));
path.Push(new ODataOperationSegment(operation.Item2, Context.Settings.UnqualifiedCall));
_paths.Add(path.Clone());
path.Pop();
path.Pop();
}
else
{
path.Push(new ODataOperationSegment(operation.Item2, Context.Settings.UnqualifiedCall));
_paths.Add(path.Clone());
path.Pop();
}
}
}
// for single
if (entitySet != null)
{
path.Push(new ODataKeySegment(navigationSource.EntityType()));
}
operations = Context.FindOperations(navigationSource.EntityType(), collection: false);
foreach (var operation in operations)
{
// Append the type cast
if (!operation.Item1.IsEquivalentTo(navigationSource.EntityType()))
{
path.Push(new ODataTypeCastSegment(operation.Item1));
path.Push(new ODataOperationSegment(operation.Item2, Context.Settings.UnqualifiedCall));
_paths.Add(path.Clone());
path.Pop();
path.Pop();
}
else
{
path.Push(new ODataOperationSegment(operation.Item2, Context.Settings.UnqualifiedCall));
_paths.Add(path.Clone());
path.Pop();
}
}
if (entitySet != null)
{
path.Pop();
}
path.Pop();
Debug.Assert(path.Any() == false);
}
private static bool ShouldExpandNavigationProperty(IEdmNavigationProperty navigationProperty, ODataPath currentPath)
{
if (!navigationProperty.ContainsTarget)
{
return false;
}
IEdmEntityType navEntityType = navigationProperty.ToEntityType();
foreach (ODataSegment segment in currentPath)
{
if (navEntityType.IsAssignableFrom(segment.EntityType))
{
return false;
}
}
return true;
}
}
}

View file

@ -0,0 +1,43 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Enum types for Edm path.
/// </summary>
public enum ODataPathType
{
/// <summary>
/// Represents an entity set path. for example: ~/users
/// </summary>
EntitySet,
/// <summary>
/// Represents an entity path, for example: ~/users/{id}
/// </summary>
Entity,
/// <summary>
/// Represents a singleton path, for example: ~/me
/// </summary>
Singleton,
/// <summary>
/// Represents an operation (function or action) path, for example: ~/users/NS.findRooms(roomId={roomId})
/// </summary>
Operation,
/// <summary>
/// Represents an operation import (function import or action import path), for example: ~/ResetData
/// </summary>
OperationImport,
/// <summary>
/// Represents an navigation propert path, for example: ~/users/{id}/onedrive
/// </summary>
NavigationProperty
}
}

View file

@ -0,0 +1,25 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Represents an OData segment. For example, an entity set segment.
/// </summary>
public abstract class ODataSegment
{
/// <summary>
/// Gets the entity type of current segment.
/// </summary>
public abstract IEdmEntityType EntityType { get; }
/// <summary>
/// Ges the name of this segment.
/// </summary>
public abstract string Name { get; }
}
}

View file

@ -0,0 +1,37 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Type cast segment.
/// </summary>
public class ODataTypeCastSegment : ODataSegment
{
/// <summary>
/// Initializes a new instance of <see cref="ODataTypeCastSegment"/> class.
/// </summary>
/// <param name="entityType">The type cast type.</param>
public ODataTypeCastSegment(IEdmEntityType entityType)
{
EntityType = entityType ?? throw Error.ArgumentNull(nameof(entityType));
}
/// <inheritdoc />
public override IEdmEntityType EntityType { get; }
/// <inheritdoc />
public override string ToString()
{
return EntityType.FullTypeName();
}
/// <inheritdoc />
public override string Name => EntityType.FullTypeName();
}
}

View file

@ -0,0 +1,255 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Edm
{
/// <summary>
/// Extension methods for <see cref="IEdmRecordExpression"/>
/// </summary>
internal static class RecordExpressionExtensions
{
/// <summary>
/// Gets the string value of a property in the given record expression.
/// </summary>
/// <param name="record">The given record.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The property string value.</returns>
public static string GetString(this IEdmRecordExpression record, string propertyName)
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
if (record.Properties != null)
{
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmStringConstantExpression value = property.Value as IEdmStringConstantExpression;
if (value != null)
{
return value.Value;
}
}
}
return null;
}
/// <summary>
/// Get the boolean value from the record using the given property name.
/// </summary>
/// <param name="record">The record expression.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The boolean value or null.</returns>
public static bool? GetBoolean(this IEdmRecordExpression record, string propertyName)
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
if (record.Properties != null)
{
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmBooleanConstantExpression value = property.Value as IEdmBooleanConstantExpression;
if (value != null)
{
return value.Value;
}
}
}
return null;
}
/// <summary>
/// Get the Enum value from the record using the given property name.
/// </summary>
/// <typeparam name="T">The output enum type.</typeparam>
/// <param name="record">The record expression.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The Enum value or null.</returns>
public static T? GetEnum<T>(this IEdmRecordExpression record, string propertyName)
where T : struct
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
if (record.Properties != null)
{
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmEnumMemberExpression value = property.Value as IEdmEnumMemberExpression;
if (value != null && value.EnumMembers != null && value.EnumMembers.Any())
{
IEdmEnumMember member = value.EnumMembers.First();
T result;
if (Enum.TryParse(member.Name, out result))
{
return result;
}
}
}
}
return null;
}
/// <summary>
/// Get the property path from the record using the given property name.
/// </summary>
/// <param name="record">The record expression.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The property path or null.</returns>
public static string GetPropertyPath(this IEdmRecordExpression record, string propertyName)
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
if (record.Properties != null)
{
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmPathExpression value = property.Value as IEdmPathExpression;
if (value != null)
{
return value.Path;
}
}
}
return null;
}
/// <summary>
/// Get the collection of property path from the record using the given property name.
/// </summary>
/// <param name="record">The record expression.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The collection of property path or null.</returns>
public static IList<string> GetCollectionPropertyPath(this IEdmRecordExpression record, string propertyName)
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
if (record.Properties != null)
{
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmCollectionExpression value = property.Value as IEdmCollectionExpression;
if (value != null && value.Elements != null)
{
IList<string> properties = new List<string>();
foreach (var a in value.Elements.Select(e => e as IEdmPathExpression))
{
properties.Add(a.Path);
}
if (properties.Any())
{
return properties;
}
}
}
}
return null;
}
/// <summary>
/// Get the collection of <typeparamref name="T"/> from the record using the given property name.
/// </summary>
/// <typeparam name="T">The element type.</typeparam>
/// <param name="record">The record expression.</param>
/// <param name="propertyName">The property name.</param>
/// <param name="elementAction">The element action.</param>
/// <returns>The collection or null.</returns>
public static IList<T> GetCollection<T>(this IEdmRecordExpression record, string propertyName, Action<T, IEdmExpression> elementAction)
where T: new()
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmCollectionExpression collection = property.Value as IEdmCollectionExpression;
if (collection != null && collection.Elements != null)
{
IList<T> items = new List<T>();
foreach (var item in collection.Elements)
{
T a = new T();
elementAction(a, item);
items.Add(a);
}
return items;
}
}
return null;
}
public static IEnumerable<T> GetCollection<T>(this IEdmRecordExpression record, string propertyName, Func<IEdmExpression, T> elementFunc)
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmCollectionExpression collection = property.Value as IEdmCollectionExpression;
if (collection != null && collection.Elements != null)
{
return collection.Elements.Select(e => elementFunc(e));
}
}
return null;
}
/// <summary>
/// Get the collection of string from the record using the given property name.
/// </summary>
/// <param name="record">The record expression.</param>
/// <param name="propertyName">The property name.</param>
/// <returns>The collection of string or null.</returns>
public static IList<string> GetCollection(this IEdmRecordExpression record, string propertyName)
{
Utils.CheckArgumentNull(record, nameof(record));
Utils.CheckArgumentNull(propertyName, nameof(propertyName));
IEdmPropertyConstructor property = record.Properties.FirstOrDefault(e => e.Name == propertyName);
if (property != null)
{
IEdmCollectionExpression collection = property.Value as IEdmCollectionExpression;
if (collection != null && collection.Elements != null)
{
IList<string> items = new List<string>();
foreach (var item in collection.Elements)
{
IEdmStringConstantExpression itemRecord = item as IEdmStringConstantExpression;
items.Add(itemRecord.Value);
}
return items;
}
}
return null;
}
}
}

View file

@ -8,6 +8,8 @@ using Microsoft.OData.Edm;
using Microsoft.OData.Edm.Validation;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData

View file

@ -1,120 +0,0 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Capabilities;
namespace Microsoft.OpenApi.OData.Generator
{
/// <summary>
/// Context information for the <see cref="IEdmModel"/>, configuration, etc.
/// </summary>
internal class ODataContext
{
private IDictionary<IEdmTypeReference, IEdmOperation> _boundOperations;
private bool _keyAsSegmentSupported = false;
/// <summary>
/// Initializes a new instance of <see cref="ODataContext"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
public ODataContext(IEdmModel model)
: this(model, new OpenApiConvertSettings())
{
}
/// <summary>
/// Initializes a new instance of <see cref="ODataContext"/> class.
/// </summary>
/// <param name="model">The Edm model.</param>
/// <param name="settings">The convert setting.</param>
public ODataContext(IEdmModel model, OpenApiConvertSettings settings)
{
Model = model ?? throw Error.ArgumentNull(nameof(model));
Settings = settings ?? throw Error.ArgumentNull(nameof(settings));
EdmModelVisitor visitor = new EdmModelVisitor();
visitor.Visit(model);
IsSpatialTypeUsed = visitor.IsSpatialTypeUsed;
_keyAsSegmentSupported = settings.KeyAsSegment ?? model.GetKeyAsSegmentSupported();
}
/// <summary>
/// Gets the Edm model.
/// </summary>
public IEdmModel Model { get; }
/// <summary>
/// Gets the Entity Container.
/// </summary>
public IEdmEntityContainer EntityContainer
{
get
{
return Model.EntityContainer;
}
}
/// <summary>
/// Gets the boolean value indicating to support key as segment.
/// </summary>
public bool KeyAsSegment => _keyAsSegmentSupported;
/// <summary>
/// Gets the value indicating the Edm spatial type used.
/// </summary>
public bool IsSpatialTypeUsed { get; private set; }
/// <summary>
/// Gets the convert settings.
/// </summary>
public OpenApiConvertSettings Settings { get; }
public IDictionary<IEdmTypeReference, IEdmOperation> BoundOperations
{
get
{
if (_boundOperations == null)
{
GenerateBoundOperations();
}
return _boundOperations;
}
}
public IEnumerable<IEdmOperation> FindOperations(IEdmEntityType entityType, bool collection)
{
string fullTypeName = collection ? "Collection(" + entityType.FullName() + ")" :
entityType.FullName();
foreach (var item in BoundOperations)
{
if (item.Key.FullName() == fullTypeName)
{
yield return item.Value;
}
}
}
private void GenerateBoundOperations()
{
if (_boundOperations != null)
{
return;
}
_boundOperations = new Dictionary<IEdmTypeReference, IEdmOperation>();
foreach (var edmOperation in Model.SchemaElements.OfType<IEdmOperation>().Where(e => e.IsBound))
{
IEdmOperationParameter bindingParameter = edmOperation.Parameters.First();
_boundOperations.Add(bindingParameter.Type, edmOperation);
}
}
}
}

View file

@ -4,6 +4,8 @@
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -21,10 +23,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiComponents"/> object.</returns>
public static OpenApiComponents CreateComponents(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
// "components": {
// "schemas": …,
@ -51,7 +50,7 @@ namespace Microsoft.OpenApi.OData.Generator
Examples = null,
SecuritySchemes = null,
SecuritySchemes = context.CreateSecuritySchemes(),
Links = null,

View file

@ -3,8 +3,9 @@
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -20,10 +21,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiDocument"/> object.</returns>
public static OpenApiDocument CreateDocument(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
// An OAS document consists of a single OpenAPI Object represented as OpenApiDocument object.
// {
@ -34,13 +32,13 @@ namespace Microsoft.OpenApi.OData.Generator
// "paths": …,
// "components": …
// }
return new OpenApiDocument
OpenApiDocument doc = new OpenApiDocument
{
Info = context.CreateInfo(),
Servers = context.CreateServers(),
Tags = context.CreateTags(),
// Tags = context.CreateTags(),
Paths = context.CreatePaths(),
@ -50,6 +48,9 @@ namespace Microsoft.OpenApi.OData.Generator
ExternalDocs = null
};
doc.Tags = context.CreateTags_FromTagItems();
return doc;
}
}
}

View file

@ -5,12 +5,14 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Properties;
using System.Diagnostics;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Generator
{
@ -27,15 +29,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreateEdmTypeSchema(this ODataContext context, IEdmTypeReference edmTypeReference)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (edmTypeReference == null)
{
throw Error.ArgumentNull(nameof(edmTypeReference));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(edmTypeReference, nameof(edmTypeReference));
switch (edmTypeReference.TypeKind())
{
@ -84,15 +79,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiveTypeReference primitiveType)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (primitiveType == null)
{
throw Error.ArgumentNull(nameof(primitiveType));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(primitiveType, nameof(primitiveType));
OpenApiSchema schema = context.CreateSchema(primitiveType.PrimitiveDefinition());
if (schema != null)
@ -149,15 +137,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreateSchema(this ODataContext context, IEdmPrimitiveType primitiveType)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (primitiveType == null)
{
throw Error.ArgumentNull(nameof(primitiveType));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(primitiveType, nameof(primitiveType));
// Spec has different configure for double, AnyOf or OneOf?
OpenApiSchema schema = new OpenApiSchema

View file

@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -22,10 +24,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The string/schema dictionary.</returns>
public static IDictionary<string, OpenApiSchema> CreateODataErrorSchemas(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
IDictionary<string, OpenApiSchema> schemas = new Dictionary<string, OpenApiSchema>();
@ -50,7 +49,7 @@ namespace Microsoft.OpenApi.OData.Generator
return new OpenApiSchema
{
Type = "object",
Required = new List<string>
Required = new HashSet<string>
{
"error"
},
@ -80,7 +79,7 @@ namespace Microsoft.OpenApi.OData.Generator
return new OpenApiSchema
{
Type = "object",
Required = new List<string>
Required = new HashSet<string>
{
"code", "message"
},
@ -131,7 +130,7 @@ namespace Microsoft.OpenApi.OData.Generator
return new OpenApiSchema
{
Type = "object",
Required = new List<string>
Required = new HashSet<string>
{
"code", "message"
},

View file

@ -0,0 +1,145 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
/// <summary>
/// Extension methods to create <see cref="OpenApiExample"/> by <see cref="ODataContext"/>.
/// </summary>
internal static class OpenApiExampleGenerator
{
/// <summary>
/// Create the dictionary of <see cref="OpenApiExample"/> object.
/// </summary>
/// <param name="context">The OData to Open API context.</param>
/// <param name="securitySchemes">The securitySchemes.</param>
/// <returns>The created <see cref="OpenApiExample"/> dictionary.</returns>
public static IDictionary<string, OpenApiExample> CreateExamples(this ODataContext context)
{
Utils.CheckArgumentNull(context, nameof(context));
IDictionary<string, OpenApiExample> examples = new Dictionary<string, OpenApiExample>();
// Each entity type, complex type, enumeration type, and type definition directly
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
{
switch (element.SchemaElementKind)
{
case EdmSchemaElementKind.TypeDefinition: // Type definition
{
IEdmType reference = (IEdmType)element;
OpenApiExample example = context.CreateExample(reference);
if (example != null)
{
examples.Add(reference.FullTypeName(), example);
}
}
break;
}
}
return examples;
}
private static OpenApiExample CreateExample(this ODataContext context, IEdmType edmType)
{
Debug.Assert(context != null);
Debug.Assert(edmType != null);
switch (edmType.TypeKind)
{
case EdmTypeKind.Complex: // complex type
case EdmTypeKind.Entity: // entity type
return CreateStructuredTypeExample((IEdmStructuredType)edmType);
}
return null;
}
private static OpenApiExample CreateStructuredTypeExample(IEdmStructuredType structuredType)
{
OpenApiExample example = new OpenApiExample();
OpenApiObject value = new OpenApiObject();
IEdmEntityType entityType = structuredType as IEdmEntityType;
// properties
foreach (var property in structuredType.DeclaredProperties.OrderBy(p => p.Name))
{
// IOpenApiAny item;
IEdmTypeReference propertyType = property.Type;
IOpenApiAny item = GetTypeNameForExample(propertyType);
EdmTypeKind typeKind = propertyType.TypeKind();
if (typeKind == EdmTypeKind.Primitive && item is OpenApiString)
{
OpenApiString stringAny = item as OpenApiString;
string propertyValue = stringAny.Value;
if (entityType != null && entityType.Key().Any(k => k.Name == property.Name))
{
propertyValue += " (identifier)";
}
if (propertyType.IsDateTimeOffset() || propertyType.IsDate() || propertyType.IsTimeOfDay())
{
propertyValue += " (timestamp)";
}
item = new OpenApiString(propertyValue);
}
value.Add(property.Name, item);
}
example.Value = value;
return example;
}
private static IOpenApiAny GetTypeNameForExample(IEdmTypeReference edmTypeReference)
{
switch (edmTypeReference.TypeKind())
{
case EdmTypeKind.Primitive:
if (edmTypeReference.IsBoolean())
{
return new OpenApiBoolean(true);
}
else
{
return new OpenApiString(edmTypeReference.AsPrimitive().PrimitiveDefinition().Name);
}
case EdmTypeKind.Entity:
case EdmTypeKind.Complex:
case EdmTypeKind.Enum:
OpenApiObject obj = new OpenApiObject();
obj["@odata.type"] = new OpenApiString(edmTypeReference.FullName());
return obj;
case EdmTypeKind.Collection:
OpenApiArray array = new OpenApiArray();
IEdmTypeReference elementType = edmTypeReference.AsCollection().ElementType();
array.Add(GetTypeNameForExample(elementType));
return array;
case EdmTypeKind.Untyped:
case EdmTypeKind.TypeDefinition:
case EdmTypeKind.EntityReference:
default:
throw new OpenApiException("Not support for the type kind " + edmTypeReference.TypeKind());
}
}
}
}

View file

@ -7,6 +7,8 @@ using System.Diagnostics;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -22,10 +24,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiInfo"/> object.</returns>
public static OpenApiInfo CreateInfo(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
// The value of info is an Info Object,
// It contains the fields title and version, and optionally the field description.

View file

@ -0,0 +1,53 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
/// <summary>
/// Extension methods to create <see cref="OpenApiLink"/> by <see cref="IEdmModel"/>.
/// </summary>
internal static class OpenApiLinkGenerator
{
/// <summary>
/// Create the collection of <see cref="OpenApiLink"/> object.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="entitySet">The Entity Set.</param>
/// <returns>The created dictionary of <see cref="OpenApiLink"/> object.</returns>
public static IDictionary<string, OpenApiLink> CreateLinks(this ODataContext context, IEdmEntitySet entitySet)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(entitySet, nameof(entitySet));
IDictionary<string, OpenApiLink> links = new Dictionary<string, OpenApiLink>();
IEdmEntityType entityType = entitySet.EntityType();
foreach (var np in entityType.DeclaredNavigationProperties())
{
OpenApiLink link = new OpenApiLink();
string typeName = entitySet.EntityType().Name;
link.OperationId = entitySet.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName);
link.Parameters = new Dictionary<string, RuntimeExpressionAnyWrapper>();
foreach (var key in entityType.Key())
{
link.Parameters[key.Name] = new RuntimeExpressionAnyWrapper
{
Any = new OpenApiString("$request.path." + key.Name)
};
}
links[np.Name] = link;
}
return links;
}
}
}

View file

@ -9,6 +9,7 @@ using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Exceptions;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Properties;
using Microsoft.OpenApi.OData.Common;

View file

@ -11,6 +11,7 @@ using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OData.Edm.Vocabularies;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -27,10 +28,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created map of <see cref="OpenApiParameter"/> object.</returns>
public static IDictionary<string, OpenApiParameter> CreateParameters(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
// It allows defining query options and headers that can be reused across operations of the service.
// The value of parameters is a map of Parameter Objects.
@ -52,15 +50,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created list of <see cref="OpenApiParameter"/>.</returns>
public static IList<OpenApiParameter> CreateParameters(this ODataContext context, IEdmFunctionImport functionImport)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (functionImport == null)
{
throw Error.ArgumentNull(nameof(functionImport));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(functionImport, nameof(functionImport));
return context.CreateParameters(functionImport.Function);
}
@ -73,15 +64,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created list of <see cref="OpenApiParameter"/>.</returns>
public static IList<OpenApiParameter> CreateParameters(this ODataContext context, IEdmFunction function)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (function == null)
{
throw Error.ArgumentNull(nameof(function));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(function, nameof(function));
IList<OpenApiParameter> parameters = new List<OpenApiParameter>();
int skip = function.IsBound ? 1 : 0;
@ -134,10 +118,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created the list of <see cref="OpenApiParameter"/>.</returns>
public static IList<OpenApiParameter> CreateKeyParameters(this ODataContext context, IEdmEntityType entityType)
{
if (entityType == null)
{
throw Error.ArgumentNull(nameof(entityType));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(entityType, nameof(entityType));
IList<OpenApiParameter> parameters = new List<OpenApiParameter>();
@ -153,6 +135,8 @@ namespace Microsoft.OpenApi.OData.Generator
Schema = context.CreateEdmTypeSchema(keyProperty.Type)
};
parameter.Extensions.Add(Constants.xMsKeyType, new OpenApiString(entityType.Name));
parameters.Add(parameter);
}

View file

@ -4,12 +4,10 @@
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.PathItem;
namespace Microsoft.OpenApi.OData.Generator
{
@ -33,345 +31,13 @@ namespace Microsoft.OpenApi.OData.Generator
return pathItems;
}
// visit all elements in the container
foreach (var element in context.EntityContainer.Elements)
foreach (ODataPath path in context.Paths)
{
switch (element.ContainerElementKind)
{
case EdmContainerElementKind.EntitySet: // entity set
IEdmEntitySet entitySet = (IEdmEntitySet)element;
// entity set
string entitySetPathName = "/" + entitySet.Name;
var entitySetPathItem = context.CreateEntitySetPathItem(entitySet);
pathItems.Add(entitySetPathName, entitySetPathItem);
// entity
string entityPathName = context.CreateEntityPathName(entitySet);
var entityPathItem = context.CreateEntityPathItem(entitySet);
pathItems.Add(entityPathName, entityPathItem);
// navigation property
foreach (var item in context.CreateNavigationPathItems(entitySet))
{
pathItems.Add(item.Key, item.Value);
}
// bound operations to entity set or entity
foreach (var item in context.CreateOperationPathItems(entitySet))
{
pathItems.Add(item.Key, item.Value);
}
break;
case EdmContainerElementKind.Singleton: // singleton
IEdmSingleton singleton = (IEdmSingleton)element;
string singletonPathName = "/" + singleton.Name;
var singletonPathItem = context.CreateSingletonPathItem(singleton);
pathItems.Add(singletonPathName, singletonPathItem);
// navigation property
foreach (var item in context.CreateNavigationPathItems(singleton))
{
pathItems.Add(item.Key, item.Value);
}
// bound operations to singleton
foreach (var item in context.CreateOperationPathItems(singleton))
{
pathItems.Add(item.Key, item.Value);
}
break;
case EdmContainerElementKind.FunctionImport: // function import
IEdmFunctionImport functionImport = (IEdmFunctionImport)element;
string functionImportName = context.CreatePathItemName(functionImport);
var functionImportPathItem = context.CreatePathItem(functionImport);
pathItems.Add(functionImportName, functionImportPathItem);
break;
case EdmContainerElementKind.ActionImport: // action import
IEdmActionImport actionImport = (IEdmActionImport)element;
string actionImportName = context.CreatePathItemName(actionImport);
var actionImportPathItem = context.CreatePathItem(actionImport);
pathItems.Add(actionImportName, actionImportPathItem);
break;
}
IPathItemHandler handler = context.PathItemHanderProvider.GetHandler(path.PathType);
pathItems.Add(path.ToString(), handler.CreatePathItem(context, path));
}
return pathItems;
}
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for <see cref="IEdmEntitySet"/>.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="entitySet">The Edm entity set.</param>
/// <returns>The created <see cref="OpenApiPathItem"/>.</returns>
public static OpenApiPathItem CreateEntitySetPathItem(this ODataContext context, IEdmEntitySet entitySet)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(entitySet, nameof(entitySet));
OpenApiPathItem pathItem = new OpenApiPathItem();
pathItem.AddOperation(OperationType.Get, context.CreateEntitySetGetOperation(entitySet));
InsertRestrictions insert = new InsertRestrictions(context.Model, entitySet);
if (insert.IsInsertable())
{
pathItem.AddOperation(OperationType.Post, context.CreateEntitySetPostOperation(entitySet));
}
return pathItem;
}
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for a single entity in <see cref="IEdmEntitySet"/>.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="entitySet">The Edm entity set.</param>
/// <returns>The created <see cref="OpenApiPathItem"/>.</returns>
public static OpenApiPathItem CreateEntityPathItem(this ODataContext context, IEdmEntitySet entitySet)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(entitySet, nameof(entitySet));
OpenApiPathItem pathItem = new OpenApiPathItem();
IndexableByKey index = new IndexableByKey(context.Model, entitySet);
if (index.IsSupported())
{
pathItem.AddOperation(OperationType.Get, context.CreateEntityGetOperation(entitySet));
}
UpdateRestrictions update = new UpdateRestrictions(context.Model, entitySet);
if (update.IsUpdatable())
{
pathItem.AddOperation(OperationType.Patch, context.CreateEntityPatchOperation(entitySet));
}
DeleteRestrictions delete = new DeleteRestrictions(context.Model, entitySet);
if (delete.IsDeletable())
{
pathItem.AddOperation(OperationType.Delete, context.CreateEntityDeleteOperation(entitySet));
}
return pathItem;
}
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for <see cref="IEdmSingleton"/>.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="singleton">The singleton.</param>
/// <returns>The created <see cref="OpenApiPathItem"/> on this singleton.</returns>
public static OpenApiPathItem CreateSingletonPathItem(this ODataContext context, IEdmSingleton singleton)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(singleton, nameof(singleton));
OpenApiPathItem pathItem = new OpenApiPathItem();
// Retrieve a singleton.
pathItem.AddOperation(OperationType.Get, context.CreateSingletonGetOperation(singleton));
// Update a singleton
pathItem.AddOperation(OperationType.Patch, context.CreateSingletonPatchOperation(singleton));
return pathItem;
}
/// <summary>
/// Create the bound operations for the navigation source.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="navigationSource">The navigation source.</param>
/// <returns>The name/value pairs describing the allowed operations on this navigation source.</returns>
public static IDictionary<string, OpenApiPathItem> CreateOperationPathItems(this ODataContext context,
IEdmNavigationSource navigationSource)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(navigationSource, nameof(navigationSource));
IDictionary<string, OpenApiPathItem> operationPathItems = new Dictionary<string, OpenApiPathItem>();
IEnumerable<IEdmOperation> operations;
IEdmEntitySet entitySet = navigationSource as IEdmEntitySet;
// collection bound
if (entitySet != null)
{
operations = context.FindOperations(navigationSource.EntityType(), collection: true);
foreach (var operation in operations)
{
OpenApiPathItem pathItem = context.CreatePathItem(navigationSource, operation);
string pathName = context.CreatePathItemName(operation);
operationPathItems.Add("/" + navigationSource.Name + pathName, pathItem);
}
}
// non-collection bound
operations = context.FindOperations(navigationSource.EntityType(), collection: false);
foreach (var operation in operations)
{
OpenApiPathItem pathItem = context.CreatePathItem(navigationSource, operation);
string pathName = context.CreatePathItemName(operation);
string entityPathName;
if (entitySet != null)
{
entityPathName = context.CreateEntityPathName(entitySet);
OpenApiOperation openApiOperation = pathItem.Operations.First().Value;
Debug.Assert(openApiOperation != null);
openApiOperation.Parameters = context.CreateKeyParameters(entitySet.EntityType());
}
else
{
entityPathName = "/" + navigationSource.Name;
}
operationPathItems.Add(entityPathName + pathName, pathItem);
}
return operationPathItems;
}
/// <summary>
/// Create the navigation property path item for the navigation source.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="navigationSource">The navigation source.</param>
/// <returns>The name/value pairs describing the allowed operations on this navigation source.</returns>
public static IDictionary<string, OpenApiPathItem> CreateNavigationPathItems(this ODataContext context,
IEdmNavigationSource navigationSource)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(navigationSource, nameof(navigationSource));
IDictionary<string, OpenApiPathItem> navPathItems = new Dictionary<string, OpenApiPathItem>();
if (!context.Settings.NavigationPropertyPathItem)
{
return navPathItems;
}
IEdmEntityType entityType = navigationSource.EntityType();
foreach (var navProperty in entityType.DeclaredNavigationProperties())
{
string pathItemName = context.CreateNavigationPathItemName(navigationSource, navProperty);
OpenApiPathItem pathItem = context.CreatePathItem(navigationSource, navProperty);
navPathItems.Add(pathItemName, pathItem);
}
return navPathItems;
}
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for a single <see cref="IEdmNavigationProperty"/>.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="navigationSource">The binding navigation source.</param>
/// <param name="navigationProperty">The Edm navigation property.</param>
/// <returns>The created <see cref="OpenApiPathItem"/>.</returns>
public static OpenApiPathItem CreatePathItem(this ODataContext context, IEdmNavigationSource navigationSource,
IEdmNavigationProperty navigationProperty)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(navigationSource, nameof(navigationSource));
Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty));
OpenApiPathItem pathItem = new OpenApiPathItem();
pathItem.AddOperation(OperationType.Get, context.CreateNavigationGetOperation(navigationSource, navigationProperty));
if (navigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
InsertRestrictions insert = new InsertRestrictions(context.Model, navigationProperty);
if (insert.IsInsertable())
{
pathItem.AddOperation(OperationType.Post, context.CreateNavigationPostOperation(navigationSource, navigationProperty));
}
}
else
{
UpdateRestrictions update = new UpdateRestrictions(context.Model, navigationProperty);
if (update.IsUpdatable())
{
pathItem.AddOperation(OperationType.Patch, context.CreateNavigationPatchOperation(navigationSource, navigationProperty));
}
}
return pathItem;
}
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for a single <see cref="IEdmOperation"/>.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="navigationSource">The binding navigation source.</param>
/// <param name="edmOperation">The Edm opeation.</param>
/// <returns>The created <see cref="OpenApiPathItem"/>.</returns>
public static OpenApiPathItem CreatePathItem(this ODataContext context, IEdmNavigationSource navigationSource, IEdmOperation edmOperation)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(navigationSource, nameof(navigationSource));
Utils.CheckArgumentNull(edmOperation, nameof(edmOperation));
OpenApiPathItem pathItem = new OpenApiPathItem();
OpenApiOperation operation = context.CreateOperation(navigationSource, edmOperation);
if (edmOperation.IsAction())
{
// The Path Item Object for a bound action contains the keyword post,
// The value of the operation keyword is an Operation Object that describes how to invoke the action.
pathItem.AddOperation(OperationType.Post, operation);
}
else
{
// The Path Item Object for a bound function contains the keyword get,
// The value of the operation keyword is an Operation Object that describes how to invoke the function.
pathItem.AddOperation(OperationType.Get, operation);
}
return pathItem;
}
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for a single <see cref="IEdmOperationImport"/>.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="operationImport">The Edm operation import.</param>
/// <returns>The created <see cref="OpenApiPathItem"/>.</returns>
public static OpenApiPathItem CreatePathItem(this ODataContext context, IEdmOperationImport operationImport)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operationImport, nameof(operationImport));
OpenApiPathItem pathItem = new OpenApiPathItem();
OpenApiOperation operation = context.CreateOperation(operationImport);
if (operationImport.IsActionImport())
{
// Each action import is represented as a name/value pair whose name is the service-relative
// resource path of the action import prepended with a forward slash, and whose value is a Path
// Item Object containing the keyword post with an Operation Object as value that describes
// how to invoke the action import.
pathItem.AddOperation(OperationType.Post, operation);
}
else
{
// Each function import is represented as a name/value pair whose name is the service-relative
// resource path of the function import prepended with a forward slash, and whose value is a Path
// Item Object containing the keyword get with an Operation Object as value that describes
// how to invoke the function import.
pathItem.AddOperation(OperationType.Get, operation);
}
return pathItem;
}
}
}

View file

@ -4,6 +4,8 @@
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -23,10 +25,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiPaths"/> object.</returns>
public static OpenApiPaths CreatePaths(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
// Due to the power and flexibility of OData a full representation of all service capabilities
// in the Paths Object is typically not feasible, so this mapping only describes the minimum

View file

@ -7,6 +7,8 @@ using System.Linq;
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Generator
{
@ -23,15 +25,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiRequestBody"/> or null.</returns>
public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IEdmActionImport actionImport)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (actionImport == null)
{
throw Error.ArgumentNull(nameof(actionImport));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(actionImport, nameof(actionImport));
return context.CreateRequestBody(actionImport.Action);
}
@ -44,15 +39,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiRequestBody"/> or null.</returns>
public static OpenApiRequestBody CreateRequestBody(this ODataContext context, IEdmAction action)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (action == null)
{
throw Error.ArgumentNull(nameof(action));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(action, nameof(action));
// return null for empty action parameters
int skip = 0;

View file

@ -6,6 +6,8 @@
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -57,10 +59,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The name/value pairs for the standard OData error response.</returns>
public static IDictionary<string, OpenApiResponse> CreateResponses(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
return new Dictionary<string, OpenApiResponse>
{
@ -76,15 +75,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiResponses"/>.</returns>
public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperationImport operationImport)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (operationImport == null)
{
throw Error.ArgumentNull(nameof(operationImport));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operationImport, nameof(operationImport));
return context.CreateResponses(operationImport.Operation);
}
@ -97,15 +89,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiResponses"/>.</returns>
public static OpenApiResponses CreateResponses(this ODataContext context, IEdmOperation operation)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (operation == null)
{
throw Error.ArgumentNull(nameof(operation));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operation, nameof(operation));
OpenApiResponses responses = new OpenApiResponses();

View file

@ -10,6 +10,10 @@ using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.OData.Properties;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.Exceptions;
using System.Linq;
namespace Microsoft.OpenApi.OData.Generator
{
@ -27,16 +31,13 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The string/schema dictionary.</returns>
public static IDictionary<string, OpenApiSchema> CreateSchemas(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
IDictionary<string, OpenApiSchema> schemas = new Dictionary<string, OpenApiSchema>();
// Each entity type, complex type, enumeration type, and type definition directly
// or indirectly used in the paths field is represented as a name / value pair of the schemas map.
foreach (var element in context.Model.SchemaElements)
foreach (var element in context.Model.SchemaElements.Where(c => !c.Namespace.StartsWith("Org.OData.")))
{
switch (element.SchemaElementKind)
{
@ -74,15 +75,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreateEnumTypeSchema(this ODataContext context, IEdmEnumType enumType)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (enumType == null)
{
throw Error.ArgumentNull(nameof(enumType));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(enumType, nameof(enumType));
OpenApiSchema schema = new OpenApiSchema
{
@ -115,17 +109,10 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(structuredType, nameof(structuredType));
if (structuredType == null)
{
throw Error.ArgumentNull(nameof(structuredType));
}
return context.CreateStructuredTypeSchema(structuredType, true);
return context.CreateStructuredTypeSchema(structuredType, true, true);
}
/// <summary>
@ -139,15 +126,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created <see cref="OpenApiSchema"/>.</returns>
public static OpenApiSchema CreatePropertySchema(this ODataContext context, IEdmProperty property)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (property == null)
{
throw Error.ArgumentNull(nameof(property));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(property, nameof(property));
OpenApiSchema schema = context.CreateEdmTypeSchema(property.Type);
@ -174,6 +154,9 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created map of <see cref="OpenApiSchema"/>.</returns>
public static IDictionary<string, OpenApiSchema> CreateStructuredTypePropertiesSchema(this ODataContext context, IEdmStructuredType structuredType)
{
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(structuredType, nameof(structuredType));
// The name is the property name, the value is a Schema Object describing the allowed values of the property.
IDictionary<string, OpenApiSchema> properties = new Dictionary<string, OpenApiSchema>();
@ -209,7 +192,7 @@ namespace Microsoft.OpenApi.OData.Generator
{
case EdmTypeKind.Complex: // complex type
case EdmTypeKind.Entity: // entity type
return context.CreateStructuredTypeSchema((IEdmStructuredType)edmType, true);
return context.CreateStructuredTypeSchema((IEdmStructuredType)edmType, true, true);
case EdmTypeKind.Enum: // enum type
return context.CreateEnumTypeSchema((IEdmEnumType)edmType);
@ -223,7 +206,7 @@ namespace Microsoft.OpenApi.OData.Generator
}
}
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase)
private static OpenApiSchema CreateStructuredTypeSchema(this ODataContext context, IEdmStructuredType structuredType, bool processBase, bool processExample)
{
Debug.Assert(context != null);
Debug.Assert(structuredType != null);
@ -247,12 +230,13 @@ namespace Microsoft.OpenApi.OData.Generator
},
// 2. a Schema Object describing the derived type
context.CreateStructuredTypeSchema(structuredType, false)
context.CreateStructuredTypeSchema(structuredType, false, false)
},
AnyOf = null,
OneOf = null,
Properties = null
Properties = null,
Example = CreateStructuredTypePropertiesExample(structuredType)
};
}
else
@ -287,10 +271,86 @@ namespace Microsoft.OpenApi.OData.Generator
schema.Description = context.Model.GetDescriptionAnnotation(entity);
}
if (processExample)
{
schema.Example = CreateStructuredTypePropertiesExample(structuredType);
}
return schema;
}
}
private static IOpenApiAny CreateStructuredTypePropertiesExample(IEdmStructuredType structuredType)
{
OpenApiObject example = new OpenApiObject();
IEdmEntityType entityType = structuredType as IEdmEntityType;
// properties
foreach (var property in structuredType.Properties())
{
// IOpenApiAny item;
IEdmTypeReference propertyType = property.Type;
IOpenApiAny item = GetTypeNameForExample(propertyType);
EdmTypeKind typeKind = propertyType.TypeKind();
if (typeKind == EdmTypeKind.Primitive && item is OpenApiString)
{
OpenApiString stringAny = item as OpenApiString;
string value = stringAny.Value;
if (entityType != null && entityType.Key().Any(k => k.Name == property.Name))
{
value += " (identifier)";
}
if (propertyType.IsDateTimeOffset() || propertyType.IsDate() || propertyType.IsTimeOfDay())
{
value += " (timestamp)";
}
item = new OpenApiString(value);
}
example.Add(property.Name, item);
}
return example;
}
private static IOpenApiAny GetTypeNameForExample(IEdmTypeReference edmTypeReference)
{
switch (edmTypeReference.TypeKind())
{
case EdmTypeKind.Primitive:
if (edmTypeReference.IsBoolean())
{
return new OpenApiBoolean(true);
}
else
{
return new OpenApiString(edmTypeReference.AsPrimitive().PrimitiveDefinition().Name);
}
case EdmTypeKind.Entity:
case EdmTypeKind.Complex:
case EdmTypeKind.Enum:
OpenApiObject obj = new OpenApiObject();
obj["@odata.type"] = new OpenApiString(edmTypeReference.FullName());
return obj;
case EdmTypeKind.Collection:
OpenApiArray array = new OpenApiArray();
IEdmTypeReference elementType = edmTypeReference.AsCollection().ElementType();
array.Add(GetTypeNameForExample(elementType));
return array;
case EdmTypeKind.Untyped:
case EdmTypeKind.TypeDefinition:
case EdmTypeKind.EntityReference:
default:
throw new OpenApiException("Not support for the type kind " + edmTypeReference.TypeKind());
}
}
private static IOpenApiAny CreateDefault(this IEdmStructuralProperty property)
{
if (property == null ||

View file

@ -0,0 +1,51 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Authorizations;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
/// <summary>
/// Extension methods to create <see cref="OpenApiSecurityRequirement"/> by <see cref="ODataContext"/>.
/// </summary>
internal static class OpenApiSecurityRequirementGenerator
{
/// <summary>
/// Create the list of <see cref="OpenApiSecurityRequirement"/> object.
/// </summary>
/// <param name="context">The OData to Open API context.</param>
/// <param name="securitySchemes">The securitySchemes.</param>
/// <returns>The created <see cref="OpenApiSecurityRequirement"/> collection.</returns>
public static IEnumerable<OpenApiSecurityRequirement> CreateSecurityRequirements(this ODataContext context,
IList<SecurityScheme> securitySchemes)
{
Utils.CheckArgumentNull(context, nameof(context));
if (securitySchemes != null)
{
foreach (var securityScheme in securitySchemes)
{
yield return new OpenApiSecurityRequirement
{
[
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = securityScheme.AuthorizationSchemeName
}
}
] = new List<string>(securityScheme.RequiredScopes ?? new List<string>())
};
}
}
}
}
}

View file

@ -0,0 +1,169 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Authorizations;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
/// <summary>
/// Extension methods to create <see cref="OpenApiSecurityScheme"/> by <see cref="ODataContext"/>.
/// </summary>
internal static class OpenApiSecuritySchemeGenerator
{
/// <summary>
/// Create the dictionary of <see cref="OpenApiSecurityScheme"/> object.
/// The name of each pair is the name of authorization. The value of each pair is a <see cref="OpenApiSecurityScheme"/>.
/// </summary>
/// <param name="context">The OData to Open API context.</param>
/// <returns>The string/security scheme dictionary.</returns>
public static IDictionary<string, OpenApiSecurityScheme> CreateSecuritySchemes(this ODataContext context)
{
Utils.CheckArgumentNull(context, nameof(context));
if (context.Model == null || context.Model.EntityContainer == null)
{
return null;
}
IDictionary<string, OpenApiSecurityScheme> securitySchemes = new Dictionary<string, OpenApiSecurityScheme>();
var authorizations = context.AuthorizationProvider.GetAuthorizations(context.Model, context.EntityContainer);
foreach (var authorization in authorizations)
{
OpenApiSecurityScheme scheme = new OpenApiSecurityScheme
{
Type = authorization.SchemeType,
Description = authorization.Description
};
switch (authorization.SchemeType)
{
case SecuritySchemeType.ApiKey: // ApiKey
AppendApiKey(scheme, (ApiKey)authorization);
break;
case SecuritySchemeType.Http: // Http
AppendHttp(scheme, (Http)authorization);
break;
case SecuritySchemeType.OpenIdConnect: // OpenIdConnect
AppendOpenIdConnect(scheme, (OpenIDConnect)authorization);
break;
case SecuritySchemeType.OAuth2: // OAuth2
AppendOAuth2(scheme, (OAuthAuthorization)authorization);
break;
}
securitySchemes[authorization.Name] = scheme;
}
return securitySchemes;
}
private static void AppendApiKey(OpenApiSecurityScheme scheme, ApiKey apiKey)
{
Debug.Assert(scheme != null);
Debug.Assert(apiKey != null);
scheme.Name = apiKey.KeyName;
Debug.Assert(apiKey.Location != null);
switch(apiKey.Location.Value)
{
case KeyLocation.Cookie:
scheme.In = ParameterLocation.Cookie;
break;
case KeyLocation.Header:
scheme.In = ParameterLocation.Header;
break;
case KeyLocation.QueryOption:
scheme.In = ParameterLocation.Query;
break;
}
}
private static void AppendHttp(OpenApiSecurityScheme scheme, Http http)
{
Debug.Assert(scheme != null);
Debug.Assert(http != null);
scheme.Scheme = http.Scheme;
scheme.BearerFormat = http.BearerFormat;
}
private static void AppendOpenIdConnect(OpenApiSecurityScheme scheme, OpenIDConnect openIdConnect)
{
Debug.Assert(scheme != null);
Debug.Assert(openIdConnect != null);
scheme.OpenIdConnectUrl = new Uri(openIdConnect.IssuerUrl);
}
private static void AppendOAuth2(OpenApiSecurityScheme scheme, OAuthAuthorization oAuth2)
{
Debug.Assert(scheme != null);
Debug.Assert(oAuth2 != null);
scheme.Flows = new OpenApiOAuthFlows();
OpenApiOAuthFlow flow = null;
switch (oAuth2.OAuth2Type)
{
case OAuth2Type.AuthCode: // AuthCode
OAuth2AuthCode authCode = (OAuth2AuthCode)oAuth2;
flow = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(authCode.AuthorizationUrl),
TokenUrl = new Uri(authCode.TokenUrl)
};
scheme.Flows.AuthorizationCode = flow;
break;
case OAuth2Type.Pasword: // Password
OAuth2Password password = (OAuth2Password)oAuth2;
flow = new OpenApiOAuthFlow
{
TokenUrl = new Uri(password.TokenUrl)
};
scheme.Flows.Password = flow;
break;
case OAuth2Type.Implicit: // Implicit
OAuth2Implicit @implicit = (OAuth2Implicit)oAuth2;
flow = new OpenApiOAuthFlow
{
AuthorizationUrl = new Uri(@implicit.AuthorizationUrl)
};
scheme.Flows.Implicit = flow;
break;
case OAuth2Type.ClientCredentials: // ClientCredentials
OAuth2ClientCredentials credentials = (OAuth2ClientCredentials)oAuth2;
flow = new OpenApiOAuthFlow
{
TokenUrl = new Uri(credentials.TokenUrl)
};
scheme.Flows.ClientCredentials = flow;
break;
}
Debug.Assert(flow != null);
flow.RefreshUrl = new Uri(oAuth2.RefreshUrl);
if (oAuth2.Scopes != null)
{
flow.Scopes = oAuth2.Scopes.ToDictionary(s => s.Scope, s => s.Description);
}
}
}
}

View file

@ -5,6 +5,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -20,10 +22,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created collection of <see cref="OpenApiServer"/> object.</returns>
public static IList<OpenApiServer> CreateServers(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
// The value of servers is an array of Server Objects.
// It contains one object with a field url.

View file

@ -6,6 +6,8 @@
using System.Collections.Generic;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -23,10 +25,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The string/schema dictionary.</returns>
public static IDictionary<string, OpenApiSchema> CreateSpatialSchemas(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
IDictionary<string, OpenApiSchema> schemas = new Dictionary<string, OpenApiSchema>();
@ -243,7 +242,7 @@ namespace Microsoft.OpenApi.OData.Generator
},
{ "coordinates", new OpenApiSchema { Reference = new OpenApiReference { Type = ReferenceType.Schema, Id = "GeoJSON.position" } } }
},
Required = new List<string>
Required = new HashSet<string>
{
"type",
"coordinates"
@ -278,7 +277,7 @@ namespace Microsoft.OpenApi.OData.Generator
}
}
},
Required = new List<string>
Required = new HashSet<string>
{
"type",
"coordinates"
@ -317,7 +316,7 @@ namespace Microsoft.OpenApi.OData.Generator
}
}
},
Required = new List<string>
Required = new HashSet<string>
{
"type",
"coordinates"
@ -351,7 +350,7 @@ namespace Microsoft.OpenApi.OData.Generator
}
}
},
Required = new List<string>
Required = new HashSet<string>
{
"type",
"coordinates"
@ -390,7 +389,7 @@ namespace Microsoft.OpenApi.OData.Generator
}
}
},
Required = new List<string>
Required = new HashSet<string>
{
"type",
"coordinates"
@ -433,7 +432,7 @@ namespace Microsoft.OpenApi.OData.Generator
}
}
},
Required = new List<string>
Required = new HashSet<string>
{
"type",
"coordinates"
@ -467,7 +466,7 @@ namespace Microsoft.OpenApi.OData.Generator
}
}
},
Required = new List<string>
Required = new HashSet<string>
{
"type",
"coordinates"

View file

@ -7,6 +7,8 @@ using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -15,6 +17,12 @@ namespace Microsoft.OpenApi.OData.Generator
/// </summary>
internal static class OpenApiTagGenerator
{
public static IList<OpenApiTag> CreateTags_FromTagItems(this ODataContext context)
{
Utils.CheckArgumentNull(context, nameof(context));
return context.Tags;
}
/// <summary>
/// Create the collection of <see cref="OpenApiTag"/> object.
/// </summary>
@ -22,10 +30,7 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created collection of <see cref="OpenApiTag"/> object.</returns>
public static IList<OpenApiTag> CreateTags(this ODataContext context)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
Utils.CheckArgumentNull(context, nameof(context));
// The value of tags is an array of Tag Objects.
// For an OData service the natural groups are entity sets and singletons,

View file

@ -9,6 +9,8 @@ using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Generator
{
@ -25,15 +27,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created path item name.</returns>
public static string CreateEntityPathName(this ODataContext context, IEdmEntitySet entitySet)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (entitySet == null)
{
throw Error.ArgumentNull(nameof(entitySet));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(entitySet, nameof(entitySet));
StringBuilder sb = new StringBuilder("/" + entitySet.Name);
IList<IEdmStructuralProperty> keys = entitySet.EntityType().Key().ToList();
@ -69,15 +64,8 @@ namespace Microsoft.OpenApi.OData.Generator
/// <returns>The created path item name</returns>
public static string CreatePathItemName(this ODataContext context, IEdmOperationImport operationImport)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (operationImport == null)
{
throw Error.ArgumentNull(nameof(operationImport));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operationImport, nameof(operationImport));
if (operationImport.IsActionImport())
{
@ -86,9 +74,19 @@ namespace Microsoft.OpenApi.OData.Generator
else
{
StringBuilder functionName = new StringBuilder("/" + operationImport.Name + "(");
functionName.Append(String.Join(",",
operationImport.Operation.Parameters.Select(p => p.Name + "=" + "{" + p.Name + "}")));
operationImport.Operation.Parameters.Select(p =>
{
if (p.Type.IsStructured() || p.Type.IsCollection())
{
return p.Name + "=@" + p.Name;
}
else
{
return p.Name + "={" + p.Name + "}";
}
})));
functionName.Append(")");
return functionName.ToString();
@ -99,19 +97,12 @@ namespace Microsoft.OpenApi.OData.Generator
/// Create the path item name for a <see cref="IEdmOperation"/>.
/// </summary>
/// <param name="context">The OData context.</param>
/// <param name="function">The Edm function.</param>
/// <param name="operation">The Edm operation.</param>
/// <returns>The created path item name</returns>
public static string CreatePathItemName(this ODataContext context, IEdmOperation operation)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (operation == null)
{
throw Error.ArgumentNull(nameof(operation));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(operation, nameof(operation));
if (operation.IsAction())
{
@ -131,20 +122,9 @@ namespace Microsoft.OpenApi.OData.Generator
public static string CreateNavigationPathItemName(this ODataContext context,
IEdmNavigationSource navigationSource, IEdmNavigationProperty navigationProperty)
{
if (context == null)
{
throw Error.ArgumentNull(nameof(context));
}
if (navigationSource == null)
{
throw Error.ArgumentNull(nameof(navigationSource));
}
if (navigationProperty == null)
{
throw Error.ArgumentNull(nameof(navigationProperty));
}
Utils.CheckArgumentNull(context, nameof(context));
Utils.CheckArgumentNull(navigationSource, nameof(navigationSource));
Utils.CheckArgumentNull(navigationProperty, nameof(navigationProperty));
string pathItemName;
IEdmEntitySet entitySet = navigationSource as IEdmEntitySet;
@ -179,30 +159,17 @@ namespace Microsoft.OpenApi.OData.Generator
// Structured or collection-valued parameters are represented as a parameter alias in the path template
// and the parameters array contains a Parameter Object for the parameter alias as a query option of type string.
int skip = function.IsBound ? 1 : 0;
int index = 0;
int parameterAliasIndex = 1;
foreach (IEdmOperationParameter edmParameter in function.Parameters.Skip(skip))
functionName.Append(String.Join(",", function.Parameters.Skip(skip).Select(p =>
{
if (index == 0)
if (p.Type.IsStructured() || p.Type.IsCollection())
{
index++;
return p.Name + "=@" + p.Name;
}
else
{
functionName.Append(",");
return p.Name + "={" + p.Name + "}";
}
if (edmParameter.Type.IsStructured() ||
edmParameter.Type.IsCollection())
{
functionName.Append(edmParameter.Name).Append("=")
.Append(context.Settings.ParameterAlias).Append(parameterAliasIndex++);
}
else
{
functionName.Append(edmParameter.Name).Append("={").Append(edmParameter.Name).Append("}");
}
}
})));
functionName.Append(")");

View file

@ -20,8 +20,8 @@
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.OData.Edm" Version="7.3.1" />
<PackageReference Include="Microsoft.OpenApi" Version="1.0.0-beta012" />
<PackageReference Include="Microsoft.OData.Edm" Version="7.5.0" />
<PackageReference Include="Microsoft.OpenApi" Version="1.0.1" />
</ItemGroup>
<ItemGroup>

View file

@ -4,6 +4,7 @@
// ------------------------------------------------------------
using System;
using Microsoft.OpenApi.OData.Abstractions;
namespace Microsoft.OpenApi.OData
{
@ -42,10 +43,35 @@ namespace Microsoft.OpenApi.OData
/// </summary>
public bool EnumPrefixFree { get; set; }
/// <summary>
/// Gets/set a value indicating whether to output the path for Edm operation.
/// </summary>
public bool EnableOperationPath { get; set; } = true;
/// <summary>
/// Gets/set a value indicating whether to output the path for Edm operation import.
/// </summary>
public bool EnableOperationImportPath { get; set; } = true;
/// <summary>
/// Gets/set a value indicating whether to output the path for Edm navigation property.
/// </summary>
public bool EnableNavigationPropertyPath { get; set; }
/// <summary>
/// Gets/set a value indicating the navigation property depth.
/// </summary>
public bool NavigationPropertyPathItem { get; set; }
public int NavigationPropertyDepth { get; set; } = 0;
/// <summary>
/// Gets/set a value indicating the tags name depth.
/// </summary>
public int TagDepth { get; set; } = 4;
/// <summary>
/// Gets/set a value indicating whether we count key segment as a depth.
/// </summary>
public bool CountKeySegmentAsDepth { get; set; } = true;
/// <summary>
/// Gets/set a value indicating the prefix for the parameter alias.
@ -68,5 +94,7 @@ namespace Microsoft.OpenApi.OData
/// otherwise keep number without quotes.
/// </summary>
public bool IEEE754Compatible { get; set; }
public IAuthorizationProvider AuthorizationProvider { get; set; }
}
}

View file

@ -0,0 +1,37 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// The Open Api operation for <see cref="IEdmActionImport"/>.
/// </summary>
internal class EdmActionImportOperationHandler : EdmOperationImportOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Post;
protected override void SetRequestBody(OpenApiOperation operation)
{
IEdmActionImport actionImport = EdmOperationImport as IEdmActionImport;
// The requestBody field contains a Request Body Object describing the structure of the request body.
// Its schema value follows the rules for Schema Objects for complex types, with one property per action parameter.
operation.RequestBody = Context.CreateRequestBody(actionImport);
}
/// <inheritdoc/>
protected override void SetExtensions(OpenApiOperation operation)
{
operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiString("actionImport"));
}
}
}

View file

@ -0,0 +1,43 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// The Open Api operation for <see cref="IEdmAction"/>.
/// </summary>
internal class EdmActionOperationHandler : EdmOperationOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Post;
/// <summary>
/// Gets the Edm Action.
/// </summary>
public IEdmAction Action => EdmOperation as IEdmAction;
/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
IEdmAction action = EdmOperation as IEdmAction;
if (action != null)
{
operation.RequestBody = Context.CreateRequestBody(action);
}
}
/// <inheritdoc/>
protected override void SetExtensions(OpenApiOperation operation)
{
operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiString("action"));
}
}
}

View file

@ -0,0 +1,39 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// The Open Api operation for <see cref="IEdmFunctionImport"/>.
/// </summary>
internal class EdmFunctionImportOperationHandler : EdmOperationImportOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Get;
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
IEdmFunctionImport functionImport = EdmOperationImport as IEdmFunctionImport;
//The parameters array contains a Parameter Object for each parameter of the function overload,
// and it contains specific Parameter Objects for the allowed system query options.
operation.Parameters = Context.CreateParameters(functionImport);
}
/// <inheritdoc/>
protected override void SetExtensions(OpenApiOperation operation)
{
operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiString("functionImport"));
}
}
}

View file

@ -0,0 +1,32 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// The Open Api operation for <see cref="IEdmFunction"/>.
/// </summary>
internal class EdmFunctionOperationHandler : EdmOperationOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Get;
/// <summary>
/// Gets the Edm Function.
/// </summary>
public IEdmFunction Function => EdmOperation as IEdmFunction;
/// <inheritdoc/>
protected override void SetExtensions(OpenApiOperation operation)
{
operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiString("function"));
}
}
}

View file

@ -0,0 +1,95 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System;
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Base class for <see cref="IEdmOperationImport"/>.
/// </summary>
internal abstract class EdmOperationImportOperationHandler : OperationHandler
{
/// <summary>
/// Gets the <see cref="IEdmOperationImport"/>.
/// </summary>
protected IEdmOperationImport EdmOperationImport { get; private set; }
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataOperationImportSegment operationImportSegment = path.LastSegment as ODataOperationImportSegment;
EdmOperationImport = operationImportSegment.OperationImport;
base.Initialize(context, path);
}
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
operation.Summary = "Invoke " + (EdmOperationImport.IsActionImport() ? "action " : "function ") + EdmOperationImport.Name;
if (Context.Settings.OperationId)
{
string key = "OperationImport." + EdmOperationImport.Name;
operation.OperationId += "OperationImport." + Context.GetIndex(key) + "-" + Utils.UpperFirstChar(EdmOperationImport.Name);
}
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
// The responses object contains a name/value pair for the success case (HTTP response code 200)
// describing the structure of the success response by referencing an appropriate schema
// in the global schemas. In addition, it contains a default name/value pair for
// the OData error response referencing the global responses.
operation.Responses = Context.CreateResponses(EdmOperationImport);
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{
operation.Tags = CreateTags(EdmOperationImport);
operation.Tags[0].Extensions.Add(Constants.xMsTocType, new OpenApiString("container"));
Context.AppendTag(operation.Tags[0]);
}
private static IList<OpenApiTag> CreateTags(IEdmOperationImport operationImport)
{
if (operationImport.EntitySet != null)
{
var pathExpression = operationImport.EntitySet as IEdmPathExpression;
if (pathExpression != null)
{
return new List<OpenApiTag>
{
new OpenApiTag
{
Name = PathAsString(pathExpression.PathSegments)
}
};
}
}
return new List<OpenApiTag>{
new OpenApiTag
{
Name = operationImport.Name
}
};
}
internal static string PathAsString(IEnumerable<string> path)
{
return String.Join("/", path);
}
}
}

View file

@ -0,0 +1,121 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Base class for operation of <see cref="IEdmOperation"/>.
/// </summary>
internal abstract class EdmOperationOperationHandler : OperationHandler
{
/// <summary>
/// Gets the navigation source.
/// </summary>
protected IEdmNavigationSource NavigationSource { get; private set; }
/// <summary>
/// Gets the Edm operation.
/// </summary>
protected IEdmOperation EdmOperation { get; private set; }
/// <summary>
/// Gets a value indicating whether the path has type cast segment or not.
/// </summary>
protected bool HasTypeCast { get; private set; }
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
NavigationSource = navigationSourceSegment.NavigationSource;
ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment;
EdmOperation = operationSegment.Operation;
HasTypeCast = path.Segments.Any(s => s is ODataTypeCastSegment);
base.Initialize(context, path);
}
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Invoke " + (EdmOperation.IsAction() ? "action " : "function ") + EdmOperation.Name;
// OperationId
if (Context.Settings.OperationId)
{
string key = NavigationSource.Name + "-" + Utils.UpperFirstChar(EdmOperation.Name);
int index = Context.GetIndex(key);
operation.OperationId = NavigationSource.Name + "." + index + "-" + Utils.UpperFirstChar(EdmOperation.Name);
}
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{
string value = EdmOperation.IsAction() ? "Actions" : "Functions";
OpenApiTag tag = new OpenApiTag
{
Name = NavigationSource.Name + "." + value,
};
tag.Extensions.Add(Constants.xMsTocType, new OpenApiString("container"));
operation.Tags.Add(tag);
Context.AppendTag(tag);
}
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
/*
IEdmSingleton singleton = NavigationSource as IEdmSingleton;
if (singleton == null && EdmOperation.IsBound)
{
IEdmOperationParameter bindingParameter = EdmOperation.Parameters.FirstOrDefault();
if (bindingParameter != null &&
!bindingParameter.Type.IsCollection() && // bound to a single entity
bindingParameter.Type.IsEntity())
{
operation.Parameters = Context.CreateKeyParameters(bindingParameter
.Type.AsEntity().EntityDefinition());
}
}*/
if (EdmOperation.IsFunction())
{
IEdmFunction function = (IEdmFunction)EdmOperation;
IList<OpenApiParameter> parameters = Context.CreateParameters(function);
if (operation.Parameters == null)
{
operation.Parameters = parameters;
}
else
{
foreach (var parameter in parameters)
{
operation.Parameters.Add(parameter);
}
}
}
}
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = Context.CreateResponses(EdmOperation);
}
}
}

View file

@ -0,0 +1,70 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Delete an Entity
/// The Path Item Object for the entity set contains the keyword delete with an Operation Object as value
/// that describes the capabilities for deleting the entity.
/// </summary>
internal class EntityDeleteOperationHandler : EntitySetOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Delete;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Delete entity from " + EntitySet.Name;
// override the summary using the request.Description.
var request = Context.FindRequest(EntitySet.EntityType(), OperationType.ToString());
if (request != null && request.Description != null)
{
operation.Summary = request.Description;
}
// OperationId
if (Context.Settings.OperationId)
{
string typeName = EntitySet.EntityType().Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".Delete" + Utils.UpperFirstChar(typeName);
}
}
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
operation.Parameters.Add(new OpenApiParameter
{
Name = "If-Match",
In = ParameterLocation.Header,
Description = "ETag",
Schema = new OpenApiSchema
{
Type = "string"
}
});
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};
}
}
}

View file

@ -0,0 +1,113 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Retrieve an Entity:
/// The Path Item Object for the entity contains the keyword get with an Operation Object as value
/// that describes the capabilities for retrieving a single entity.
/// </summary>
internal class EntityGetOperationHandler : EntitySetOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Get;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Get entity from " + EntitySet.Name + " by key";
// override the summary using the request.Description.
var request = Context.FindRequest(EntitySet.EntityType(), OperationType.ToString());
if (request != null && request.Description != null)
{
operation.Summary = request.Description;
}
// OperationId
if (Context.Settings.OperationId)
{
string typeName = EntitySet.EntityType().Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName);
}
}
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
// $select
OpenApiParameter parameter = Context.CreateSelect(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $expand
parameter = Context.CreateExpand(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
var request = Context.FindRequest(EntitySet.EntityType(), OperationType.ToString());
AppendCustomParameters(operation, request);
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode200,
new OpenApiResponse
{
Description = "Retrieved entity",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = EntitySet.EntityType().FullName()
}
}
}
}
},
Links = Context.CreateLinks(EntitySet)
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
}
/// <inheritdoc/>
protected override void SetSecurity(OpenApiOperation operation)
{
var request = Context.FindRequest(EntitySet.EntityType(), OperationType.ToString());
if (request != null)
{
operation.Security = Context.CreateSecurityRequirements(request.SecuritySchemes).ToList();
}
}
}
}

View file

@ -0,0 +1,80 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Update an Entity
/// The Path Item Object for the entity set contains the keyword patch with an Operation Object as value
/// that describes the capabilities for updating the entity.
/// </summary>
internal class EntityPatchOperationHandler : EntitySetOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Patch;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Update entity in " + EntitySet.Name;
// override the summary using the request.Description.
var request = Context.FindRequest(EntitySet.EntityType(), OperationType.ToString());
if (request != null && request.Description != null)
{
operation.Summary = request.Description;
}
// OperationId
if (Context.Settings.OperationId)
{
string typeName = EntitySet.EntityType().Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName);
}
}
/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Description = "New property values",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = EntitySet.EntityType().FullName()
}
}
}
}
}
};
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};
}
}
}

View file

@ -0,0 +1,166 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Query a Collection of Entities, it's a "Get" operation for <see cref="IEdmEntitySet"/>
/// The Path Item Object for the entity set contains the keyword get with an Operation Object as value
/// that describes the capabilities for querying the entity set.
/// For example: "/users"
/// </summary>
internal class EntitySetGetOperationHandler : EntitySetOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Get;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Get entities from " + EntitySet.Name;
var request = Context.FindRequest(EntitySet, OperationType.ToString());
if (request != null && request.Description != null)
{
operation.Summary = request.Description;
}
// OperationId
if (Context.Settings.OperationId)
{
string typeName = EntitySet.EntityType().Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".List" + Utils.UpperFirstChar(typeName);
}
}
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
// The parameters array contains Parameter Objects for all system query options allowed for this collection,
// and it does not list system query options not allowed for this collection, see terms
// Capabilities.TopSupported, Capabilities.SkipSupported, Capabilities.SearchRestrictions,
// Capabilities.FilterRestrictions, and Capabilities.CountRestrictions
// $top
OpenApiParameter parameter = Context.CreateTop(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $skip
parameter = Context.CreateSkip(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $search
parameter = Context.CreateSearch(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $filter
parameter = Context.CreateFilter(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $count
parameter = Context.CreateCount(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// the syntax of the system query options $expand, $select, and $orderby is too flexible
// to be formally described with OpenAPI Specification means, yet the typical use cases
// of just providing a comma-separated list of properties can be expressed via an array-valued
// parameter with an enum constraint
// $order
parameter = Context.CreateOrderBy(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $select
parameter = Context.CreateSelect(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $expand
parameter = Context.CreateExpand(EntitySet);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
var request = Context.FindRequest(EntitySet, OperationType.ToString());
AppendCustomParameters(operation, request);
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode200,
new OpenApiResponse
{
Description = "Retrieved entities",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Title = "Collection of " + EntitySet.EntityType().Name,
Type = "object",
Properties = new Dictionary<string, OpenApiSchema>
{
{
"value",
new OpenApiSchema
{
Type = "array",
Items = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = EntitySet.EntityType().FullName()
}
}
}
}
}
}
}
}
}
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
}
}
}

View file

@ -0,0 +1,46 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Base class for entity set operation.
/// </summary>
internal abstract class EntitySetOperationHandler : OperationHandler
{
/// <summary>
/// Gets/sets the <see cref="IEdmEntitySet"/>.
/// </summary>
protected IEdmEntitySet EntitySet { get; private set; }
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
// get the entity set.
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet;
base.Initialize(context, path);
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{
OpenApiTag tag = new OpenApiTag
{
Name = EntitySet.Name + "." + EntitySet.EntityType().Name,
};
tag.Extensions.Add(Constants.xMsTocType, new OpenApiString("page"));
operation.Tags.Add(tag);
Context.AppendTag(tag);
}
}
}

View file

@ -0,0 +1,114 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Create an Entity:
/// The Path Item Object for the entity set contains the keyword "post" with an Operation Object as value
/// that describes the capabilities for creating new entities.
/// </summary>
internal class EntitySetPostOperationHandler : EntitySetOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Post;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Add new entity to " + EntitySet.Name;
var request = Context.FindRequest(EntitySet, OperationType.ToString());
if (request != null && request.Description != null)
{
operation.Summary = request.Description;
}
// OperationId
if (Context.Settings.OperationId)
{
string typeName = EntitySet.EntityType().Name;
operation.OperationId = EntitySet.Name + "." + typeName + ".Create" + Utils.UpperFirstChar(typeName);
}
}
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
var request = Context.FindRequest(EntitySet, OperationType.ToString());
AppendCustomParameters(operation, request);
}
/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
// The requestBody field contains a Request Body Object for the request body
// that references the schema of the entity sets entity type in the global schemas.
operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Description = "New entity",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = EntitySet.EntityType().FullName()
}
}
}
}
}
};
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode201,
new OpenApiResponse
{
Description = "Created entity",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = EntitySet.EntityType().FullName()
}
}
}
}
}
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
}
}
}

View file

@ -0,0 +1,29 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// An interface to create a <see cref="OpenApiOperation"/> based on <see cref="ODataPath"/>.
/// </summary>
internal interface IOperationHandler
{
/// <summary>
/// The operation type.
/// </summary>
OperationType OperationType { get; }
/// <summary>
/// Create the <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="path">The OData path.</param>
/// <returns>The created <see cref="OpenApiOperation"/>.</returns>
OpenApiOperation CreateOperation(ODataContext context, ODataPath path);
}
}

View file

@ -0,0 +1,24 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// An interface to provider <see cref="IOperationHandler"/>.
/// </summary>
internal interface IOperationHandlerProvider
{
/// <summary>
/// Get the <see cref="IOperationHandler"/>.
/// </summary>
/// <param name="pathType">The path type.</param>
/// <param name="operationType">The operation type.</param>
/// <returns>The corresponding <see cref="IOperationHandler"/>.</returns>
IOperationHandler GetHandler(ODataPathType pathType, OperationType operationType);
}
}

View file

@ -0,0 +1,159 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Retrieve a navigation property from a navigation source.
/// The Path Item Object for the entity contains the keyword get with an Operation Object as value
/// that describes the capabilities for retrieving a navigation property form a navigation source.
/// </summary>
internal class NavigationPropertyGetOperationHandler : NavigationPropertyOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Get;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Get " + NavigationProperty.Name + " from " + NavigationSource.Name;
// OperationId
if (Context.Settings.OperationId)
{
string prefix = "Get";
if (!LastSegmentIsKeySegment && NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
prefix = "List";
}
/*
string key = NavigationSource.Name + "." + NavigationProperty.Name + "-" + prefix + Utils.UpperFirstChar(NavigationProperty.ToEntityType().Name);
int index = Context.GetIndex(key);
operation.OperationId = NavigationSource.Name + "." + NavigationProperty.Name + index + "-" + prefix + Utils.UpperFirstChar(NavigationProperty.ToEntityType().Name);
*/
operation.OperationId = GetOperationId(prefix);
}
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode200,
new OpenApiResponse
{
Description = "Retrieved navigation property",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = NavigationProperty.ToEntityType().FullName()
}
}
}
}
}
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
}
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
if (operation.Parameters == null)
{
operation.Parameters = new List<OpenApiParameter>();
}
if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
// The parameters array contains Parameter Objects for system query options allowed for this entity set,
// and it does not list system query options not allowed for this entity set.
OpenApiParameter parameter = Context.CreateTop(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateSkip(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateSearch(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateFilter(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateCount(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateOrderBy(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateSelect(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateExpand(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
}
else
{
OpenApiParameter parameter = Context.CreateSelect(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
parameter = Context.CreateExpand(NavigationProperty);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
}
}
}
}

View file

@ -0,0 +1,136 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Base class for operation of <see cref="IEdmNavigationProperty"/>.
/// </summary>
internal abstract class NavigationPropertyOperationHandler : OperationHandler
{
/// <summary>
/// Gets the navigation property.
/// </summary>
protected IEdmNavigationProperty NavigationProperty { get; private set; }
/// <summary>
/// Gets the navigation source.
/// </summary>
protected IEdmNavigationSource NavigationSource { get; private set; }
/// <summary>
/// Gets a bool value indicating whether the last segment is a key segment.
/// </summary>
protected bool LastSegmentIsKeySegment { get; private set; }
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
NavigationSource = navigationSourceSegment.NavigationSource;
LastSegmentIsKeySegment = path.LastSegment is ODataKeySegment;
ODataNavigationPropertySegment npSegment = path.LastSegment as ODataNavigationPropertySegment;
if (npSegment == null)
{
npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment;
}
NavigationProperty = npSegment.NavigationProperty;
base.Initialize(context, path);
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{
IList<string> items = new List<string>
{
NavigationSource.Name
};
foreach (var segment in Path.Segments.Skip(1))
{
if (segment is ODataNavigationPropertySegment)
{
ODataNavigationPropertySegment npSegment = (ODataNavigationPropertySegment)segment;
if (npSegment.NavigationProperty == NavigationProperty)
{
items.Add(NavigationProperty.ToEntityType().Name);
break;
}
else
{
if (items.Count >= Context.Settings.TagDepth - 1)
{
items.Add(npSegment.NavigationProperty.ToEntityType().Name);
break;
}
else
{
items.Add(segment.Name);
}
}
}
}
string name = string.Join(".", items);
OpenApiTag tag = new OpenApiTag
{
// Name = NavigationSource.Name + "." + NavigationProperty.ToEntityType().Name,
Name = name
};
tag.Extensions.Add(Constants.xMsTocType, new OpenApiString("page"));
operation.Tags.Add(tag);
Context.AppendTag(tag);
}
protected string GetOperationId(string prefix)
{
IList<string> items = new List<string>
{
NavigationSource.Name
};
var lastpath = Path.Segments.Last(c => c is ODataNavigationPropertySegment);
foreach (var segment in Path.Segments.Skip(1))
{
if (segment is ODataNavigationPropertySegment)
{
ODataNavigationPropertySegment npSegment = (ODataNavigationPropertySegment)segment;/*
if (npSegment.NavigationProperty == NavigationProperty)
{
items.Add(prefix + Utils.UpperFirstChar(NavigationProperty.ToEntityType().Name));
break;
}
else
{
items.Add(segment.Name);
}*/
if (segment == lastpath)
{
items.Add(prefix + Utils.UpperFirstChar(segment.Name));
break;
}
else
{
items.Add(segment.Name);
}
}
}
return string.Join(".", items);
}
}
}

View file

@ -0,0 +1,78 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Update a navigation property for a navigation source.
/// The Path Item Object for the entity set contains the keyword patch with an Operation Object as value
/// that describes the capabilities for updating the navigation property for a navigation source.
/// </summary>
internal class NavigationPropertyPatchOperationHandler : NavigationPropertyOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Patch;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Update the navigation property " + NavigationProperty.Name + " in " + NavigationSource.Name;
// OperationId
if (Context.Settings.OperationId)
{
string prefix = "Update";
//string key = NavigationSource.Name + "." + NavigationProperty.Name + "-" + prefix + Utils.UpperFirstChar(NavigationProperty.ToEntityType().Name);
// int index = Context.GetIndex(key);
// operation.OperationId = NavigationSource.Name + "." + NavigationProperty.Name + index + "-" + prefix + Utils.UpperFirstChar(NavigationProperty.ToEntityType().Name);
operation.OperationId = GetOperationId(prefix);
}
}
/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Description = "New navigation property values",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = NavigationProperty.ToEntityType().FullName()
}
}
}
}
}
};
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};
}
}
}

View file

@ -0,0 +1,102 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Create a navigation for a navigation source.
/// The Path Item Object for the entity set contains the keyword delete with an Operation Object as value
/// that describes the capabilities for create a navigation for a navigation source.
/// </summary>
internal class NavigationPropertyPostOperationHandler : NavigationPropertyOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Post;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Create new navigation property to " + NavigationProperty.Name + " for " + NavigationSource.Name;
// OperationId
if (Context.Settings.OperationId)
{
string prefix = "Create";
/*
string key = NavigationSource.Name + "." + NavigationProperty.Name + "-" + prefix + Utils.UpperFirstChar(NavigationProperty.ToEntityType().Name);
int index = Context.GetIndex(key);
operation.OperationId = NavigationSource.Name + "." + NavigationProperty.Name + index + "-" + prefix + Utils.UpperFirstChar(NavigationProperty.ToEntityType().Name);
*/
operation.OperationId = GetOperationId(prefix);
}
}
/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Description = "New navigation property",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = NavigationProperty.ToEntityType().FullName()
}
}
}
}
}
};
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode201,
new OpenApiResponse
{
Description = "Created navigation property.",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = NavigationProperty.ToEntityType().FullName()
}
}
}
}
}
}
}
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
}
}
}

View file

@ -0,0 +1,212 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using System.Linq;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Annotations;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Base class for <see cref="OpenApiOperation"/> handler.
/// </summary>
internal abstract class OperationHandler : IOperationHandler
{
/// <inheritdoc/>
public abstract OperationType OperationType { get; }
/// <inheritdoc/>
public virtual OpenApiOperation CreateOperation(ODataContext context, ODataPath path)
{
Context = context ?? throw Error.ArgumentNull(nameof(context));
Path = path ?? throw Error.ArgumentNull(nameof(path));
// Initialize the object ahead.
Initialize(context, path);
OpenApiOperation operation = new OpenApiOperation();
// Description / Summary / OperationId
SetBasicInfo(operation);
// Security
SetSecurity(operation);
// Responses
SetResponses(operation);
// RequestBody
SetRequestBody(operation);
// Parameters
SetParameters(operation);
// Tags
SetTags(operation);
// Extensions
SetExtensions(operation);
return operation;
}
/// <summary>
/// Gets the OData context.
/// </summary>
protected ODataContext Context { get; private set; }
/// <summary>
/// Gets the OData path.
/// </summary>
protected ODataPath Path { get; private set; }
/// <summary>
/// Initialize the handler.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="path">The path.</param>
protected virtual void Initialize(ODataContext context, ODataPath path)
{ }
/// <summary>
/// Set the basic information for <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="operation">The <see cref="OpenApiOperation"/>.</param>
protected virtual void SetBasicInfo(OpenApiOperation operation)
{ }
/// <summary>
/// Set the security information for <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="operation">The <see cref="OpenApiOperation"/>.</param>
protected virtual void SetSecurity(OpenApiOperation operation)
{ }
/// <summary>
/// Set the responses information for <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="operation">The <see cref="OpenApiOperation"/>.</param>
protected virtual void SetResponses(OpenApiOperation operation)
{ }
/// <summary>
/// Set the request body information for <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="operation">The <see cref="OpenApiOperation"/>.</param>
protected virtual void SetRequestBody(OpenApiOperation operation)
{ }
/// <summary>
/// Set the parameters information for <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="operation">The <see cref="OpenApiOperation"/>.</param>
protected virtual void SetParameters(OpenApiOperation operation)
{
foreach (ODataKeySegment keySegment in Path.OfType<ODataKeySegment>())
{
foreach (var p in Context.CreateKeyParameters(keySegment.EntityType))
{
operation.Parameters.Add(p);
}
}
}
/// <summary>
/// Set the Tags information for <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="operation">The <see cref="OpenApiOperation"/>.</param>
protected virtual void SetTags(OpenApiOperation operation)
{ }
/// <summary>
/// Set the Extensions information for <see cref="OpenApiOperation"/>.
/// </summary>
/// <param name="operation">The <see cref="OpenApiOperation"/>.</param>
protected virtual void SetExtensions(OpenApiOperation operation)
{
operation.Extensions.Add(Constants.xMsDosOperationType, new OpenApiString("operation"));
}
protected static void AppendCustomParameters(OpenApiOperation operation, HttpRequest request)
{
if (request == null)
{
return;
}
if (operation.Parameters == null)
{
operation.Parameters = new List<OpenApiParameter>();
}
if (request.CustomQueryOptions != null)
{
AppendCustomParameters(operation.Parameters, request.CustomQueryOptions, ParameterLocation.Query);
}
if (request.CustomQueryOptions != null)
{
AppendCustomParameters(operation.Parameters, request.CustomHeaders, ParameterLocation.Header);
}
}
private static void AppendCustomParameters(IList<OpenApiParameter> parameters, IList<CustomParameter> headers, ParameterLocation location)
{
foreach (var param in headers)
{
OpenApiParameter parameter = new OpenApiParameter
{
In = location,
Name = param.Name,
Description = param.Description,
Schema = new OpenApiSchema
{
// Type = param.Type
},
Required = param.Required ?? false
};
if (param.DocumentationURL != null)
{
parameter.Example = new OpenApiString(param.DocumentationURL?? "N/A");
}
if (param.ExampleValues != null)
{
parameter.Examples = new Dictionary<string, OpenApiExample>();
int index = 1;
foreach (var example in param.ExampleValues)
{
OpenApiExample ex = new OpenApiExample
{
Description = example.Description
};
if (example is ExternalExample)
{
var externalExample = (ExternalExample)example;
ex.Value = new OpenApiString(externalExample.ExternalValue ?? "N/A");
}
else
{
var inlineExample = (InlineExample)example;
ex.Value = new OpenApiString(inlineExample.InlineValue ?? "N/A");
}
parameter.Examples.Add("example-" + index++, ex);
}
}
parameters.Add(parameter);
}
}
}
}

View file

@ -0,0 +1,77 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using System.Collections.Generic;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// A class to provide the <see cref="IOperationHandler"/>.
/// </summary>
internal class OperationHandlerProvider : IOperationHandlerProvider
{
private IDictionary<ODataPathType, IDictionary<OperationType, IOperationHandler>> _handlers;
/// <summary>
/// Initializes a new instance of <see cref="OperationHandlerProvider"/> class.
/// </summary>
public OperationHandlerProvider()
{
_handlers = new Dictionary<ODataPathType, IDictionary<OperationType, IOperationHandler>>();
// entity set (Get/Post)
_handlers[ODataPathType.EntitySet] = new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EntitySetGetOperationHandler() },
{OperationType.Post, new EntitySetPostOperationHandler() }
};
// entity (Get/Patch/Delete)
_handlers[ODataPathType.Entity] = new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EntityGetOperationHandler() },
{OperationType.Patch, new EntityPatchOperationHandler() },
{OperationType.Delete, new EntityDeleteOperationHandler() }
};
// singleton (Get/Patch)
_handlers[ODataPathType.Singleton] = new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new SingletonGetOperationHandler() },
{OperationType.Patch, new SingletonPatchOperationHandler() }
};
// edm operation (Get|Post)
_handlers[ODataPathType.Operation] = new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EdmFunctionOperationHandler() },
{OperationType.Post, new EdmActionOperationHandler() }
};
// edm operation import (Get|Post)
_handlers[ODataPathType.OperationImport] = new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new EdmFunctionImportOperationHandler() },
{OperationType.Post, new EdmActionImportOperationHandler() }
};
// navigation property (Get/Patch/Post)
_handlers[ODataPathType.NavigationProperty] = new Dictionary<OperationType, IOperationHandler>
{
{OperationType.Get, new NavigationPropertyGetOperationHandler() },
{OperationType.Patch, new NavigationPropertyPatchOperationHandler() },
{OperationType.Post, new NavigationPropertyPostOperationHandler() }
};
}
/// <inheritdoc/>
public IOperationHandler GetHandler(ODataPathType pathType, OperationType operationType)
{
return _handlers[pathType][operationType];
}
}
}

View file

@ -0,0 +1,102 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Retrieve a Singleton
/// The Path Item Object for the entity set contains the keyword get with an Operation Object as value
/// that describes the capabilities for retrieving the singleton.
/// </summary>
internal class SingletonGetOperationHandler : SingletonOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Get;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Get " + Singleton.Name;
var request = Context.FindRequest(Singleton, OperationType.ToString());
if (request != null && request.Description != null)
{
operation.Summary = request.Description;
}
// OperationId
if (Context.Settings.OperationId)
{
string typeName = Singleton.EntityType().Name;
operation.OperationId = Singleton.Name + "." + typeName + ".Get" + Utils.UpperFirstChar(typeName);
}
}
/// <inheritdoc/>
protected override void SetParameters(OpenApiOperation operation)
{
base.SetParameters(operation);
operation.Parameters = new List<OpenApiParameter>();
IEdmEntityType entityType = Singleton.EntityType();
// $select
OpenApiParameter parameter = Context.CreateSelect(Singleton);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
// $expand
parameter = Context.CreateExpand(Singleton);
if (parameter != null)
{
operation.Parameters.Add(parameter);
}
var request = Context.FindRequest(Singleton, OperationType.ToString());
AppendCustomParameters(operation, request);
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{
Constants.StatusCode200,
new OpenApiResponse
{
Description = "Retrieved entity",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType,
new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = Singleton.EntityType().FullName()
}
}
}
}
}
}
},
};
operation.Responses.Add(Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse());
}
}
}

View file

@ -0,0 +1,47 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Base class for operation of <see cref="IEdmSingleton"/>.
/// </summary>
internal abstract class SingletonOperationHandler : OperationHandler
{
/// <summary>
/// Gets the <see cref="IEdmSingleton"/>.
/// </summary>
protected IEdmSingleton Singleton { get; private set; }
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton;
base.Initialize(context, path);
}
/// <inheritdoc/>
protected override void SetTags(OpenApiOperation operation)
{
OpenApiTag tag = new OpenApiTag
{
Name = Singleton.Name + "." + Singleton.EntityType().Name,
};
tag.Extensions.Add(Constants.xMsTocType, new OpenApiString("page"));
operation.Tags.Add(tag);
Context.AppendTag(tag);
}
}
}

View file

@ -0,0 +1,79 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Generator;
namespace Microsoft.OpenApi.OData.Operation
{
/// <summary>
/// Update a Singleton
/// The Path Item Object for the entity set contains the keyword patch with an Operation Object as value
/// that describes the capabilities for updating the singleton, unless the singleton is read-only.
/// </summary>
internal class SingletonPatchOperationHandler : SingletonOperationHandler
{
/// <inheritdoc/>
public override OperationType OperationType => OperationType.Patch;
/// <inheritdoc/>
protected override void SetBasicInfo(OpenApiOperation operation)
{
// Summary
operation.Summary = "Update " + Singleton.Name;
var request = Context.FindRequest(Singleton, OperationType.ToString());
if (request != null && request.Description != null)
{
operation.Summary = request.Description;
}
// OperationId
if (Context.Settings.OperationId)
{
string typeName = Singleton.EntityType().Name;
operation.OperationId = Singleton.Name + "." + typeName + ".Update" + Utils.UpperFirstChar(typeName);
}
}
/// <inheritdoc/>
protected override void SetRequestBody(OpenApiOperation operation)
{
operation.RequestBody = new OpenApiRequestBody
{
Required = true,
Description = "New property values",
Content = new Dictionary<string, OpenApiMediaType>
{
{
Constants.ApplicationJsonMediaType, new OpenApiMediaType
{
Schema = new OpenApiSchema
{
Reference = new OpenApiReference
{
Type = ReferenceType.Schema,
Id = Singleton.EntityType().FullName()
}
}
}
}
}
};
}
/// <inheritdoc/>
protected override void SetResponses(OpenApiOperation operation)
{
operation.Responses = new OpenApiResponses
{
{ Constants.StatusCode204, Constants.StatusCode204.GetResponse() },
{ Constants.StatusCodeDefault, Constants.StatusCodeDefault.GetResponse() }
};
}
}
}

View file

@ -0,0 +1,38 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Capabilities;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Path item handler for Entity Set.
/// </summary>
internal class EntityPathItemHandler : EntitySetPathItemHandler
{
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
IndexableByKey index = new IndexableByKey(Context.Model, EntitySet);
if (index.IsSupported())
{
AddOperation(item, OperationType.Get);
}
UpdateRestrictions update = new UpdateRestrictions(Context.Model, EntitySet);
if (update.IsUpdatable())
{
AddOperation(item, OperationType.Patch);
}
DeleteRestrictions delete = new DeleteRestrictions(Context.Model, EntitySet);
if (delete.IsDeletable())
{
AddOperation(item, OperationType.Delete);
}
}
}
}

View file

@ -0,0 +1,44 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Capabilities;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for <see cref="IEdmEntitySet"/>.
/// </summary>
internal class EntitySetPathItemHandler : PathItemHandler
{
/// <summary>
/// Gets the entity set.
/// </summary>
protected IEdmEntitySet EntitySet { get; private set; }
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
AddOperation(item, OperationType.Get);
InsertRestrictions insert = new InsertRestrictions(Context.Model, EntitySet);
if (insert.IsInsertable())
{
AddOperation(item, OperationType.Post);
}
}
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
EntitySet = navigationSourceSegment.NavigationSource as IEdmEntitySet;
base.Initialize(context, path);
}
}
}

View file

@ -0,0 +1,24 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Interface for <see cref="OpenApiPathItem"/>.
/// </summary>
internal interface IPathItemHandler
{
/// <summary>
/// Create <see cref="OpenApiPathItem"/> based on <see cref="ODataContext"/> and <see cref="ODataPath"/>.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="path">The path.</param>
/// <returns>The created <see cref="OpenApiPathItem"/>.</returns>
OpenApiPathItem CreatePathItem(ODataContext context, ODataPath path);
}
}

View file

@ -0,0 +1,22 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Interface for <see cref="IPathItemHandler"/>.
/// </summary>
internal interface IPathItemHandlerProvider
{
/// <summary>
/// Get the <see cref="IPathItemHandler"/> based on the path type.
/// </summary>
/// <param name="pathType">The path type.</param>
/// <returns>The <see cref="IPathItemHandler"/>.</returns>
IPathItemHandler GetHandler(ODataPathType pathType);
}
}

View file

@ -0,0 +1,136 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Linq;
using System.Collections.Generic;
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.Any;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for a single <see cref="IEdmNavigationProperty"/>.
/// </summary>
internal class NavigationPropertyPathItemHandler : PathItemHandler
{
/// <summary>
/// Gets the navigation property.
/// </summary>
public IEdmNavigationProperty NavigationProperty { get; private set; }
/// <summary>
/// Gets the navigation source.
/// </summary>
public IEdmNavigationSource NavigationSource { get; private set; }
/// <summary>
/// Gets a bool value indicating whether the last segment is a key segment.
/// </summary>
protected bool LastSegmentIsKeySegment { get; private set; }
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
// contaiment: Get / (Post - Collection | Patch - Single)
// non-containment: only Get
AddOperation(item, OperationType.Get);
if (NavigationProperty.ContainsTarget)
{
if (NavigationProperty.TargetMultiplicity() == EdmMultiplicity.Many)
{
if (LastSegmentIsKeySegment)
{
UpdateRestrictions update = new UpdateRestrictions(Context.Model, NavigationProperty);
if (update.IsUpdatable())
{
AddOperation(item, OperationType.Patch);
}
}
else
{
InsertRestrictions insert = new InsertRestrictions(Context.Model, NavigationProperty);
if (insert.IsInsertable())
{
AddOperation(item, OperationType.Post);
}
}
}
else
{
UpdateRestrictions update = new UpdateRestrictions(Context.Model, NavigationProperty);
if (update.IsUpdatable())
{
AddOperation(item, OperationType.Patch);
}
}
}
}
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
NavigationSource = navigationSourceSegment.NavigationSource;
LastSegmentIsKeySegment = path.LastSegment is ODataKeySegment;
ODataNavigationPropertySegment npSegment = path.LastSegment as ODataNavigationPropertySegment;
if (npSegment == null)
{
npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment;
}
NavigationProperty = npSegment.NavigationProperty;
base.Initialize(context, path);
}
/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem item)
{
IList<ODataPath> samePaths = new List<ODataPath>();
foreach (var path in Context.Paths.Where(p => p.PathType == ODataPathType.NavigationProperty && p != Path))
{
bool lastIsKeySegment = path.LastSegment is ODataKeySegment;
if (LastSegmentIsKeySegment != lastIsKeySegment)
{
continue;
}
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
if (NavigationSource != navigationSourceSegment.NavigationSource)
{
continue;
}
ODataNavigationPropertySegment npSegment = path.LastSegment as ODataNavigationPropertySegment;
if (npSegment == null)
{
npSegment = path.Segments[path.Count - 2] as ODataNavigationPropertySegment;
}
if (NavigationProperty != npSegment.NavigationProperty)
{
continue;
}
samePaths.Add(path);
}
if (samePaths.Any())
{
OpenApiArray array = new OpenApiArray();
foreach(var p in samePaths)
{
array.Add(new OpenApiString(p.ToString()));
}
item.Extensions.Add(Constants.xMsDosGroupPath, array);
}
}
}
}

View file

@ -0,0 +1,52 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for a single <see cref="IEdmOperationImport"/>.
/// </summary>
internal class OperationImportPathItemHandler : PathItemHandler
{
/// <summary>
/// Gets the operation import.
/// </summary>
public IEdmOperationImport EdmOperationImport { get; private set; }
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
if (EdmOperationImport.IsActionImport())
{
// Each action import is represented as a name/value pair whose name is the service-relative
// resource path of the action import prepended with a forward slash, and whose value is a Path
// Item Object containing the keyword post with an Operation Object as value that describes
// how to invoke the action import.
AddOperation(item, OperationType.Post);
}
else
{
// Each function import is represented as a name/value pair whose name is the service-relative
// resource path of the function import prepended with a forward slash, and whose value is a Path
// Item Object containing the keyword get with an Operation Object as value that describes
// how to invoke the function import.
AddOperation(item, OperationType.Get);
}
}
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataOperationImportSegment operationImportSegment = path.FirstSegment as ODataOperationImportSegment;
EdmOperationImport = operationImportSegment.OperationImport;
base.Initialize(context, path);
}
}
}

View file

@ -0,0 +1,87 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Any;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using System.Collections.Generic;
using System.Linq;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Create the bound operations for the navigation source.
/// </summary>
internal class OperationPathItemHandler : PathItemHandler
{
/// <summary>
/// Gets the Edm operation.
/// </summary>
public IEdmOperation EdmOperation { get; private set; }
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
if (EdmOperation.IsAction())
{
// The Path Item Object for a bound action contains the keyword post,
// The value of the operation keyword is an Operation Object that describes how to invoke the action.
AddOperation(item, OperationType.Post);
}
else
{
// The Path Item Object for a bound function contains the keyword get,
// The value of the operation keyword is an Operation Object that describes how to invoke the function.
AddOperation(item, OperationType.Get);
}
}
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment;
EdmOperation = operationSegment.Operation;
base.Initialize(context, path);
}
/// <inheritdoc/>
protected override void SetExtensions(OpenApiPathItem item)
{
ODataNavigationSourceSegment navigationSourceSegment = Path.FirstSegment as ODataNavigationSourceSegment;
IEdmNavigationSource currentNavSource = navigationSourceSegment.NavigationSource;
IList<ODataPath> samePaths = new List<ODataPath>();
foreach (var path in Context.Paths.Where(p => p.PathType == ODataPathType.Operation && p != Path))
{
navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
if (currentNavSource != navigationSourceSegment.NavigationSource)
{
continue;
}
ODataOperationSegment operationSegment = path.LastSegment as ODataOperationSegment;
if (EdmOperation.FullName() != operationSegment.Operation.FullName())
{
continue;
}
samePaths.Add(path);
}
if (samePaths.Any())
{
OpenApiArray array = new OpenApiArray();
foreach (var p in samePaths)
{
array.Add(new OpenApiString(p.ToString()));
}
item.Extensions.Add(Constants.xMsDosGroupPath, array);
}
}
}
}

View file

@ -0,0 +1,79 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Common;
using Microsoft.OpenApi.OData.Edm;
using Microsoft.OpenApi.OData.Operation;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Base class for <see cref="IPathItemHandler"/>.
/// </summary>
internal abstract class PathItemHandler : IPathItemHandler
{
/// <summary>
/// Gets the OData Context.
/// </summary>
protected ODataContext Context { get; private set; }
/// <summary>
/// Gets the OData Path.
/// </summary>
protected ODataPath Path { get; private set; }
/// <inheritdoc/>
public virtual OpenApiPathItem CreatePathItem(ODataContext context, ODataPath path)
{
Context = context ?? throw Error.ArgumentNull(nameof(context));
Path = path ?? throw Error.ArgumentNull(nameof(path));
Initialize(context, path);
OpenApiPathItem item = new OpenApiPathItem();
SetOperations(item);
SetExtensions(item);
return item;
}
/// <summary>
/// Set the operation for the path item.
/// </summary>
/// <param name="item">The path item.</param>
protected abstract void SetOperations(OpenApiPathItem item);
/// <summary>
/// Initialize the Handler.
/// </summary>
/// <param name="context">The context.</param>
/// <param name="path">The path.</param>
protected virtual void Initialize(ODataContext context, ODataPath path)
{ }
/// <summary>
/// Set the extensions for the path item.
/// </summary>
/// <param name="item">The path item.</param>
protected virtual void SetExtensions(OpenApiPathItem item)
{ }
/// <summary>
/// Add one operation into path item.
/// </summary>
/// <param name="item">The path item.</param>
/// <param name="operationType">The operatin type.</param>
protected void AddOperation(OpenApiPathItem item, OperationType operationType)
{
IOperationHandlerProvider provider = Context.OperationHanderProvider;
IOperationHandler operationHander = provider.GetHandler(Path.PathType, operationType);
item.AddOperation(operationType, operationHander.CreateOperation(Context, Path));
}
}
}

View file

@ -0,0 +1,43 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using System.Collections.Generic;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Default path item handler provider.
/// </summary>
internal class PathItemHandlerProvider : IPathItemHandlerProvider
{
private IDictionary<ODataPathType, IPathItemHandler> _handlers = new Dictionary<ODataPathType, IPathItemHandler>
{
// Entity
{ ODataPathType.EntitySet, new EntitySetPathItemHandler() },
// Entity
{ ODataPathType.Entity, new EntityPathItemHandler() },
// Singleton
{ ODataPathType.Singleton, new SingletonPathItemHandler() },
// Navigation property
{ ODataPathType.NavigationProperty, new NavigationPropertyPathItemHandler() },
// Edm Operation
{ ODataPathType.Operation, new OperationPathItemHandler() },
// Edm OperationImport
{ ODataPathType.OperationImport, new OperationImportPathItemHandler() },
};
/// <inheritdoc/>
public IPathItemHandler GetHandler(ODataPathType pathType)
{
return _handlers[pathType];
}
}
}

View file

@ -0,0 +1,45 @@
// ------------------------------------------------------------
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
// ------------------------------------------------------------
using Microsoft.OData.Edm;
using Microsoft.OpenApi.Models;
using Microsoft.OpenApi.OData.Capabilities;
using Microsoft.OpenApi.OData.Edm;
namespace Microsoft.OpenApi.OData.PathItem
{
/// <summary>
/// Create a <see cref="OpenApiPathItem"/> for <see cref="IEdmSingleton"/>.
/// </summary>
internal class SingletonPathItemHandler : PathItemHandler
{
/// <summary>
/// Gets the entity set.
/// </summary>
protected IEdmSingleton Singleton { get; private set; }
/// <inheritdoc/>
protected override void SetOperations(OpenApiPathItem item)
{
// Retrieve a singleton.
AddOperation(item, OperationType.Get);
// Update a singleton
UpdateRestrictions update = new UpdateRestrictions(Context.Model, Singleton);
if (update.IsUpdatable())
{
AddOperation(item, OperationType.Patch);
}
}
/// <inheritdoc/>
protected override void Initialize(ODataContext context, ODataPath path)
{
ODataNavigationSourceSegment navigationSourceSegment = path.FirstSegment as ODataNavigationSourceSegment;
Singleton = navigationSourceSegment.NavigationSource as IEdmSingleton;
base.Initialize(context, path);
}
}
}

View file

@ -69,6 +69,15 @@ namespace Microsoft.OpenApi.OData.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to The authorization record type name &apos;{0}&apos; is not correct..
/// </summary>
internal static string AuthorizationRecordTypeNameNotCorrect {
get {
return ResourceManager.GetString("AuthorizationRecordTypeNameNotCorrect", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The filed name of extension doesn&apos;t begin with x-..
/// </summary>

View file

@ -120,6 +120,9 @@
<data name="ArgumentNullOrEmpty" xml:space="preserve">
<value>The argument '{0}' is null or empty.</value>
</data>
<data name="AuthorizationRecordTypeNameNotCorrect" xml:space="preserve">
<value>The authorization record type name '{0}' is not correct.</value>
</data>
<data name="ExtensionFieldNameMustBeginWithXMinus" xml:space="preserve">
<value>The filed name of extension doesn't begin with x-.</value>
</data>

View file

@ -254,7 +254,7 @@ namespace OoasGui
private void NavPathcheckBox_CheckedChanged(object sender, EventArgs e)
{
Settings.NavigationPropertyPathItem = !Settings.NavigationPropertyPathItem;
Settings.EnableNavigationPropertyPath = !Settings.EnableNavigationPropertyPath;
Convert();
}
}

View file

@ -32,11 +32,11 @@
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Microsoft.OData.Edm, Version=7.3.1.10814, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OData.Edm.7.3.1\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
<Reference Include="Microsoft.OData.Edm, Version=7.5.0.20627, Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OData.Edm.7.5.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll</HintPath>
</Reference>
<Reference Include="Microsoft.OpenApi, Version=1.0.0.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OpenApi.1.0.0-beta012\lib\net46\Microsoft.OpenApi.dll</HintPath>
<Reference Include="Microsoft.OpenApi, Version=1.0.1.0, Culture=neutral, PublicKeyToken=3f5743946376f042, processorArchitecture=MSIL">
<HintPath>..\..\packages\Microsoft.OpenApi.1.0.1\lib\net46\Microsoft.OpenApi.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Core" />

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Microsoft.OData.Edm" version="7.3.1" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.0.0-beta012" targetFramework="net461" />
<package id="Microsoft.OData.Edm" version="7.5.0" targetFramework="net461" />
<package id="Microsoft.OpenApi" version="1.0.1" targetFramework="net461" />
</packages>

Some files were not shown because too many files have changed in this diff Show more