/// <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); }
/// TODO GitHubIssue#51 : Support model lazy loading /// <summary> /// Maps the API routes to the RestierController. /// </summary> /// <typeparam name="TApi">The user API.</typeparam> /// <param name="config">The <see cref="HttpConfiguration"/> instance.</param> /// <param name="routeName">The name of the route.</param> /// <param name="routePrefix">The prefix of the route.</param> /// <param name="apiFactory">The callback to create API instances.</param> /// <param name="batchHandler">The handler for batch requests.</param> /// <returns>The task object containing the resulted <see cref="ODataRoute"/> instance.</returns> public static async Task <ODataRoute> MapRestierRoute <TApi>( this HttpConfiguration config, string routeName, string routePrefix, Func <IApi> apiFactory, RestierBatchHandler batchHandler = null) where TApi : ApiBase { Ensure.NotNull(apiFactory, "apiFactory"); using (var api = apiFactory()) { var model = await api.GetModelAsync(); model.EnsurePayloadValueConverter(); var conventions = CreateRestierRoutingConventions(config, model, apiFactory); if (batchHandler != null && batchHandler.ApiFactory == null) { batchHandler.ApiFactory = apiFactory; } return(config.MapODataServiceRoute( routeName, routePrefix, model, new DefaultODataPathHandler(), conventions, batchHandler)); } }
#pragma warning restore CA1823 // Do not declare static members on generic types /// TODO GitHubIssue#51 : Support model lazy loading /// <summary> /// Maps the API routes to the RestierController. /// </summary> /// <typeparam name="TApi">The user API.</typeparam> /// <param name="config">The <see cref="HttpConfiguration"/> instance.</param> /// <param name="routeName">The name of the route.</param> /// <param name="routePrefix">The prefix of the route.</param> /// <param name="batchHandler">The handler for batch requests.</param> /// <returns>The task object containing the resulted <see cref="ODataRoute"/> instance.</returns> public static Task <ODataRoute> MapRestierRoute <TApi>( this HttpConfiguration config, string routeName, string routePrefix, RestierBatchHandler batchHandler = null) where TApi : ApiBase { // This will be added a service to callback stored in ApiConfiguration // Callback is called by ApiBase.AddApiServices method to add real services. ApiBase.AddPublisherServices(typeof(TApi), services => { services.AddODataServices <TApi>(); }); IContainerBuilder func() => new RestierContainerBuilder(typeof(TApi)); config.UseCustomContainerBuilder(func); var conventions = CreateRestierRoutingConventions(config, routeName); if (batchHandler != null) { batchHandler.ODataRouteName = routeName; } void configureAction(IContainerBuilder builder) => builder .AddService <IEnumerable <IODataRoutingConvention> >(ServiceLifetime.Singleton, sp => conventions) .AddService <ODataBatchHandler>(ServiceLifetime.Singleton, sp => batchHandler); var route = config.MapODataServiceRoute(routeName, routePrefix, configureAction); return(Task.FromResult(route)); }
/// <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); }
/// <summary> /// Maps the API routes to the RestierController. /// </summary> /// <typeparam name="TApi">The user API.</typeparam> /// <param name="config">The <see cref="HttpConfiguration"/> instance.</param> /// <param name="routeName">The name of the route.</param> /// <param name="routePrefix">The prefix of the route.</param> /// <param name="batchHandler">The handler for batch requests.</param> /// <returns>The task object containing the resulted <see cref="ODataRoute"/> instance.</returns> public static async Task <ODataRoute> MapRestierRoute <TApi>( this HttpConfiguration config, string routeName, string routePrefix, RestierBatchHandler batchHandler = null) where TApi : ApiBase, new() { return(await MapRestierRoute <TApi>( config, routeName, routePrefix, () => new TApi(), batchHandler)); }
/// TODO GitHubIssue#51 : Support model lazy loading /// <summary> /// Maps the API routes to the RestierController. /// </summary> /// <typeparam name="TApi">The user API.</typeparam> /// <param name="config">The <see cref="HttpConfiguration"/> instance.</param> /// <param name="routeName">The name of the route.</param> /// <param name="routePrefix">The prefix of the route.</param> /// <param name="apiFactory">The callback to create API instances.</param> /// <param name="batchHandler">The handler for batch requests.</param> /// <returns>The task object containing the resulted <see cref="ODataRoute"/> instance.</returns> public static Task <ODataRoute> MapRestierRoute <TApi>( this HttpConfiguration config, string routeName, string routePrefix, Func <ApiBase> apiFactory, RestierBatchHandler batchHandler = null) where TApi : ApiBase { Ensure.NotNull(apiFactory, "apiFactory"); // This will be added a service to callback stored in ApiConfiguration // Callback is called by ApiBase.AddApiServices method to add real services. ApiConfiguration.AddPublisherServices <TApi>(services => { services.AddODataServices <TApi>(); }); using (var api = apiFactory()) { var model = GetModel(api); var conventions = CreateRestierRoutingConventions(config, model, apiFactory); if (batchHandler != null && batchHandler.ApiFactory == null) { batchHandler.ApiFactory = apiFactory; } // Customized path handler should be added in ConfigureApi as service // Allow to handle URL encoded slash (%2F), and backslash(%5C) with customized handler var handler = api.Context.GetApiService <IODataPathHandler>(); if (handler == null) { handler = new DefaultODataPathHandler(); } var route = config.MapODataServiceRoute( routeName, routePrefix, model, handler, conventions, batchHandler); // Customized converter should be added in ConfigureApi as service var converter = api.Context.GetApiService <ODataPayloadValueConverter>(); if (converter == null) { converter = new RestierPayloadValueConverter(); } model.SetPayloadValueConverter(converter); return(Task.FromResult(route)); } }
public static async void Register(HttpConfiguration config) { #if !PROD config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always; #endif config.Filter().Expand().Select().OrderBy().MaxTop(100).Count(); config.SetTimeZoneInfo(TimeZoneInfo.Utc); config.MapHttpAttributeRoutes(); var batchHandler = new RestierBatchHandler(GlobalConfiguration.DefaultServer); #pragma warning disable CA2007 // Do not directly await a Task await config.MapRestierRoute <NorthwindApi>("ApiV1", "", batchHandler); #pragma warning restore CA2007 // Do not directly await a Task }
/// <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> /// 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); }
/// TODO GitHubIssue#51 : Support model lazy loading /// <summary> /// Maps the API routes to the RestierController. /// </summary> /// <typeparam name="TApi">The user API.</typeparam> /// <param name="config">The <see cref="HttpConfiguration"/> instance.</param> /// <param name="routeName">The name of the route.</param> /// <param name="routePrefix">The prefix of the route.</param> /// <param name="apiFactory">The callback to create API instances.</param> /// <param name="batchHandler">The handler for batch requests.</param> /// <returns>The task object containing the resulted <see cref="ODataRoute"/> instance.</returns> public static Task <ODataRoute> MapRestierRoute <TApi>( this HttpConfiguration config, string routeName, string routePrefix, Func <ApiBase> apiFactory, RestierBatchHandler batchHandler = null) where TApi : ApiBase { Ensure.NotNull(apiFactory, "apiFactory"); // ApiBase.ConfigureApi is called before this method is called. ApiConfiguration.Configure <TApi>(services => { services.AddScoped <RestierQueryExecutorOptions>() .ChainPrevious <IQueryExecutor, RestierQueryExecutor>(); }); using (var api = apiFactory()) { var model = api.GetModelAsync().Result; var conventions = CreateRestierRoutingConventions(config, model, apiFactory); if (batchHandler != null && batchHandler.ApiFactory == null) { batchHandler.ApiFactory = apiFactory; } var route = config.MapODataServiceRoute( routeName, routePrefix, model, new DefaultODataPathHandler(), conventions, batchHandler); // Customized converter should be added in ConfigureApi as service var converter = api.Context.GetApiService <ODataPayloadValueConverter>(); if (converter == null) { converter = new RestierPayloadValueConverter(); } model.SetPayloadValueConverter(converter); return(Task.FromResult(route)); } }