/// <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); }
public void GetSupportedContentTypesODataOutputFormatter_WorksForContentType() { // Arrange ODataOutputFormatter formatter = ODataOutputFormatterFactory.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))); }
/// <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); }
/// <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 <ODataOutputFormatter> CreateOutputFormatters(IEdmModel model = null) { // Model is not used in AspNetCore. return(ODataOutputFormatterFactory.Create()); }
/// <summary> /// Create the OData formatters. /// </summary> /// <param name="configuration">The configuration.</param> /// <returns>The OData formatters.</returns> public static IList <ODataOutputFormatter> CreateOData(WebRouteConfiguration configuration) { return(ODataOutputFormatterFactory.Create()); }
/// <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)); }