/// <summary> /// Maps the specified versioned OData routes. When the <paramref name="batchHandler"/> is provided, it will create a /// '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="configuration">The extended <see cref="HttpConfiguration">HTTP configuration</see>.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler">OData batch handler</see>.</param> /// <returns>The <see cref="IReadOnlyList{T}">read-only list</see> of added <see cref="ODataRoute">OData routes</see>.</returns> /// <remarks>The specified <paramref name="models"/> must contain the <see cref="ApiVersionAnnotation">API version annotation</see>. This annotation is /// automatically applied when you use the <see cref="VersionedODataModelBuilder"/> and call <see cref="VersionedODataModelBuilder.GetEdmModels"/> to /// create the <paramref name="models"/>.</remarks> public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes( this HttpConfiguration configuration, string routeName, string routePrefix, IEnumerable <IEdmModel> models, ODataBatchHandler batchHandler) => MapVersionedODataRoutes(configuration, routeName, routePrefix, models, new DefaultODataPathHandler(), ODataRoutingConventions.CreateDefault(), batchHandler);
private static void MapHttpBatchRoute(HttpRouteCollection routes, ODataBatchHandler batchHandler, string routeName, string routePrefix) { batchHandler.ODataRouteName = routeName; var batchTemplate = string.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); }
/// <summary> /// /// </summary> /// <typeparam name="TApi"></typeparam> /// <param name="config"></param> /// <param name="routeName"></param> /// <param name="routePrefix"></param> /// <param name="allowBatching"></param> /// <param name="httpServer"></param> /// <returns></returns> public static HttpConfiguration MapRestier <TApi>(this HttpConfiguration config, string routeName, string routePrefix, bool allowBatching, HttpServer httpServer) { ODataBatchHandler batchHandler = null; var conventions = CreateRestierRoutingConventions(config, routeName); if (allowBatching) { if (httpServer == null) { throw new ArgumentNullException(nameof(httpServer), owinException); } #pragma warning disable IDE0067 // Dispose objects before losing scope batchHandler = new RestierBatchHandler(httpServer) { ODataRouteName = routeName }; #pragma warning restore IDE0067 // Dispose objects before losing scope } config.MapODataServiceRoute(routeName, routePrefix, (builder) => { builder.AddService <IEnumerable <IODataRoutingConvention> >(ServiceLifetime.Singleton, sp => conventions); if (batchHandler != null) { //RWM: DO NOT simplify this generic signature. It HAS to stay this way, otherwise the code breaks. builder.AddService <ODataBatchHandler>(ServiceLifetime.Singleton, sp => batchHandler); } }); return(config); }
/// <summary> /// /// </summary> /// <typeparam name="TApi"></typeparam> /// <param name="config"></param> /// <param name="routeName"></param> /// <param name="routePrefix"></param> /// <param name="allowBatching"></param> /// <returns></returns> public static HttpConfiguration MapRestier <TApi>(this HttpConfiguration config, string routeName, string routePrefix, bool allowBatching = true) { ODataBatchHandler batchHandler = null; var conventions = CreateRestierRoutingConventions(config, routeName); if (allowBatching) { #pragma warning disable IDE0067 // Dispose objects before losing scope batchHandler = new RestierBatchHandler(GlobalConfiguration.DefaultServer) { ODataRouteName = routeName }; #pragma warning restore IDE0067 // Dispose objects before losing scope } config.MapODataServiceRoute(routeName, routePrefix, (builder) => { builder.AddService <IEnumerable <IODataRoutingConvention> >(ServiceLifetime.Singleton, sp => conventions); if (batchHandler != null) { builder.AddService(ServiceLifetime.Singleton, sp => batchHandler); } }); return(config); }
public static void MapODataRoute(this HttpRouteCollection routes, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { Extensions.HttpRouteCollectionExtensions.MapODataServiceRoute(routes, routeName, routePrefix, model, pathHandler, routingConventions, batchHandler); }
/// <summary> /// Maps a versioned OData route. /// </summary> /// <param name="configuration">The extended <see cref="HttpConfiguration">HTTP configuration</see>.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The <see cref="IEdmModel">EDM model</see> to use for parsing OData paths.</param> /// <param name="apiVersion">The <see cref="ApiVersion">API version</see> associated with the model.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler">OData batch handler</see>.</param> /// <returns>The mapped <see cref="ODataRoute">OData route</see>.</returns> /// <remarks>The <see cref="ApiVersionAnnotation">API version annotation</see> will be added or updated on the specified <paramref name="model"/> using /// the provided <paramref name="apiVersion">API version</paramref>.</remarks> public static ODataRoute MapVersionedODataRoute( this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, ApiVersion apiVersion, ODataBatchHandler batchHandler) => MapVersionedODataRoute(configuration, routeName, routePrefix, model, apiVersion, new DefaultODataPathHandler(), ODataRoutingConventions.CreateDefault(), batchHandler, null);
/// <summary> /// Maps the specified versioned OData routes. /// </summary> /// <param name="configuration">The extended <see cref="HttpConfiguration">HTTP configuration</see>.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param> /// <param name="configureAction">The configuring action to add the services to the root container.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler">OData batch handler</see>.</param> /// <returns>The <see cref="IReadOnlyList{T}">read-only list</see> of added <see cref="ODataRoute">OData routes</see>.</returns> /// <remarks>The specified <paramref name="models"/> must contain the <see cref="ApiVersionAnnotation">API version annotation</see>. This annotation is /// automatically applied when you use the <see cref="VersionedODataModelBuilder"/> and call <see cref="VersionedODataModelBuilder.GetEdmModels"/> to /// create the <paramref name="models"/>.</remarks> public static IReadOnlyList <ODataRoute> MapVersionedODataRoutes( this HttpConfiguration configuration, string routeName, string routePrefix, IEnumerable <IEdmModel> models, Action <IContainerBuilder> configureAction, ODataBatchHandler batchHandler) => MapVersionedODataRoutes(configuration, routeName, routePrefix, models, configureAction, default, batchHandler);
/// <summary> /// Maps a versioned OData route. /// </summary> /// <param name="builder">The extended <see cref="IRouteBuilder">route builder</see>.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The <see cref="IEdmModel">EDM model</see> to use for parsing OData paths.</param> /// <param name="apiVersion">The <see cref="ApiVersion">API version</see> associated with the model.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler">OData batch handler</see>.</param> /// <returns>The mapped <see cref="ODataRoute">OData route</see>.</returns> /// <remarks>The <see cref="ApiVersionAnnotation">API version annotation</see> will be added or updated on the specified <paramref name="model"/> using /// the provided <paramref name="apiVersion">API version</paramref>.</remarks> public static ODataRoute MapVersionedODataRoute( this IRouteBuilder builder, string routeName, string routePrefix, IEdmModel model, ApiVersion apiVersion, ODataBatchHandler batchHandler) => MapVersionedODataRoute(builder, routeName, routePrefix, model, apiVersion, new DefaultODataPathHandler(), VersionedODataRoutingConventions.CreateDefault(), batchHandler);
private static void MapService <TContext>( HttpConfiguration config, string routeName = "DynamicODataRoute", string routePrefix = "odata", IList <IODataRoutingConvention> conventions = null, ODataBatchHandler batchHandler = null) where TContext : DbContext, new() { config.EnableDependencyInjection(); ODataModelBuilder builder = new ODataConventionModelBuilder(); //Register all properties of IComponentModel as Odata entities MethodInfo baseMethod = typeof(ODataModelBuilder).GetMethod(nameof(builder.EntitySet)); //All of this reflection only affects the startup time and not during the actual running of the program var entityProperties = typeof(TContext).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.DeclaredOnly) .Where(p => p.PropertyType.GetInterfaces().Contains(typeof(IQueryable))); foreach (var prop in entityProperties) { var entityType = prop.PropertyType.GetGenericArguments()[0]; MethodInfo generic = baseMethod.MakeGenericMethod(entityType); generic.Invoke(builder, new[] { prop.Name }); } config.Count().Filter().OrderBy().Expand().Select().MaxTop(null); config.AddODataQueryFilter(); if (conventions == null) { conventions = ODataRoutingConventions.CreateDefault(); } conventions.Insert(0, new KeyEntityRoutingConvention()); conventions.Insert(0, new DynamicNavigationPropertyConvention()); conventions.Insert(0, new PropertyAccessConvention()); var entityModels = builder.GetEdmModel(); config.MapODataServiceRoute( routeName: routeName, routePrefix: routePrefix, model: entityModels, pathHandler: new DefaultODataPathHandler(), routingConventions: conventions, batchHandler: batchHandler); var controllerSelector = new GenericControllerSelector <TContext>(config, builder.EntitySets, config.Services.GetHttpControllerSelector() ?? new DefaultHttpControllerSelector(config)); config.Services.Replace(typeof(IHttpControllerSelector), controllerSelector); foreach (var item in controllerSelector.GetEntityControllers()) { var entitySetInfo = entityModels.EntityContainer.FindEntitySet(item.Key); item.Value.Configuration.Services.Replace(typeof(IHttpActionSelector), new GenericActionSelector(config.Services.GetActionSelector(), item, entitySetInfo)); } }
public static ODataRoute MapVersionedODataRoute( this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, ApiVersion apiVersion, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) => MapVersionedODataRoute(configuration, routeName, routePrefix, model, apiVersion, pathHandler, routingConventions, batchHandler, null);
public static IReadOnlyList<ODataRoute> MapVersionedODataRoutes( this HttpConfiguration configuration, string routeName, string routePrefix, IEnumerable<IEdmModel> models, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler ) { Arg.NotNull( configuration, nameof( configuration ) ); Arg.NotNull( models, nameof( models ) ); Contract.Ensures( Contract.Result<IReadOnlyList<ODataRoute>>() != null ); var routeConventions = EnsureConventions( routingConventions.ToList() ); var routes = configuration.Routes; if ( !IsNullOrEmpty( routePrefix ) ) { routePrefix = routePrefix.TrimEnd( '/' ); } if ( batchHandler != null ) { var batchTemplate = IsNullOrEmpty( routePrefix ) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute( routeName + "Batch", batchTemplate, batchHandler ); } configuration.SetResolverSettings( pathHandler ); routeConventions.Insert( 0, null ); var odataRoutes = new List<ODataRoute>(); var unversionedConstraints = new List<IHttpRouteConstraint>(); foreach ( var model in models ) { var versionedRouteName = routeName; var routeConstraint = default( ODataPathRouteConstraint ); routeConventions[0] = new VersionedAttributeRoutingConvention( model, configuration ); routeConstraint = new ODataPathRouteConstraint( pathHandler, model, versionedRouteName, routeConventions.ToArray() ); unversionedConstraints.Add( routeConstraint ); routeConstraint = MakeVersionedODataRouteConstraint( routeConstraint, pathHandler, routeConventions, model, ref versionedRouteName ); var route = new ODataRoute( routePrefix, routeConstraint ); AddApiVersionConstraintIfNecessary( route ); routes.Add( versionedRouteName, route ); odataRoutes.Add( route ); } AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch( routeName, routePrefix, routes, odataRoutes, unversionedConstraints ); return odataRoutes; }
/// <summary> /// Maps a versioned OData route. When the <paramref name="batchHandler"/> is provided, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The extended <see cref="IRouteBuilder">route builder</see>.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The <see cref="IEdmModel">EDM model</see> to use for parsing OData paths.</param> /// <param name="apiVersion">The <see cref="ApiVersion">API version</see> associated with the model.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler">OData path handler</see> to use for parsing the OData path.</param> /// <param name="routingConventions">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IODataRoutingConvention">OData routing conventions</see> /// to use for controller and action selection.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler">OData batch handler</see>.</param> /// <returns>The mapped <see cref="ODataRoute">OData route</see>.</returns> /// <remarks>The <see cref="ApiVersionAnnotation">API version annotation</see> will be added or updated on the specified <paramref name="model"/> using /// the provided <paramref name="apiVersion">API version</paramref>.</remarks> public static ODataRoute MapVersionedODataRoute( this IRouteBuilder builder, string routeName, string routePrefix, IEdmModel model, ApiVersion apiVersion, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { Arg.NotNull(builder, nameof(builder)); Arg.NotNullOrEmpty(routeName, nameof(routeName)); Arg.NotNull(model, nameof(model)); Arg.NotNull(apiVersion, nameof(apiVersion)); Contract.Ensures(Contract.Result <ODataRoute>() != null); IEnumerable <IODataRoutingConvention> NewRoutingConventions(IServiceProvider serviceProvider) { var conventions = VersionedODataRoutingConventions.AddOrUpdate(routingConventions.ToList()); conventions.Insert(0, new VersionedAttributeRoutingConvention(routeName, builder.ServiceProvider, apiVersion)); return(conventions.ToArray()); } var routeCollection = builder.ServiceProvider.GetRequiredService <IODataRouteCollectionProvider>(); var perRouteContainer = builder.ServiceProvider.GetRequiredService <IPerRouteContainer>(); var options = builder.ServiceProvider.GetRequiredService <ODataOptions>(); var inlineConstraintResolver = builder.ServiceProvider.GetRequiredService <IInlineConstraintResolver>(); if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter; } model.SetAnnotationValue(model, new ApiVersionAnnotation(apiVersion)); var configureAction = builder.ConfigureDefaultServices(container => container.AddService(Singleton, typeof(IEdmModel), sp => model) .AddService(Singleton, typeof(IODataPathHandler), sp => pathHandler) .AddService(Singleton, typeof(IEnumerable <IODataRoutingConvention>), NewRoutingConventions) .AddService(Singleton, typeof(ODataBatchHandler), sp => batchHandler)); var rootContainer = perRouteContainer.CreateODataRootContainer(routeName, configureAction); var router = rootContainer.GetService <IRouter>() ?? builder.DefaultHandler; var routeConstraint = new VersionedODataPathRouteConstraint(routeName, apiVersion); var route = new ODataRoute(router, routeName, routePrefix.RemoveTrailingSlash(), routeConstraint, inlineConstraintResolver); builder.ConfigureBatchHandler(rootContainer, route); builder.Routes.Add(route); routeCollection.Add(new ODataRouteMapping(route, apiVersion, rootContainer)); builder.AddRouteToRespondWithBadRequestWhenAtLeastOneRouteCouldMatch(routeName, routePrefix, apiVersion, inlineConstraintResolver); NotifyRoutesMapped(); return(route); }
/// <summary> /// Maps the specified OData route and the OData route attributes. When the <paramref name="batchHandler"/> is /// non-<c>null</c>, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The <see cref="IEndpointRouteBuilder"/>.</returns> public static IEndpointRouteBuilder MapODataRoute(this IEndpointRouteBuilder builder, string routeName, string routePrefix, IEdmModel model, ODataBatchHandler batchHandler) { return(builder.MapODataRoute(routeName, routePrefix, containerBuilder => containerBuilder.AddService(ServiceLifetime.Singleton, sp => model) .AddService(ServiceLifetime.Singleton, sp => batchHandler) .AddService <IEnumerable <IODataRoutingConvention> >(ServiceLifetime.Singleton, sp => ODataRoutingConventions.CreateDefaultWithAttributeRouting(routeName, builder.ServiceProvider)))); }
/// <summary> /// Maps the specified OData route and the OData route attributes. When the <paramref name="batchHandler"/> is /// non-<c>null</c>, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The <see cref="IRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapVersionedODataRoute( this IRouteBuilder builder, string routeName, string routePrefix, IEnumerable <IEdmModel> models, ODataBatchHandler batchHandler) => AddRoute( builder, builder.MapODataServiceRoute( routeName, routePrefix, container => container.AddApiVersioning(routeName, models, builder.ServiceProvider) .AddService(Singleton, sp => batchHandler)));
/// <summary> /// Maps the specified OData route and the OData route attributes. When the <paramref name="batchHandler"/> is /// non-<c>null</c>, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapVersionedODataRoute( this HttpConfiguration configuration, string routeName, string routePrefix, IEnumerable <IEdmModel> models, ODataBatchHandler batchHandler) => AddApiVersionConstraintIfNecessary( configuration, configuration.MapODataServiceRoute( routeName, routePrefix, builder => builder.AddApiVersioning(routeName, models) .AddService(Singleton, sp => batchHandler)));
/// <summary> /// Maps the specified OData route. When the <paramref name="batchHandler"/> is non-<c>null</c>, it will /// create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The <see cref="IEndpointRouteBuilder"/>.</returns> public static IEndpointRouteBuilder MapODataRoute(this IEndpointRouteBuilder builder, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { return(builder.MapODataRoute(routeName, routePrefix, containerBuilder => containerBuilder.AddService(ServiceLifetime.Singleton, sp => model) .AddService(ServiceLifetime.Singleton, sp => pathHandler) .AddService(ServiceLifetime.Singleton, sp => routingConventions.ToList().AsEnumerable()) .AddService(ServiceLifetime.Singleton, sp => batchHandler))); }
/// <summary> /// Maps the specified OData route. When the <paramref name="defaultHandler"/> is non-<c>null</c>, it will map /// it as the handler for the route. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <param name="defaultHandler">The default <see cref="HttpMessageHandler"/> for this route.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, HttpMessageHandler defaultHandler) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } // We have a more specific overload to map batch handlers that creates a different route for the batch // endpoint instead of mapping that handler as the per route handler. Given that HttpMessageHandler is a // base type of ODataBatchHandler, it's possible the compiler will call this overload instead of the one // for the batch handler, so we detect that case and call the appropiate overload for the user. // The case in which the compiler picks the wrong overload is: // HttpRequestMessageHandler batchHandler = new DefaultODataBatchHandler(httpServer); // config.Routes.MapODataServiceRoute("routeName", "routePrefix", model, batchHandler); if (defaultHandler != null) { ODataBatchHandler batchHandler = defaultHandler as ODataBatchHandler; if (batchHandler != null) { return(MapODataServiceRoute(configuration, routeName, routePrefix, model, batchHandler)); } } HttpRouteCollection routes = configuration.Routes; routePrefix = RemoveTrailingSlash(routePrefix); DefaultODataPathHandler odataPathHandler = pathHandler as DefaultODataPathHandler; if (odataPathHandler != null) { odataPathHandler.ResolverSetttings = configuration.GetResolverSettings(); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); ODataRoute route = new ODataRoute( routePrefix, routeConstraint, defaults: null, constraints: null, dataTokens: null, handler: defaultHandler); routes.Add(routeName, route); return(route); }
static void Configure(this ODataBatchHandler batchHandler, IRouteBuilder builder, ODataRoute route) { batchHandler.ODataRoute = route; batchHandler.ODataRouteName = route.Name; var batchPath = '/' + ODataRouteConstants.Batch; if (!IsNullOrEmpty(route.RoutePrefix)) { batchPath = '/' + route.RoutePrefix + batchPath; } var batchMapping = builder.ServiceProvider.GetRequiredService <ODataBatchPathMapping>(); batchMapping.AddRoute(route.Name, batchPath); }
public static ODataRoute MapVersionedODataRoute( this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, ApiVersion apiVersion, IODataPathHandler pathHandler, IEnumerable<IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler ) { Arg.NotNull( configuration, nameof( configuration ) ); Arg.NotNull( model, nameof( model ) ); Arg.NotNull( apiVersion, nameof( apiVersion ) ); Contract.Ensures( Contract.Result<ODataRoute>() != null ); var routeConventions = EnsureConventions( routingConventions.ToList() ); var routes = configuration.Routes; if ( !IsNullOrEmpty( routePrefix ) ) { routePrefix = routePrefix.TrimEnd( '/' ); } if ( batchHandler != null ) { var batchTemplate = IsNullOrEmpty( routePrefix ) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute( routeName + "Batch", batchTemplate, batchHandler ); } configuration.SetResolverSettings( pathHandler ); model.SetAnnotationValue( model, new ApiVersionAnnotation( apiVersion ) ); routeConventions.Insert( 0, new VersionedAttributeRoutingConvention( model, configuration ) ); var routeConstraint = new VersionedODataPathRouteConstraint( pathHandler, model, routeName, routeConventions.ToArray(), apiVersion ); var route = new ODataRoute( routePrefix, routeConstraint ); AddApiVersionConstraintIfNecessary( route ); routes.Add( routeName, route ); var unversionedRouteConstraint = new ODataPathRouteConstraint( pathHandler, model, routeName, routeConventions.ToArray() ); var unversionedRoute = new ODataRoute( routePrefix, new UnversionedODataPathRouteConstraint( unversionedRouteConstraint, apiVersion ) ); AddApiVersionConstraintIfNecessary( unversionedRoute ); routes.Add( routeName + UnversionedRouteSuffix, unversionedRoute ); return route; }
/// <summary> /// Instructs WebApi to map one or more of the registered Restier APIs to the specified Routes, each with it's own isolated Dependency Injection container. /// </summary> /// <param name="config">The <see cref="HttpConfiguration"/> instance to enhance.</param> /// <param name="configureRoutesAction">The action for configuring a set of routes.</param> /// <param name="httpServer">The HttpServer instance to create the routes on.</param> /// <returns>The <see cref="HttpConfiguration"/> instance to allow for fluent method chaining.</returns> /// <example> /// <code> /// config.MapRestier(builder => /// builder /// .MapApiRoute<SomeApi>("SomeApiV1", "someapi/") /// .MapApiRoute<AnotherApi>("AnotherApiV1", "anotherapi/") /// ); /// </code> /// </example> public static HttpConfiguration MapRestier(this HttpConfiguration config, Action <RestierRouteBuilder> configureRoutesAction, HttpServer httpServer) { Ensure.NotNull(configureRoutesAction, nameof(configureRoutesAction)); var rrb = new RestierRouteBuilder(); configureRoutesAction.Invoke(rrb); foreach (var route in rrb.Routes) { ODataBatchHandler batchHandler = null; var conventions = CreateRestierRoutingConventions(config, route.Key); if (route.Value.AllowBatching) { if (httpServer == null) { throw new ArgumentNullException(nameof(httpServer), OwinException); } #pragma warning disable IDE0067 // Dispose objects before losing scope batchHandler = new RestierBatchHandler(httpServer) { ODataRouteName = route.Key }; #pragma warning restore IDE0067 // Dispose objects before losing scope } var odataRoute = config.MapODataServiceRoute(route.Key, route.Value.RoutePrefix, (containerBuilder, routeName) => { var rcb = containerBuilder as RestierContainerBuilder; rcb.routeBuilder = rrb; rcb.RouteName = routeName; containerBuilder.AddService <IEnumerable <IODataRoutingConvention> >(ServiceLifetime.Singleton, sp => conventions); if (batchHandler != null) { //RWM: DO NOT simplify this generic signature. It HAS to stay this way, otherwise the code breaks. containerBuilder.AddService <ODataBatchHandler>(ServiceLifetime.Singleton, sp => batchHandler); } }); } return(config); }
/// <summary> /// Maps the specified OData route. When the <paramref name="batchHandler"/> is non-<c>null</c>, it will /// create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="models">The <see cref="IEnumerable{T}">sequence</see> of <see cref="IEdmModel">EDM models</see> to use for parsing OData paths.</param> /// <param name="pathHandler">The <see cref="IODataPathHandler" /> to use for parsing the OData path.</param> /// <param name="routingConventions"> /// The OData routing conventions to use for controller and action selection. /// </param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The <see cref="IEndpointRouteBuilder"/>.</returns> public static IEndpointRouteBuilder MapVersionedODataRoute( this IEndpointRouteBuilder builder, string routeName, string routePrefix, IEnumerable <IEdmModel> models, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) => AddRoute( builder.MapODataRoute( routeName, routePrefix, container => container.AddApiVersioning(models, routingConventions, builder.ServiceProvider) .AddService(Singleton, sp => pathHandler) .AddService(Singleton, sp => batchHandler)), routeName, routePrefix);
/// <summary> /// Instructs WebApi to map one or more of the registered Restier APIs to the specified Routes, each with it's own isolated Dependency Injection container. /// </summary> /// <param name="routeBuilder">The <see cref="HttpConfiguration"/> instance to enhance.</param> /// <param name="configureRoutesAction">The action for configuring a set of routes.</param> /// <returns>The <see cref="HttpConfiguration"/> instance to allow for fluent method chaining.</returns> /// <example> /// <code> /// config.MapRestier(builder => /// builder /// .MapApiRoute<SomeApi>("SomeApiV1", "someapi/") /// .MapApiRoute<AnotherApi>("AnotherApiV1", "anotherapi/") /// ); /// </code> /// </example> public static IRouteBuilder MapRestier(this IRouteBuilder routeBuilder, Action <RestierRouteBuilder> configureRoutesAction) { Ensure.NotNull(routeBuilder, nameof(routeBuilder)); Ensure.NotNull(configureRoutesAction, nameof(configureRoutesAction)); var perRouteContainer = routeBuilder.ServiceProvider.GetRequiredService <IPerRouteContainer>(); perRouteContainer.BuilderFactory = () => routeBuilder.ServiceProvider.GetRequiredService <IContainerBuilder>(); var rrb = new RestierRouteBuilder(); configureRoutesAction.Invoke(rrb); foreach (var route in rrb.Routes) { ODataBatchHandler batchHandler = null; if (route.Value.AllowBatching) { #pragma warning disable IDE0067 // Dispose objects before losing scope batchHandler = new RestierBatchHandler() { ODataRouteName = route.Key }; #pragma warning restore IDE0067 // Dispose objects before losing scope } var odataRoute = routeBuilder.MapODataServiceRoute(route.Key, route.Value.RoutePrefix, (containerBuilder) => { var rcb = containerBuilder as RestierContainerBuilder; rcb.routeBuilder = rrb; rcb.RouteName = route.Key; containerBuilder.AddService <IEnumerable <IODataRoutingConvention> >(OData.ServiceLifetime.Singleton, sp => routeBuilder.CreateRestierRoutingConventions(route.Key)); if (batchHandler != null) { //RWM: DO NOT simplify this generic signature. It HAS to stay this way, otherwise the code breaks. containerBuilder.AddService <ODataBatchHandler>(OData.ServiceLifetime.Singleton, sp => batchHandler); } }); } return(routeBuilder); }
public void AddModel_WithBatchHandler_SetModel() { // Arrange ODataOptions options = new ODataOptions(); IEdmModel edmModel = EdmCoreModel.Instance; ODataBatchHandler handler = new Mock <ODataBatchHandler>().Object; // Act options.AddModel(edmModel, handler); // Assert KeyValuePair <string, (IEdmModel, IServiceProvider)> model = Assert.Single(options.Models); Assert.Equal(String.Empty, model.Key); Assert.Same(edmModel, model.Value.Item1); Assert.NotNull(model.Value.Item2); ODataBatchHandler actual = model.Value.Item2.GetService <ODataBatchHandler>(); Assert.Same(handler, actual); }
private static ODataRoute CustomMapODataServiceRoute( HttpRouteCollection routes, string routeName, string routePrefix, Func <HttpRequestMessage, IEdmModel> modelProvider, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (!string.IsNullOrEmpty(routePrefix)) { int prefixLastIndex = routePrefix.Length - 1; if (routePrefix[prefixLastIndex] == '/') { routePrefix = routePrefix.Substring(0, routePrefix.Length - 1); } } if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = string.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } CustomODataPathRouteConstraint routeConstraint = new CustomODataPathRouteConstraint( pathHandler, modelProvider, routeName, routingConventions); CustomODataRoute odataRoute = new CustomODataRoute(routePrefix, routeConstraint); routes.Add(routeName, odataRoute); return(odataRoute); }
public virtual void Configure(IAppBuilder owinApp) { if (owinApp == null) { throw new ArgumentNullException(nameof(owinApp)); } _webApiConfig = new HttpConfiguration(); _webApiConfig.SuppressHostPrincipal(); _webApiConfig.SetTimeZoneInfo(TimeZoneInfo.Utc); _webApiConfig.Formatters.Clear(); _webApiConfig.IncludeErrorDetailPolicy = _activeAppEnvironment.DebugMode ? IncludeErrorDetailPolicy.LocalOnly : IncludeErrorDetailPolicy.Never; _webApiConfgurationCustomizers.ToList() .ForEach(webApiConfigurationCustomizer => { webApiConfigurationCustomizer.CustomizeWebApiConfiguration(_webApiConfig); }); _webApiConfig.DependencyResolver = _webApiDependencyResolver; _server = new HttpServer(_webApiConfig); foreach (IGrouping <string, IEdmModelProvider> edmModelProviders in _emdEdmModelProviders.GroupBy(mp => mp.GetEdmName())) { ODataModelBuilder modelBuilder = _oDataModelBuilderProvider.GetODataModelBuilder(_webApiConfig, containerName: $"{edmModelProviders.Key}Context", @namespace: edmModelProviders.Key); foreach (IEdmModelProvider edmModelProvider in edmModelProviders) { edmModelProvider.BuildEdmModel(modelBuilder); } string routeName = $"{edmModelProviders.Key}-odata"; _odataBatchHandler = new DefaultODataBatchHandler(_server); _odataBatchHandler.MessageQuotas.MaxOperationsPerChangeset = int.MaxValue; _odataBatchHandler.MessageQuotas.MaxPartsPerBatch = int.MaxValue; _odataBatchHandler.MessageQuotas.MaxNestingDepth = int.MaxValue; _odataBatchHandler.MessageQuotas.MaxReceivedMessageSize = long.MaxValue; _odataBatchHandler.ODataRouteName = routeName; IEnumerable <IODataRoutingConvention> conventions = ODataRoutingConventions.CreateDefault(); IEdmModel edmModel = modelBuilder.GetEdmModel(); _webApiConfig.MapODataServiceRoute(routeName, edmModelProviders.Key, builder => { builder.AddService(ServiceLifetime.Singleton, sp => conventions); builder.AddService(ServiceLifetime.Singleton, sp => edmModel); builder.AddService(ServiceLifetime.Singleton, sp => _odataBatchHandler); builder.AddService(ServiceLifetime.Singleton, sp => _webApiDependencyResolver); _oDataContainerBuilderCustomizer.Customize(builder); }); } owinApp.UseAutofacWebApi(_webApiConfig); _webApiOwinPipelineInjector.UseWebApiOData(owinApp, _server); _webApiConfig.EnsureInitialized(); }
/// <summary> /// Maps the specified OData route and the OData route attributes. /// </summary> /// <param name="builder">The <see cref="IEndpointRouteBuilder"/> to add the route to.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="configureAction">The configuring action to add the services to the root container.</param> /// <returns>The input <see cref="IEndpointRouteBuilder"/>.</returns> public static IEndpointRouteBuilder MapODataRoute(this IEndpointRouteBuilder builder, string routeName, string routePrefix, Action <IContainerBuilder> configureAction) { if (builder == null) { throw Error.ArgumentNull("builder"); } if (routeName == null) { throw Error.ArgumentNull("routeName"); } // Build and configure the root container. IServiceProvider serviceProvider = builder.ServiceProvider; IPerRouteContainer perRouteContainer = serviceProvider.GetRequiredService <IPerRouteContainer>(); if (perRouteContainer == null) { throw Error.InvalidOperation(SRResources.MissingODataServices, nameof(IPerRouteContainer)); } // Make sure the MetadataController is registered with the ApplicationPartManager. ApplicationPartManager applicationPartManager = serviceProvider.GetRequiredService <ApplicationPartManager>(); applicationPartManager.ApplicationParts.Add(new AssemblyPart(typeof(MetadataController).Assembly)); // Create an service provider for this route. Add the default services to the custom configuration actions. Action <IContainerBuilder> builderAction = ConfigureDefaultServices(builder, configureAction); IServiceProvider subServiceProvider = perRouteContainer.CreateODataRootContainer(routeName, builderAction); // Resolve the path handler and set URI resolver to it. IODataPathHandler pathHandler = subServiceProvider.GetRequiredService <IODataPathHandler>(); // If settings is not on local, use the global configuration settings. ODataOptions options = serviceProvider.GetRequiredService <ODataOptions>(); if (pathHandler != null && pathHandler.UrlKeyDelimiter == null) { pathHandler.UrlKeyDelimiter = options.UrlKeyDelimiter; } // Resolve HTTP handler, create the OData route and register it. routePrefix = RemoveTrailingSlash(routePrefix); // If a batch handler is present, register the route with the batch path mapper. This will be used // by the batching middleware to handle the batch request. Batching still requires the injection // of the batching middleware via UseODataBatching(). ODataBatchHandler batchHandler = subServiceProvider.GetService <ODataBatchHandler>(); if (batchHandler != null) { // TODO: for the $batch, i need more time to refactor/test it. // batchHandler.ODataRoute = route; batchHandler.ODataRouteName = routeName; string batchPath = String.IsNullOrEmpty(routePrefix) ? '/' + ODataRouteConstants.Batch : '/' + routePrefix + '/' + ODataRouteConstants.Batch; ODataBatchPathMapping batchMapping = builder.ServiceProvider.GetRequiredService <ODataBatchPathMapping>(); batchMapping.AddRoute(routeName, batchPath); } builder.MapDynamicControllerRoute <ODataEndpointRouteValueTransformer>( ODataEndpointPattern.CreateODataEndpointPattern(routeName, routePrefix)); perRouteContainer.AddRoute(routeName, routePrefix); return(builder); }
public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { if (configuration == null) { throw Error.ArgumentNull("configuration"); } HttpRouteCollection routes = configuration.Routes; routePrefix = RemoveTrailingSlash(routePrefix); if (batchHandler != null) { batchHandler.ODataRouteName = routeName; string batchTemplate = String.IsNullOrEmpty(routePrefix) ? ODataRouteConstants.Batch : routePrefix + '/' + ODataRouteConstants.Batch; routes.MapHttpBatchRoute(routeName + "Batch", batchTemplate, batchHandler); } DefaultODataPathHandler odataPathHandler = pathHandler as DefaultODataPathHandler; if (odataPathHandler != null) { odataPathHandler.ResolverSetttings = configuration.GetResolverSettings(); } ODataPathRouteConstraint routeConstraint = new ODataPathRouteConstraint(pathHandler, model, routeName, routingConventions); ODataRoute route = new ODataRoute(routePrefix, routeConstraint); routes.Add(routeName, route); return(route); }
/// <summary> /// Maps the specified OData route and the OData route attributes. When the <paramref name="batchHandler"/> is /// non-<c>null</c>, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, ODataBatchHandler batchHandler) { return(MapODataServiceRoute(configuration, routeName, routePrefix, model, new DefaultODataPathHandler(), ODataRoutingConventions.CreateDefaultWithAttributeRouting(configuration, model), batchHandler)); }
public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, IODataPathHandler pathHandler, IEnumerable <IODataRoutingConvention> routingConventions, ODataBatchHandler batchHandler) { return(configuration.MapODataServiceRoute(routeName, routePrefix, builder => builder.AddService(ServiceLifetime.Singleton, sp => model) .AddService(ServiceLifetime.Singleton, sp => pathHandler) .AddService(ServiceLifetime.Singleton, sp => routingConventions.ToList().AsEnumerable()) .AddService(ServiceLifetime.Singleton, sp => batchHandler))); }
/// <summary> /// Maps the specified OData route and the OData route attributes. When the <paramref name="batchHandler"/> is /// non-<c>null</c>, it will create a '$batch' endpoint to handle the batch requests. /// </summary> /// <param name="configuration">The server configuration.</param> /// <param name="routeName">The name of the route to map.</param> /// <param name="routePrefix">The prefix to add to the OData route's path template.</param> /// <param name="model">The EDM model to use for parsing OData paths.</param> /// <param name="batchHandler">The <see cref="ODataBatchHandler"/>.</param> /// <returns>The added <see cref="ODataRoute"/>.</returns> public static ODataRoute MapODataServiceRoute(this HttpConfiguration configuration, string routeName, string routePrefix, IEdmModel model, ODataBatchHandler batchHandler) { return(configuration.MapODataServiceRoute(routeName, routePrefix, builder => builder.AddService(ServiceLifetime.Singleton, sp => model) .AddService(ServiceLifetime.Singleton, sp => batchHandler) .AddService <IEnumerable <IODataRoutingConvention> >(ServiceLifetime.Singleton, sp => ODataRoutingConventions.CreateDefaultWithAttributeRouting(routeName, configuration)))); }