/// <summary>
        /// Adds essential OData services to the specified <see cref="IServiceCollection" />.
        /// </summary>
        /// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
        /// <returns>An <see cref="IODataBuilder"/> that can be used to further configure the OData services.</returns>
        public static IODataBuilder AddOData(this IServiceCollection services)
        {
            if (services == null)
            {
                throw Error.ArgumentNull(nameof(services));
            }

            // Setup per-route dependency injection. When routes are added, additional
            // per-route classes will be injected, such as IEdmModel and IODataRoutingConventions.
            services.AddSingleton <IPerRouteContainer, PerRouteContainer>();

            // Add OData and query options. Opting not to use IConfigurationOptions in favor of
            // fluent extensions APIs to IRouteBuilder.
            services.AddSingleton <ODataOptions>();
            services.AddSingleton <DefaultQuerySettings>();

            // Add the batch path mapping class to store batch route names and prefixes.
            services.AddSingleton <ODataBatchPathMapping>();

            // Configure MvcCore to use formatters. The OData formatters do go into the global service
            // provider and get picked up by the AspNetCore MVC framework. However, they ignore non-OData
            // requests so they won't be used for non-OData formatting.
            services.AddMvcCore(options =>
            {
                // Add OData input formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataInputFormatter inputFormatter in ODataInputFormatterFactory.Create().Reverse())
                {
                    options.InputFormatters.Insert(0, inputFormatter);
                }

                // Add OData output formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataOutputFormatter outputFormatter in ODataOutputFormatterFactory.Create().Reverse())
                {
                    options.OutputFormatters.Insert(0, outputFormatter);
                }

                // Add the value provider.
                options.ValueProviderFactories.Add(new ODataValueProviderFactory());
            });

            // Add our action selector. The ODataActionSelector creates an ActionSelector in it's constructor
            // and pass all non-OData calls to this inner selector.
            services.AddSingleton <IActionSelector, ODataActionSelector>();

            // Add the ActionContextAccessor; this allows access to the ActionContext which is needed
            // during the formatting process to construct a IUrlHelper.
            services.AddSingleton <IActionContextAccessor, ActionContextAccessor>();

            return(new ODataBuilder(services));
        }
        /// <summary>
        /// Adds the core OData services required for OData requests, excluding the <see cref="ODataOptions"/> configuration.
        /// </summary>
        /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
        /// <returns>The <see cref="IODataBuilder"/> so that additional calls can be chained.</returns>
        private static IODataBuilder AddODataCore(this IServiceCollection services)
        {
            if (services == null)
            {
                throw Error.ArgumentNull(nameof(services));
            }

            services.TryAddEnumerable(
                ServiceDescriptor.Singleton <IODataQueryRequestParser, DefaultODataQueryRequestParser>());
            services.TryAddSingleton <IAssemblyResolver, DefaultAssemblyResolver>();
            services.TryAddSingleton <IODataTypeMappingProvider, ODataTypeMappingProvider>();

            // Configure MvcCore to use formatters. The OData formatters do go into the global service
            // provider and get picked up by the AspNetCore MVC framework. However, they ignore non-OData
            // requests so they won't be used for non-OData formatting.
            services.AddControllers(options =>
            {
                // Add OData input formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataInputFormatter inputFormatter in ODataInputFormatterFactory.Create().Reverse())
                {
                    options.InputFormatters.Insert(0, inputFormatter);
                }

                // Add OData output formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataOutputFormatter outputFormatter in ODataOutputFormatterFactory.Create().Reverse())
                {
                    options.OutputFormatters.Insert(0, outputFormatter);
                }

                // Add the value provider.
                // options.ValueProviderFactories.Insert(0, new ODataValueProviderFactory());
            })
            .AddJsonOptions(options =>
            {
                // Add the Select expand and other wrapper converter factory
                options.JsonSerializerOptions.Converters.Add(new SelectExpandWrapperConverter());
                options.JsonSerializerOptions.Converters.Add(new PageResultValueConverter());
                options.JsonSerializerOptions.Converters.Add(new DynamicTypeWrapperConverter());
            });

            services.AddODataRouting();

            IODataBuilder builder = new DefaultODataBuilder(services);

            return(builder);
        }
Beispiel #3
0
        public void GetSupportedContentTypesODataInputFormatter_WorksForContentType()
        {
            // Arrange
            ODataInputFormatter formatter = ODataInputFormatterFactory.Create().First();

            Assert.NotNull(formatter); // guard

            // Act & Assert
            IReadOnlyList <string> contentTypes = formatter.GetSupportedContentTypes("application/json", typeof(string));

            Assert.Equal(12, contentTypes.Count);

            // Act & Assert
            formatter.SupportedMediaTypes.Clear();
            ExceptionAssert.DoesNotThrow(() => formatter.GetSupportedContentTypes("application/json", typeof(string)));
        }
Beispiel #4
0
        /// <summary>
        /// Adds services required for OData requests.
        /// </summary>
        /// <param name="services">The <see cref="IServiceCollection"/> to add the services to.</param>
        /// <param name="setupAction">The OData options to configure the services with.</param>
        /// <returns>The <see cref="IODataBuilder"/> so that additional calls can be chained.</returns>
        public static IODataBuilder AddOData(this IServiceCollection services, Action <ODataOptions> setupAction)
        {
            if (services == null)
            {
                throw new ArgumentNullException(nameof(services));
            }

            if (setupAction == null)
            {
                throw new ArgumentNullException(nameof(setupAction));
            }

            services.TryAddSingleton <IAssemblyResolver, DefaultAssemblyResolver>();
            services.TryAddSingleton <IODataTypeMappingProvider, ODataTypeMappingProvider>();

            // Configure MvcCore to use formatters. The OData formatters do go into the global service
            // provider and get picked up by the AspNetCore MVC framework. However, they ignore non-OData
            // requests so they won't be used for non-OData formatting.
            services.AddControllers(options =>
            {
                // Add OData input formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataInputFormatter inputFormatter in ODataInputFormatterFactory.Create().Reverse())
                {
                    options.InputFormatters.Insert(0, inputFormatter);
                }

                // Add OData output formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataOutputFormatter outputFormatter in ODataOutputFormatterFactory.Create().Reverse())
                {
                    options.OutputFormatters.Insert(0, outputFormatter);
                }

                // Add the value provider.
                // options.ValueProviderFactories.Insert(0, new ODataValueProviderFactory());
            });

            services.Configure(setupAction);

            services.AddODataRouting();

            IODataBuilder builder = new DefaultODataBuilder(services);

            return(builder);
        }
Beispiel #5
0
        /// <summary>
        /// Configure the default <see cref="MvcOptions"/>
        /// </summary>
        /// <param name="options">The <see cref="MvcOptions"/> to configure.</param>
        public void Configure(MvcOptions options)
        {
            if (options == null)
            {
                throw Error.ArgumentNull(nameof(options));
            }

            // Read formatters
            foreach (ODataInputFormatter inputFormatter in ODataInputFormatterFactory.Create().Reverse())
            {
                options.InputFormatters.Insert(0, inputFormatter);
            }

            // Write formatters
            foreach (ODataOutputFormatter outputFormatter in ODataOutputFormatterFactory.Create().Reverse())
            {
                options.OutputFormatters.Insert(0, outputFormatter);
            }
        }
 private static IEnumerable <ODataInputFormatter> CreateInputFormatters(IEdmModel model = null)
 {
     // Model is not used in AspNetCore.
     return(ODataInputFormatterFactory.Create());
 }
Beispiel #7
0
 private static ODataInputFormatter GetInputFormatter()
 {
     return(ODataInputFormatterFactory.Create().FirstOrDefault());
 }
        /// <summary>
        /// Adds essential OData services to the specified <see cref="IServiceCollection" />.
        /// </summary>
        /// <param name="services">The <see cref="IServiceCollection" /> to add services to.</param>
        /// <returns>An <see cref="IODataBuilder"/> that can be used to further configure the OData services.</returns>
        public static IODataBuilder AddOData(this IServiceCollection services)
        {
            if (services == null)
            {
                throw Error.ArgumentNull(nameof(services));
            }

            // Setup per-route dependency injection. When routes are added, additional
            // per-route classes will be injected, such as IEdmModel and IODataRoutingConventions.
            services.AddSingleton <IPerRouteContainer, PerRouteContainer>();

            // Add OData and query options. Opting not to use IConfigurationOptions in favor of
            // fluent extensions APIs to IRouteBuilder.
            services.AddSingleton <ODataOptions>();
            services.AddSingleton <DefaultQuerySettings>();

            // Add the batch path mapping class to store batch route names and prefixes.
            services.AddSingleton <ODataBatchPathMapping>();

            // Configure MvcCore to use formatters. The OData formatters do go into the global service
            // provider and get picked up by the AspNetCore MVC framework. However, they ignore non-OData
            // requests so they won't be used for non-OData formatting.
            services.AddMvcCore(options =>
            {
                // Add OData input formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataInputFormatter inputFormatter in ODataInputFormatterFactory.Create().Reverse())
                {
                    options.InputFormatters.Insert(0, inputFormatter);
                }

                // Add OData output formatters at index 0, which overrides the built-in json and xml formatters.
                // Add in reverse order at index 0 to preserve order from the factory in the final list.
                foreach (ODataOutputFormatter outputFormatter in ODataOutputFormatterFactory.Create().Reverse())
                {
                    options.OutputFormatters.Insert(0, outputFormatter);
                }

                // Add the value provider.
                options.ValueProviderFactories.Insert(0, new ODataValueProviderFactory());
            });

#if NETSTANDARD2_0
            // Add our action selector. The ODataActionSelector creates an ActionSelector in it's constructor
            // and pass all non-OData calls to this inner selector.
            services.AddSingleton <IActionSelector, ODataActionSelector>();
#else
            // We need to decorate the ActionSelector.
            var selector = services.First(s => s.ServiceType == typeof(IActionSelector) && s.ImplementationType != null);
            services.Remove(selector);
            services.Add(new ServiceDescriptor(selector.ImplementationType, selector.ImplementationType, ServiceLifetime.Singleton));

            // Add our action selector. The ODataActionSelector creates an ActionSelector in it's constructor
            // and pass all non-OData calls to this inner selector.
            services.AddSingleton <IActionSelector>(s =>
            {
                return(new ODataActionSelector(
                           (IActionSelector)s.GetRequiredService(selector.ImplementationType),
                           (IModelBinderFactory)s.GetRequiredService(typeof(IModelBinderFactory)),
                           (IModelMetadataProvider)s.GetRequiredService(typeof(IModelMetadataProvider))));
            });

            services.AddSingleton <ODataEndpointRouteValueTransformer>();

            // OData Endpoint selector policy
            services.AddSingleton <MatcherPolicy, ODataEndpointSelectorPolicy>();

            // LinkGenerator
            var linkGenerator = services.First(s => s.ServiceType == typeof(LinkGenerator) && s.ImplementationType != null);
            services.Remove(linkGenerator);
            services.Add(new ServiceDescriptor(linkGenerator.ImplementationType, linkGenerator.ImplementationType, ServiceLifetime.Singleton));

            services.AddSingleton <LinkGenerator>(s =>
            {
                return(new ODataEndpointLinkGenerator((LinkGenerator)s.GetRequiredService(linkGenerator.ImplementationType)));
            });
#endif

            // Add the ActionContextAccessor; this allows access to the ActionContext which is needed
            // during the formatting process to construct a IUrlHelper.
            services.AddSingleton <IActionContextAccessor, ActionContextAccessor>();

            return(new ODataBuilder(services));
        }