From 32cf19d94a6f8e82c3f89930c483ab0a119ed38d Mon Sep 17 00:00:00 2001 From: Vincent He Date: Wed, 24 Aug 2016 08:15:36 +0800 Subject: [PATCH 1/2] 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 From 607baf4cbbd2d3a39dd990ad5b116185b3a45aa5 Mon Sep 17 00:00:00 2001 From: Vincent He Date: Wed, 24 Aug 2016 13:31:28 +0800 Subject: [PATCH 2/2] Remove restier container and use WAO container --- src/Microsoft.Restier.Core/ApiBase.cs | 37 ++--- .../ApiConfiguration.cs | 21 --- .../ApiConfigurationExtensions.cs | 133 ------------------ src/Microsoft.Restier.Core/ApiContext.cs | 6 +- .../Microsoft.Restier.Core.csproj | 3 +- src/Microsoft.Restier.Core/packages.config | 2 +- .../EntityFrameworkApi.cs | 10 ++ ...t.Restier.Providers.EntityFramework.csproj | 4 +- .../packages.config | 4 +- .../Batch/RestierBatchChangeSetRequestItem.cs | 15 +- .../Batch/RestierBatchHandler.cs | 17 +-- .../Batch/RestierChangeSetProperty.cs | 6 +- .../RestierResourceSetSerializer.cs | 6 +- .../Microsoft.Restier.Publishers.OData.csproj | 8 +- .../RestierController.cs | 6 +- .../Routing/HttpConfigurationExtensions.cs | 66 ++------- .../Routing/RestierRoutingConvention.cs | 13 -- .../packages.config | 8 +- .../Microsoft.Restier.Core.Tests/Api.Tests.cs | 40 +++--- .../ApiBase.Tests.cs | 14 +- .../ApiConfiguration.Tests.cs | 33 ++++- .../ApiContext.Tests.cs | 4 +- .../InvocationContext.Tests.cs | 15 +- .../Microsoft.Restier.Core.Tests.csproj | 2 +- .../Model/DefaultModelHandler.Tests.cs | 56 ++++++-- .../PropertyBag.Tests.cs | 30 ++-- .../ServiceConfiguration.Tests.cs | 105 ++++++++++++-- .../packages.config | 2 +- .../ChangeSetPreparerTests.cs | 7 +- ...ier.Providers.EntityFramework.Tests.csproj | 8 +- .../Models/Library/LibraryApi.cs | 4 + .../packages.config | 8 +- .../ExceptionHandlerTests.cs | 4 + .../FallbackTests.cs | 4 + ...osoft.Restier.Publishers.OData.Test.csproj | 8 +- .../Model/LibraryApi.cs | 4 + .../Model/RestierModelBuilderTests.cs | 10 +- .../Model/RestierModelExtender.Tests.cs | 51 ++++++- .../StoreApi.cs | 6 +- .../packages.config | 8 +- .../PublicApi.bsl | 58 ++------ ...Data.Service.Sample.Northwind.Tests.csproj | 8 +- .../QueryTests.cs | 39 ++--- .../SaveTests.cs | 9 +- .../packages.config | 8 +- .../Controllers/NorthwindController.cs | 38 +---- ...soft.OData.Service.Sample.Northwind.csproj | 8 +- .../Models/NorthwindApi.cs | 4 + .../packages.config | 8 +- .../Api/TrippinApi.cs | 4 + .../Controllers/PeopleController.cs | 20 +-- .../Controllers/TrippinController.cs | 37 +---- ...rosoft.OData.Service.Sample.Trippin.csproj | 8 +- .../packages.config | 8 +- .../Api/TrippinApi.cs | 6 +- .../Controllers/TrippinController.cs | 5 +- ...Data.Service.Sample.TrippinInMemory.csproj | 8 +- .../packages.config | 8 +- ...icrosoft.Restier.Providers.InMemory.csproj | 8 +- .../packages.config | 8 +- 60 files changed, 493 insertions(+), 595 deletions(-) delete mode 100644 src/Microsoft.Restier.Core/ApiConfigurationExtensions.cs diff --git a/src/Microsoft.Restier.Core/ApiBase.cs b/src/Microsoft.Restier.Core/ApiBase.cs index 3b50359f..a2b74469 100644 --- a/src/Microsoft.Restier.Core/ApiBase.cs +++ b/src/Microsoft.Restier.Core/ApiBase.cs @@ -21,13 +21,21 @@ namespace Microsoft.Restier.Core /// public abstract class ApiBase : IDisposable { - private static readonly ConcurrentDictionary Configurations = - new ConcurrentDictionary(); - private ApiConfiguration apiConfiguration; private ApiContext apiContext; private IServiceProvider serviceProvider; + /// + /// Initializes a new instance of the class. + /// + /// + /// An containing all services of this . + /// + protected ApiBase(IServiceProvider serviceProvider) + { + this.serviceProvider = serviceProvider; + } + /// /// Gets the which contains all services of this . /// @@ -37,12 +45,6 @@ public IServiceProvider ServiceProvider { return serviceProvider; } - - set - { - // TODO use set but not in constructor as need to update lots of test cases - this.serviceProvider = value; - } } /// @@ -72,7 +74,7 @@ public ApiContext Context public bool IsDisposed { get; private set; } /// - /// Gets or sets the API configuration for this API. + /// Gets the API configuration for this API. /// public ApiConfiguration Configuration { @@ -85,13 +87,6 @@ public ApiConfiguration Configuration return this.apiConfiguration; } - - set - { - // TODO keep now as lots of test cases need to update - this.apiConfiguration = value; - Configurations.TryAdd(GetType(), apiConfiguration); - } } /// @@ -137,13 +132,5 @@ public void Dispose() GC.SuppressFinalize(this); } - - // Registered as a scoped service so that IApi and ApiContext could be exposed as scoped service. - // If a descendant class wants to expose these 2 services in another way, it must ensure they could be - // resolved after CreateApiContext call. - internal class ApiHolder - { - public ApiBase Api { get; set; } - } } } diff --git a/src/Microsoft.Restier.Core/ApiConfiguration.cs b/src/Microsoft.Restier.Core/ApiConfiguration.cs index fad124c0..6cd200d2 100644 --- a/src/Microsoft.Restier.Core/ApiConfiguration.cs +++ b/src/Microsoft.Restier.Core/ApiConfiguration.cs @@ -30,29 +30,8 @@ public class ApiConfiguration private static Action emptyConfig = _ => { }; - private IServiceProvider serviceProvider; - private Task modelTask; - /// - /// Initializes a new instance of the class. - /// - /// - /// An containing all services of this . - /// - public ApiConfiguration(IServiceProvider serviceProvider) - { - this.serviceProvider = serviceProvider; - } - - /// - /// Gets the which contains all services of this . - /// - internal IServiceProvider ServiceProvider - { - get { return serviceProvider; } - } - internal IEdmModel Model { get; private set; } /// diff --git a/src/Microsoft.Restier.Core/ApiConfigurationExtensions.cs b/src/Microsoft.Restier.Core/ApiConfigurationExtensions.cs deleted file mode 100644 index a2c1f067..00000000 --- a/src/Microsoft.Restier.Core/ApiConfigurationExtensions.cs +++ /dev/null @@ -1,133 +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.Extensions.DependencyInjection; - -namespace Microsoft.Restier.Core -{ - /// - /// Offers a collection of extension methods to . - /// - public static class ApiConfigurationExtensions - { - #region GetApiService - - /// - /// Gets a service instance. - /// - /// - /// An API configuration. - /// - /// The service type. - /// The service instance. - public static T GetApiService(this ApiConfiguration configuration) where T : class - { - Ensure.NotNull(configuration, "configuration"); - return configuration.ServiceProvider.GetService(); - } - - #endregion - - #region PropertyBag - - /// - /// Indicates if this object has a property. - /// - /// - /// An API configuration. - /// - /// - /// The name of a property. - /// - /// - /// true if this object has the - /// property; otherwise, false. - /// - public static bool HasProperty(this ApiConfiguration configuration, string name) - { - return configuration.GetPropertyBag().HasProperty(name); - } - - /// - /// Gets a property. - /// - /// - /// The type of the property. - /// - /// - /// An API configuration. - /// - /// - /// The name of a property. - /// - /// - /// The value of the property. - /// - public static T GetProperty(this ApiConfiguration configuration, string name) - { - return configuration.GetPropertyBag().GetProperty(name); - } - - /// - /// Gets a property. - /// - /// - /// An API configuration. - /// - /// - /// The name of a property. - /// - /// - /// The value of the property. - /// - public static object GetProperty(this ApiConfiguration configuration, string name) - { - return configuration.GetPropertyBag().GetProperty(name); - } - - /// - /// Sets a property. - /// - /// - /// An API configuration. - /// - /// - /// The name of a property. - /// - /// - /// A value for the property. - /// - public static void SetProperty(this ApiConfiguration configuration, string name, object value) - { - configuration.GetPropertyBag().SetProperty(name, value); - } - - /// - /// Clears a property. - /// - /// - /// An API configuration. - /// - /// - /// The name of a property. - /// - public static void ClearProperty(this ApiConfiguration configuration, string name) - { - configuration.GetPropertyBag().ClearProperty(name); - } - - #endregion - - #region PropertyBag Private - - private static PropertyBag GetPropertyBag(this ApiConfiguration configuration) - { - Ensure.NotNull(configuration, "configuration"); - return configuration.GetApiService(); - } - - #endregion - } -} \ No newline at end of file diff --git a/src/Microsoft.Restier.Core/ApiContext.cs b/src/Microsoft.Restier.Core/ApiContext.cs index f0bf0877..925e281b 100644 --- a/src/Microsoft.Restier.Core/ApiContext.cs +++ b/src/Microsoft.Restier.Core/ApiContext.cs @@ -19,12 +19,12 @@ public class ApiContext /// /// Initializes a new instance of the class. /// - /// - /// An API configuration. - /// /// /// The service provider. /// + /// + /// An API configuration. + /// public ApiContext(IServiceProvider provider, ApiConfiguration configuration) { Ensure.NotNull(configuration, "configuration"); diff --git a/src/Microsoft.Restier.Core/Microsoft.Restier.Core.csproj b/src/Microsoft.Restier.Core/Microsoft.Restier.Core.csproj index 99868f3d..b8b53ed8 100644 --- a/src/Microsoft.Restier.Core/Microsoft.Restier.Core.csproj +++ b/src/Microsoft.Restier.Core/Microsoft.Restier.Core.csproj @@ -27,7 +27,7 @@ ..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll - ..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True @@ -73,7 +73,6 @@ - diff --git a/src/Microsoft.Restier.Core/packages.config b/src/Microsoft.Restier.Core/packages.config index 3918a147..fcc3a38f 100644 --- a/src/Microsoft.Restier.Core/packages.config +++ b/src/Microsoft.Restier.Core/packages.config @@ -2,7 +2,7 @@ - + diff --git a/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs b/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs index 46456252..f57d3b8f 100644 --- a/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs +++ b/src/Microsoft.Restier.Providers.EntityFramework/EntityFrameworkApi.cs @@ -30,6 +30,16 @@ namespace Microsoft.Restier.Providers.EntityFramework #endif public class EntityFrameworkApi : ApiBase where T : DbContext { + /// + /// Initializes a new instance of the class. + /// + /// + /// An containing all services of this . + /// + public EntityFrameworkApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + /// /// Gets the underlying DbContext for this API. /// diff --git a/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj b/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj index f76ffbd0..f026b542 100644 --- a/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj +++ b/src/Microsoft.Restier.Providers.EntityFramework/Microsoft.Restier.Providers.EntityFramework.csproj @@ -26,11 +26,11 @@ True - ..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True diff --git a/src/Microsoft.Restier.Providers.EntityFramework/packages.config b/src/Microsoft.Restier.Providers.EntityFramework/packages.config index 1e4c077c..34f77b9e 100644 --- a/src/Microsoft.Restier.Providers.EntityFramework/packages.config +++ b/src/Microsoft.Restier.Providers.EntityFramework/packages.config @@ -2,8 +2,8 @@ - - + + diff --git a/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchChangeSetRequestItem.cs b/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchChangeSetRequestItem.cs index 47285fd9..8095c1c7 100644 --- a/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchChangeSetRequestItem.cs +++ b/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchChangeSetRequestItem.cs @@ -7,6 +7,8 @@ using System.Threading; using System.Threading.Tasks; using System.Web.OData.Batch; +using System.Web.OData.Extensions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Restier.Core; using Microsoft.Restier.Core.Submit; @@ -17,19 +19,13 @@ namespace Microsoft.Restier.Publishers.OData.Batch /// public class RestierBatchChangeSetRequestItem : ChangeSetRequestItem { - private Func apiFactory; - /// /// Initializes a new instance of the class. /// /// The request messages. - /// Gets or sets the callback to create API. - public RestierBatchChangeSetRequestItem(IEnumerable requests, Func apiFactory) + public RestierBatchChangeSetRequestItem(IEnumerable requests) : base(requests) { - Ensure.NotNull(apiFactory, "apiFactory"); - - this.apiFactory = apiFactory; } /// @@ -89,9 +85,10 @@ public override async Task SendRequestAsync( return new ChangeSetResponseItem(responses); } - internal async Task SubmitChangeSet(ChangeSet changeSet) + internal async Task SubmitChangeSet(HttpRequestMessage request, ChangeSet changeSet) { - using (var api = this.apiFactory()) + var requestContainer = request.GetRequestContainer(); + using (var api = requestContainer.GetService()) { SubmitResult submitResults = await api.SubmitAsync(changeSet); } diff --git a/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchHandler.cs b/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchHandler.cs index a6e4d992..fdc543af 100644 --- a/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchHandler.cs +++ b/src/Microsoft.Restier.Publishers.OData/Batch/RestierBatchHandler.cs @@ -12,7 +12,6 @@ using System.Web.OData.Extensions; using Microsoft.Extensions.DependencyInjection; using Microsoft.OData; -using Microsoft.Restier.Core; namespace Microsoft.Restier.Publishers.OData.Batch { @@ -25,18 +24,11 @@ public class RestierBatchHandler : DefaultODataBatchHandler /// Initializes a new instance of the class. /// /// The HTTP server instance. - /// Gets or sets the callback to create API. - public RestierBatchHandler(HttpServer httpServer, Func apiFactory = null) + public RestierBatchHandler(HttpServer httpServer) : base(httpServer) { - this.ApiFactory = apiFactory; } - /// - /// Gets or sets the callback to create API. - /// - public Func ApiFactory { get; set; } - /// /// Asynchronously parses the batch requests. /// @@ -47,11 +39,6 @@ public override async Task> ParseBatchRequestsAsync HttpRequestMessage request, CancellationToken cancellationToken) { - if (this.ApiFactory == null) - { - throw new InvalidOperationException(Resources.BatchHandlerRequiresApiContextFactory); - } - Ensure.NotNull(request, "request"); IServiceProvider requestContainer = request.CreateRequestContainer(ODataRouteName); @@ -99,7 +86,7 @@ ODataMessageReader reader protected virtual RestierBatchChangeSetRequestItem CreateRestierBatchChangeSetRequestItem( IList changeSetRequests) { - return new RestierBatchChangeSetRequestItem(changeSetRequests, this.ApiFactory); + return new RestierBatchChangeSetRequestItem(changeSetRequests); } } } diff --git a/src/Microsoft.Restier.Publishers.OData/Batch/RestierChangeSetProperty.cs b/src/Microsoft.Restier.Publishers.OData/Batch/RestierChangeSetProperty.cs index 91f3f3b5..59a9cbc6 100644 --- a/src/Microsoft.Restier.Publishers.OData/Batch/RestierChangeSetProperty.cs +++ b/src/Microsoft.Restier.Publishers.OData/Batch/RestierChangeSetProperty.cs @@ -2,6 +2,7 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using Microsoft.Restier.Core.Submit; @@ -37,12 +38,13 @@ public RestierChangeSetProperty(RestierBatchChangeSetRequestItem changeSetReques /// /// The callback to execute when the changeset is completed. /// + /// The http request message. /// The task object that represents this callback execution. - public Task OnChangeSetCompleted() + public Task OnChangeSetCompleted(HttpRequestMessage request) { if (Interlocked.Decrement(ref this.subRequestCount) == 0) { - this.changeSetRequestItem.SubmitChangeSet(this.ChangeSet) + this.changeSetRequestItem.SubmitChangeSet(request, this.ChangeSet) .ContinueWith(t => { if (t.Exception != null) diff --git a/src/Microsoft.Restier.Publishers.OData/Formatter/Serialization/RestierResourceSetSerializer.cs b/src/Microsoft.Restier.Publishers.OData/Formatter/Serialization/RestierResourceSetSerializer.cs index 389207c7..ac0f4527 100644 --- a/src/Microsoft.Restier.Publishers.OData/Formatter/Serialization/RestierResourceSetSerializer.cs +++ b/src/Microsoft.Restier.Publishers.OData/Formatter/Serialization/RestierResourceSetSerializer.cs @@ -56,17 +56,17 @@ private bool TryWriteAggregationResult( Type type, ODataMessageWriter messageWriter, ODataSerializerContext writeContext, - IEdmTypeReference feedType) + IEdmTypeReference resourceSetType) { if (typeof(IEnumerable).IsAssignableFrom(type)) { - IEdmTypeReference elementType = feedType.AsCollection().ElementType(); + IEdmTypeReference elementType = resourceSetType.AsCollection().ElementType(); if (elementType.IsEntity()) { var entitySet = writeContext.NavigationSource as IEdmEntitySetBase; var entityType = elementType.AsEntity(); var writer = messageWriter.CreateODataResourceSetWriter(entitySet, entityType.EntityDefinition()); - WriteObjectInline(graph, feedType, writer, writeContext); + WriteObjectInline(graph, resourceSetType, writer, writeContext); return true; } } 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 9aed1bfd..774d0ca4 100644 --- a/src/Microsoft.Restier.Publishers.OData/Microsoft.Restier.Publishers.OData.csproj +++ b/src/Microsoft.Restier.Publishers.OData/Microsoft.Restier.Publishers.OData.csproj @@ -22,15 +22,15 @@ True - ..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -50,7 +50,7 @@ True - ..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True diff --git a/src/Microsoft.Restier.Publishers.OData/RestierController.cs b/src/Microsoft.Restier.Publishers.OData/RestierController.cs index dfea734d..1e450fe3 100644 --- a/src/Microsoft.Restier.Publishers.OData/RestierController.cs +++ b/src/Microsoft.Restier.Publishers.OData/RestierController.cs @@ -179,7 +179,7 @@ public async Task Post(EdmEntityObject edmEntityObject, Cance { changeSetProperty.ChangeSet.Entries.Add(postItem); - await changeSetProperty.OnChangeSetCompleted(); + await changeSetProperty.OnChangeSetCompleted(this.Request); } return this.CreateCreatedODataResult(postItem.Resource); @@ -258,7 +258,7 @@ public async Task Delete(CancellationToken cancellationToken) { changeSetProperty.ChangeSet.Entries.Add(deleteItem); - await changeSetProperty.OnChangeSetCompleted(); + await changeSetProperty.OnChangeSetCompleted(this.Request); } return this.StatusCode(HttpStatusCode.NoContent); @@ -426,7 +426,7 @@ private async Task Update( { changeSetProperty.ChangeSet.Entries.Add(updateItem); - await changeSetProperty.OnChangeSetCompleted(); + await changeSetProperty.OnChangeSetCompleted(this.Request); } return this.CreateUpdatedODataResult(updateItem.Resource); diff --git a/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs b/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs index 8017a127..e4a0206f 100644 --- a/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs +++ b/src/Microsoft.Restier.Publishers.OData/Routing/HttpConfigurationExtensions.cs @@ -38,19 +38,15 @@ public static class HttpConfigurationExtensions /// The instance. /// The name of the route. /// The prefix of the route. - /// The callback to create API instances. /// The handler for batch requests. /// The task object containing the resulted instance. public static Task MapRestierRoute( this HttpConfiguration config, string routeName, string routePrefix, - Func apiFactory, RestierBatchHandler batchHandler = null) where TApi : ApiBase { - Ensure.NotNull(apiFactory, "apiFactory"); - // This will be added a service to callback stored in ApiConfiguration // Callback is called by ApiBase.AddApiServices method to add real services. ApiConfiguration.AddPublisherServices( @@ -60,55 +56,22 @@ public static Task MapRestierRoute( services.AddODataServices(); }); - using (var api = apiFactory()) - { - Func func = () => new RestierContainerBuilder(api.GetType()); - config.UseCustomContainerBuilder(func); + Func func = () => new RestierContainerBuilder(typeof(TApi)); + config.UseCustomContainerBuilder(func); - var conventions = CreateRestierRoutingConventions(config, routeName, apiFactory); - if (batchHandler != null && batchHandler.ApiFactory == null) - { - batchHandler.ApiFactory = apiFactory; - batchHandler.ODataRouteName = routeName; - } - - Action configureAction = builder => builder - .AddService>(ServiceLifetime.Singleton, sp => conventions) - .AddService(ServiceLifetime.Singleton, sp => batchHandler); - - var route = config.MapODataServiceRoute(routeName, routePrefix, configureAction); + var conventions = CreateRestierRoutingConventions(config, routeName); + if (batchHandler != null) + { + batchHandler.ODataRouteName = routeName; + } - // Set ApiConfiguration instance for further usage - if (config != null) - { - var mapping = (ConcurrentDictionary)config.Properties[RootContainerKey]; - IServiceProvider rootContainer; - mapping.TryGetValue(routeName, out rootContainer); - api.Configuration = rootContainer.GetService(); - } + Action configureAction = builder => builder + .AddService>(ServiceLifetime.Singleton, sp => conventions) + .AddService(ServiceLifetime.Singleton, sp => batchHandler); - return Task.FromResult(route); - } - } + var route = config.MapODataServiceRoute(routeName, routePrefix, configureAction); - /// - /// Maps the API routes to the RestierController. - /// - /// The user API. - /// The instance. - /// The name of the route. - /// The prefix of the route. - /// The handler for batch requests. - /// The task object containing the resulted instance. - public static Task MapRestierRoute( - this HttpConfiguration config, - string routeName, - string routePrefix, - RestierBatchHandler batchHandler = null) - where TApi : ApiBase, new() - { - return MapRestierRoute( - config, routeName, routePrefix, () => new TApi(), batchHandler); + return Task.FromResult(route); } /// @@ -157,10 +120,9 @@ public static void SetUseVerboseErrors(this HttpConfiguration configuration, boo /// /// The instance. /// The name of the route. - /// The API factory. /// The routing conventions created. private static IList CreateRestierRoutingConventions( - this HttpConfiguration config, string routeName, Func apiFactory) + this HttpConfiguration config, string routeName) { var conventions = ODataRoutingConventions.CreateDefaultWithAttributeRouting(routeName, config); var index = 0; @@ -173,7 +135,7 @@ private static IList CreateRestierRoutingConventions( } } - conventions.Insert(index + 1, new RestierRoutingConvention(apiFactory)); + conventions.Insert(index + 1, new RestierRoutingConvention()); return conventions; } } diff --git a/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs b/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs index f900ceb1..876343c9 100644 --- a/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs +++ b/src/Microsoft.Restier.Publishers.OData/Routing/RestierRoutingConvention.cs @@ -30,17 +30,6 @@ internal class RestierRoutingConvention : IODataRoutingConvention private const string MethodNameOfDelete = "Delete"; private const string MethodNameOfPostAction = "PostAction"; - private readonly Func apiFactory; - - /// - /// Initializes a new instance of the class. - /// - /// The API factory method. - public RestierRoutingConvention(Func apiFactory) - { - this.apiFactory = apiFactory; - } - /// /// Selects OData controller based on parsed OData URI /// @@ -69,10 +58,8 @@ public string SelectController(ODataPath odataPath, HttpRequestMessage request) } // Create ApiBase instance - // 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/src/Microsoft.Restier.Publishers.OData/packages.config b/src/Microsoft.Restier.Publishers.OData/packages.config index 7c4125c9..5a170e23 100644 --- a/src/Microsoft.Restier.Publishers.OData/packages.config +++ b/src/Microsoft.Restier.Publishers.OData/packages.config @@ -1,13 +1,13 @@  - + - - - + + + diff --git a/test/Microsoft.Restier.Core.Tests/Api.Tests.cs b/test/Microsoft.Restier.Core.Tests/Api.Tests.cs index 79ba6d44..2624423f 100644 --- a/test/Microsoft.Restier.Core.Tests/Api.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/Api.Tests.cs @@ -80,7 +80,7 @@ public Task ExecuteSubmitAsync(SubmitContext context, Cancellation private class TestApi : ApiBase { - public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { var modelBuilder = new TestModelBuilder(); var modelMapper = new TestModelMapper(); @@ -97,10 +97,17 @@ private class TestApi : ApiBase return services; } + + public TestApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiEmpty : ApiBase { + public TestApiEmpty(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } [Fact] @@ -109,7 +116,6 @@ public void ApiSourceOfEntityContainerElementIsCorrect() var container = new RestierContainerBuilder(typeof(TestApi)); var provider = container.BuildContainer(); var api = provider.GetService(); - api.ServiceProvider = provider; var arguments = new object[0]; @@ -132,9 +138,9 @@ public void ApiSourceOfEntityContainerElementIsCorrect() [Fact] public void SourceOfEntityContainerElementThrowsIfNotMapped() { - var api = new TestApiEmpty(); var container = new RestierContainerBuilder(typeof(TestApiEmpty)); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var provider = container.BuildContainer(); + var api = provider.GetService(); var context = api.Context; var arguments = new object[0]; @@ -147,7 +153,6 @@ public void SourceOfEntityContainerElementIsCorrect() 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]; @@ -173,7 +178,6 @@ public void ApiSourceOfComposableFunctionIsCorrect() var container = new RestierContainerBuilder(typeof(TestApi)); var provider = container.BuildContainer(); var api = provider.GetService(); - api.ServiceProvider = provider; var arguments = new object[0]; @@ -201,7 +205,6 @@ public void SourceOfComposableFunctionThrowsIfNotMapped() 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]; @@ -214,7 +217,6 @@ public void SourceOfComposableFunctionIsCorrect() 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]; @@ -243,7 +245,6 @@ public void GenericApiSourceOfEntityContainerElementIsCorrect() var container = new RestierContainerBuilder(typeof(TestApi)); var provider = container.BuildContainer(); var api = provider.GetService(); - api.ServiceProvider = provider; var arguments = new object[0]; @@ -269,7 +270,6 @@ public void GenericSourceOfEntityContainerElementThrowsIfWrongType() 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]; @@ -282,7 +282,6 @@ public void GenericSourceOfEntityContainerElementIsCorrect() 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]; @@ -309,7 +308,6 @@ public void GenericApiSourceOfComposableFunctionIsCorrect() var container = new RestierContainerBuilder(typeof(TestApi)); var provider = container.BuildContainer(); var api = provider.GetService(); - api.ServiceProvider = provider; var arguments = new object[0]; @@ -338,7 +336,6 @@ public void GenericSourceOfComposableFunctionThrowsIfWrongType() 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]; @@ -352,7 +349,6 @@ public void GenericSourceOfComposableFunctionIsCorrect() 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]; @@ -380,7 +376,6 @@ public void SourceQueryableCannotGenericEnumerate() 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"); @@ -393,7 +388,6 @@ public void SourceQueryableCannotEnumerate() 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"); @@ -403,7 +397,9 @@ public void SourceQueryableCannotEnumerate() [Fact] public void SourceQueryProviderCannotGenericExecute() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); var context = api.Context; var source = context.GetQueryableSource("Test"); @@ -413,9 +409,9 @@ public void SourceQueryProviderCannotGenericExecute() [Fact] public void SourceQueryProviderCannotExecute() { - var api = new TestApi(); var container = new RestierContainerBuilder(typeof(TestApi)); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var provider = container.BuildContainer(); + var api = provider.GetService(); var context = api.Context; var source = context.GetQueryableSource("Test"); @@ -428,7 +424,6 @@ public async Task ApiQueryAsyncWithQueryReturnsResults() 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); @@ -443,7 +438,6 @@ public async Task ApiQueryAsyncCorrectlyForwardsCall() var container = new RestierContainerBuilder(typeof(TestApi)); var provider = container.BuildContainer(); var api = provider.GetService(); - api.ServiceProvider = provider; var queryRequest = new QueryRequest( api.GetQueryableSource("Test")); @@ -455,7 +449,9 @@ public async Task ApiQueryAsyncCorrectlyForwardsCall() [Fact] public async Task ApiSubmitAsyncCorrectlyForwardsCall() { - var api = new TestApi(); + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); var submitResult = await api.SubmitAsync(); Assert.NotNull(submitResult.CompletedChangeSet); diff --git a/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs b/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs index 7d08fa96..5025baca 100644 --- a/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ApiBase.Tests.cs @@ -17,6 +17,10 @@ private class TestApi : ApiBase .MakeScoped() .AddService(); } + + public TestApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } interface IService @@ -42,10 +46,10 @@ public Service(ApiBase api, ApiContext context) [Fact] public void DefaultApiBaseCanBeCreatedAndDisposed() { - using (var api = new TestApi()) - { - api.Dispose(); - } + var container = new RestierContainerBuilder(typeof(TestApi)); + var provider = container.BuildContainer(); + var api = provider.GetService(); + api.Dispose(); } [Fact] @@ -54,9 +58,7 @@ public void ApiAndApiContextCanBeInjectedByDI() var container = new RestierContainerBuilder(typeof(TestApi)); var provider = container.BuildContainer(); var api = provider.GetService(); - api.ServiceProvider = provider; - // TODO, this will create a new scope and a new provider.... var context = api.Context; var svc = context.GetApiService(); diff --git a/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs b/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs index 95e6a612..cf4372e8 100644 --- a/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ApiConfiguration.Tests.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.OData.Edm; using Microsoft.Restier.Core.Model; using Xunit; @@ -20,12 +21,10 @@ public void CachedConfigurationIsCachedCorrectly() 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; + ApiBase anotherApi = provider.GetService(); var cached = anotherApi.Context.Configuration; Assert.Same(configuration, cached); } @@ -36,15 +35,13 @@ public void ConfigurationRegistersApiServicesCorrectly() 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()); container = new RestierContainerBuilder(typeof(TestApiB)); var provider2 = container.BuildContainer(); - var apiB = provider.GetService(); - apiB.ServiceProvider = provider2; + var apiB = provider2.GetService(); Assert.Same(TestApiB.serviceA, apiB.Context.GetApiService()); @@ -67,7 +64,6 @@ public void ServiceChainTest() 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()); @@ -75,6 +71,9 @@ public void ServiceChainTest() private class TestApiA : ApiBase { + public TestApiA(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiB : ApiBase @@ -114,8 +113,18 @@ public static ServiceB serviceB services.AddService(); services.AddSingleton(new ServiceB()); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiB(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiC : ApiBase { @@ -130,8 +139,18 @@ private class TestApiC : ApiBase return q2; }); + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); + return services; } + + public TestApiC(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestModelBuilder : IModelBuilder diff --git a/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs b/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs index ad6a0861..060398b0 100644 --- a/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ApiContext.Tests.cs @@ -11,6 +11,9 @@ public class ApiContextTests { private class TestApi : ApiBase { + public TestApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } [Fact] @@ -19,7 +22,6 @@ public void NewApiContextIsConfiguredCorrectly() 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 d363efb6..fb760933 100644 --- a/test/Microsoft.Restier.Core.Tests/InvocationContext.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/InvocationContext.Tests.cs @@ -3,6 +3,7 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Xunit; namespace Microsoft.Restier.Core.Tests @@ -25,12 +26,22 @@ public static ApiServiceA ApiService } } - public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); + services.AddService((sp, next) => ApiService); return services; } + + public TestApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } [Fact] @@ -39,7 +50,6 @@ public void NewInvocationContextIsConfiguredCorrectly() 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); @@ -51,7 +61,6 @@ public void InvocationContextGetsApiServicesCorrectly() 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(TestApi.ApiService, context.GetApiService()); diff --git a/test/Microsoft.Restier.Core.Tests/Microsoft.Restier.Core.Tests.csproj b/test/Microsoft.Restier.Core.Tests/Microsoft.Restier.Core.Tests.csproj index 2f69805a..5ce687a4 100644 --- a/test/Microsoft.Restier.Core.Tests/Microsoft.Restier.Core.Tests.csproj +++ b/test/Microsoft.Restier.Core.Tests/Microsoft.Restier.Core.Tests.csproj @@ -49,7 +49,7 @@ ..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll - ..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True diff --git a/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs b/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs index 35bf0c39..ef9e4861 100644 --- a/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/Model/DefaultModelHandler.Tests.cs @@ -6,6 +6,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.OData.Edm; using Microsoft.Restier.Core.Model; using Xunit; @@ -27,8 +28,19 @@ private class TestApiA : ApiBase { InnerHandler = next, }); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); + return services; } + + public TestApiA(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiB : ApiBase @@ -37,8 +49,18 @@ private class TestApiB : ApiBase { var service = new TestSingleCallModelBuilder(); services.AddService((sp, next) => service); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiB(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiC : ApiBase @@ -47,8 +69,19 @@ private class TestApiC : ApiBase { var service = new TestRetryModelBuilder(); services.AddService((sp, next) => service); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); + return services; } + + public TestApiC(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestModelProducer : IModelBuilder @@ -107,7 +140,6 @@ public async Task GetModelUsingDefaultModelHandler() 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(); @@ -140,12 +172,8 @@ public async Task GetModelAsync(ModelContext context, CancellationTok } } - private static Task[] PrepareThreads(int count, Type apiType, ManualResetEventSlim wait) + private static Task[] PrepareThreads(int count, IServiceProvider provider, ManualResetEventSlim wait) { - var api2 = (ApiBase)Activator.CreateInstance(apiType); - var container = new RestierContainerBuilder(apiType); - api2.Configuration = new ApiConfiguration(container.BuildContainer()); - var tasks = new Task[count]; var result = Parallel.For(0, count, (inx, state) => { @@ -155,8 +183,9 @@ private static Task[] PrepareThreads(int count, Type apiType, ManualR // To make threads better aligned. wait.Wait(); - var api = (ApiBase)Activator.CreateInstance(apiType); - + var scopedProvider = + provider.GetRequiredService().CreateScope().ServiceProvider; + var api = scopedProvider.GetService(); var context = api.Context; try { @@ -182,7 +211,9 @@ public async Task ModelBuilderShouldBeCalledOnlyOnceIfSucceeded() { for (int i = 0; i < 2; i++) { - var tasks = PrepareThreads(50, typeof(TestApiB), wait); + var container = new RestierContainerBuilder(typeof(TestApiB)); + var provider = container.BuildContainer(); + var tasks = PrepareThreads(50, provider, wait); wait.Set(); var models = await Task.WhenAll(tasks); @@ -212,7 +243,10 @@ public async Task GetModelAsyncRetriableAfterFailure() { using (var wait = new ManualResetEventSlim(false)) { - var tasks = PrepareThreads(6, typeof(TestApiC), wait); + var container = new RestierContainerBuilder(typeof(TestApiC)); + var provider = container.BuildContainer(); + + var tasks = PrepareThreads(6, provider, wait); wait.Set(); await Task.WhenAll(tasks).ContinueWith(t => @@ -221,7 +255,7 @@ await Task.WhenAll(tasks).ContinueWith(t => Assert.True(tasks.All(e => e.IsFaulted)); }); - tasks = PrepareThreads(150, typeof(TestApiC), wait); + tasks = PrepareThreads(150, provider, wait); var models = await Task.WhenAll(tasks); Assert.True(models.All(e => object.ReferenceEquals(e, models[42]))); diff --git a/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs b/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs index 3e995679..70dfe2a0 100644 --- a/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/PropertyBag.Tests.cs @@ -15,7 +15,6 @@ public void PropertyBagManipulatesPropertiesCorrectly() 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")); @@ -41,15 +40,9 @@ public void DifferentPropertyBagsDoNotConflict() 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; - - configuration.SetProperty("Test", 1); context.SetProperty("Test", 2); - - Assert.Equal(1, configuration.GetProperty("Test")); Assert.Equal(2, context.GetProperty("Test")); } @@ -58,22 +51,23 @@ public void PropertyBagsAreDisposedCorrectly() { var container = new RestierContainerBuilder(typeof(TestApi)); var provider = container.BuildContainer(); - var api = provider.GetService(); - api.ServiceProvider = provider; + var scope = provider.GetRequiredService().CreateScope(); + var scopedProvider = scope.ServiceProvider; + var api = scopedProvider.GetService(); var context = api.Context; - var configuration = context.Configuration; - Assert.NotNull(configuration.GetApiService()); + Assert.NotNull(context.GetApiService()); Assert.Equal(1, MyPropertyBag.InstanceCount); - Assert.NotNull(context.GetApiService()); + var scopedProvider2 = provider.GetRequiredService().CreateScope().ServiceProvider; + var api2 = scopedProvider2.GetService(); + var context2 = api2.Context; + + Assert.NotNull(context2.GetApiService()); Assert.Equal(2, MyPropertyBag.InstanceCount); - // This will dispose all the scoped and transient instances registered - // in the ApiContext scope. - api.Dispose(); + scope.Dispose(); - // The one in ApiConfiguration will NOT be disposed until the service ends. Assert.Equal(1, MyPropertyBag.InstanceCount); } @@ -103,6 +97,10 @@ private class TestApi : ApiBase { return ApiBase.ConfigureApi(apiType, services).AddScoped(); } + + public TestApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } } } diff --git a/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs b/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs index be91333c..cb07e400 100644 --- a/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs +++ b/test/Microsoft.Restier.Core.Tests/ServiceConfiguration.Tests.cs @@ -3,6 +3,7 @@ using System; using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; using Xunit; namespace Microsoft.Restier.Core.Tests @@ -36,8 +37,17 @@ private class TestApiA : ApiBase }) .AddService(); + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiA(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiB : ApiBase @@ -52,8 +62,17 @@ private class TestApiB : ApiBase .AddService() .MakeTransient(); + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiB(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiC : ApiBase @@ -62,8 +81,18 @@ private class TestApiC : ApiBase { services.MakeScoped() .AddService((sp, next) => new SomeService()); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiC(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiD : ApiBase @@ -77,8 +106,18 @@ private class TestApiD : ApiBase }) .AddService() .MakeTransient(); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiD(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiE : ApiBase @@ -94,8 +133,17 @@ private class TestApiE : ApiBase .AddService() .AddSingleton("Text"); + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiE(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiF : ApiBase @@ -109,8 +157,18 @@ private class TestApiF : ApiBase .MakeTransient() .AddService(); + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); + return services; } + + public TestApiF(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiG : ApiBase @@ -130,8 +188,18 @@ private class TestApiG : ApiBase .AddService((sp, next) => { return "0"; }) .MakeTransient(); + + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiG(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiH : ApiBase @@ -147,8 +215,17 @@ private class TestApiH : ApiBase .AddService((sp, next) => { return "0"; }) .MakeTransient(); + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiH(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class TestApiI : ApiBase @@ -166,8 +243,17 @@ private class TestApiI : ApiBase }) .AddService(); + services.AddScoped(apiType, apiType) + .AddScoped(typeof(ApiBase), apiType) + .AddScoped(); + + services.TryAddSingleton(); return services; } + + public TestApiI(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } @@ -299,7 +385,6 @@ public void ContributorsAreCalledCorrectly() 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); } @@ -310,7 +395,6 @@ public void NextInjectedViaProperty() 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); @@ -325,19 +409,20 @@ public void ContextApiScopeWorksCorrectly() 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(typeof(TestApiC)); - api2.Configuration = new ApiConfiguration(container.BuildContainer()); + provider = container.BuildContainer(); + var api2 = provider.GetService(); var service2 = api2.Context.GetApiService(); Assert.NotEqual(service1, service2); - var api3 = new TestApiC(); + container = new RestierContainerBuilder(typeof(TestApiC)); + provider = container.BuildContainer(); + var api3 = provider.GetService(); var service3 = api3.Context.GetApiService(); Assert.NotEqual(service3, service2); @@ -350,7 +435,6 @@ public void NothingInjectedStillWorks() 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); @@ -368,7 +452,6 @@ public void ServiceInjectedViaProperty() 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(); @@ -391,7 +474,6 @@ public void DefaultValueInConstructorUsedIfNoService() 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); @@ -409,7 +491,6 @@ public void MultiInjectionViaConstructor() 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); @@ -427,7 +508,6 @@ public void ThrowOnNoServiceFound() var container = new RestierContainerBuilder(typeof(TestApiH)); var provider = container.BuildContainer(); var api = provider.GetService(); - api.ServiceProvider = provider; Assert.Throws(() => { api.Context.GetApiService(); }); } @@ -438,7 +518,6 @@ public void NextInjectedWithInheritedField() 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.Core.Tests/packages.config b/test/Microsoft.Restier.Core.Tests/packages.config index f7b385b9..2f607f5a 100644 --- a/test/Microsoft.Restier.Core.Tests/packages.config +++ b/test/Microsoft.Restier.Core.Tests/packages.config @@ -2,7 +2,7 @@ - + diff --git a/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs b/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs index 01534347..8cdd0bae 100644 --- a/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs +++ b/test/Microsoft.Restier.Providers.EntityFramework.Tests/ChangeSetPreparerTests.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Restier.Core; using Microsoft.Restier.Core.Submit; using Microsoft.Restier.Providers.EntityFramework.Tests.Models.Library; @@ -18,9 +19,9 @@ public class ChangeSetPreparerTests public async Task ComplexTypeUpdate() { // Arrange - var libraryApi = new LibraryApi(); var container = new RestierContainerBuilder(typeof(LibraryApi)); - libraryApi.Configuration = new ApiConfiguration(container.BuildContainer()); + var provider = container.BuildContainer(); + var libraryApi = provider.GetService(); var item = new DataModificationItem( "Readers", @@ -34,7 +35,7 @@ public async Task ComplexTypeUpdate() var sc = new SubmitContext(libraryApi.Context, changeSet); // Act - var changeSetPreparer = libraryApi.Context.Configuration.GetApiService(); + var changeSetPreparer = libraryApi.Context.GetApiService(); await changeSetPreparer.InitializeAsync(sc, CancellationToken.None); var person = item.Resource as Person; diff --git a/test/Microsoft.Restier.Providers.EntityFramework.Tests/Microsoft.Restier.Providers.EntityFramework.Tests.csproj b/test/Microsoft.Restier.Providers.EntityFramework.Tests/Microsoft.Restier.Providers.EntityFramework.Tests.csproj index 9a31f632..77b54efe 100644 --- a/test/Microsoft.Restier.Providers.EntityFramework.Tests/Microsoft.Restier.Providers.EntityFramework.Tests.csproj +++ b/test/Microsoft.Restier.Providers.EntityFramework.Tests/Microsoft.Restier.Providers.EntityFramework.Tests.csproj @@ -52,15 +52,15 @@ True - ..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -79,7 +79,7 @@ True - ..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True 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 72e70edb..8b6dfa9f 100644 --- a/test/Microsoft.Restier.Providers.EntityFramework.Tests/Models/Library/LibraryApi.cs +++ b/test/Microsoft.Restier.Providers.EntityFramework.Tests/Models/Library/LibraryApi.cs @@ -33,5 +33,9 @@ public Task GetModelAsync(ModelContext context, CancellationToken can return Task.FromResult(model); } } + + public LibraryApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } } diff --git a/test/Microsoft.Restier.Providers.EntityFramework.Tests/packages.config b/test/Microsoft.Restier.Providers.EntityFramework.Tests/packages.config index 3e4b21a4..b7ad8a88 100644 --- a/test/Microsoft.Restier.Providers.EntityFramework.Tests/packages.config +++ b/test/Microsoft.Restier.Providers.EntityFramework.Tests/packages.config @@ -1,14 +1,14 @@  - + - - - + + + diff --git a/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs b/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs index ded9f2cf..ba8bec91 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/ExceptionHandlerTests.cs @@ -38,6 +38,10 @@ private class ExcApi : StoreApi return StoreApi.ConfigureApi(apiType, services) .AddService((sp, next) => new FakeSourcer()); } + + public ExcApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } private class FakeSourcer : IQueryExpressionSourcer diff --git a/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs b/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs index a2920f82..124eea0e 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/FallbackTests.cs @@ -110,6 +110,10 @@ public IQueryable PreservedOrders { get { return this.GetQueryableSource("Orders").Where(o => o.Id > 123); } } + + public FallbackApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class PeopleController : ODataController diff --git a/test/Microsoft.Restier.Publishers.OData.Test/Microsoft.Restier.Publishers.OData.Test.csproj b/test/Microsoft.Restier.Publishers.OData.Test/Microsoft.Restier.Publishers.OData.Test.csproj index 47eb9dd4..0f175aa9 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/Microsoft.Restier.Publishers.OData.Test.csproj +++ b/test/Microsoft.Restier.Publishers.OData.Test/Microsoft.Restier.Publishers.OData.Test.csproj @@ -52,15 +52,15 @@ True - ..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -79,7 +79,7 @@ True - ..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True diff --git a/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs b/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs index 13773a73..2ebf0175 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/Model/LibraryApi.cs @@ -16,5 +16,9 @@ class LibraryApi : EntityFrameworkApi services.AddODataServices(); return services; } + + public LibraryApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } } diff --git a/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs b/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs index c7aaabfc..34afa351 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelBuilderTests.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Linq; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Edm; using Microsoft.OData.Edm.Validation; using Microsoft.Restier.Core; @@ -15,9 +16,10 @@ public class RestierModelBuilderTests [Fact] public void ComplexTypeShoudWork() { - var api = new LibraryApi(); var container = new RestierContainerBuilder(typeof(LibraryApi)); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var provider = container.BuildContainer(); + var api = provider.GetService(); + var model = api.Context.GetModelAsync().Result; IEnumerable errors; @@ -33,9 +35,9 @@ public void ComplexTypeShoudWork() [Fact] public void PrimitiveTypesShouldWork() { - var api = new LibraryApi(); var container = new RestierContainerBuilder(typeof(LibraryApi)); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var provider = container.BuildContainer(); + var api = provider.GetService(); var model = api.Context.GetModelAsync().Result; IEnumerable errors; 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 a44460c3..5211a707 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelExtender.Tests.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/Model/RestierModelExtender.Tests.cs @@ -1,9 +1,11 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using System.Web.Http; +using System.Web.OData.Extensions; using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Edm; using Microsoft.Restier.Core; @@ -124,17 +126,20 @@ public async Task ApiModelBuilderShouldNotAddAmbiguousNavigationPropertyBindings // In this case, two entity sets Employees and People have entity type Person. // Bindings for collection navigation property Customer.Friends should NOT be added. // Bindings for singleton navigation property Customer.BestFriend should NOT be added. - var model = await this.GetModelAsync(); + var model = await GetModelAsync(); Assert.Empty(model.EntityContainer.FindEntitySet("Customers").NavigationPropertyBindings); Assert.Empty(model.EntityContainer.FindSingleton("Me").NavigationPropertyBindings); } - private async Task GetModelAsync() where T : BaseApi, new() + private async Task GetModelAsync() where T : BaseApi { - var api = (BaseApi)Activator.CreateInstance(); HttpConfiguration config = new HttpConfiguration(); await config.MapRestierRoute( "test", "api/test",null); + + var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test"); + request.SetConfiguration(config); + var api = request.CreateRequestContainer("test").GetService(); return await api.Context.GetModelAsync(); } } @@ -178,10 +183,17 @@ public ApiConfiguration ApiConfiguration { get { return base.Configuration; } } + + public BaseApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class EmptyApi : BaseApi { + public EmptyApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class Person @@ -197,17 +209,25 @@ public class ApiA : BaseApi public Person Me { get; set; } public IQueryable Invisible { get; set; } - public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services.AddService((sp, next) => new TestModelBuilder()); return BaseApi.ConfigureApi(apiType, services); } + + public ApiA(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class ApiB : ApiA { [Resource] public IQueryable Customers { get; set; } + + public ApiB(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class Customer @@ -227,10 +247,17 @@ public class ApiC : ApiB public new IQueryable Customers { get; set; } [Resource(IsSingleton = true)] public new Customer Me { get; set; } + + public ApiC(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class ApiD : ApiC { + public ApiD(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class Order @@ -250,6 +277,10 @@ public class ApiE : BaseApi services.AddService((sp, next) => new TestModelBuilder()); return BaseApi.ConfigureApi(apiType, services); } + + public ApiE(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class ApiF : BaseApi @@ -261,12 +292,20 @@ public class ApiF : BaseApi services.AddService((sp, next) => new TestModelBuilder()); return BaseApi.ConfigureApi(apiType, services); } + + public ApiF(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class ApiG : ApiC { [Resource] public IQueryable Employees { get; set; } + + public ApiG(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } public class ApiH : BaseApi @@ -283,5 +322,9 @@ public class ApiH : BaseApi services.AddService((sp, next) => new TestModelBuilder()); return BaseApi.ConfigureApi(apiType, services); } + + public ApiH(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } } \ 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 e3903241..9dbdaeeb 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/StoreApi.cs +++ b/test/Microsoft.Restier.Publishers.OData.Test/StoreApi.cs @@ -36,7 +36,7 @@ static StoreModel() internal class StoreApi : ApiBase { - public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { services = ApiBase.ConfigureApi(apiType, services); services.AddService((sp, next) => new TestModelProducer(StoreModel.Model)); @@ -46,6 +46,10 @@ internal class StoreApi : ApiBase services.AddService((sp, next) => new TestSubmitExecutor()); return services; } + + public StoreApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } class Product diff --git a/test/Microsoft.Restier.Publishers.OData.Test/packages.config b/test/Microsoft.Restier.Publishers.OData.Test/packages.config index 3e4b21a4..b7ad8a88 100644 --- a/test/Microsoft.Restier.Publishers.OData.Test/packages.config +++ b/test/Microsoft.Restier.Publishers.OData.Test/packages.config @@ -1,14 +1,14 @@  - + - - - + + + diff --git a/test/Microsoft.Restier.TestCommon/PublicApi.bsl b/test/Microsoft.Restier.TestCommon/PublicApi.bsl index c3af0c26..5b294c9b 100644 --- a/test/Microsoft.Restier.TestCommon/PublicApi.bsl +++ b/test/Microsoft.Restier.TestCommon/PublicApi.bsl @@ -1,16 +1,16 @@ public abstract class Microsoft.Restier.Core.ApiBase : IDisposable { - protected ApiBase () + protected ApiBase (System.IServiceProvider serviceProvider) - Microsoft.Restier.Core.ApiConfiguration Configuration { public get; public set; } + Microsoft.Restier.Core.ApiConfiguration Configuration { public get; } Microsoft.Restier.Core.ApiContext Context { public get; } bool IsDisposed { [CompilerGeneratedAttribute(),]public get; } + System.IServiceProvider ServiceProvider { public get; } [ CLSCompliantAttribute(), ] 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 () } @@ -54,41 +54,6 @@ public sealed class Microsoft.Restier.Core.ApiBaseExtensions { public static System.Threading.Tasks.Task`1[[Microsoft.Restier.Core.Submit.SubmitResult]] SubmitAsync (Microsoft.Restier.Core.ApiBase api, params Microsoft.Restier.Core.Submit.ChangeSet changeSet, params System.Threading.CancellationToken cancellationToken) } -[ -ExtensionAttribute(), -] -public sealed class Microsoft.Restier.Core.ApiConfigurationExtensions { - [ - ExtensionAttribute(), - ] - public static void ClearProperty (Microsoft.Restier.Core.ApiConfiguration configuration, string name) - - [ - ExtensionAttribute(), - ] - public static T GetApiService (Microsoft.Restier.Core.ApiConfiguration configuration) - - [ - ExtensionAttribute(), - ] - public static object GetProperty (Microsoft.Restier.Core.ApiConfiguration configuration, string name) - - [ - ExtensionAttribute(), - ] - public static T GetProperty (Microsoft.Restier.Core.ApiConfiguration configuration, string name) - - [ - ExtensionAttribute(), - ] - public static bool HasProperty (Microsoft.Restier.Core.ApiConfiguration configuration, string name) - - [ - ExtensionAttribute(), - ] - public static void SetProperty (Microsoft.Restier.Core.ApiConfiguration configuration, string name, object value) -} - [ ExtensionAttribute(), ] @@ -235,7 +200,7 @@ public sealed class Microsoft.Restier.Core.ServiceCollectionExtensions { } public class Microsoft.Restier.Core.ApiConfiguration { - public ApiConfiguration (System.IServiceProvider serviceProvider) + public ApiConfiguration () [ CLSCompliantAttribute(), @@ -249,7 +214,7 @@ public class Microsoft.Restier.Core.ApiConfiguration { } public class Microsoft.Restier.Core.ApiContext { - public ApiContext (Microsoft.Restier.Core.ApiConfiguration configuration) + public ApiContext (System.IServiceProvider provider, Microsoft.Restier.Core.ApiConfiguration configuration) Microsoft.Restier.Core.ApiConfiguration Configuration { [CompilerGeneratedAttribute(),]public get; } } @@ -561,7 +526,7 @@ public class Microsoft.Restier.Providers.EntityFramework.ChangeSetInitializer : } public class Microsoft.Restier.Providers.EntityFramework.EntityFrameworkApi`1 : Microsoft.Restier.Core.ApiBase, IDisposable { - public EntityFrameworkApi`1 () + public EntityFrameworkApi`1 (System.IServiceProvider serviceProvider) T DbContext { protected get; } @@ -586,11 +551,6 @@ public sealed class Microsoft.Restier.Publishers.OData.HttpConfigurationExtensio ] public static System.Threading.Tasks.Task`1[[System.Web.OData.Routing.ODataRoute]] MapRestierRoute (System.Web.Http.HttpConfiguration config, string routeName, string routePrefix, params Microsoft.Restier.Publishers.OData.Batch.RestierBatchHandler batchHandler) - [ - ExtensionAttribute(), - ] - public static System.Threading.Tasks.Task`1[[System.Web.OData.Routing.ODataRoute]] MapRestierRoute (System.Web.Http.HttpConfiguration config, string routeName, string routePrefix, System.Func`1[[Microsoft.Restier.Core.ApiBase]] apiFactory, params Microsoft.Restier.Publishers.OData.Batch.RestierBatchHandler batchHandler) - [ ExtensionAttribute(), ] @@ -654,7 +614,7 @@ public class Microsoft.Restier.Publishers.OData.RestierPayloadValueConverter : M } public class Microsoft.Restier.Publishers.OData.Batch.RestierBatchChangeSetRequestItem : System.Web.OData.Batch.ChangeSetRequestItem, IDisposable { - public RestierBatchChangeSetRequestItem (System.Collections.Generic.IEnumerable`1[[System.Net.Http.HttpRequestMessage]] requests, System.Func`1[[Microsoft.Restier.Core.ApiBase]] apiFactory) + public RestierBatchChangeSetRequestItem (System.Collections.Generic.IEnumerable`1[[System.Net.Http.HttpRequestMessage]] requests) [ AsyncStateMachineAttribute(), @@ -663,9 +623,7 @@ public class Microsoft.Restier.Publishers.OData.Batch.RestierBatchChangeSetReque } public class Microsoft.Restier.Publishers.OData.Batch.RestierBatchHandler : System.Web.OData.Batch.DefaultODataBatchHandler, IDisposable { - public RestierBatchHandler (System.Web.Http.HttpServer httpServer, params System.Func`1[[Microsoft.Restier.Core.ApiBase]] apiFactory) - - System.Func`1[[Microsoft.Restier.Core.ApiBase]] ApiFactory { [CompilerGeneratedAttribute(),]public get; [CompilerGeneratedAttribute(),]public set; } + public RestierBatchHandler (System.Web.Http.HttpServer httpServer) protected virtual Microsoft.Restier.Publishers.OData.Batch.RestierBatchChangeSetRequestItem CreateRestierBatchChangeSetRequestItem (System.Collections.Generic.IList`1[[System.Net.Http.HttpRequestMessage]] changeSetRequests) [ diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/Microsoft.OData.Service.Sample.Northwind.Tests.csproj b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/Microsoft.OData.Service.Sample.Northwind.Tests.csproj index 17b25189..4dd5d372 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/Microsoft.OData.Service.Sample.Northwind.Tests.csproj +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/Microsoft.OData.Service.Sample.Northwind.Tests.csproj @@ -54,15 +54,15 @@ True - ..\..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -85,7 +85,7 @@ True - ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/QueryTests.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/QueryTests.cs index a940dfe9..6415fb8e 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/QueryTests.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/QueryTests.cs @@ -2,8 +2,11 @@ // Licensed under the MIT License. See License.txt in the project root for license information. using System.Linq; +using System.Net.Http; using System.Threading.Tasks; using System.Web.Http; +using System.Web.OData.Extensions; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Service.Sample.Northwind.Models; using Microsoft.Restier.Core; using Microsoft.Restier.Core.Query; @@ -13,13 +16,6 @@ namespace Microsoft.OData.Service.Sample.Northwind.Tests { public class QueryTests : TestBase { - private NorthwindApi api = new NorthwindApi(); - - private IQueryable OrdersQuery - { - get { return this.api.GetQueryableSource("Orders"); } - } - [Fact] public async Task TestTakeIncludeTotalCount() { @@ -27,9 +23,11 @@ public async Task TestTakeIncludeTotalCount() { using (HttpServer server = new HttpServer(config)) { - WebApiConfig.RegisterNorthwind(config, server); - QueryResult result = await this.api.QueryAsync( - new QueryRequest(this.OrdersQuery.OrderBy(o => o.OrderDate).Take(10))); + WebApiConfig.RegisterNorthwind(config, server); var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test"); + request.SetConfiguration(config); + var api = request.CreateRequestContainer("NorthwindApi").GetService(); + QueryResult result = await api.QueryAsync( + new QueryRequest(api.GetQueryableSource("Orders").OrderBy(o => o.OrderDate).Take(10))); var orderResults = result.Results.OfType(); Assert.Equal(10, orderResults.Count()); @@ -45,8 +43,11 @@ public async Task TestSkipIncludeTotalCount() using (HttpServer server = new HttpServer(config)) { WebApiConfig.RegisterNorthwind(config, server); - QueryResult result = await this.api.QueryAsync( - new QueryRequest(this.OrdersQuery.OrderBy(o => o.OrderDate).Skip(10))); + var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test"); + request.SetConfiguration(config); + var api = request.CreateRequestContainer("NorthwindApi").GetService(); + QueryResult result = await api.QueryAsync( + new QueryRequest(api.GetQueryableSource("Orders").OrderBy(o => o.OrderDate).Skip(10))); var orderResults = result.Results.OfType(); Assert.Equal(820, orderResults.Count()); @@ -62,8 +63,11 @@ public async Task TestSkipTakeIncludeTotalCount() using (HttpServer server = new HttpServer(config)) { WebApiConfig.RegisterNorthwind(config, server); - QueryResult result = await this.api.QueryAsync( - new QueryRequest(this.OrdersQuery.OrderBy(o => o.OrderDate).Skip(10).Take(25))); + var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test"); + request.SetConfiguration(config); + var api = request.CreateRequestContainer("NorthwindApi").GetService(); + QueryResult result = await api.QueryAsync( + new QueryRequest(api.GetQueryableSource("Orders").OrderBy(o => o.OrderDate).Skip(10).Take(25))); var orderResults = result.Results.OfType(); Assert.Equal(25, orderResults.Count()); @@ -83,8 +87,11 @@ public async Task TestTakeNotStrippedIncludeTotalCount() using (HttpServer server = new HttpServer(config)) { WebApiConfig.RegisterNorthwind(config, server); - QueryResult result = await this.api.QueryAsync( - new QueryRequest(this.OrdersQuery.Take(10).OrderBy(o => o.OrderDate))); + var request = new HttpRequestMessage(HttpMethod.Get, "http://localhost/api/test"); + request.SetConfiguration(config); + var api = request.CreateRequestContainer("NorthwindApi").GetService(); + QueryResult result = await api.QueryAsync( + new QueryRequest(api.GetQueryableSource("Orders").Take(10).OrderBy(o => o.OrderDate))); var orderResults = result.Results.OfType(); Assert.Equal(10, orderResults.Count()); 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 3fea4bf5..0c5521e1 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/SaveTests.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/SaveTests.cs @@ -45,6 +45,10 @@ protected async Task OnInsertingCustomers(Customer customer) await Task.Delay(10); customer.CompanyName += "OnInserting"; } + + public TestEntityFilterReturnsTaskApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } /// @@ -53,9 +57,10 @@ protected async Task OnInsertingCustomers(Customer customer) [Fact] public async Task TestEntityFilterReturnsTask() { - TestEntityFilterReturnsTaskApi api = new TestEntityFilterReturnsTaskApi(); var container = new RestierContainerBuilder(typeof(TestEntityFilterReturnsTaskApi)); - api.Configuration = new ApiConfiguration(container.BuildContainer()); + var provider = container.BuildContainer(); + var api = provider.GetService(); + DataModificationItem createCustomer = new DataModificationItem( "Customers", typeof(Customer), diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/packages.config b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/packages.config index 4774e229..12cf5010 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/packages.config +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind.Tests/packages.config @@ -1,15 +1,15 @@  - + - - - + + + diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Controllers/NorthwindController.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Controllers/NorthwindController.cs index d3195fbf..155c33a9 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Controllers/NorthwindController.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Controllers/NorthwindController.cs @@ -12,33 +12,22 @@ using System.Net; using System.Web.Http; using System.Web.OData; +using System.Web.OData.Extensions; using System.Web.OData.Routing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Service.Sample.Northwind.Models; +using Microsoft.Restier.Core; namespace Microsoft.OData.Service.Sample.Northwind.Controllers { public class NorthwindController : ODataController { - private NorthwindApi api; - - private NorthwindApi Api - { - get - { - if (api == null) - { - api = new NorthwindApi(); - } - - return api; - } - } - private NorthwindContext DbContext { get { - return Api.Context; + var api =(NorthwindApi)this.Request.GetRequestContainer().GetService(); + return api.Context; } } @@ -116,22 +105,5 @@ public IHttpActionResult ResetDataSource() DbContext.ResetDataSource(); return StatusCode(HttpStatusCode.NoContent); } - - /// - /// Disposes the API and the controller. - /// - /// Indicates whether disposing is happening. - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (this.api != null) - { - this.api.Dispose(); - } - } - - base.Dispose(disposing); - } } } diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Microsoft.OData.Service.Sample.Northwind.csproj b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Microsoft.OData.Service.Sample.Northwind.csproj index 758ee629..96c202b7 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Microsoft.OData.Service.Sample.Northwind.csproj +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Microsoft.OData.Service.Sample.Northwind.csproj @@ -58,15 +58,15 @@ True - ..\..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -101,7 +101,7 @@ - ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True 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 31d93cd5..720219d6 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Models/NorthwindApi.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/Models/NorthwindApi.cs @@ -104,5 +104,9 @@ public async Task GetModelAsync(ModelContext context, CancellationTok return model; } } + + public NorthwindApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } } \ No newline at end of file diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/packages.config b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/packages.config index 2183d93a..c9abcf9e 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/packages.config +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Northwind/packages.config @@ -1,16 +1,16 @@  - + - - - + + + 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 556f4a40..a44f1841 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Api/TrippinApi.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Api/TrippinApi.cs @@ -648,5 +648,9 @@ public async Task GetModelAsync(ModelContext context, CancellationTok return model; } } + + public TrippinApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } } } \ No newline at end of file diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/PeopleController.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/PeopleController.cs index 7c4d914a..894d0521 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/PeopleController.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/PeopleController.cs @@ -9,34 +9,22 @@ using System.Web.OData; using System.Web.OData.Extensions; using System.Web.OData.Routing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Edm; using Microsoft.OData.Service.Sample.Trippin.Api; using Microsoft.OData.Service.Sample.Trippin.Models; +using Microsoft.Restier.Core; namespace Microsoft.OData.Service.Sample.Trippin.Controllers { public class PeopleController : ODataController { - private TrippinApi api; - - private TrippinApi Api - { - get - { - if (api == null) - { - api = new TrippinApi(); - } - - return api; - } - } - private TrippinModel DbContext { get { - return Api.ModelContext; + var api = (TrippinApi)this.Request.GetRequestContainer().GetService(); + return api.ModelContext; } } diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/TrippinController.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/TrippinController.cs index 4d9056bd..2214343e 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/TrippinController.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Controllers/TrippinController.cs @@ -8,33 +8,21 @@ using System.Web.OData; using System.Web.OData.Extensions; using System.Web.OData.Routing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Service.Sample.Trippin.Api; using Microsoft.OData.Service.Sample.Trippin.Models; +using Microsoft.Restier.Core; namespace Microsoft.OData.Service.Sample.Trippin.Controllers { public class TrippinController : ODataController { - private TrippinApi api; - - private TrippinApi Api - { - get - { - if (api == null) - { - api = new TrippinApi(); - } - - return api; - } - } - private TrippinModel DbContext { get { - return Api.ModelContext; + var api = (TrippinApi)this.Request.GetRequestContainer().GetService(); + return api.ModelContext; } } @@ -98,23 +86,6 @@ public IHttpActionResult DeleteRefToAirLineFromFlight([FromODataUri] int key) return StatusCode(HttpStatusCode.NoContent); } - /// - /// Disposes the API and the controller. - /// - /// Indicates whether disposing is happening. - protected override void Dispose(bool disposing) - { - if (disposing) - { - if (this.api != null) - { - this.api.Dispose(); - } - } - - base.Dispose(disposing); - } - private string GetServiceRootUri() { var routeName = Request.ODataProperties().RouteName; diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Microsoft.OData.Service.Sample.Trippin.csproj b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Microsoft.OData.Service.Sample.Trippin.csproj index d55c2434..df8d09ab 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Microsoft.OData.Service.Sample.Trippin.csproj +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/Microsoft.OData.Service.Sample.Trippin.csproj @@ -123,15 +123,15 @@ True - ..\..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -160,7 +160,7 @@ True - ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/packages.config b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/packages.config index 2183d93a..c9abcf9e 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/packages.config +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.Trippin/packages.config @@ -1,16 +1,16 @@  - + - - - + + + 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 744ef5ea..322cd71b 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Api/TrippinApi.cs @@ -34,6 +34,10 @@ private string Key get { return InMemoryProviderUtils.GetSessionId(); } } + public TrippinApi(IServiceProvider serviceProvider) : base(serviceProvider) + { + } + #region Entity Set [Resource] @@ -337,7 +341,7 @@ private static double CalculateDistance(GeographyPoint p1, GeographyPoint p2) #endregion - public new static IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) + public static new IServiceCollection ConfigureApi(Type apiType, IServiceCollection services) { Func> defaultDataStoreManager = sp => new DefaultDataStoreManager() diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs index d4cb4976..6b7433cd 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Controllers/TrippinController.cs @@ -4,8 +4,11 @@ using System.Linq; using System.Web.Http; using System.Web.OData; +using System.Web.OData.Extensions; using System.Web.OData.Routing; +using Microsoft.Extensions.DependencyInjection; using Microsoft.OData.Service.Sample.TrippinInMemory.Api; +using Microsoft.Restier.Core; namespace Microsoft.OData.Service.Sample.TrippinInMemory.Controllers { @@ -18,7 +21,7 @@ private TrippinApi Api { if (_api == null) { - _api = new TrippinApi(); + _api = (TrippinApi)this.Request.GetRequestContainer().GetService(); } return _api; diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj index 3948488b..425ce830 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/Microsoft.OData.Service.Sample.TrippinInMemory.csproj @@ -52,15 +52,15 @@ True - ..\..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -92,7 +92,7 @@ True - ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True diff --git a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/packages.config b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/packages.config index b2a89a5d..c0d4e7dc 100644 --- a/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/packages.config +++ b/test/ODataEndToEnd/Microsoft.OData.Service.Sample.TrippinInMemory/packages.config @@ -1,15 +1,15 @@  - + - - - + + + diff --git a/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/Microsoft.Restier.Providers.InMemory.csproj b/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/Microsoft.Restier.Providers.InMemory.csproj index 03ef1c18..437ecc8e 100644 --- a/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/Microsoft.Restier.Providers.InMemory.csproj +++ b/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/Microsoft.Restier.Providers.InMemory.csproj @@ -39,15 +39,15 @@ True - ..\..\..\packages\Microsoft.OData.Core.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll + ..\..\..\packages\Microsoft.OData.Core.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Core.dll True - ..\..\..\packages\Microsoft.OData.Edm.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll + ..\..\..\packages\Microsoft.OData.Edm.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.OData.Edm.dll True - ..\..\..\packages\Microsoft.Spatial.7.0.0-beta\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll + ..\..\..\packages\Microsoft.Spatial.7.0.0\lib\portable-net45+win8+wpa81\Microsoft.Spatial.dll True @@ -66,7 +66,7 @@ True - ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160819\lib\net45\System.Web.OData.dll + ..\..\..\packages\Microsoft.AspNet.OData.6.0.0-Nightly160825\lib\net45\System.Web.OData.dll True diff --git a/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/packages.config b/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/packages.config index b5340e2e..383d37bd 100644 --- a/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/packages.config +++ b/test/ODataEndToEnd/Microsoft.Restier.Providers.InMemory/packages.config @@ -1,13 +1,13 @@  - + - - - + + +