diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/ActionConstraintProviderContext.cs b/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/ActionConstraintProviderContext.cs index 155f8923c9..950d204ecb 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/ActionConstraintProviderContext.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/ActionConstraintProviderContext.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; +using Microsoft.AspNet.Http; namespace Microsoft.AspNet.Mvc { @@ -16,13 +17,17 @@ namespace Microsoft.AspNet.Mvc /// The for which constraints are being created. /// The list of objects. public ActionConstraintProviderContext( + [NotNull] HttpContext context, [NotNull] ActionDescriptor action, [NotNull] IList items) { + HttpContext = context; Action = action; Results = items; } + public HttpContext HttpContext { get; } + /// /// The for which constraints are being created. /// diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/DefaultActionConstraintProvider.cs b/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/DefaultActionConstraintProvider.cs index 33008d0d21..9225d25ea5 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/DefaultActionConstraintProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ActionConstraints/DefaultActionConstraintProvider.cs @@ -16,17 +16,6 @@ namespace Microsoft.AspNet.Mvc /// public class DefaultActionConstraintProvider : INestedProvider { - private readonly IServiceProvider _services; - - /// - /// Creates a new . - /// - /// The per-request services. - public DefaultActionConstraintProvider(IServiceProvider services) - { - _services = services; - } - /// public int Order { @@ -38,13 +27,13 @@ namespace Microsoft.AspNet.Mvc { foreach (var item in context.Results) { - ProvideConstraint(item); + ProvideConstraint(item, context.HttpContext.RequestServices); } callNext(); } - private void ProvideConstraint(ActionConstraintItem item) + private void ProvideConstraint(ActionConstraintItem item, IServiceProvider services) { // Don't overwrite anything that was done by a previous provider. if (item.Constraint != null) @@ -62,7 +51,7 @@ namespace Microsoft.AspNet.Mvc var factory = item.Metadata as IActionConstraintFactory; if (factory != null) { - item.Constraint = factory.CreateInstance(_services); + item.Constraint = factory.CreateInstance(services); return; } } diff --git a/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs b/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs index 3baa17a60b..935da371df 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DefaultActionSelector.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.Routing; @@ -43,7 +44,7 @@ namespace Microsoft.AspNet.Mvc var candidates = new List(); foreach (var action in matchingRouteConstraints) { - var constraints = GetConstraints(action); + var constraints = GetConstraints(context.HttpContext, action); candidates.Add(new ActionSelectorCandidate(action, constraints)); } @@ -253,7 +254,7 @@ namespace Microsoft.AspNet.Mvc return descriptors.Items; } - private IReadOnlyList GetConstraints(ActionDescriptor action) + private IReadOnlyList GetConstraints(HttpContext httpContext, ActionDescriptor action) { if (action.ActionConstraints == null || action.ActionConstraints.Count == 0) { @@ -261,7 +262,7 @@ namespace Microsoft.AspNet.Mvc } var items = action.ActionConstraints.Select(c => new ActionConstraintItem(c)).ToList(); - var context = new ActionConstraintProviderContext(action, items); + var context = new ActionConstraintProviderContext(httpContext, action, items); _actionConstraintProvider.Invoke(context); diff --git a/src/Microsoft.AspNet.Mvc/MvcServices.cs b/src/Microsoft.AspNet.Mvc/MvcServices.cs index 42ed31f887..276b72b062 100644 --- a/src/Microsoft.AspNet.Mvc/MvcServices.cs +++ b/src/Microsoft.AspNet.Mvc/MvcServices.cs @@ -23,22 +23,24 @@ namespace Microsoft.AspNet.Mvc { public class MvcServices { - public static IEnumerable GetDefaultServices(IConfiguration configuration = null) + public static IEnumerable GetDefaultServices() + { + return GetDefaultServices(null); + } + + public static IEnumerable GetDefaultServices(IConfiguration configuration) { var describe = new ServiceDescriber(configuration); // Options and core services. - yield return describe.Transient, MvcOptionsSetup>(); yield return describe.Transient, RazorViewEngineOptionsSetup>(); yield return describe.Transient(); - yield return describe.Transient(typeof(INestedProviderManager<>), typeof(NestedProviderManager<>)); - yield return describe.Transient( - typeof(INestedProviderManagerAsync<>), - typeof(NestedProviderManagerAsync<>)); + yield return describe.Transient(); yield return describe.Singleton(typeof(ITypeActivatorCache), typeof(DefaultTypeActivatorCache)); yield return describe.Scoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>)); + // Core action discovery, filters and action execution. // These are consumed only when creating action descriptors, then they can be de-allocated @@ -56,25 +58,34 @@ namespace Microsoft.AspNet.Mvc // This provider needs access to the per-request services, but might be used many times for a given // request. - yield return describe.Scoped, + yield return describe.Transient, + NestedProviderManager>(); + yield return describe.Transient, DefaultActionConstraintProvider>(); yield return describe.Singleton(); - yield return describe.Scoped(); + yield return describe.Singleton(); yield return describe.Transient(); yield return describe.Transient(); + yield return describe.Transient, + NestedProviderManager>(); yield return describe.Transient, ControllerActionDescriptorProvider>(); + + yield return describe.Transient, + NestedProviderManager>(); yield return describe.Transient, ControllerActionInvokerProvider>(); + yield return describe.Singleton(); // The IGlobalFilterProvider is used to build the action descriptors (likely once) and so should // remain transient to avoid keeping it in memory. yield return describe.Transient(); - + yield return describe.Transient, + NestedProviderManager>(); yield return describe.Transient, DefaultFilterProvider>(); yield return describe.Transient(); @@ -89,7 +100,7 @@ namespace Microsoft.AspNet.Mvc yield return describe.Transient(); yield return describe.Transient(); yield return describe.Transient(); - yield return describe.Instance(new JsonOutputFormatter()); + yield return describe.Instance(new JsonOutputFormatter()); yield return describe.Transient(); yield return describe.Transient(); yield return describe.Transient(); yield return describe.Singleton(); + // Virtual path view factory needs to stay scoped so views can get get scoped services. yield return describe.Scoped(); // View and rendering helpers - yield return describe.Transient(); yield return describe.Transient(typeof(IHtmlHelper<>), typeof(HtmlHelper<>)); yield return describe.Scoped(); @@ -152,19 +163,21 @@ namespace Microsoft.AspNet.Mvc yield return describe.Transient(); yield return describe.Singleton(); yield return describe.Transient(); + yield return describe.Transient, + NestedProviderManager>(); yield return describe.Transient, DefaultViewComponentInvokerProvider>(); yield return describe.Transient(); // Security and Authorization - yield return describe.Singleton(); yield return describe.Singleton(); yield return describe.Singleton(); // Api Description - + yield return describe.Transient, + NestedProviderManager>(); yield return describe.Singleton(); yield return describe.Transient, diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultActionSelectorTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultActionSelectorTests.cs index 882b2efdc4..c78ad3364f 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultActionSelectorTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultActionSelectorTests.cs @@ -745,7 +745,7 @@ namespace Microsoft.AspNet.Mvc var actionConstraintProvider = new NestedProviderManager( new INestedProvider[] { - new DefaultActionConstraintProvider(serviceContainer), + new DefaultActionConstraintProvider(), }); var defaultActionSelector = new DefaultActionSelector( @@ -831,7 +831,7 @@ namespace Microsoft.AspNet.Mvc var actionConstraintProvider = new NestedProviderManager( new INestedProvider[] { - new DefaultActionConstraintProvider(new ServiceContainer()), + new DefaultActionConstraintProvider(), new BooleanConstraintProvider(), }); @@ -860,14 +860,17 @@ namespace Microsoft.AspNet.Mvc var routeData = new RouteData(); routeData.Routers.Add(new Mock(MockBehavior.Strict).Object); + var serviceContainer = new ServiceContainer(); + var httpContext = new Mock(MockBehavior.Strict); var request = new Mock(MockBehavior.Strict); - httpContext.SetupGet(c => c.Request).Returns(request.Object); - request.SetupGet(r => r.Method).Returns(httpMethod); request.SetupGet(r => r.Path).Returns(new PathString()); + httpContext.SetupGet(c => c.Request).Returns(request.Object); + httpContext.SetupGet(c => c.RequestServices).Returns(serviceContainer); + return new RouteContext(httpContext.Object) { RouteData = routeData,