I integrated Swashbuckle.OData 3.2.0 and Swashbuckle.Core 5.5.3 in my WepAPI OData webservice to generate Swagger documentaion.
When I try to access the swagger endpoint ( http://localhost:52460/swagger ) I get the below exception, which seems to be caused by a function (AppointmentsForUsers) that takes 2 parameters of the type Microsoft.OData.Edm.Date (a date type without time component).
When I comment out the var function = builder,Function...part in my Register function, everything is working fine,
When I replace the parameter type Microsoft.OData.Edm.Date with System.DateTimeOffset it's working fine as well, but that's not a solution for us/our project.
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.EntitySet<UserDTO>("Users");
builder.EntitySet<AppointmentDTO>("Appointments");
var function = builder.Function("AppointmentsForUsers");
function.ReturnsCollectionFromEntitySet<AppointmentDTO>("Appointments");
function.Parameter<Date>("FromDate");
function.Parameter<Date>("ToDate");
function.CollectionParameter<int>("UserIds");
config.MapODataServiceRoute(
routeName: "odata",
routePrefix: "odata",
model: builder.GetEdmModel());
}
}
public async Task<IHttpActionResult> AppointmentsForUsers(Date DateFrom, Date DateTo, Enumerable<int> UserIds)
{
...
}
The error I get in the browser is:
500 : {"Message":"An error has occurred.","ExceptionMessage":"Der DateTimeOffset-Text \"2015-12-12T12:00\" sollte das Format \"yyyy-mm-ddThh:mm:ss('.'s+)?(zzzzzz)?\" aufweisen, und jeder Feldwert muss innerhalb des gültigen Bereichs liegen.","ExceptionType":"Microsoft.OData.ODataException","StackTrace":" bei Microsoft.OData.UriUtils.ConvertUriStringToDateTimeOffset(String text, DateTimeOffset& targetValue)\r\n bei Microsoft.OData.UriParser.ExpressionLexer.TryParseDateTimeoffset(Int32 tokenPos)\r\n bei Microsoft.OData.UriParser.ExpressionLexer.ParseFromDigit()\r\n bei Microsoft.OData.UriParser.ExpressionLexer.NextTokenImplementation(Exception& error)\r\n bei Microsoft.OData.UriParser.ExpressionLexer.NextToken()\r\n bei Microsoft.OData.UriParser.FunctionParameterParser.TrySplitOperationParameters(UriQueryExpressionParser parser, ExpressionTokenKind endTokenKind, ICollection1& splitParameters)\r\n bei Microsoft.OData.UriParser.FunctionParameterParser.TrySplitOperationParameters(String parenthesisExpression, ODataUriParserConfiguration configuration, ICollection1& splitParameters)\r\n bei Microsoft.OData.UriParser.ODataPathParser.TryBindingParametersAndMatchingOperationImport(String identifier, String parenthesisExpression, ODataUriParserConfiguration configuration, ICollection1& boundParameters, IEdmOperationImport& matchingFunctionImport)\r\n bei Microsoft.OData.UriParser.ODataPathParser.TryCreateSegmentForOperationImport(String identifier, String parenthesisExpression)\r\n bei Microsoft.OData.UriParser.ODataPathParser.CreateFirstSegment(String segmentText)\r\n bei Microsoft.OData.UriParser.ODataPathParser.ParsePath(ICollection1 segments)\r\n bei Microsoft.OData.UriParser.ODataPathFactory.BindPath(ICollection1 segments, ODataUriParserConfiguration configuration)\r\n bei Microsoft.OData.UriParser.ODataUriParser.ParsePathImplementation()\r\n bei Microsoft.OData.UriParser.ODataUriParser.Initialize()\r\n bei System.Web.OData.Routing.DefaultODataPathHandler.Parse(String serviceRoot, String odataPath, IServiceProvider requestContainer, Boolean template)\r\n bei System.Web.OData.Routing.DefaultODataPathHandler.Parse(String serviceRoot, String odataPath, IServiceProvider requestContainer)\r\n bei Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GenerateSampleODataPath(Operation operation, SwaggerRoute swaggerRoute, IServiceProvider rootContainer) in C:\\Users\\rbeauchamp\\Documents\\GitHub\\Swashbuckle.OData\\Swashbuckle.OData\\Descriptions\\SwaggerRouteStrategy.cs:Zeile 162.\r\n bei Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.CreateHttpRequestMessage(HttpMethod httpMethod, Operation potentialOperation, SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig) in C:\\Users\\rbeauchamp\\Documents\\GitHub\\Swashbuckle.OData\\Swashbuckle.OData\\Descriptions\\SwaggerRouteStrategy.cs:Zeile 94.\r\n bei Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(HttpMethod httpMethod, Operation potentialOperation, SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig) in C:\\Users\\rbeauchamp\\Documents\\GitHub\\Swashbuckle.OData\\Swashbuckle.OData\\Descriptions\\SwaggerRouteStrategy.cs:Zeile 67.\r\n bei Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.GetActionDescriptors(SwaggerRoute potentialSwaggerRoute, HttpConfiguration httpConfig) in C:\\Users\\rbeauchamp\\Documents\\GitHub\\Swashbuckle.OData\\Swashbuckle.OData\\Descriptions\\SwaggerRouteStrategy.cs:Zeile 52.\r\n bei Swashbuckle.OData.Descriptions.SwaggerRouteStrategy.<>c__DisplayClass3_0.<Generate>b__1(SwaggerRoute potentialSwaggerRoute) in C:\\Users\\rbeauchamp\\Documents\\GitHub\\Swashbuckle.OData\\Swashbuckle.OData\\Descriptions\\SwaggerRouteStrategy.cs:Zeile 41.\r\n bei System.Linq.Enumerable.<SelectManyIterator>d__162.MoveNext()\r\n bei System.Linq.Enumerable.d__162.MoveNext()\r\n bei System.Linq.Enumerable.<DistinctIterator>d__631.MoveNext()\r\n bei System.Linq.Enumerable.d__162.MoveNext()\r\n bei System.Collections.Generic.List1..ctor(IEnumerable1 collection)\r\n bei System.Linq.Enumerable.ToList[TSource](IEnumerable1 source)\r\n bei Swashbuckle.OData.CollectionExtentions.ToCollection[T](IEnumerable1 source) in C:\\Users\\rbeauchamp\\Documents\\GitHub\\Swashbuckle.OData\\Swashbuckle.OData\\CollectionExtentions.cs:Zeile 77.\r\n bei Swashbuckle.OData.Descriptions.ODataApiExplorer.GetApiDescriptions() in C:\\Users\\rbeauchamp\\Documents\\GitHub\\Swashbuckle.OData\\Swashbuckle.OData\\Descriptions\\ODataApiExplorer.cs:Zeile 43.\r\n bei System.Lazy1.CreateValue()\r\n bei System.Lazy1.LazyInitValue()\r\n bei System.Lazy1.get_Value()\r\n bei Swashbuckle.OData.Descriptions.ODataApiExplorer.get_ApiDescriptions() in C:\Users\rbeauchamp\Documents\GitHub\Swashbuckle.OData\Swashbuckle.OData\Descriptions\ODataApiExplorer.cs:Zeile 39.\r\n bei Swashbuckle.OData.ODataSwaggerProvider.GetApiDescriptionsFor(String apiVersion) in C:\Users\rbeauchamp\Documents\GitHub\Swashbuckle.OData\Swashbuckle.OData\ODataSwaggerProvider.cs:Zeile 297.\r\n bei Swashbuckle.OData.ODataSwaggerProvider.GetSwagger(String rootUrl, String apiVersion) in C:\Users\rbeauchamp\Documents\GitHub\Swashbuckle.OData\Swashbuckle.OData\ODataSwaggerProvider.cs:Zeile 57.\r\n bei Swashbuckle.Application.SwaggerDocsHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n bei System.Net.Http.HttpMessageInvoker.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n bei System.Web.Http.Dispatcher.HttpRoutingDispatcher.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n bei System.Net.Http.DelegatingHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)\r\n bei System.Web.Http.HttpServer.d__0.MoveNext()","InnerException":{"Message":"An error has occurred.","ExceptionMessage":"Im DateTimeOffset-Wert '2015-12-12T12:00:00' fehlen die Zeitzoneninformationen. Ein DateTimeOffset-Wert muss Zeitzoneninformationen enthalten.","ExceptionType":"System.FormatException","StackTrace":" bei Microsoft.OData.PlatformHelper.ValidateTimeZoneInformationInDateTimeOffsetString(String text)\r\n bei Microsoft.OData.PlatformHelper.ConvertStringToDateTimeOffset(String text)\r\n bei Microsoft.OData.UriUtils.ConvertUriStringToDateTimeOffset(String text, DateTimeOffset& targetValue)"}} http://localhost:52460/swagger/docs/v1
the german part of the message
Der DateTimeOffset-Text \"2015-12-12T12:00\" sollte das Format \"yyyy-mm-ddThh:mm:ss('.'s+)?(zzzzzz)?\" aufweisen, und jeder Feldwert muss innerhalb des gültigen Bereichs liegen."
means: The DateTimeOffset text \"2015-12-12T12:00\" should have the format \"yyyy-mm-ddThh:mm:ss('.'s+)?(zzzzzz)?\" and each field value must be within the valid range
m DateTimeOffset-Wert '2015-12-12T12:00:00' fehlen die Zeitzoneninformationen. Ein DateTimeOffset-Wert muss Zeitzoneninformationen enthalten."
means: DateTimeOffset value is missing time zone information. A DateTimeOffset value must contain time zone information.
Is this a bug? Is there any workaround (beside not using the Date type)? Any help would be much appreciated.
I have also opened an issue on the Swashbuckle.Odata Github site: https://github.com/rbeauchamp/Swashbuckle.OData/issues/134
Update: as a workaround I changed the parameter types to System.DateTime
public async Task<IHttpActionResult> AppointmentsForUsers(DateTime DateFrom, DateTime DateTo, Enumerable<int> UserIds)
{
...
}
with this workaround I'm still able to use a date as a parameter, e.g. AppointmentsForUsers(DateFrom=2017-04-07,.... The actual paramter contains a time component (depending on the timezone) but then internally I continue with Date (implicit conversion from DateTime). Works well for us at least, though the original problem still persists.