Git Product home page Git Product logo

swashbuckle.odata's Introduction

Swashbuckle.OData

Coverage Status

Extends Swashbuckle with OData v4 support! Supports both WebApi and OData controllers!

Getting Started

Install Swashbuckle

Install the Swashbuckle.OData NuGet package:

Install-Package Swashbuckle.OData

In SwaggerConfig configure the custom provider:

c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, GlobalConfiguration.Configuration));

Include Navigation Properties in your entity swagger models

By default, OData does not get related entities unless you specify $expand on a navigation property. Swashbuckle.OData tries to accurately reflect this behavior and therefore, by default, does not include navigation properties in your entity swagger models. You can override this though by specifying:

c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, GlobalConfiguration.Configuration).Configure(odataConfig =>
                    {
                        odataConfig.IncludeNavigationProperties();
                    }));

Enable caching of swagger requests

To enable the built-in cache functionality you must set this configuration:

c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, GlobalConfiguration.Configuration).Configure(odataConfig =>
                    {
                        // Enable Cache for swagger doc requests
                        odataConfig.EnableSwaggerRequestCaching();
                    }));

Assemblies Resolver dependency injection for OData Models

Configuration example to inject your own IAssembliesResolver instead of using DefaultAssembliesResolver:

c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, GlobalConfiguration.Configuration).Configure(odataConfig =>
                    {
                        //Set custom AssembliesResolver
                        odataConfig.SetAssembliesResolver(new CustomAssembliesResolver());
                    }));

Custom Swagger Routes

The following snippet demonstrates how to configure a custom swagger route such that it will appear in the Swagger UI:

// Let's say you map a custom OData route that doesn't follow the OData conventions 
// and where the target controller action doesn't have an [ODataRoute] attribute
var customODataRoute = config.MapODataServiceRoute("CustomODataRoute", ODataRoutePrefix, GetModel(), batchHandler: null, pathHandler: new DefaultODataPathHandler(), routingConventions: myCustomConventions);

// Then describe your route to Swashbuckle.OData so that it will appear in the Swagger UI
config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders")
    .Operation(HttpMethod.Post)
    // The name of the parameter as it appears in the path
    .PathParameter<int>("Id")
    // The name of the parameter as it appears in the controller action
    .BodyParameter<Order>("order");

The above route resolves to an OrdersController (the last path segment defining the controller) and hits the Post action:

[ResponseType(typeof(Order))]
public async Task<IHttpActionResult> Post([FromODataUri] int customerId, Order order)
{
  ...
}

Custom property resolver

The following snippet demonstrates how to configure a custom property resolver, which resolves a schema's property name, instead of using a DataMemberAttribute:

c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, GlobalConfiguration.Configuration).Configure(odataConfig =>
                    {
                        //Set custom ProperyResolver
                        odataConfig.SetProperyResolver(new DefaultProperyResolver());
                    }));

RESTier

By default, Swashbuckle.OData only displays RESTier routes for top-level entity types. You can describe and display additional routes, for related types, in the Swagger UI by configuring custom swagger routes. For example from the Northwind model, to display a route that queries an Order (a related type) for a Customer (a top-level entity type), configure the following:

var restierRoute = await config.MapRestierRoute<DbApi<NorthwindContext>>("RESTierRoute", "restier", new RestierBatchHandler(server));

config.AddCustomSwaggerRoute(restierRoute, "/Customers({CustomerId})/Orders({OrderId})")
    .Operation(HttpMethod.Get)
    .PathParameter<string>("CustomerId")
    .PathParameter<int>("OrderId");

Route prefixes that have parameters

The follow snippet demonstrates how to configure route prefixes that have parameters:

// For example, if you have a route prefix with a parameter "tenantId" of type long
var odataRoute = config.MapODataServiceRoute("odata", "odata/{tenantId}", builder.GetEdmModel());

// Then add the following route constraint so that Swashbuckle.OData knows the parameter type.
// If you don't add this line then the parameter will be assumed to be of type string.
odataRoute.Constraints.Add("tenantId", new LongRouteConstraint());

Swashbuckle.OData supports the following route constraints:

Parameter Type Route Constraint
bool BoolRouteConstraint
DateTime DateTimeRouteConstraint
decimal DecimalRouteConstraint
double DoubleRouteConstraint
float FloatRouteConstraint
Guid GuidRouteConstraint
int IntRouteConstraint
long LongRouteConstraint

OWIN

If your service is hosted using OWIN middleware, configure the custom provider as follows:

httpConfiguration
    .EnableSwagger(c =>
    {
        // Use "SingleApiVersion" to describe a single version API. Swagger 2.0 includes an "Info" object to
        // hold additional metadata for an API. Version and title are required but you can also provide
        // additional fields by chaining methods off SingleApiVersion.
        //
        c.SingleApiVersion("v1", "A title for your API");

        // Wrap the default SwaggerGenerator with additional behavior (e.g. caching) or provide an
        // alternative implementation for ISwaggerProvider with the CustomProvider option.
        //
        c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c, httpConfiguration));
    })
    .EnableSwaggerUi();

Development

You'll need:

  1. Visual Studio 2015
  2. Code Contracts
  3. NuGet Package Project to generate the NuGet package.

If you submit an enhancement or bug fix, please include a unit test similar to this that verifies the change. Let's shoot for 100% unit test coverage of the code base.

swashbuckle.odata's People

Contributors

0xced avatar andyward avatar bigred8982 avatar bkwdesign avatar cibergarri avatar cilerler avatar jondavis-ineight avatar kdet avatar kfstorm avatar mjolka avatar rbeauchamp avatar seanmaber avatar vantubbe avatar will-chan-sage avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

swashbuckle.odata's Issues

Include default response schema for error handling

I believe the original code in ODataSwaggerUitlites included a generic default response on every operation which referenced the error schema in definitions section. Somewhere along the line this got lost. It would be great to fix so that every operation gets something like:

    "responses": {
      "200": {...
      },
      "default": {
        "description": "Unexpected error",
        "schema": { "$ref": "#/definitions/_Error" }
      }
    }

And also include schema in the definition section something like:

  "definitions": {
    "_Error": { "properties": { "error": { "$ref": "#/definitions/_InError" } } },
    "_InError": {
      "properties": {
        "code": { "type": "string" },
        "message": { "type": "string" }
      }
    }
  }

Controllers not being rendered depending on what functions defined (issue started the transition from 2.0.0 to 2.1.0)

After upgrading to 2.6.1, my controllers are not rendering on the UI.

The swagger ui screen just display "Finished Loading Resource Information. Rendering Swagger UI..." and never loads the controllers.

Did anything change between those versions?

I actually was able to narrow it down when it started breaking and that was from version 2.0.0 to version 2.1.0. In my project, I injected a custom route which implements the SelectAction & SelectController methods. Surprisingly in 2.0.0, when you trigger the swagger UI the code will hit the SelectionAction and the controllerContext will not be null. However, in 2.1.0+ the controllerContext is null and that is why the Swagger UI does not render any of the controllers or actions.

Any idea of what could have caused this?

Update

So it seems the issue is because from 2.0.0 to 2.1.1, more stricter logic was put into place. For some reason Swashbuckle.OData would crap out and the exception would never be thrown or never be displayed in the UI. As a result, controllers that are process after that exception never gets rendered in the swagger UI. I believe it process the controllers in ABC order.

I was also able to isolate the problem even further. There is three problems that I've seen.

  1. If you implement a function with the signature:
[EnableQuery]
public Task<IHttpActionResult> Get(int value)
{
        throw new NotImplementedException();
}

This will throw an exception "{"Processing of the HTTP request resulted in an exception. Please see the HTTP response returned by the 'Response' property of this exception for details."}"

Inner Exception: "
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
at System.Web.OData.Routing.ODataActionSelector.SelectAction(HttpControllerContext controllerContext)
at Swashbuckle.OData.Descriptions.HttpRequestMessageExtensions.GetHttpActionDescriptor(HttpRequestMessage request)
"

  1. If you have a function parameter of ODataQueryOptions
[EnableQuery]
 public Task<IHttpActionResult> Get(ODataQueryOptions<Customer> queryOptions)
{
        throw new NotImplementedException();
 }

This will actually cause the controller to be not rendered completely on the swagger UI. This will also prevent any other processing of any further controllers that have not be processed. The UI will only display the controller that were processed before the issue occurred.

  1. It's also interesting that if your "Customer" controller has a function Get() instead of GetCustomer(), the swagger will automatically generate two "Get" calls for the UI. One that takes in only the [enableQuery] parameters, and the other takes in an "int id" and a "select" parameter, but none of the other [enableQuery] parameters you would expect.

BTW: the current sample that is checked in goes in an infinite loop and never the swagger UI never loads. the 2.6.1 tagged sample. Also it doesn't compile due to some minor issue that can be fixed easily.

Let me know if this make sense,
You can actually just add to the project i linked you before and just add the methods I mentioned above to reproduce the problems.

Thanks,
Derek

Support Rest and OData API Mix?

I have an API that combines both ApiController and ODataController in a single app. Adding the ODataSwaggerProvider properly documents the OData calls, but hides the documentation for the REST calls. Is this a known issue? Is there a workaround?

Accurate OData response schema

The response schema isn't exactly what's coming back from OData. For example, when you request Orders_Get the response body contains a context string followed by a values aray of Order objects like this:
{
"@odata.context": "https://microsoft-apiapp18a6d.azurewebsites.net/Northwind/v4/$metadata#Orders",
"value": [
{
"OrderID": 10248,
"CustomerID": "VINET",
"EmployeeID": 5,
"OrderDate": "1996-07-04",
"RequiredDate": "1996-08-01",
"ShippedDate": "1996-07-16",
"ShipVia": 3,
"Freight": 32.38,
"ShipName": "Vins et alcools Chevalier",
"ShipAddress": "59 rue de l'Abbaye",
"ShipCity": "Reims",
"ShipRegion": null,
"ShipPostalCode": "51100",
"ShipCountry": "France"
},
{...}
]}

With the following swagger we're not describing that the data will be inside the value array property:

    "responses": {
      "200": {
        "description": "EntitySet Orders",
        "schema": { "$ref": "#/definitions/NorthwindAPI.Models.Order" }
      },
      "default": {
        "description": "Unexpected error",
        "schema": { "$ref": "#/definitions/_Error" }
      }

As a result, some tools don't like it.

Perhaps this schema in swagger output would be better:

    "responses": {
      "200": {
        "description": "OK",
        "schema": {
          "title": "response",
          "type": "object",
          "properties": {
            "context": {
              "type": "string"
            },
            "value": {
              "type": "array",
              "items": {
                "$ref": "#/definitions/Order"
              }
            }
          }
        }
      },
    },

I'd like to do some more testing to see how this change might be beneficial, but reached a dead end so thought I'd share the idea if you're interested.

Limit graph nesting

Is there a way to limit graph nesting, like telling it to include no deeper than 2 levels of navigation properties?

I'm not sure if this is an Swashbuckle.OData issue or a Swashbuckle issue, but we have a model being returned that, in the way it is used, would normally have null navigation properties at the second or third level, but Swashbuckle.OData is outputting a response object graph that is like 10 levels deep, so the browser locks up for a long time or blows up with out of memory exceptions.

Navigation property not automatically routed, requires custom route declaration

The OData EDM should have all the navigation properties fully disclosed for introspection, so to expose the route to a navigation property should be automatic.

We have this route.

    // GET: odata/AppLicenses(5)/Application
    [EnableQuery]
    public SingleResult<Application> GetApplication([FromODataUri] Guid key)
    {
        return SingleResult.Create(ConfigurationDataContext.AppLicenses.Where(m => m.AccountConfigurationID == key).Select(m => m.Application));
    }

In order to get this otherwise fully functional OData route to appear in Swagger, I had to make the following change.

    [EnableQuery]
    [ODataRoute("AppLicenses({AccountConfigurationID})/Application")]
    public SingleResult<Application> GetApplication([FromODataUri] Guid AccountConfigurationID)
    {
        return SingleResult.Create(ConfigurationDataContext.AppLicenses.Where(m => m.AccountConfigurationID == AccountConfigurationID).Select(m => m.Application));
    }

It would be ideal if this didn't have to be treated as a custom route.

Support Custom Swagger Routes with RESTier

Is it possible to add a custom route when using RESTier? I was not able to accomplish that... Do I have to use the CustomNavigationPropertyRoutingConvention? At the moment Operations are only created for top level entities (e.g. GET /Accounts(id) or GET /Locations(id)) but for linked entities are no operation available (e.g. I would like to see: GET /Accounts(id)/Locations)

Any hints how to accomplish that?

Full object graph should be displayed for WebApi controller models

Hi,
the use of the following line is hiding all the no primitive type property in the Swagger JSON.

c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c));

example:

.NET

public int Id { get; set; }
public string Name { get; set; }
public bool ReadPermission { get; set; }
public bool WritePermission { get; set; }
public ICollection IPWhitelist { get; set; }
public string ApiKey { get; set; }
public string ApiSecret { get; set; }
public bool IsActive { get; set; }

JSON

{
"Id": 0,
"Name": "string",
"ReadPermission": true,
"WritePermission": true,
"ApiKey": "string",
"ApiSecret": "string",
"IsActive": true
}

EnsureUniqueOperationIdsFilter

We use our own logic to generate operation id's.It would be very helpfull if there would be an option to turn off the EnsureUniqueOperationIdsFilter when setting up Swashbuckle.OData in the Swagger pipeline.

Thanks in advance.

Parameter Constructor expected or exception is thrown

It seems that with one of my controller, it requires that you have a parameter less Constructor. If one isn't present, an exception will be thrown when you try to load the swagger UI. Is this a specific requirement for using swashbuckle Odata?

500 : {
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred when trying to create a controller of type 'ProductsController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at Swashbuckle.OData.Descriptions.HttpRequestMessageExtensions.GetHttpActionDescriptor(HttpRequestMessage request)\r\n at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(HttpMethod httpMethod, Operation potentialOperation, String potentialPathTemplate, ODataRoute oDataRoute, HttpConfiguration httpConfig)\r\n at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig)\r\n at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.<>c__DisplayClass3_0.b__1(SwaggerRoute potentialSwaggerRoute)\r\n at System.Linq.Enumerable.d__12.MoveNext()\r\n at System.Linq.Enumerable.<SelectManyIterator>d__12.MoveNext()\r\n at System.Linq.Enumerable.d__12.MoveNext()\r\n at System.Linq.Enumerable.<DistinctIterator>d__11.MoveNext()\r\n at System.Collections.Generic.List1..ctor(IEnumerable1 collection)\r\n at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)\r\n at Swashbuckle.OData.CollectionExtentions.ToCollection[T](IEnumerable1 source)\r\n at Swashbuckle.OData.Descriptions.ODataApiExplorer.GetApiDescriptions()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at System.Lazy1.get_Value()\r\n at Swashbuckle.OData.Descriptions.ODataApiExplorer.get_ApiDescriptions()\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Cors.CorsMessageHandler.<>n__FabricatedMethod3(HttpRequestMessage , CancellationToken )\r\n at System.Web.Http.Cors.CorsMessageHandler.<SendAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter1.GetResult()\r\n at System.Web.Http.HttpServer.d__0.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Type ProductsController' does not have a default constructor",
"ExceptionType": "System.ArgumentException",
"StackTrace": " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
} http://localhost:4448/swagger/docs/v1

Thanks,
D

Exception Value cannot be null. Parameter name: baseUrl

Hi,

In the latest version (v.2.12.0), I get this error when opening swagger UI. In version 2.1.1 this error doesn't occur:

JavaScript runtime error: 500 : {"Message":"An error has occurred.","ExceptionMessage":"Value cannot be null.\r\nParameter name: baseUrl","ExceptionType":"System.ArgumentNullException","StackTrace":" at Flurl.Url..ctor(String baseUrl) in c:\Aldenteware\Flurl\code\Flurl\Url.cs:line 28\r\n at Flurl.StringExtensions.AppendPathSegment(String url, String segment) in c:\Aldenteware\Flurl\code\Flurl\StringExtensions.cs:line 27\r\n at Swashbuckle.OData.Descriptions.ODataSwaggerUtilities.GetPathForEntitySet(String routePrefix, IEdmEntitySet entitySet)\r\n at Swashbuckle.OData.Descriptions.EntityDataModelRouteGenerator.<>c__DisplayClass2_0.b__0(IEdmEntitySet entitySet)\r\n at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()\r\n at System.Collections.Generic.List1.InsertRange(Int32 index, IEnumerable1 collection)\r\n at System.Collections.Generic.List1.AddRange(IEnumerable1 collection)\r\n at Swashbuckle.OData.CollectionExtentions.AddRangeIfNotNull[T](List1 source, IEnumerable1 collection)\r\n at Swashbuckle.OData.Descriptions.EntityDataModelRouteGenerator.Generate(ODataRoute oDataRoute)\r\n at System.Linq.Enumerable.<SelectManyIterator>d__162.MoveNext()\r\n at System.Linq.Enumerable.d__162.MoveNext()\r\n at System.Linq.Enumerable.<SelectManyIterator>d__162.MoveNext()\r\n at System.Linq.Enumerable.d__162.MoveNext()\r\n at System.Linq.Enumerable.<SelectManyIterator>d__162.MoveNext()\r\n at System.Linq.Enumerable.d__631.MoveNext()\r\n at System.Collections.Generic.List1..ctor(IEnumerable1 collection)\r\n at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)\r\n at Swashbuckle.OData.CollectionExtentions.ToCollection[T](IEnumerable1 source)\r\n at Swashbuckle.OData.Descriptions.ODataApiExplorer.GetApiDescriptions()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at System.Lazy1.get_Value()\r\n at Swashbuckle.OData.Descriptions.ODataApiExplorer.get_ApiDescriptions()\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.HttpServer.<>n__FabricatedMethod9(HttpRequestMessage , CancellationToken )\r\n at System.Web.Http.HttpServer.d__0.MoveNext()"}

I'm testing a simple Web API project with OData and hosted with OWIN.

Generate valid JSON expected by http://editor.swagger.io

Hi,

I'm not sure if this is really an issue, but an observation that I notice. I'm not sure if this is related to an issue with swashbuckle or is it swashbuckle.OData.

I noticed that when you take the swagger json via "swagger/docs/v1" and copy and paste it on http://editor.swagger.io/#/, there are some potential issues/improvements:

  1. It doesn't take advantage of the ""basePath" attribute, and as a result for each end point will copy the basePath. This seems a bit repetitive.

Example: if the URL is "localhost/api/vi/Products GET

Generated json will display: "GET /api/vi/Products" If the baseURL is used, then you can display "GET /Products/" instead.

  1. Also the generated json populates each endpoint with a
"consumes": [],
"produces": [],

If these two fields are not filled in, then you will not be able to use the "Try this" for the end point on the swagger UI and an error "Object is missing the required property 'accept'"

It's expecting the "produces": ["application/json"]". If all the endpoints, accept the same it can be marked at the higher level then each endpoint.

However, its interesting the the swagger UI that is generated doesn't have this issue, but the generated .json does. I would expect it to be consistent in terms of the swagger UI and the swagger json that represents the UI to be consistent.

Thanks,
D

Custom Attribute Route implementation

The method GetODataActionDescriptorsFromAttributeRoutes in Swashbuckle.OData.Descriptions uses the Reflection Helper to get the field _attributeMappings form the Attribute Routing convention. If you create a custom implementation of AttributeRoutingConvention, for instance to override ShouldMapController this results in a error in the Reflection Helper. This because the fact that the field that is looked up could be a field of one of the base classes is not taken into account. This could be fixed by checking if the base class of the incoming object contains the requested field if the first lookup fails in the GetInstanceField method of the reflection helpers. I would be very grateful if this could be implemented.

Value cannot be null Parameter name: virtualPath

The following error happens just after Install-Package Swashbuckle.OData and the adding of c.CustomProvider(defaultProvider => new ODataSwaggerProvider(defaultProvider, c)); into my existing Swagger config file.

Any idea?

500 : {"Message":"An error has occurred.","ExceptionMessage":"Value cannot be null.\r\nParameter name: virtualPath","ExceptionType":"System.ArgumentNullException","StackTrace":" at System.Web.VirtualPath.Create(String virtualPath, VirtualPathOptions options)\r\n at System.Web.Hosting.MapPathBasedVirtualPathProvider.CacheLookupOrInsert(String virtualPath, Boolean isFile)\r\n at System.Web.Routing.RouteCollection.IsRouteToExistingFile(HttpContextBase httpContext)\r\n at System.Web.Routing.RouteCollection.GetRouteData(HttpContextBase httpContext)\r\n at System.Web.Http.WebHost.Routing.HostedHttpRouteCollection.GetRouteData(HttpRequestMessage request)\r\n at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.CreateHttpRequestMessage(HttpMethod httpMethod, Operation potentialOperation, String potentialPathTemplate, ODataRoute oDataRoute, HttpConfiguration httpConfig)\r\n at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(HttpMethod httpMethod, Operation potentialOperation, String potentialPathTemplate, ODataRoute oDataRoute, HttpConfiguration httpConfig)\r\n at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig)\r\n at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.<>c__DisplayClass3_0.b__1(SwaggerRoute potentialSwaggerRoute)\r\n at System.Linq.Enumerable.d__162.MoveNext()\r\n at System.Linq.Enumerable.<SelectManyIterator>d__162.MoveNext()\r\n at System.Linq.Enumerable.d__162.MoveNext()\r\n at System.Linq.Enumerable.<DistinctIterator>d__631.MoveNext()\r\n at System.Collections.Generic.List1..ctor(IEnumerable1 collection)\r\n at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)\r\n at Swashbuckle.OData.CollectionExtentions.ToCollection[T](IEnumerable1 source)\r\n at Swashbuckle.OData.Descriptions.ODataApiExplorer.GetApiDescriptions()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at Swashbuckle.OData.Descriptions.ODataApiExplorer.get_ApiDescriptions()\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Owin.PassiveAuthenticationMessageHandler.d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.HttpServer.d__0.MoveNext()"} http://localhost/Easy.Docs.API/swagger/docs/v1

Exception received when accessing UI @ URL/swagger/ui/index

I receive the following error when accessing the UI document. Please fix. Thank you.

500 : {"Message":"An error has occurred.","ExceptionMessage":"Bad Request - Error in query syntax.","ExceptionType":"Microsoft.OData.Core.ODataException","StackTrace":" at Microsoft.OData.Core.UriParser.Parsers.SegmentKeyHandler.TryCreateKeySegmentFromParentheses(ODataPathSegment previous, KeySegment previousKeySegment, String parenthesisExpression, ODataPathSegment& keySegment, Boolean enableUriTemplateParsing, ODataUriResolver resolver)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.TryBindKeyFromParentheses(String parenthesesSection)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.TryCreateSegmentForNavigationSource(String identifier, String parenthesisExpression)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreateFirstSegment(String segmentText)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.ParsePath(ICollection1 segments)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathFactory.BindPath(ICollection1 segments, ODataUriParserConfiguration configuration)\r\n at Microsoft.OData.Core.UriParser.ODataUriParser.ParsePathImplementation()\r\n at Microsoft.OData.Core.UriParser.ODataUriParser.Initialize()\r\n at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath, ODataUriResolverSetttings resolverSettings, Boolean enableUriTemplateParsing)\r\n at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath)\r\n at Swashbuckle.OData.ODataApiExplorer.GenerateSampleODataPath(ODataRoute oDataRoute, String pathTemplate, Operation operation)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescription(HttpMethod httpMethod, ODataRoute oDataRoute, String potentialPathTemplate, Operation potentialOperation)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute, String potentialPathTemplate, PathItem potentialOperations)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at System.Lazy`1.get_Value()\r\n at Swashbuckle.OData.ODataApiExplorer.get_ApiDescriptions()\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.HttpServer.d__0.MoveNext()"} http://localhost:59758/swagger/docs/v1

System.MissingMethodException Swashbuckle.Swagger.SchemaRegistry..ctor

Hi

I am getting the following error when accessing /swagger for

Swashbuckle.Core" version="5.3.1"
Swashbuckle.OData" version="2.16.0"

System.MissingMethodException: Method not found: 'Void Swashbuckle.Swagger.SchemaRegistry..ctor(Newtonsoft.Json.JsonSerializerSettings, System.Collections.Generic.IDictionary2<System.Type,System.Func1<Swashbuckle.Swagger.Schema>>, System.Collections.Generic.IEnumerable1<Swashbuckle.Swagger.ISchemaFilter>, System.Collections.Generic.IEnumerable1<Swashbuckle.Swagger.IModelFilter>, Boolean, System.Func`2<System.Type,System.String>, Boolean, Boolean)'

at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)
at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
....

Thanks
Jรผrg

Child Collections of ODataController in Swagger UI

Child collections are not shown for ODataControllers.

In the example here: http://swashbuckleodata.azurewebsites.net/swagger/ui/index

The Customers ODataController resource does not show that in the GET, that Orders is available. It only shows primitive types (string, int etc).

The ApiController resource shows child resources (in the example Projects is a child collection of Client GET ApiController).

Can child collections be added to ODataControllers please?

Provide support for multiple routes

Currently if multiple OData routes are configured, an exception is thrown when getting the Swagger UI:

500 : {"Message":"An error has occurred.","ExceptionMessage":"Sequence contains more than one matching element","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.Linq.Enumerable.SingleOrDefault[TSource](IEnumerable1 source, Func2 predicate)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.HttpServer.<>n__FabricatedMethod9(HttpRequestMessage , CancellationToken )\r\n at System.Web.Http.HttpServer.d__0.MoveNext()"} http://localhost:59758/swagger/docs/v1

Error installing package from nuget

PM> Install-Package Swashbuckle.OData
Installing 'Swashbuckle.OData 2.10.1'.
Successfully installed 'Swashbuckle.OData 2.10.1'.
Adding 'Swashbuckle.OData 2.10.1' to GlobalCalendarWebApi.
Uninstalling 'Swashbuckle.OData 2.10.1'.
Successfully uninstalled 'Swashbuckle.OData 2.10.1'.
Install failed. Rolling back...
Install-Package : Could not install package 'Swashbuckle.OData 2.10.1'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.5', but the package does not contain any assembly
references or content files that are compatible with that framework. For more information, contact the package author.
At line:1 char:16

  • Install-Package <<<< Swashbuckle.OData
    • CategoryInfo : NotSpecified: (:) [Install-Package], InvalidOperationException
    • FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.InstallPackageCommand

Issue with odata routes that contain route prefixes with parameters

If a ODataRoute is registered with a route prefix that contains parameters I received the following exception when requesting the swagger route.

Ex) Within a WebApiConfig class or similar

config.MapODataServiceRoute(
    routeName: "ODataRoute",
    routePrefix: "{version}/{tenant}",
    model: builder.GetEdmModel()
);

Exception Message
The path variable 'VERSION' in the UriTemplate must be bound to a non-empty string value. Parameter name: parameters

Stack Trace
at System.UriTemplate.VariablesCollection.LoadDefaultsAndValidate(String[] normalizedParameters, Int32& lastNonDefaultPathParameter, Int32& lastNonNullablePathParameter) at System.UriTemplate.VariablesCollection.ProcessDefaultsAndCreateBindInfo(Boolean omitDefaults, String[] normalizedParameters, IDictionary2 extraParameters, BindInformation& bindInfo) at System.UriTemplate.VariablesCollection.PrepareBindInformation(IDictionary2 parameters, Boolean omitDefaults) at System.UriTemplate.BindByName(Uri baseAddress, IDictionary2 parameters, Boolean omitDefaults) at Swashbuckle.OData.Descriptions.OperationExtensions.GenerateSampleODataAbsoluteUri(Operation operation, String serviceRoot, String pathTemplate) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.CreateHttpRequestMessage(HttpMethod httpMethod, Operation potentialOperation, String potentialPathTemplate, ODataRoute oDataRoute, HttpConfiguration httpConfig) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(HttpMethod httpMethod, Operation potentialOperation, String potentialPathTemplate, ODataRoute oDataRoute, HttpConfiguration httpConfig) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.<>c__DisplayClass3_0.<Generate>b__1(SwaggerRoute potentialSwaggerRoute) at System.Linq.Enumerable.<SelectManyIterator>d__162.MoveNext() at System.Linq.Enumerable.d__162.MoveNext() at System.Linq.Enumerable.<SelectManyIterator>d__162.MoveNext() at System.Linq.Enumerable.d__631.MoveNext() at System.Collections.Generic.List1..ctor(IEnumerable1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source) at Swashbuckle.OData.CollectionExtentions.ToCollection[T](IEnumerable1 source) at Swashbuckle.OData.Descriptions.ODataApiExplorer.GetApiDescriptions() at System.Lazy1.CreateValue() at System.Lazy`1.LazyInitValue() at Swashbuckle.OData.Descriptions.ODataApiExplorer.get_ApiDescriptions() at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion) at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion) at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.HttpServer.<>n__FabricatedMethod9(HttpRequestMessage , CancellationToken ) at System.Web.Http.HttpServer.d__0.MoveNext()

Enhancement to Custom Routing

I haven't had a chance to really take a look at the inner workings of the swashbuckle.OData code base, so please bear with me.

Here are some suggestions (not sure how difficult or complex it would be):

Problem:

The extra steps that you require the user to define the custom route seems a bit much. The reason being is that the user would have to do this for every single route at this point because of the injected custom route class. From my understanding the key appeal of swagger/swashbuckle is that it automatically scans the code with little additional work on the user side to display the endpoints. If that is true, here are some suggestions:

Suggestion:

  1. If you choose this method, is it possible to trigger off special OData attribute similar to Route(" ") on top of every function in the controller for custom routes. This will make the code more readable/maintainable. If the function has say a special attribute "[ODataCustomRoute("")] then trigger off that. By doing this, you wouldn't have to specify the Controller or even the parameters in the config file since you have all that info from being in the Controller class and the attribute would be connected to the function signature where you can attract the params.

  2. If that is too complicated, you can just have the user associate the attributes at the controller level.

  3. Another possible way to resolve the issue, is it possible to take advantage of the return functions of the custom route class.

I'm not really sure how the code scan for routes works, so not sure if this is possible. However, The custom route class overrides two functions. SelectAction & SelectController. When the application starts up & swagger OData starts scanning the code for endpoints, is it possible to use the custom route class to retrieve the Controller (This eliminates the need to specify the controller) and also the action (eliminates the need to specify the action). By using reflection, is it possible to scan for function in the controller and the parameters. These would indicate the possible routes no? There is probably a lot of details that i'm leaving out which makes it difficult.

Please let me know if the suggestions make sense,
Thanks,
Derek

Installation issue?

HI,

I tried to install the package, but get the following issue? Any idea of how to resolve it?

PM> Install-Package Swashbuckle.OData
Installing 'Swashbuckle.OData 2.0.0'.
Successfully installed 'Swashbuckle.OData 2.0.0'.
Adding 'Swashbuckle.OData 2.0.0' to Swagger.
Uninstalling 'Swashbuckle.OData 2.0.0'.
Successfully uninstalled 'Swashbuckle.OData 2.0.0'.
Install failed. Rolling back...
Install-Package : Could not install package 'Swashbuckle.OData 2.0.0'. You are
trying to install this package into a project that targets
'.NETFramework,Version=v4.5', but the package does not contain any assembly
references or content files that are compatible with that framework. For more
information, contact the package author.
At line:1 char:1

  • Install-Package Swashbuckle.OData
  • - CategoryInfo          : NotSpecified: (:) [Install-Package], InvalidOper 
      ationException
    - FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.C 
      ommands.InstallPackageCommand
    

Router not registering with string based keys

By default the route created with swagger for the delete operation looks like this:

https://localhost:44300/odata/v1/SafetyEquipment(testthis!)

but that wont work because the way to use a string based key is to surround the string with quotes in the parenthesis like so:

https://localhost:44300/odata/v1/SafetyEquipment('testthis!')

The result is a 404 because that route (the one without quotes) doesn't exist.

from the controller:

public virtual async Task<IHttpActionResult> Delete([FromODataUri] string key)
{
    // delete tasks
}

Support for other methods

Hi,

Having upgraded to .Net 4.6 and added this to the project we are now trying out the documentation created. It appears this creates a standard set of operations (get, post, patch, delete). Our OData controllers never implement patch, and instead implement put. Also not all controllers implement the full range of operations. Am I missing something, or is there no way for it to discover the API methods, or to enable or disable methods such as patch and put?

Exception "An item with the same key has already been added." when using CustomProvider ODataSwaggerProvider

I get an exception on SendAsync of my main handler when the request for http://localhost/swagger/ui/index comes in.

The exception is "An item with the same key has already been added" and the stacktrace is added below. It only happens when adding c.CustomProvider((defaultProvider) => new ODataSwaggerProvider(defaultProvider, c)); to the SwaggerConfig, otherwise Swashbuckle works fine, only with the non-OData controllers in my project.

---Stacktrace---
at System.ThrowHelper.ThrowArgumentException(ExceptionResource resource) at System.Collections.Generic.Dictionary``2.Insert(TKey key, TValue value, Boolean add) at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable``1 source, Func``2 keySelector, Func``2 elementSelector, IEqualityComparer``1 comparer) at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable``1 source, Func``2 keySelector, Func``2 elementSelector) at Swashbuckle.OData.Descriptions.OperationExtensions.GenerateSamplePathParameterValues(Operation operation) at Swashbuckle.OData.Descriptions.OperationExtensions.GenerateSampleODataUri(Operation operation, String serviceRoot, String pathTemplate) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.CreateHttpRequestMessage(HttpMethod httpMethod, Operation potentialOperation, SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(HttpMethod httpMethod, Operation potentialOperation, SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig) at Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.<>c__DisplayClass3_0.<Generate>b__1(SwaggerRoute potentialSwaggerRoute) at System.Linq.Enumerable.<SelectManyIterator>d__16``2.MoveNext() at System.Linq.Enumerable.<SelectManyIterator>d__16``2.MoveNext() at System.Linq.Enumerable.<DistinctIterator>d__63``1.MoveNext() at System.Linq.Enumerable.<SelectManyIterator>d__16``2.MoveNext() at System.Collections.Generic.List``1..ctor(IEnumerable``1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable``1 source) at Swashbuckle.OData.CollectionExtentions.ToCollection[T](IEnumerable``1 source) at Swashbuckle.OData.Descriptions.ODataApiExplorer.GetApiDescriptions() at System.Lazy``1.CreateValue() at System.Lazy``1.LazyInitValue() at System.Lazy``1.get_Value() at Swashbuckle.OData.Descriptions.ODataApiExplorer.get_ApiDescriptions() at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion) at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion) at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) at System.Web.Http.Cors.CorsMessageHandler.<>n__FabricatedMethod3(HttpRequestMessage , CancellationToken ) at System.Web.Http.Cors.CorsMessageHandler.<SendAsync>d__0.MoveNext()
---End of stacktrace---

I'm using NuGet packages:

  • Swashbuckle.OData (2.16.2)
  • Swashbuckle (5.2.2, cannot use higher versions due to restriction in dependencies from Swashbuckle.OData)
  • Swashbuckle.Core (5.2.2, cannot use higher versions due to restriction in dependencies from Swashbuckle.OData)
  • Microsoft.OData.Core (6.14.0)
  • Microsoft.AspNet.OData (5.8.0)
  • Microsoft.OData.Edm (6.14.0)
  • Microsoft.Spatial (6.14.0)
  • Microsoft.AspNet.WebApi.WebHost (5.2.3)
  • Microsoft.AspNet.WebApi.Client (5.2.3)
  • Microsoft.AspNet.WebApi.Core (5.2.3)
  • Newtonsoft.Json (8.0.2)
  • Flurl (1.0.10)

Version 2 nuget installation

Hi,

I am trying to install the new version of the nuget package to a .Net 4.5 application but I am getting the following error:

Could not install package 'Swashbuckle.OData 2.0.0'. You are trying to install this package into a project that targets '.NETFramework,Version=v4.5', but the package does not contain any assembly references or content files that are compatible with that framework. For more information, contact the package author.

Displayed model schema should match the EDM Model

When using automatic property name conversion via the EnableLowerCamelCase() method on the ODataConventionModelBuilder, the models displayed in the Swagger UI do not match the models in the payload.

For example, the C# model will have a property called 'Id' The service is returning the property as 'id' in the payload. The Model and Model Schema sections are displaying the C# property name in Pascal case.

I have prepared an example to illustrate the issue. Please refer to Swashbuckle.OData.Sample project in the branch below:

https://github.com/bigred8982/Swashbuckle.OData/tree/property_casing_sample

Issue with custom routing

I'm having issue displaying other custom route other then HttpMethod.Post & HttpMethod.Get

Controller signature:

public async Task Delete([FromODataUri] int customerId, [FromODataUri] int orderID)
{
...
}

public async Task Patch([FromODataUri] int customerId,[FromODataUri] int orderID, Order order)
{
...
}

Config file:

config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders/({orderID}")
.Operation(HttpMethod.Delete)
.PathParameter("Id")
.PathParameter("orderID");

config.AddCustomSwaggerRoute(customODataRoute, "/Customers({Id})/Orders/({orderID}")
.Operation(new HttpMethod("PATCH"))
.PathParameter("Id")
.PathParameter("orderID")
.BodyParameter("order");

Thanks,
D

operations: consider concise summary - verbose description

Swagger spec shows operations have both a summary and a description property. The summary is supposed to be short and description more verbose. Although the summary technically can be up to 120 characters, I'd suggest, for the standard operations, it should be just two words. This will help with tooling that uses the summary as the 'friendly name' for an operation.

For example:

"/Northwind/v4/Orders": {
  "get": {
    "tags": [ "Orders" ],
    "summary": "Get Orders",
    "description": "Returns the EntitySet Orders",
    "operationId": "Orders_Get",
    ...},
  "post": {
    "tags": [ "Orders" ],
    "summary": "Create Order",
    "description": "Post a new entity to EntitySet Orders",
    "operationId": "Orders_Post",
    ...}
},
"/Northwind/v4/Orders({OrderID})": {
  "get": {
    "tags": [ "Orders" ],
    "summary": "Get Order",
    "description": "Returns the entity with the key from Orders",
    "operationId": "Orders_GetByOrderid",
    ...},
  "put": {
    "tags": [ "Orders" ],
    "summary": "Replace Order",
    "description": "Replace entity in EntitySet Orders",
    "operationId": "Orders_PutByOrderid",
    ...},
  "delete": {
    "tags": [ "Orders" ],
    "summary": "Delete Order",
    "description": "Delete entity in EntitySet Orders",
    "operationId": "Orders_DeleteByOrderid",
    ...},
  "patch": {
    "tags": [ "Orders" ],
    "summary": "Update Order",
    "description": "Update entity in EntitySet Orders",
    "operationId": "Orders_PatchByOrderid",
    ...}
},

Nice Work! Would global routes help eliminate path magic string?

First this is great work. I hope WebAPI OData team will work their implementation into swashbuckle like this - out of the box.

OData/WebApi#302
OData/WebApi#520
OData/WebApi#552

I wonder if you can get global ODataRoutes to eliminate the '/odata' magic string:
something like:

var odataRoutes = GlobalConfiguration.Configuration.Routes.Where(a=>a.GetType() == typeof(ODataRoute)).ToList();
if (!odataRoutes.Any()) return;
var route = odataRoutes.FirstOrDefault() as ODataRoute;
var path = "/" + route.RoutePrefix;
c.CustomProvider(defaultProvider => new ODataSwaggerProvider(path, edmModel));

Or better yet, maybe do it in ODataSwaggerProvider so you don't need to pass edm through SwaggerConfig.

PS - side question: have you tested to see whether swashbuckle filters work to post-modify swagger output? CUrious if IOperationFilter works for custom ISwaggerProvider.

Keep up the great work!

Exception thrown for non implemented routes

I noticed that when you don't implement a potential route such as a "PUT" an exception gets thrown

at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.GetInitialCandidateList(HttpControllerContext controllerContext, Boolean ignoreVerbs)
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.GetInitialCandidateWithParameterListForRegularRoutes(HttpControllerContext controllerContext, Boolean ignoreVerbs)
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.FindMatchingActions(HttpControllerContext controllerContext, Boolean ignoreVerbs)
at System.Web.Http.Controllers.ApiControllerActionSelector.ActionSelectorCacheItem.SelectAction(HttpControllerContext controllerContext)
at System.Web.Http.Controllers.ApiControllerActionSelector.SelectAction(HttpControllerContext controllerContext)
at System.Web.OData.Routing.ODataActionSelector.SelectAction(HttpControllerContext controllerContext)
at Swashbuckle.OData.Descriptions.HttpRequestMessageExtensions.GetHttpActionDescriptor(HttpRequestMessage request)

I think there is a chance that an application would not want to implement some of these routes, but they would have to deal with this exception being thrown. Also if you just return null from your SelectAction method for your custom route, I don't believe the Swashbuckle.Odata library will handle it gracefully and will either crash or not load the rest of the controller for the swagger UI.

Thanks,
D

AttributeRouteStrategy ignores ODataRoutePrefix when generating the path template

We are running into an issue with the path templates not being generated correctly when using an ODataRoutePrefix. Our OData endpoint is set up in the following way.

Config

config.MapODataServiceRoute("AdminOData", "api/v1/admin", ODataEdmModelProvider.GetEdmModel());

Controller

    [ODataRoutePrefix("products")]
    public class ProductsController : ODataController
    {
        [EnableQuery]
        [ODataRoute("({key})/attributevalues({attributevalueKey})")]
        public IHttpActionResult GetAttributeValue(Guid key, Guid attributevalueKey)
        {
            return this.Ok();
        }
    }

It looks like the ODataActionDescriptor is created by the AttributeRouteStrategy. To generate the path template it looks like it is using the ODataRoute prefix (in this scenario "api/v1/admin") and ODataRouteAttribute.PathTemplate (in this scenario "({key})/attributevalues({attributevalueKey})") to generate the path template. The resulting path template ends up looking like the following.

api/v1/admin/({key})/attributevalues({attributevalueKey})

I would expect it to be

api/v1/admin/products({key})/attributevalues({attributevalueKey})

I think the same logic that is being used by AttributeRoutingConvention.GetODataPathTemplate would be needed to generate the correct path.

$expand not showing on single entity paths

The $expand option is not showing up on paths created to query a single entity from an EntitySet. It looks like it is being added in the ODataSwaggerUtilities.CreateSwaggerPathForEntity() method. But for some reason it seems to not be part of the PathItem after all is said and done.

https://github.com/rbeauchamp/Swashbuckle.OData/blob/master/Swashbuckle.OData/Descriptions/ODataSwaggerUtilities.cs

I'm looking specifically at this code:

    get = new Operation()
    .Summary("Get entity from " + entitySet.Name + " by key.")
    .OperationId(entitySet.Name + "_GetById")
    .Description("Returns the entity with the key from " + entitySet.Name)
    .Tags(entitySet.Name)
    .Parameters(keyParameters.DeepClone()
    .Parameter("$expand", "query", "Expands related entities inline.", "string", false))
    .Parameters(keyParameters.DeepClone()
    .Parameter("$select", "query", "Selects which properties to include in the response.", "string", false))
    .Responses(new Dictionary<string, Response>().Response("200", "EntitySet " + entitySet.Name, entitySet.GetEntityType()).DefaultErrorResponse()),

I am using the sample application to test this.

OData query parameters should be limited to $expand and $select for APIs that return a single result

I have this scenary:

Model

public class ToolHistory
{
        [Key] 
        public int ID { get; set; }
        public string Code { get; set; }
        public string Name { get; set; }
        public string Description { get; set; }
}

ODataModel

var builder = new ODataConventionModelBuilder()
builder.EntitySet<ToolHistory>("ToolHistories");
var model = builder.GetEdmModel();
var edmEntityType = model.FindType(namespace + "ToolHistory") as IEdmEntityType;
var edmProperty = edmEntityType.FindProperty("Code");
(model as EdmModel).AddAlternateKeyAnnotation(edmEntityType, new Dictionary<string, IEdmProperty>
{
    {"Code", edmProperty}
});

Controller

This actions allow get item by key and by code.

public class ToolHistoriesController : ODataController
{
        [EnableQuery]
        public IHttpActionResult Get([FromODataUri] int key)
        {
            throw new NotImplementedException();
        }

        [EnableQuery]
        [ODataRoute("ToolHistories(Code={code})")]
        public IHttpActionResult Get([FromODataUri] string code)
        {
            throw new NotImplementedException();
        }
}

If I add the [ODataRoute("ToolHistories(Code={code})")], the metadata is generate through AttributeRouteStrategy, but add all query parameters because I add EnableQuery attribute which is incorrect.I think that you should only add $expand and $select.

If I missing the odataroute attribute, the metadata for this action is not generated. There is another way for do this, maybe a SwaggerRoute Attribute?

attach a image

path with annotation

Should display query string parameters not described by the EDM model or in the ODataRoute

Given this example ..

[EnableQuery]
[ODataRoute("Foobars")]
public IQueryable<Foobar> GetFoobars(bool bar)
{
    IEnumerable<Foobar> foobars = new[]
    {
        new Foobar { Id=1, Variation = "a"},
        new Foobar { Id=2, Variation = "b"},
        new Foobar { Id=3, Variation = "c"},
        new Foobar { Id=4, Variation = "d"}
    };
    if (bar == true) foobars = foobars.Where(fb => fb.Id >= 3);
    return foobars.AsQueryable();
}

.. if I change bool bar to [FromODataUri] bool? bar = null the parameter drops off completely from Swagger UI. I tried also updating [ODataRoute(..)] with [ODataRoute("Foobars?bar={bar:bool?}")]. I don't know if this is a missing feature (or bug) or if there's something I can do to make the parameter reappear. I'm not particularly concerned if, given whatever change I would make to get it to reappear, Swagger UI would still a true/false option here, I'd rather Swagger force an option than it not show the parameter at all, but I won't be able to make this parameter non-nullable outside of Swagger.

If I were to assume I'm doing it wrong, what am I missing? If it's a missing feature, any clue which class to get started poking at?

camelCasing for REST API

Hi there @rbeauchamp, curious how to get the camelCasing to work? I think your live example also does not have. Do you not need or want that? A few weeks ago I tried using techniques found online for WEB API 2, but to no avail. thx

Error is SwaggerUI - Nullable object must have a value

I have setup a Odata project based on the sample using the customprovider and document filter, however I receive this error when generating the UI:

0x800a139e - JavaScript runtime error: 500 : {"Message":"An error has occurred.","ExceptionMessage":"Nullable object must have a value.","ExceptionType":"System.InvalidOperationException","StackTrace":" at System.ThrowHelper.ThrowInvalidOperationException(ExceptionResource resource)\r\n at System.Nullable1.get_Value()\r\n at Swashbuckle.OData.MapToDefault.Map(Parameter parameter, Int32 index, HttpActionDescriptor actionDescriptor)\r\n at Swashbuckle.OData.SwaggerToApiExplorerMapper.<>c__DisplayClass2_0.<Map>b__0(IParameterMapper mapper)\r\n at System.Linq.Enumerable.WhereSelectListIterator2.MoveNext()\r\n at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable1 source, Func2 predicate)\r\n at Swashbuckle.OData.SwaggerToApiExplorerMapper.Map(Parameter parameter, Int32 index, HttpActionDescriptor actionDescriptor)\r\n at Swashbuckle.OData.ODataApiExplorer.GetHttpParameterDescriptor(Parameter parameter, Int32 index, HttpActionDescriptor actionDescriptor)\r\n at Swashbuckle.OData.ODataApiExplorer.GetParameterDescription(Parameter parameter, Int32 index, HttpActionDescriptor actionDescriptor)\r\n at Swashbuckle.OData.ODataApiExplorer.<>c__DisplayClass19_0.b__0(Parameter parameter, Int32 index)\r\n at System.Linq.Enumerable.d__52.MoveNext()\r\n at System.Collections.Generic.List1..ctor(IEnumerable1 collection)\r\n at System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)\r\n at Swashbuckle.OData.ODataApiExplorer.CreateParameterDescriptions(Operation operation, HttpActionDescriptor actionDescriptor)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescription(HttpActionDescriptor actionDescriptor, HttpMethod httpMethod, Operation operation, ODataRoute route, String potentialPathTemplate)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescription(HttpMethod httpMethod, ODataRoute oDataRoute, String potentialPathTemplate, Operation potentialOperation, HttpControllerDescriptor controllerDesciptor, HttpRequestMessage request, HttpRequestContext requestContext)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescription(HttpMethod httpMethod, ODataRoute oDataRoute, String potentialPathTemplate, Operation potentialOperation)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute, String potentialPathTemplate, PathItem potentialOperations)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at System.Lazy`1.get_Value()\r\n at Swashbuckle.OData.ODataApiExplorer.get_ApiDescriptions()\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.HttpServer.<>n__FabricatedMethod9(HttpRequestMessage , CancellationToken )\r\n at System.Web.Http.HttpServer.d__0.MoveNext()"} http://localhost:2015/swagger/docs/v1

[FromODataUri] vs standard parameter behaves differently

This may be a little hard to explain but I will give it a shot.... I stumbled across this issue tonight and was totally confused as to why my EF context was not returning an entity I knew existed. It turns out, the way the Swagger-UI fields are handling the strings has some subtle differences.

These two signatures are actually returning the string differently:

public virtual async Task<IHttpActionResult> Put([FromODataUri] string key, [FromBody] T safetyEquipment)
{
     // magic stuff
}
public virtual async Task<IHttpActionResult> Put(string key, [FromBody] T safetyEquipment)
{
     // magic stuff
}

The string value that returned correctly was when using the [FromODataUri] version of the function.

Custom Routing with OData

Hi,

In my project, I overrided the EntitySetRoutingConvention class that override the selectAction and selectController method for custom routing. The swagger doesn't seem to pick up the correct routes.

Not sure if this is really an issue vs. a question.

Example:

Actual route: /Products(1)/Suppliers Controller in this case: Suppliers
Swagger display route: /Products Controller in this case: Products

since it only recognizes the default controllers vs. the custom routing where it would return supplies as the controller)

Is there any specific Annotation that can resolve this issue?
Thanks!

Error when URL parameter is of type array

I'll try to follow up with a dummy sample gist but I'm getting this error while the Swashbuckle.OData provider is enabled.

<Error><Message>An error has occurred.</Message><ExceptionMessage>Could not generate sample value for query parameter type array and format null</ExceptionMessage><ExceptionType>System.Exception</ExceptionType><StackTrace>   at Swashbuckle.OData.ODataApiExplorer.GenerateSampleQueryParameterValue(Parameter queryParameter)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector, IEqualityComparer`1 comparer)
   at System.Linq.Enumerable.ToDictionary[TSource,TKey,TElement](IEnumerable`1 source, Func`2 keySelector, Func`2 elementSelector)
   at Swashbuckle.OData.ODataApiExplorer.GenerateSampleQueryParameterValues(Operation operation)
   at Swashbuckle.OData.ODataApiExplorer.GenerateSampleODataAbsoluteUri(String pathTemplate, Operation operation)
   at Swashbuckle.OData.ODataApiExplorer.GetApiDescription(HttpMethod httpMethod, ODataRoute oDataRoute, String potentialPathTemplate, Operation potentialOperation)
   at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute, String potentialPathTemplate, PathItem potentialOperations)
   at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute)
   at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions()
   at System.Lazy`1.CreateValue()
   at System.Lazy`1.LazyInitValue()
   at System.Lazy`1.get_Value()
   at Swashbuckle.OData.ODataApiExplorer.get_ApiDescriptions()
   at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)
   at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)
   at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   at System.Web.Http.Cors.CorsMessageHandler.&lt;&gt;n__FabricatedMethod3(HttpRequestMessage , CancellationToken )
   at System.Web.Http.Cors.CorsMessageHandler.&lt;SendAsync&gt;d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Tracing.ITraceWriterExtensions.&lt;TraceBeginEndAsyncCore&gt;d__18`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Owin.PassiveAuthenticationMessageHandler.&lt;SendAsync&gt;d__0.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Tracing.ITraceWriterExtensions.&lt;TraceBeginEndAsyncCore&gt;d__18`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.Tracing.ITraceWriterExtensions.&lt;TraceBeginEndAsyncCore&gt;d__18`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at System.Web.Http.HttpServer.&lt;SendAsync&gt;d__0.MoveNext()</StackTrace></Error>

Provide explicit support for RESTier

Unfortunately, I don't think ODataAPIExplorer and RESTier are friendly.
I get the following exception:
500 : {"Message":"An error has occurred.","ExceptionMessage":"Object reference not set to an instance of an object.","ExceptionType":"System.NullReferenceException","StackTrace":" at Microsoft.Restier.WebApi.Routing.RestierRoutingConvention.HasControllerForEntitySetOrSingleton(ODataPath odataPath, HttpRequestMessage request)\r\n at Microsoft.Restier.WebApi.Routing.RestierRoutingConvention.SelectController(ODataPath odataPath, HttpRequestMessage request)\r\n at Swashbuckle.OData.ODataApiExplorer.<>c__DisplayClass27_0.b__0(IODataRoutingConvention routingConvention)\r\n at System.Linq.Enumerable.WhereSelectEnumerableIterator 2.MoveNext()\r\n at System.Linq.Enumerable.FirstOrDefault[TSource](IEnumerable 1 source, Func 2 predicate)\r\n at Swashbuckle.OData.ODataApiExplorer.GetControllerName(ODataPathRouteConstraint oDataPathRouteConstraint, ODataPath path)\r\n at Swashbuckle.OData.ODataApiExplorer.GetControllerDesciptor(ODataRoute oDataRoute, ODataPath potentialPath)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescription(HttpMethod httpMethod, ODataRoute oDataRoute, String potentialPathTemplate, Operation potentialOperation)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute, String potentialPathTemplate, PathItem potentialOperations)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions()\r\n at System.Lazy 1.CreateValue()\r\n at System.Lazy 1.LazyInitValue()\r\n at System.Lazy 1.get_Value()\r\n at Swashbuckle.OData.ODataApiExplorer.get_ApiDescriptions()\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.HttpServer.d__0.MoveNext()"} http://localhost:57336/swagger/docs/v1

Error: Segments with mutiple keys

500 : {"Message":"An error has occurred.","ExceptionMessage":"Segments with multiple key values must specify them in 'name=value' form.","ExceptionType":"Microsoft.OData.Core.ODataException","StackTrace":" at Microsoft.OData.Core.UriParser.Parsers.SegmentKeyHandler.CreateKeySegment(ODataPathSegment segment, KeySegment previousKeySegment, SegmentArgumentParser key, ODataUriResolver resolver)\r\n at Microsoft.OData.Core.UriParser.Parsers.SegmentKeyHandler.TryCreateKeySegmentFromParentheses(ODataPathSegment previous, KeySegment previousKeySegment, String parenthesisExpression, ODataPathSegment& keySegment, Boolean enableUriTemplateParsing, ODataUriResolver resolver)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.TryBindKeyFromParentheses(String parenthesesSection)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.TryCreateSegmentForNavigationSource(String identifier, String parenthesisExpression)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.CreateFirstSegment(String segmentText)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathParser.ParsePath(ICollection1 segments)\r\n at Microsoft.OData.Core.UriParser.Parsers.ODataPathFactory.BindPath(ICollection1 segments, ODataUriParserConfiguration configuration)\r\n at Microsoft.OData.Core.UriParser.ODataUriParser.ParsePathImplementation()\r\n at Microsoft.OData.Core.UriParser.ODataUriParser.Initialize()\r\n at Microsoft.OData.Core.UriParser.ODataUriParser.ParsePath()\r\n at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath, ODataUriResolverSetttings resolverSettings, Boolean enableUriTemplateParsing)\r\n at System.Web.OData.Routing.DefaultODataPathHandler.Parse(IEdmModel model, String serviceRoot, String odataPath)\r\n at Swashbuckle.OData.ODataApiExplorer.GenerateSampleODataPath(ODataRoute oDataRoute, String sampleODataAbsoluteUri)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescription(HttpMethod httpMethod, ODataRoute oDataRoute, String potentialPathTemplate, Operation potentialOperation)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute, String potentialPathTemplate, PathItem potentialOperations)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions(ODataRoute oDataRoute)\r\n at Swashbuckle.OData.ODataApiExplorer.GetApiDescriptions()\r\n at System.Lazy1.CreateValue()\r\n at System.Lazy1.LazyInitValue()\r\n at System.Lazy`1.get_Value()\r\n at Swashbuckle.OData.ODataApiExplorer.get_ApiDescriptions()\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion)\r\n at Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion)\r\n at Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n at System.Web.Http.HttpServer.<>n__FabricatedMethod9(HttpRequestMessage , CancellationToken )\r\n at System.Web.Http.HttpServer.d__0.MoveNext()"} http://localhost:57336/swagger/docs/v1

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.