From 32cf19d94a6f8e82c3f89930c483ab0a119ed38d Mon Sep 17 00:00:00 2001 From: Vincent He Date: Wed, 24 Aug 2016 08:15:36 +0800 Subject: [PATCH] Add resource attribute Make ConfigureApi static Add ApiBase,ApiContext as DI service Make container does not require ApiFactory --- src/GlobalSuppressions.cs | 1 + src/Microsoft.Restier.Core/ApiBase.cs | 104 ++++++++---------- .../ApiConfiguration.cs | 13 ++- src/Microsoft.Restier.Core/ApiContext.cs | 17 ++- .../RestierContainerBuilder.cs | 40 ++++--- .../ServiceCollectionExtensions.cs | 12 +- .../EntityFrameworkApi.cs | 7 +- .../Microsoft.Restier.Publishers.OData.csproj | 2 +- .../Model/ApiConfigurationExtensions.cs | 65 ----------- .../Model/ResourceAttribute.cs | 21 ++++ .../Model/RestierModelExtender.cs | 24 ++-- .../Routing/HttpConfigurationExtensions.cs | 6 +- .../Routing/RestierRoutingConvention.cs | 8 +- .../Microsoft.Restier.Core.Tests/Api.Tests.cs | 103 +++++++++++------ .../ApiBase.Tests.cs | 26 ++--- .../ApiConfiguration.Tests.cs | 47 ++++---- .../ApiContext.Tests.cs | 7 +- .../InvocationContext.Tests.cs | 22 ++-- .../Model/DefaultModelHandler.Tests.cs | 15 +-- .../PropertyBag.Tests.cs | 25 +++-- .../ServiceConfiguration.Tests.cs | 83 +++++++------- .../ChangeSetPreparerTests.cs | 2 +- .../Models/Library/LibraryApi.cs | 5 +- .../ExceptionHandlerTests.cs | 7 +- .../FallbackTests.cs | 6 +- .../Model/LibraryApi.cs | 5 +- .../Model/RestierModelBuilderTests.cs | 4 +- .../Model/RestierModelExtender.Tests.cs | 45 ++++---- .../StoreApi.cs | 4 +- .../PublicApi.bsl | 31 +++--- .../SaveTests.cs | 5 +- .../Models/NorthwindApi.cs | 6 +- .../Api/TrippinApi.cs | 10 +- .../Api/TrippinApi.cs | 9 +- 34 files changed, 397 insertions(+), 390 deletions(-) delete mode 100644 src/Microsoft.Restier.Publishers.OData/Model/ApiConfigurationExtensions.cs create mode 100644 src/Microsoft.Restier.Publishers.OData/Model/ResourceAttribute.cs diff --git a/src/GlobalSuppressions.cs b/src/GlobalSuppressions.cs index f4741ddc..46a66f80 100644 --- a/src/GlobalSuppressions.cs +++ b/src/GlobalSuppressions.cs @@ -4,6 +4,7 @@ using System.Diagnostics.CodeAnalysis; #region Permanent Exclusions +[assembly: SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes", Scope = "member", Target = "Microsoft.Restier.Providers.EntityFramework.EntityFrameworkApi`1.#ConfigureApi(System.Type,Microsoft.Extensions.DependencyInjection.IServiceCollection)")] [assembly: SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Scope = "member", Target = "Microsoft.Restier.Core.Query.QueryRequest.#Create`2(System.Linq.IQueryable`1,System.Linq.Expressions.Expression`1,!!1>>,System.Nullable`1)")] [assembly: SuppressMessage("Microsoft.Design", "CA1032:ImplementStandardExceptionConstructors", Scope = "type", Target = "Microsoft.Restier.Core.Submit.ChangeSetValidationException", Justification = "We do not intend to support serialization of this exception yet")] [assembly: SuppressMessage("Microsoft.Design", "CA1061:DoNotHideBaseClassMethods", Scope = "member", Target = "Microsoft.Restier.Publishers.OData.Batch.RestierBatchChangeSetRequestItem.#DisposeResponses(System.Collections.Generic.IEnumerable`1)")] diff --git a/src/Microsoft.Restier.Core/ApiBase.cs b/src/Microsoft.Restier.Core/ApiBase.cs index b92a446f..3b50359f 100644 --- a/src/Microsoft.Restier.Core/ApiBase.cs +++ b/src/Microsoft.Restier.Core/ApiBase.cs @@ -26,6 +26,24 @@ public abstract class ApiBase : IDisposable private ApiConfiguration apiConfiguration; private ApiContext apiContext; + private IServiceProvider serviceProvider; + + /// + /// Gets the which contains all services of this . + /// + public IServiceProvider ServiceProvider + { + get + { + return serviceProvider; + } + + set + { + // TODO use set but not in constructor as need to update lots of test cases + this.serviceProvider = value; + } + } /// /// Gets the API context for this API. @@ -41,13 +59,7 @@ public ApiContext Context if (this.apiContext == null) { - this.apiContext = this.CreateApiContext( - this.Configuration); - var apiScope = this.apiContext.GetApiService(); - if (apiScope != null) - { - apiScope.Api = this; - } + this.apiContext = serviceProvider.GetService(); } return this.apiContext; @@ -66,60 +78,35 @@ public ApiConfiguration Configuration { get { - if (this.apiConfiguration != null) + if (this.apiConfiguration == null) { - return this.apiConfiguration; + this.apiConfiguration = serviceProvider.GetService(); } - Configurations.TryGetValue(this.GetType(), out this.apiConfiguration); return this.apiConfiguration; } set { + // TODO keep now as lots of test cases need to update this.apiConfiguration = value; - bool isSuccess = Configurations.TryAdd(GetType(), apiConfiguration); - if (isSuccess) - { - UpdateApiConfiguration(this.apiConfiguration); - } - } - } - - /// - /// Performs application-defined tasks associated with - /// freeing, releasing, or resetting unmanaged resources. - /// - public void Dispose() - { - if (this.IsDisposed) - { - return; - } - - this.IsDisposed = true; - - if (this.apiContext != null) - { - this.apiContext.DisposeScope(); - this.apiContext = null; + Configurations.TryAdd(GetType(), apiConfiguration); } - - GC.SuppressFinalize(this); } /// /// Configure services for this API. /// + /// + /// The Api type. + /// /// - /// The with which to create an . + /// The with which is used to store all services. /// /// The . [CLSCompliant(false)] - public virtual IServiceCollection ConfigureApi(IServiceCollection services) + public static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - Type apiType = this.GetType(); - // Add core and convention's services services = services.AddCoreServices(apiType) .AddConventionBasedServices(apiType); @@ -131,29 +118,24 @@ public virtual IServiceCollection ConfigureApi(IServiceCollection services) } /// - /// Allow user to update the ApiConfiguration - /// . + /// Performs application-defined tasks associated with + /// freeing, releasing, or resetting unmanaged resources. /// - /// The for the Api instance. - [CLSCompliant(false)] - protected virtual void UpdateApiConfiguration(ApiConfiguration configuration) + public void Dispose() { - } + if (this.IsDisposed) + { + return; + } - /// - /// Creates the API context for this API. - /// Descendants may further configure the built . - /// - /// - /// The API configuration to use. - /// - /// - /// The API context for this API. - /// - protected virtual ApiContext CreateApiContext( - ApiConfiguration configuration) - { - return new ApiContext(configuration); + this.IsDisposed = true; + + if (this.apiContext != null) + { + this.apiContext = null; + } + + GC.SuppressFinalize(this); } // Registered as a scoped service so that IApi and ApiContext could be exposed as scoped service. diff --git a/src/Microsoft.Restier.Core/ApiConfiguration.cs b/src/Microsoft.Restier.Core/ApiConfiguration.cs index 68181683..fad124c0 100644 --- a/src/Microsoft.Restier.Core/ApiConfiguration.cs +++ b/src/Microsoft.Restier.Core/ApiConfiguration.cs @@ -56,19 +56,20 @@ internal IServiceProvider ServiceProvider internal IEdmModel Model { get; private set; } /// - /// Adds a configuration procedure for API type . + /// Adds a configuration procedure for apiType. /// This is expected to be called by publisher like WebApi to add services. /// - /// The API type. + /// + /// The Api Type. + /// /// - /// An action that will be called during the configuration of . + /// An action that will be called during the configuration of apiType. /// [CLSCompliant(false)] - public static void AddPublisherServices(Action configurationCallback) - where TApi : ApiBase + public static void AddPublisherServices(Type apiType, Action configurationCallback) { publisherServicesCallback.AddOrUpdate( - typeof(TApi), + apiType, configurationCallback, (type, existing) => existing + configurationCallback); } diff --git a/src/Microsoft.Restier.Core/ApiContext.cs b/src/Microsoft.Restier.Core/ApiContext.cs index 267f8112..f0bf0877 100644 --- a/src/Microsoft.Restier.Core/ApiContext.cs +++ b/src/Microsoft.Restier.Core/ApiContext.cs @@ -14,7 +14,7 @@ namespace Microsoft.Restier.Core /// public class ApiContext { - private readonly IServiceScope scope; + private IServiceProvider serviceProvider; /// /// Initializes a new instance of the class. @@ -22,13 +22,15 @@ public class ApiContext /// /// An API configuration. /// - public ApiContext(ApiConfiguration configuration) + /// + /// The service provider. + /// + public ApiContext(IServiceProvider provider, ApiConfiguration configuration) { Ensure.NotNull(configuration, "configuration"); this.Configuration = configuration; - this.scope = configuration.ServiceProvider - .GetRequiredService().CreateScope(); + this.serviceProvider = provider; } /// @@ -41,12 +43,7 @@ public ApiContext(ApiConfiguration configuration) /// internal IServiceProvider ServiceProvider { - get { return this.scope.ServiceProvider; } - } - - internal void DisposeScope() - { - this.scope.Dispose(); + get { return this.serviceProvider; } } } } diff --git a/src/Microsoft.Restier.Core/RestierContainerBuilder.cs b/src/Microsoft.Restier.Core/RestierContainerBuilder.cs index f913606d..4160fc0a 100644 --- a/src/Microsoft.Restier.Core/RestierContainerBuilder.cs +++ b/src/Microsoft.Restier.Core/RestierContainerBuilder.cs @@ -3,6 +3,7 @@ using System; using System.Globalization; +using System.Reflection; using System.Threading; using Microsoft.Extensions.DependencyInjection; using Microsoft.OData; @@ -17,15 +18,15 @@ namespace Microsoft.Restier.Core public class RestierContainerBuilder : IContainerBuilder { private readonly IServiceCollection services = new ServiceCollection(); - private Func apiFactory; + private Type apiType; /// /// Initializes a new instance of the class. /// - /// The Api factory to create the Api instance - public RestierContainerBuilder(Func apiFactory) + /// The Api Type + public RestierContainerBuilder(Type apiType) { - this.apiFactory = apiFactory; + this.apiType = apiType; } /// @@ -103,24 +104,29 @@ internal IContainerBuilder AddRestierService() { Func modelFactory = sp => { - using (var api = apiFactory()) - { - var configuation = sp.GetService(); - if (api.Configuration == null) - { - api.Configuration = configuation; - } - - var model = api.Context.GetModelAsync(default(CancellationToken)).Result; - return model; - } + var context = sp.GetService(); + var model = context.GetModelAsync(default(CancellationToken)).Result; + return model; }; - using (var api = apiFactory()) + // Configure the API via reflection call + var methodDeclaredType = apiType; + + MethodInfo method = null; + while (method == null && methodDeclaredType != null) { - api.ConfigureApi(services); + // In case the subclass does not override the method, call super class method + method = methodDeclaredType.GetMethod("ConfigureApi"); + methodDeclaredType = methodDeclaredType.BaseType; } + var parameters = new object[] + { + apiType, services + }; + + method.Invoke(null, parameters); + services.AddSingleton(modelFactory); return this; } diff --git a/src/Microsoft.Restier.Core/ServiceCollectionExtensions.cs b/src/Microsoft.Restier.Core/ServiceCollectionExtensions.cs index 45269913..3e498df9 100644 --- a/src/Microsoft.Restier.Core/ServiceCollectionExtensions.cs +++ b/src/Microsoft.Restier.Core/ServiceCollectionExtensions.cs @@ -211,13 +211,11 @@ public static IServiceCollection MakeTransient(this IServiceCollection /// Current public static IServiceCollection AddCoreServices(this IServiceCollection services, Type apiType) { - if (!services.HasService()) - { - services.AddScoped() - .AddScoped(apiType, sp => sp.GetService().Api) - .AddScoped(sp => sp.GetService().Api) - .AddScoped(sp => sp.GetService().Api.Context); - } + Ensure.NotNull(apiType, "apiType"); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); services.TryAddSingleton(); diff --git a/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs b/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs index 48294fc2..46456252 100644 --- a/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs +++ b/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs @@ -45,6 +45,9 @@ protected T DbContext /// Configures the API services for this API. Descendants may override this method to register /// as a scoped service. /// + /// + /// The Api type. + /// /// /// The with which to create an . /// @@ -52,10 +55,8 @@ protected T DbContext /// The . /// [CLSCompliant(false)] - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - Type apiType = this.GetType(); - // Add core and convention's services services = services.AddCoreServices(apiType) .AddConventionBasedServices(apiType); diff --git a/src/Microsoft.Restier.Publishers.OData/Microsoft.Restier.Publishers.OData.csproj b/src/Microsoft.Restier.Publishers.OData/Microsoft.Restier.Publishers.OData.csproj index 2378dbd8..9aed1bfd 100644 --- a/src/Microsoft.Restier.Publishers.OData/Microsoft.Restier.Publishers.OData.csproj +++ b/src/Microsoft.Restier.Publishers.OData/Microsoft.Restier.Publishers.OData.csproj @@ -86,8 +86,8 @@ - + diff --git a/src/Microsoft.Restier.Publishers.OData/Model/ApiConfigurationExtensions.cs b/src/Microsoft.Restier.Publishers.OData/Model/ApiConfigurationExtensions.cs deleted file mode 100644 index 56bf26d3..00000000 --- a/src/Microsoft.Restier.Publishers.OData/Model/ApiConfigurationExtensions.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. -// Licensed under the MIT License. See License.txt in the project root for license information. - -using System; -using System.Collections.Generic; -using Microsoft.Restier.Core; - -namespace Microsoft.Restier.Publishers.OData.Model -{ - /// - /// Offers a collection of extension methods to . - /// - public static class ApiConfigurationExtensions - { - private const string IgnoredPropertiesKey = "Microsoft.Restier.Publishers.OData.IgnoredProperties"; - - #region IgnoreProperty - - /// - /// Ignores the given property in ApiBase or sub-class when building the model. - /// - /// An API configuration. - /// The name of the property to be ignored. - /// The current API configuration instance. - public static ApiConfiguration IgnoreProperty( - this ApiConfiguration configuration, - string propertyName) - { - Ensure.NotNull(configuration, "configuration"); - Ensure.NotNull(propertyName, "propertyName"); - - configuration.GetIgnoredPropertiesImplementation().Add(propertyName); - return configuration; - } - - #endregion - - #region IgnoreProperty Internal - - internal static bool IsPropertyIgnored(this ApiConfiguration configuration, string propertyName) - { - Ensure.NotNull(configuration, "configuration"); - - return configuration.GetIgnoredPropertiesImplementation().Contains(propertyName); - } - - #endregion - - #region IgnoreProperty Private - - private static ICollection GetIgnoredPropertiesImplementation(this ApiConfiguration configuration) - { - var ignoredProperties = configuration.GetProperty>(IgnoredPropertiesKey); - if (ignoredProperties == null) - { - ignoredProperties = new HashSet(); - configuration.SetProperty(IgnoredPropertiesKey, ignoredProperties); - } - - return ignoredProperties; - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Microsoft.Restier.Publishers.OData/Model/ResourceAttribute.cs b/src/Microsoft.Restier.Publishers.OData/Model/ResourceAttribute.cs new file mode 100644 index 00000000..5c79ce96 --- /dev/null +++ b/src/Microsoft.Restier.Publishers.OData/Model/ResourceAttribute.cs @@ -0,0 +1,21 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. See License.txt in the project root for license information. + +using System; + +namespace Microsoft.Restier.Publishers.OData.Model +{ + /// + /// Attribute that indicates a property is an entity set or singleton. + /// The name will be same as property name. + /// + [AttributeUsage(AttributeTargets.Property)] + public sealed class ResourceAttribute : Attribute + { + /// + /// Gets or sets a value indicating whether it is singleton or entity set. + /// The default value is false means it is an entity set + /// + public bool IsSingleton { get; set; } + } +} diff --git a/src/Microsoft.Restier.Publishers.OData/Model/RestierModelExtender.cs b/src/Microsoft.Restier.Publishers.OData/Model/RestierModelExtender.cs index df0d4365..f689458b 100644 --- a/src/Microsoft.Restier.Publishers.OData/Model/RestierModelExtender.cs +++ b/src/Microsoft.Restier.Publishers.OData/Model/RestierModelExtender.cs @@ -176,27 +176,27 @@ private void ScanForDeclaredPublicProperties() } } - private void BuildEntitySetsAndSingletons(ModelContext context, EdmModel model) + private void BuildEntitySetsAndSingletons(EdmModel model) { - var configuration = context.ServiceProvider.GetService(); foreach (var property in this.publicProperties) { - if (configuration.IsPropertyIgnored(property.Name)) + var resourceAttribute = property.GetCustomAttributes(true).FirstOrDefault(); + if (resourceAttribute == null) { continue; } - var isEntitySet = IsEntitySetProperty(property); - if (!isEntitySet) + bool isSingleton = resourceAttribute.IsSingleton; + if ((!isSingleton && !IsEntitySetProperty(property)) + || (isSingleton && !IsSingletonProperty(property))) { - if (!IsSingletonProperty(property)) - { - continue; - } + // This means property type is not IQueryable when indicating an entityset + // or not non-generic type when indicating a singleton + continue; } var propertyType = property.PropertyType; - if (isEntitySet) + if (!isSingleton) { propertyType = propertyType.GetGenericArguments()[0]; } @@ -209,7 +209,7 @@ private void BuildEntitySetsAndSingletons(ModelContext context, EdmModel model) } var container = model.EnsureEntityContainer(this.targetType); - if (isEntitySet) + if (!isSingleton) { if (container.FindEntitySet(property.Name) == null) { @@ -341,7 +341,7 @@ public async Task GetModelAsync(ModelContext context, CancellationTok } ModelCache.ScanForDeclaredPublicProperties(); - ModelCache.BuildEntitySetsAndSingletons(context, edmModel); + ModelCache.BuildEntitySetsAndSingletons(edmModel); ModelCache.AddNavigationPropertyBindings(edmModel); return edmModel; } diff --git a/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs b/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs index 48b72f1b..8017a127 100644 --- a/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs +++ b/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs @@ -53,14 +53,16 @@ public static Task MapRestierRoute( // This will be added a service to callback stored in ApiConfiguration // Callback is called by ApiBase.AddApiServices method to add real services. - ApiConfiguration.AddPublisherServices(services => + ApiConfiguration.AddPublisherServices( + typeof(TApi), + services => { services.AddODataServices(); }); using (var api = apiFactory()) { - Func func = () => new RestierContainerBuilder(apiFactory); + Func func = () => new RestierContainerBuilder(api.GetType()); config.UseCustomContainerBuilder(func); var conventions = CreateRestierRoutingConventions(config, routeName, apiFactory); diff --git a/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs b/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs index dfaeb523..f900ceb1 100644 --- a/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs +++ b/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs @@ -7,7 +7,9 @@ using System.Web.Http; using System.Web.Http.Controllers; using System.Web.Http.Routing; +using System.Web.OData.Extensions; using System.Web.OData.Routing.Conventions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Edm; using Microsoft.OData.UriParser; using Microsoft.Restier.Core; @@ -67,7 +69,11 @@ public string SelectController(ODataPath odataPath, HttpRequestMessage request) } // Create ApiBase instance - request.SetApiInstance(apiFactory.Invoke()); + // TODO need to change the way to create ApiBase + var provider = request.GetRequestContainer(); + var apiBase = provider.GetService(); + apiBase.ServiceProvider = provider; + request.SetApiInstance(apiBase); return RestierControllerName; } diff --git a/test/Microsoft.Restier.Core.Tests/Api.Tests.cs b/test/Microsoft.Restier.Core.Tests/Api.Tests.cs index ed0d375d..79ba6d44 100644 --- a/test/Microsoft.Restier.Core.Tests/Api.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/Api.Tests.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Linq; using System.Linq.Expressions; +using System.Net; using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; @@ -79,7 +80,7 @@ public Task ExecuteSubmitAsync(SubmitContext context, Cancellation private class TestApi : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { var modelBuilder = new TestModelBuilder(); var modelMapper = new TestModelMapper(); @@ -87,7 +88,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) var changeSetPreparer = new TestChangeSetInitializer(); var submitExecutor = new TestSubmitExecutor(); - services.AddCoreServices(this.GetType()); + services.AddCoreServices(apiType); services.AddService((sp, next) => modelBuilder); services.AddService((sp, next) => modelMapper); services.AddService((sp, next) => querySourcer); @@ -105,9 +106,10 @@ private class TestApiEmpty : ApiBase [Fact] public void ApiSourceOfEntityContainerElementIsCorrect() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var arguments = new object[0]; @@ -131,7 +133,7 @@ public void ApiSourceOfEntityContainerElementIsCorrect() public void SourceOfEntityContainerElementThrowsIfNotMapped() { var api = new TestApiEmpty(); - var container = new RestierContainerBuilder(() => new TestApiEmpty()); + var container = new RestierContainerBuilder(typeof(TestApiEmpty)); api.Configuration = new ApiConfiguration(container.BuildContainer()); var context = api.Context; var arguments = new object[0]; @@ -142,7 +144,10 @@ public void SourceOfEntityContainerElementThrowsIfNotMapped() [Fact] public void SourceOfEntityContainerElementIsCorrect() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var arguments = new object[0]; @@ -165,9 +170,10 @@ public void SourceOfEntityContainerElementIsCorrect() [Fact] public void ApiSourceOfComposableFunctionIsCorrect() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var arguments = new object[0]; @@ -192,10 +198,10 @@ public void ApiSourceOfComposableFunctionIsCorrect() [Fact] public void SourceOfComposableFunctionThrowsIfNotMapped() { - var api = new TestApiEmpty(); - var container = new RestierContainerBuilder(() => new TestApiEmpty()); - var serviceProvider = container.BuildContainer(); - api.Configuration = serviceProvider.GetService(); + var container = new RestierContainerBuilder(typeof(TestApiEmpty)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var arguments = new object[0]; @@ -205,9 +211,10 @@ public void SourceOfComposableFunctionThrowsIfNotMapped() [Fact] public void SourceOfComposableFunctionIsCorrect() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var arguments = new object[0]; @@ -233,7 +240,11 @@ public void SourceOfComposableFunctionIsCorrect() [Fact] public void GenericApiSourceOfEntityContainerElementIsCorrect() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; + var arguments = new object[0]; var source = api.GetQueryableSource("Test", arguments); @@ -255,7 +266,10 @@ public void GenericApiSourceOfEntityContainerElementIsCorrect() [Fact] public void GenericSourceOfEntityContainerElementThrowsIfWrongType() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var arguments = new object[0]; @@ -265,9 +279,10 @@ public void GenericSourceOfEntityContainerElementThrowsIfWrongType() [Fact] public void GenericSourceOfEntityContainerElementIsCorrect() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var arguments = new object[0]; @@ -291,7 +306,11 @@ public void GenericSourceOfEntityContainerElementIsCorrect() [Fact] public void GenericApiSourceOfComposableFunctionIsCorrect() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; + var arguments = new object[0]; var source = api.GetQueryableSource( @@ -316,9 +335,10 @@ public void GenericApiSourceOfComposableFunctionIsCorrect() [Fact] public void GenericSourceOfComposableFunctionThrowsIfWrongType() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var arguments = new object[0]; @@ -329,7 +349,10 @@ public void GenericSourceOfComposableFunctionThrowsIfWrongType() [Fact] public void GenericSourceOfComposableFunctionIsCorrect() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var arguments = new object[0]; @@ -354,7 +377,10 @@ public void GenericSourceOfComposableFunctionIsCorrect() [Fact] public void SourceQueryableCannotGenericEnumerate() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var source = context.GetQueryableSource("Test"); @@ -364,7 +390,10 @@ public void SourceQueryableCannotGenericEnumerate() [Fact] public void SourceQueryableCannotEnumerate() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var source = context.GetQueryableSource("Test"); @@ -385,7 +414,7 @@ public void SourceQueryProviderCannotGenericExecute() public void SourceQueryProviderCannotExecute() { var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); + var container = new RestierContainerBuilder(typeof(TestApi)); api.Configuration = new ApiConfiguration(container.BuildContainer()); var context = api.Context; @@ -396,9 +425,10 @@ public void SourceQueryProviderCannotExecute() [Fact] public async Task ApiQueryAsyncWithQueryReturnsResults() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var request = new QueryRequest(api.GetQueryableSource("Test")); var result = await api.Context.QueryAsync(request); @@ -410,9 +440,10 @@ public async Task ApiQueryAsyncWithQueryReturnsResults() [Fact] public async Task ApiQueryAsyncCorrectlyForwardsCall() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var queryRequest = new QueryRequest( api.GetQueryableSource("Test")); diff --git a/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs b/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs index 0827a48c..7d08fa96 100644 --- a/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs @@ -11,9 +11,9 @@ public class ApiBaseTests { private class TestApi : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - return base.ConfigureApi(services) + return ApiBase.ConfigureApi(apiType, services) .MakeScoped() .AddService(); } @@ -51,20 +51,20 @@ public void DefaultApiBaseCanBeCreatedAndDisposed() [Fact] public void ApiAndApiContextCanBeInjectedByDI() { - using (var api = new TestApi()) - { - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; - var context = api.Context; - var svc = context.GetApiService(); + // TODO, this will create a new scope and a new provider.... + var context = api.Context; + var svc = context.GetApiService(); - Assert.Same(svc.Api, api); - Assert.Same(svc.Context, context); + Assert.Same(svc.Api, api); + Assert.Same(svc.Context, context); - api.Dispose(); - Assert.Throws(() => api.Context); - } + api.Dispose(); + Assert.Throws(() => api.Context); } } } diff --git a/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs b/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs index 57d7a7a1..95e6a612 100644 --- a/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs @@ -17,13 +17,15 @@ public class ApiConfigurationTests [Fact] public void CachedConfigurationIsCachedCorrectly() { - ApiBase api = new TestApiA(); - var container = new RestierContainerBuilder(() => new TestApiA()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiA)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var configuration = api.Context.Configuration; ApiBase anotherApi = new TestApiA(); + anotherApi.ServiceProvider = provider; var cached = anotherApi.Context.Configuration; Assert.Same(configuration, cached); } @@ -31,19 +33,20 @@ public void CachedConfigurationIsCachedCorrectly() [Fact] public void ConfigurationRegistersApiServicesCorrectly() { - var api = new TestApiA(); - var container = new RestierContainerBuilder(() => new TestApiA()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiA)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; Assert.Null(api.Context.GetApiService()); Assert.Null(api.Context.GetApiService()); - var apiB = new TestApiB(); - container = new RestierContainerBuilder(() => new TestApiB()); - apiB.Configuration = new ApiConfiguration(container.BuildContainer()); + container = new RestierContainerBuilder(typeof(TestApiB)); + var provider2 = container.BuildContainer(); + var apiB = provider.GetService(); + apiB.ServiceProvider = provider2; - // This is not same as during configure Api, a new APi is created which has new Service A registered. - Assert.NotSame(apiB.serviceA, apiB.Context.GetApiService()); + Assert.Same(TestApiB.serviceA, apiB.Context.GetApiService()); var serviceBInstance = apiB.Context.GetApiService(); var serviceBInterface = apiB.Context.GetApiService(); @@ -55,16 +58,16 @@ public void ConfigurationRegistersApiServicesCorrectly() var serviceBFirst = serviceBInterface as ServiceB; Assert.NotNull(serviceBFirst); - // This is not same as during configure Api, a new APi is created which has new Service B registered. - Assert.NotSame(apiB.serviceB, serviceBFirst.InnerHandler); + Assert.Same(TestApiB.serviceB, serviceBFirst.InnerHandler); } [Fact] public void ServiceChainTest() { - var api = new TestApiC(); - var container = new RestierContainerBuilder(() => new TestApiC()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiC)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var handler = api.Context.GetApiService(); Assert.Equal("q2Pre_q1Pre_q1Post_q2Post_", handler.GetStr()); @@ -76,11 +79,11 @@ private class TestApiA : ApiBase private class TestApiB : ApiBase { - private ServiceA _serviceA; + private static ServiceA _serviceA; - private ServiceB _serviceB; + private static ServiceB _serviceB; - public ServiceA serviceA + public static ServiceA serviceA { get { @@ -92,7 +95,7 @@ public ServiceA serviceA } } - public ServiceB serviceB + public static ServiceB serviceB { get { @@ -104,7 +107,7 @@ public ServiceB serviceB } } - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => serviceA); services.AddService((sp, next) => serviceB); @@ -116,7 +119,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) } private class TestApiC : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { var q1 = new ServiceB("q1Pre", "q1Post"); var q2 = new ServiceB("q2Pre", "q2Post"); diff --git a/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs b/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs index ab8412b8..ad6a0861 100644 --- a/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs @@ -16,9 +16,10 @@ private class TestApi : ApiBase [Fact] public void NewApiContextIsConfiguredCorrectly() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; Assert.NotNull(context.Configuration); diff --git a/test/Microsoft.Restier.Core.Tests/InvocationContext.Tests.cs b/test/Microsoft.Restier.Core.Tests/InvocationContext.Tests.cs index 9562c251..d363efb6 100644 --- a/test/Microsoft.Restier.Core.Tests/InvocationContext.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/InvocationContext.Tests.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using Microsoft.Extensions.DependencyInjection; using Xunit; @@ -12,7 +13,7 @@ private class TestApi : ApiBase { private static ApiServiceA _service; - public ApiServiceA ApiService + public static ApiServiceA ApiService { get { @@ -23,7 +24,8 @@ public ApiServiceA ApiService return _service; } } - public override IServiceCollection ConfigureApi(IServiceCollection services) + + public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => ApiService); @@ -34,9 +36,10 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) [Fact] public void NewInvocationContextIsConfiguredCorrectly() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var apiContext = api.Context; var context = new InvocationContext(apiContext); Assert.Same(apiContext, context.ApiContext); @@ -45,12 +48,13 @@ public void NewInvocationContextIsConfiguredCorrectly() [Fact] public void InvocationContextGetsApiServicesCorrectly() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var apiContext = api.Context; var context = new InvocationContext(apiContext); - Assert.Same(api.ApiService, context.GetApiService()); + Assert.Same(TestApi.ApiService, context.GetApiService()); } private interface IServiceA diff --git a/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs b/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs index 3d64b337..35bf0c39 100644 --- a/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs @@ -16,7 +16,7 @@ public class DefaultModelHandlerTests { private class TestApiA : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new TestModelProducer()); services.AddService((sp, next) => new TestModelExtender(2) @@ -33,7 +33,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiB : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { var service = new TestSingleCallModelBuilder(); services.AddService((sp, next) => service); @@ -43,7 +43,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiC : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { var service = new TestRetryModelBuilder(); services.AddService((sp, next) => service); @@ -104,9 +104,10 @@ public async Task GetModelAsync(ModelContext context, CancellationTok [Fact] public async Task GetModelUsingDefaultModelHandler() { - var api = new TestApiA(); - var container = new RestierContainerBuilder(() => new TestApiA()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiA)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var model = await context.GetModelAsync(); @@ -142,7 +143,7 @@ public async Task GetModelAsync(ModelContext context, CancellationTok private static Task[] PrepareThreads(int count, Type apiType, ManualResetEventSlim wait) { var api2 = (ApiBase)Activator.CreateInstance(apiType); - var container = new RestierContainerBuilder(() => (ApiBase)Activator.CreateInstance(apiType)); + var container = new RestierContainerBuilder(apiType); api2.Configuration = new ApiConfiguration(container.BuildContainer()); var tasks = new Task[count]; diff --git a/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs b/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs index b5c4cfe9..3e995679 100644 --- a/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs @@ -12,9 +12,10 @@ public class PropertyBagTests [Fact] public void PropertyBagManipulatesPropertiesCorrectly() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context =api.Context; Assert.False(context.HasProperty("Test")); @@ -37,9 +38,10 @@ public void PropertyBagManipulatesPropertiesCorrectly() [Fact] public void DifferentPropertyBagsDoNotConflict() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var configuration = context.Configuration; @@ -54,9 +56,10 @@ public void DifferentPropertyBagsDoNotConflict() [Fact] public void PropertyBagsAreDisposedCorrectly() { - var api = new TestApi(); - var container = new RestierContainerBuilder(() => new TestApi()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var context = api.Context; var configuration = context.Configuration; @@ -96,9 +99,9 @@ public void Dispose() private class TestApi : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - return base.ConfigureApi(services).AddScoped(); + return ApiBase.ConfigureApi(apiType, services).AddScoped(); } } } diff --git a/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs b/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs index ea7cbbb8..be91333c 100644 --- a/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs @@ -11,7 +11,7 @@ public class ServiceConfigurationTests { private class TestApiA : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { var i = 0; services.AddService((sp, next) => new SomeService @@ -42,7 +42,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiB : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new SomeService { @@ -58,7 +58,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiC : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.MakeScoped() .AddService((sp, next) => new SomeService()); @@ -68,7 +68,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiD : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new SomeService { @@ -83,7 +83,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiE : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { var first = new SomeService { @@ -100,7 +100,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiF : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new SomeService { @@ -115,7 +115,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiG : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new SomeService { @@ -136,7 +136,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiH : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new SomeService { @@ -153,7 +153,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) private class TestApiI : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.MakeTransient() .AddService((sp, next) => new SomeService @@ -296,9 +296,10 @@ public string Call() [Fact] public void ContributorsAreCalledCorrectly() { - var api = new TestApiA(); - var container = new RestierContainerBuilder(() => new TestApiA()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiA)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var value = api.Context.GetApiService().Call(); Assert.Equal("03210", value); } @@ -306,9 +307,10 @@ public void ContributorsAreCalledCorrectly() [Fact] public void NextInjectedViaProperty() { - var api = new TestApiB(); - var container = new RestierContainerBuilder(() => new TestApiB()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiB)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var value = api.Context.GetApiService().Call(); Assert.Equal("01", value); @@ -320,14 +322,15 @@ public void NextInjectedViaProperty() [Fact] public void ContextApiScopeWorksCorrectly() { - var api = new TestApiC(); - var container = new RestierContainerBuilder(() => new TestApiC()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiC)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var service1 = api.Context.GetApiService(); var api2 = new TestApiC(); - container = new RestierContainerBuilder(() => new TestApiC()); + container = new RestierContainerBuilder(typeof(TestApiC)); api2.Configuration = new ApiConfiguration(container.BuildContainer()); var service2 = api2.Context.GetApiService(); @@ -344,9 +347,10 @@ public void ContextApiScopeWorksCorrectly() public void NothingInjectedStillWorks() { // Outmost service does not call inner service - var api = new TestApiD(); - var container = new RestierContainerBuilder(() => new TestApiD()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiD)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var value = api.Context.GetApiService().Call(); Assert.Equal("42", value); @@ -361,9 +365,10 @@ public void NothingInjectedStillWorks() [Fact] public void ServiceInjectedViaProperty() { - var api = new TestApiE(); - var container = new RestierContainerBuilder(() => new TestApiE()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiE)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var expected = "Text42"; var value = api.Context.GetApiService().Call(); @@ -383,9 +388,10 @@ public void ServiceInjectedViaProperty() [Fact] public void DefaultValueInConstructorUsedIfNoService() { - var api = new TestApiF(); - var container = new RestierContainerBuilder(() => new TestApiF()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiF)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var value = api.Context.GetApiService().Call(); Assert.Equal("42", value); @@ -400,9 +406,10 @@ public void DefaultValueInConstructorUsedIfNoService() [Fact] public void MultiInjectionViaConstructor() { - var api = new TestApiG(); - var container = new RestierContainerBuilder(() => new TestApiG()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiG)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var value = api.Context.GetApiService().Call(); Assert.Equal("0122", value); @@ -417,9 +424,10 @@ public void MultiInjectionViaConstructor() [Fact] public void ThrowOnNoServiceFound() { - var api = new TestApiH(); - var container = new RestierContainerBuilder(() => new TestApiH()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiH)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; Assert.Throws(() => { api.Context.GetApiService(); }); } @@ -427,9 +435,10 @@ public void ThrowOnNoServiceFound() [Fact] public void NextInjectedWithInheritedField() { - var api = new TestApiI(); - var container = new RestierContainerBuilder(() => new TestApiI()); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var container = new RestierContainerBuilder(typeof(TestApiI)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.ServiceProvider = provider; var value = api.Context.GetApiService().Call(); Assert.Equal("4200", value); diff --git a/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs b/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs index 958cba16..01534347 100644 --- a/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs +++ b/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs @@ -19,7 +19,7 @@ public async Task ComplexTypeUpdate() { // Arrange var libraryApi = new LibraryApi(); - var container = new RestierContainerBuilder(() => new LibraryApi()); + var container = new RestierContainerBuilder(typeof(LibraryApi)); libraryApi.Configuration = new ApiConfiguration(container.BuildContainer()); var item = new DataModificationItem( diff --git a/test/Microsoft.Restier.Providers.EntityFramework.Tests/Models/Library/LibraryApi.cs b/test/Microsoft.Restier.Providers.EntityFramework.Tests/Models/Library/LibraryApi.cs index 5dc766b9..72e70edb 100644 --- a/test/Microsoft.Restier.Providers.EntityFramework.Tests/Models/Library/LibraryApi.cs +++ b/test/Microsoft.Restier.Providers.EntityFramework.Tests/Models/Library/LibraryApi.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using System.Threading; using System.Threading.Tasks; using System.Web.OData.Builder; @@ -14,9 +15,9 @@ namespace Microsoft.Restier.Providers.EntityFramework.Tests.Models.Library class LibraryApi : EntityFrameworkApi { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - base.ConfigureApi(services); + EntityFrameworkApi.ConfigureApi(apiType, services); services.AddService(); return services; diff --git a/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs b/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs index 380ba1dd..ded9f2cf 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs @@ -1,4 +1,5 @@ -using System.Linq.Expressions; +using System; +using System.Linq.Expressions; using System.Net; using System.Net.Http; using System.Security; @@ -32,9 +33,9 @@ public async Task ShouldReturn403HandlerThrowsSecurityException() private class ExcApi : StoreApi { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - return base.ConfigureApi(services) + return StoreApi.ConfigureApi(apiType, services) .AddService((sp, next) => new FakeSourcer()); } } diff --git a/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs b/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs index af0b224f..a2920f82 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs @@ -17,6 +17,7 @@ using Microsoft.Restier.Core; using Microsoft.Restier.Core.Model; using Microsoft.Restier.Core.Query; +using Microsoft.Restier.Publishers.OData.Model; using Xunit; namespace Microsoft.Restier.Publishers.OData.Test @@ -95,15 +96,16 @@ static FallbackModel() internal class FallbackApi : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new TestModelProducer(FallbackModel.Model)); services.AddService((sp, next) => new FallbackModelMapper()); services.AddService((sp, next) => new FallbackQueryExpressionSourcer()); - services = base.ConfigureApi(services); + services = ApiBase.ConfigureApi(apiType, services); return services; } + [Resource] public IQueryable PreservedOrders { get { return this.GetQueryableSource("Orders").Where(o => o.Id > 123); } diff --git a/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs b/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs index 45f0c64b..13773a73 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs @@ -1,6 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. See License.txt in the project root for license information. +using System; using Microsoft.Extensions.DependencyInjection; using Microsoft.Restier.Providers.EntityFramework; @@ -9,9 +10,9 @@ namespace Microsoft.Restier.Publishers.OData.Test.Model class LibraryApi : EntityFrameworkApi { // Need to register publisher services as MapRestierRoute is not called - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - base.ConfigureApi(services); + EntityFrameworkApi.ConfigureApi(apiType, services); services.AddODataServices(); return services; } diff --git a/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs b/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs index 36a833f9..c7aaabfc 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs @@ -16,7 +16,7 @@ public class RestierModelBuilderTests public void ComplexTypeShoudWork() { var api = new LibraryApi(); - var container = new RestierContainerBuilder(() => new LibraryApi()); + var container = new RestierContainerBuilder(typeof(LibraryApi)); api.Configuration = new ApiConfiguration(container.BuildContainer()); var model = api.Context.GetModelAsync().Result; @@ -34,7 +34,7 @@ public void ComplexTypeShoudWork() public void PrimitiveTypesShouldWork() { var api = new LibraryApi(); - var container = new RestierContainerBuilder(() => new LibraryApi()); + var container = new RestierContainerBuilder(typeof(LibraryApi)); api.Configuration = new ApiConfiguration(container.BuildContainer()); var model = api.Context.GetModelAsync().Result; diff --git a/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelExtender.Tests.cs b/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelExtender.Tests.cs index 3220fc92..a44460c3 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelExtender.Tests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelExtender.Tests.cs @@ -65,7 +65,6 @@ public async Task ApiModelBuilderShouldProduceCorrectModelForIgnoringInheritedPr Assert.DoesNotContain("ApiConfiguration", model.EntityContainer.Elements.Select(e => e.Name)); Assert.DoesNotContain("ApiContext", model.EntityContainer.Elements.Select(e => e.Name)); Assert.DoesNotContain("Invisible", model.EntityContainer.Elements.Select(e => e.Name)); - Assert.DoesNotContain("People", model.EntityContainer.Elements.Select(e => e.Name)); Assert.Equal("Customer", model.EntityContainer.FindEntitySet("Customers").EntityType().Name); Assert.Equal("Customer", model.EntityContainer.FindSingleton("Me").EntityType().Name); } @@ -179,12 +178,6 @@ public ApiConfiguration ApiConfiguration { get { return base.Configuration; } } - - protected override void UpdateApiConfiguration(ApiConfiguration config) - { - config.IgnoreProperty("ApiConfiguration") - .IgnoreProperty("ApiContext"); - } } public class EmptyApi : BaseApi @@ -198,25 +191,22 @@ public class Person public class ApiA : BaseApi { + [Resource] public IQueryable People { get; set; } + [Resource(IsSingleton = true)] public Person Me { get; set; } public IQueryable Invisible { get; set; } - protected override void UpdateApiConfiguration(ApiConfiguration config) - { - base.UpdateApiConfiguration(config); - config.IgnoreProperty("Invisible"); - } - - public override IServiceCollection ConfigureApi(IServiceCollection services) + public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new TestModelBuilder()); - return base.ConfigureApi(services); + return BaseApi.ConfigureApi(apiType, services); } } public class ApiB : ApiA { + [Resource] public IQueryable Customers { get; set; } } @@ -233,17 +223,14 @@ public class VipCustomer : Customer public class ApiC : ApiB { + [Resource] public new IQueryable Customers { get; set; } + [Resource(IsSingleton = true)] public new Customer Me { get; set; } } public class ApiD : ApiC { - protected override void UpdateApiConfiguration(ApiConfiguration config) - { - base.UpdateApiConfiguration(config); - config.IgnoreProperty("People"); - } } public class Order @@ -253,13 +240,15 @@ public class Order public class ApiE : BaseApi { + [Resource] public IQueryable People { get; set; } + [Resource] public IQueryable Orders { get; set; } - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new TestModelBuilder()); - return base.ConfigureApi(services); + return BaseApi.ConfigureApi(apiType, services); } } @@ -267,28 +256,32 @@ public class ApiF : BaseApi { public IQueryable VipCustomers { get; set; } - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new TestModelBuilder()); - return base.ConfigureApi(services); + return BaseApi.ConfigureApi(apiType, services); } } public class ApiG : ApiC { + [Resource] public IQueryable Employees { get; set; } } public class ApiH : BaseApi { + [Resource(IsSingleton = true)] public Person Me { get; set; } + [Resource] public IQueryable Customers { get; set; } + [Resource(IsSingleton = true)] public Customer Me2 { get; set; } - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new TestModelBuilder()); - return base.ConfigureApi(services); + return BaseApi.ConfigureApi(apiType, services); } } } \ No newline at end of file diff --git a/test/Microsoft.Restier.Publishers.OData.Test/StoreApi.cs b/test/Microsoft.Restier.Publishers.OData.Test/StoreApi.cs index 5c521efe..e3903241 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/StoreApi.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/StoreApi.cs @@ -36,9 +36,9 @@ static StoreModel() internal class StoreApi : ApiBase { - public override IServiceCollection ConfigureApi(IServiceCollection services) + public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - services = base.ConfigureApi(services); + services = ApiBase.ConfigureApi(apiType, services); services.AddService((sp, next) => new TestModelProducer(StoreModel.Model)); services.AddService((sp, next) => new TestModelMapper()); services.AddService((sp, next) => new TestQueryExpressionSourcer()); diff --git a/test/Microsoft.Restier.TestCommon/PublicApi.bsl b/test/Microsoft.Restier.TestCommon/PublicApi.bsl index 314d87df..c3af0c26 100644 --- a/test/Microsoft.Restier.TestCommon/PublicApi.bsl +++ b/test/Microsoft.Restier.TestCommon/PublicApi.bsl @@ -8,14 +8,10 @@ public abstract class Microsoft.Restier.Core.ApiBase : IDisposable { [ CLSCompliantAttribute(), ] - public virtual Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureApi (Microsoft.Extensions.DependencyInjection.IServiceCollection services) + public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureApi (System.Type apiType, Microsoft.Extensions.DependencyInjection.IServiceCollection services) protected virtual Microsoft.Restier.Core.ApiContext CreateApiContext (Microsoft.Restier.Core.ApiConfiguration configuration) public virtual void Dispose () - [ - CLSCompliantAttribute(), - ] - protected virtual void UpdateApiConfiguration (Microsoft.Restier.Core.ApiConfiguration configuration) } [ @@ -244,7 +240,7 @@ public class Microsoft.Restier.Core.ApiConfiguration { [ CLSCompliantAttribute(), ] - public static void AddPublisherServices (System.Action`1[[Microsoft.Extensions.DependencyInjection.IServiceCollection]] configurationCallback) + public static void AddPublisherServices (System.Type apiType, System.Action`1[[Microsoft.Extensions.DependencyInjection.IServiceCollection]] configurationCallback) [ CLSCompliantAttribute(), @@ -294,7 +290,7 @@ public class Microsoft.Restier.Core.ResourceNotFoundException : System.Exception } public class Microsoft.Restier.Core.RestierContainerBuilder : IContainerBuilder { - public RestierContainerBuilder (System.Func`1[[Microsoft.Restier.Core.ApiBase]] apiFactory) + public RestierContainerBuilder (System.Type apiType) public virtual Microsoft.OData.IContainerBuilder AddService (Microsoft.OData.ServiceLifetime lifetime, System.Type serviceType, System.Func`2[[System.IServiceProvider],[System.Object]] implementationFactory) public virtual Microsoft.OData.IContainerBuilder AddService (Microsoft.OData.ServiceLifetime lifetime, System.Type serviceType, System.Type implementationType) @@ -572,7 +568,7 @@ public class Microsoft.Restier.Providers.EntityFramework.EntityFrameworkApi`1 : [ CLSCompliantAttribute(), ] - public virtual Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureApi (Microsoft.Extensions.DependencyInjection.IServiceCollection services) + public static Microsoft.Extensions.DependencyInjection.IServiceCollection ConfigureApi (System.Type apiType, Microsoft.Extensions.DependencyInjection.IServiceCollection services) } [ @@ -728,16 +724,6 @@ public class Microsoft.Restier.Publishers.OData.Formatter.RestierResourceSetSeri public virtual void WriteObject (object graph, System.Type type, Microsoft.OData.ODataMessageWriter messageWriter, System.Web.OData.Formatter.Serialization.ODataSerializerContext writeContext) } -[ -ExtensionAttribute(), -] -public sealed class Microsoft.Restier.Publishers.OData.Model.ApiConfigurationExtensions { - [ - ExtensionAttribute(), - ] - public static Microsoft.Restier.Core.ApiConfiguration IgnoreProperty (Microsoft.Restier.Core.ApiConfiguration configuration, string propertyName) -} - [ AttributeUsageAttribute(), ] @@ -752,3 +738,12 @@ public sealed class Microsoft.Restier.Publishers.OData.Model.OperationAttribute string Namespace { [CompilerGeneratedAttribute(),]public get; [CompilerGeneratedAttribute(),]public set; } } +[ +AttributeUsageAttribute(), +] +public sealed class Microsoft.Restier.Publishers.OData.Model.ResourceAttribute : System.Attribute, _Attribute { + public ResourceAttribute () + + bool IsSingleton { [CompilerGeneratedAttribute(),]public get; [CompilerGeneratedAttribute(),]public set; } +} + diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/SaveTests.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/SaveTests.cs index a6170dda..3fea4bf5 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/SaveTests.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/SaveTests.cs @@ -27,9 +27,8 @@ private class TestEntityFilterReturnsTaskApi : NorthwindApi /// /// /// - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - Type apiType = this.GetType(); // Add core and convention's services services = services.AddCoreServices(apiType) .AddConventionBasedServices(apiType); @@ -55,7 +54,7 @@ protected async Task OnInsertingCustomers(Customer customer) public async Task TestEntityFilterReturnsTask() { TestEntityFilterReturnsTaskApi api = new TestEntityFilterReturnsTaskApi(); - var container = new RestierContainerBuilder(() => new TestEntityFilterReturnsTaskApi()); + var container = new RestierContainerBuilder(typeof(TestEntityFilterReturnsTaskApi)); api.Configuration = new ApiConfiguration(container.BuildContainer()); DataModificationItem createCustomer = new DataModificationItem( "Customers", diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Models/NorthwindApi.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Models/NorthwindApi.cs index 16af6c00..31d93cd5 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Models/NorthwindApi.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Models/NorthwindApi.cs @@ -22,6 +22,7 @@ public class NorthwindApi : EntityFrameworkApi public new NorthwindContext Context { get { return DbContext; } } // Imperative views. Currently CUD operations not supported + [Resource] public IQueryable ExpensiveProducts { get @@ -31,6 +32,7 @@ public IQueryable ExpensiveProducts } } + [Resource] public IQueryable CurrentOrders { get @@ -56,9 +58,9 @@ public double MostExpensive(IEnumerable bindingParameter) return 0.0; } - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { - return base.ConfigureApi(services) + return EntityFrameworkApi.ConfigureApi(apiType, services) .AddService(); } diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Api/TrippinApi.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Api/TrippinApi.cs index a4bc7fb7..556f4a40 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Api/TrippinApi.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Api/TrippinApi.cs @@ -30,6 +30,7 @@ public TrippinModel ModelContext get { return DbContext; } } + [Resource(IsSingleton = true)] public Person Me { get @@ -42,16 +43,19 @@ public Person Me } } + [Resource] public IQueryable Flights1 { get { return DbContext.Flights; } } + [Resource] public IQueryable Flights2 { get { return this.GetQueryableSource("Flights"); } } + [Resource] public IQueryable PeopleWithAge { get @@ -66,6 +70,7 @@ public IQueryable PeopleWithAge } } + [Resource] public IQueryable PeopleWithAge1 { get @@ -80,6 +85,7 @@ public IQueryable PeopleWithAge1 } } + [Resource(IsSingleton = true)] public PersonWithAge PeopleWithAgeMe { get @@ -561,7 +567,7 @@ protected bool CanDeleteTrips() return false; } - public override IServiceCollection ConfigureApi(IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { // Add customized OData validation settings Func validationSettingFactory = sp => new ODataValidationSettings @@ -572,7 +578,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) services.AddService(); - return base.ConfigureApi(services) + return EntityFrameworkApi.ConfigureApi(apiType, services) .AddSingleton() .AddSingleton(validationSettingFactory) .AddSingleton() diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs index 78b2fc0f..744ef5ea 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs @@ -36,6 +36,7 @@ private string Key #region Entity Set + [Resource] public IQueryable People { get @@ -50,6 +51,7 @@ public IQueryable People } } + [Resource] public IQueryable NewComePeople { get @@ -64,6 +66,7 @@ public IQueryable NewComePeople } } + [Resource(IsSingleton = true)] public Person Me { get @@ -78,6 +81,7 @@ public Person Me } } + [Resource] public IQueryable Airlines { get @@ -92,6 +96,7 @@ public IQueryable Airlines } } + [Resource] public IQueryable Airports { get @@ -332,7 +337,7 @@ private static double CalculateDistance(GeographyPoint p1, GeographyPoint p2) #endregion - public override IServiceCollection ConfigureApi(IServiceCollection services) + public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { Func> defaultDataStoreManager = sp => new DefaultDataStoreManager() @@ -345,7 +350,7 @@ public override IServiceCollection ConfigureApi(IServiceCollection services) services.AddService((sp, next) => new ChangeSetInitializer()); services.AddService((sp, next) => new SubmitExecutor()); services.AddSingleton(defaultDataStoreManager); - return base.ConfigureApi(services); + return ApiBase.ConfigureApi(apiType, services); } private class ModelBuilder : IModelBuilder