From 89a8d0e36c54c18918653e3c7c8cfe33843d6811 Mon Sep 17 00:00:00 2001 From: Ryan Nowak Date: Thu, 23 Jul 2015 17:30:46 -0700 Subject: [PATCH] Remove IScopedInstance - use AsyncLocal for ActionContext and ActionBindingContext This change replaces IScopedInstance in favor or IActionContextAccessor and IActionBindingContextAccessor. In the spirit of IHttpContextAccessor, these are both singletons which use AsyncLocal for storage. This change allows the invoker factory to be cached which results in some significant perf gains. --- .../ActionBindingContextAccessor.cs | 40 +++++++++++ .../ActionContextAccessor.cs | 40 +++++++++++ .../ControllerActionInvoker.cs | 6 +- .../ControllerActionInvokerProvider.cs | 11 +-- .../DefaultControllerPropertyActivator.cs | 38 +++++++---- .../MvcCoreServiceCollectionExtensions.cs | 9 +-- .../FilterActionInvoker.cs | 46 ++++++------- src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs | 6 +- .../IActionBindingContextAccessor.cs | 10 +++ .../IActionContextAccessor.cs | 10 +++ .../IScopedInstance.cs | 12 ---- .../MvcRouteHandler.cs | 50 ++++++++------ src/Microsoft.AspNet.Mvc.Core/ObjectResult.cs | 4 +- .../ScopedInstance.cs | 21 ------ src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs | 35 +++++----- .../ControllerActionInvokerTest.cs | 14 ++-- .../CreatedAtActionResultTests.cs | 13 ++-- .../CreatedAtRouteResultTests.cs | 10 +-- .../CreatedResultTests.cs | 12 ++-- .../DefaultControllerFactoryTest.cs | 9 ++- .../FormatFilterTest.cs | 31 +++++---- .../HttpNotFoundObjectResultTest.cs | 14 ++-- .../HttpOkObjectResultTest.cs | 6 +- .../MockScopedInstance.cs | 16 ----- .../ModelBinding/BodyModelBinderTests.cs | 19 ------ .../MvcRouteHandlerTests.cs | 6 +- .../ObjectResultTests.cs | 16 ++--- .../RedirectResultTest.cs | 5 +- .../ScopedInstanceTest.cs | 68 ------------------- .../UrlHelperTest.cs | 15 ++-- .../ModelBindingTestHelper.cs | 10 +-- ...MutableObjectModelBinderIntegrationTest.cs | 4 +- .../RemoteAttributeTest.cs | 12 ++-- .../BadRequestErrorMessageResultTest.cs | 13 ++-- .../ActionResults/ExceptionResultTest.cs | 11 +-- .../InvalidModelStateResultTest.cs | 12 +--- .../NegotiatedContentResultTest.cs | 11 +-- .../RoutingWebSite/TestResponseGenerator.cs | 4 +- .../UrlHelperWebSite/CustomUrlHelper.cs | 9 +-- .../TestResponseGenerator.cs | 4 +- 40 files changed, 311 insertions(+), 371 deletions(-) create mode 100644 src/Microsoft.AspNet.Mvc.Core/ActionBindingContextAccessor.cs create mode 100644 src/Microsoft.AspNet.Mvc.Core/ActionContextAccessor.cs create mode 100644 src/Microsoft.AspNet.Mvc.Core/IActionBindingContextAccessor.cs create mode 100644 src/Microsoft.AspNet.Mvc.Core/IActionContextAccessor.cs delete mode 100644 src/Microsoft.AspNet.Mvc.Core/IScopedInstance.cs delete mode 100644 src/Microsoft.AspNet.Mvc.Core/ScopedInstance.cs delete mode 100644 test/Microsoft.AspNet.Mvc.Core.Test/MockScopedInstance.cs delete mode 100644 test/Microsoft.AspNet.Mvc.Core.Test/ScopedInstanceTest.cs diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionBindingContextAccessor.cs b/src/Microsoft.AspNet.Mvc.Core/ActionBindingContextAccessor.cs new file mode 100644 index 0000000000..278ab08054 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/ActionBindingContextAccessor.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#if DNX451 +using System.Runtime.Remoting; +using System.Runtime.Remoting.Messaging; +#else +using System.Threading; +#endif + +namespace Microsoft.AspNet.Mvc +{ + public class ActionBindingContextAccessor : IActionBindingContextAccessor + { +#if DNX451 + private static string Key = typeof(ActionBindingContext).FullName; + + public ActionBindingContext ActionBindingContext + { + get + { + var handle = CallContext.LogicalGetData(Key) as ObjectHandle; + return handle != null ? (ActionBindingContext)handle.Unwrap() : null; + } + set + { + CallContext.LogicalSetData(Key, new ObjectHandle(value)); + } + } +#else + private readonly AsyncLocal _storage = new AsyncLocal(); + + public ActionBindingContext ActionBindingContext + { + get { return _storage.Value; } + set { _storage.Value = value; } + } +#endif + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/ActionContextAccessor.cs b/src/Microsoft.AspNet.Mvc.Core/ActionContextAccessor.cs new file mode 100644 index 0000000000..4feeb26838 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/ActionContextAccessor.cs @@ -0,0 +1,40 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +#if DNX451 +using System.Runtime.Remoting; +using System.Runtime.Remoting.Messaging; +#else +using System.Threading; +#endif + +namespace Microsoft.AspNet.Mvc +{ + public class ActionContextAccessor : IActionContextAccessor + { +#if DNX451 + private static string Key = typeof(ActionContext).FullName; + + public ActionContext ActionContext + { + get + { + var handle = CallContext.LogicalGetData(Key) as ObjectHandle; + return handle != null ? (ActionContext)handle.Unwrap() : null; + } + set + { + CallContext.LogicalSetData(Key, new ObjectHandle(value)); + } + } +#else + private readonly AsyncLocal _storage = new AsyncLocal(); + + public ActionContext ActionContext + { + get { return _storage.Value; } + set { _storage.Value = value; } + } +#endif + } +} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs index 0a8504b522..2feb17ab07 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvoker.cs @@ -30,8 +30,8 @@ namespace Microsoft.AspNet.Mvc.Core [NotNull] IReadOnlyList modelBinders, [NotNull] IReadOnlyList modelValidatorProviders, [NotNull] IReadOnlyList valueProviderFactories, - [NotNull] IScopedInstance actionBindingContextAccessor, - [NotNull] ILoggerFactory loggerFactory, + [NotNull] IActionBindingContextAccessor actionBindingContextAccessor, + [NotNull] ILogger logger, int maxModelValidationErrors) : base( actionContext, @@ -42,7 +42,7 @@ namespace Microsoft.AspNet.Mvc.Core modelValidatorProviders, valueProviderFactories, actionBindingContextAccessor, - loggerFactory, + logger, maxModelValidationErrors) { _descriptor = descriptor; diff --git a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs index 4699b06a08..943e8acd26 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ControllerActionInvokerProvider.cs @@ -21,16 +21,16 @@ namespace Microsoft.AspNet.Mvc.Core private readonly IReadOnlyList _outputFormatters; private readonly IReadOnlyList _modelValidatorProviders; private readonly IReadOnlyList _valueProviderFactories; - private readonly IScopedInstance _actionBindingContextAccessor; + private readonly IActionBindingContextAccessor _actionBindingContextAccessor; private readonly int _maxModelValidationErrors; - private readonly ILoggerFactory _loggerFactory; + private readonly ILogger _logger; public ControllerActionInvokerProvider( IControllerFactory controllerFactory, IEnumerable filterProviders, IControllerActionArgumentBinder argumentBinder, IOptions optionsAccessor, - IScopedInstance actionBindingContextAccessor, + IActionBindingContextAccessor actionBindingContextAccessor, ILoggerFactory loggerFactory) { _controllerFactory = controllerFactory; @@ -43,7 +43,8 @@ namespace Microsoft.AspNet.Mvc.Core _valueProviderFactories = optionsAccessor.Options.ValueProviderFactories.ToArray(); _actionBindingContextAccessor = actionBindingContextAccessor; _maxModelValidationErrors = optionsAccessor.Options.MaxModelValidationErrors; - _loggerFactory = loggerFactory; + + _logger = loggerFactory.CreateLogger(); } public int Order @@ -70,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.Core _modelValidatorProviders, _valueProviderFactories, _actionBindingContextAccessor, - _loggerFactory, + _logger, _maxModelValidationErrors); } } diff --git a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerPropertyActivator.cs b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerPropertyActivator.cs index 44b67e9a9c..32fbc6b93a 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DefaultControllerPropertyActivator.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DefaultControllerPropertyActivator.cs @@ -12,12 +12,15 @@ namespace Microsoft.AspNet.Mvc { public class DefaultControllerPropertyActivator : IControllerPropertyActivator { - private readonly ConcurrentDictionary[]> _activateActions; - private readonly Func[]> _getPropertiesToActivate; + private readonly IActionBindingContextAccessor _actionBindingContextAccessor; + private readonly ConcurrentDictionary[]> _activateActions; + private readonly Func[]> _getPropertiesToActivate; - public DefaultControllerPropertyActivator() + public DefaultControllerPropertyActivator(IActionBindingContextAccessor actionBindingContextAccessor) { - _activateActions = new ConcurrentDictionary[]>(); + _actionBindingContextAccessor = actionBindingContextAccessor; + + _activateActions = new ConcurrentDictionary[]>(); _getPropertiesToActivate = GetPropertiesToActivate; } @@ -28,34 +31,39 @@ namespace Microsoft.AspNet.Mvc controllerType, _getPropertiesToActivate); + var contexts = new Contexts() + { + ActionBindingContext = _actionBindingContextAccessor.ActionBindingContext, + ActionContext = actionContext, + }; + for (var i = 0; i < propertiesToActivate.Length; i++) { var activateInfo = propertiesToActivate[i]; - activateInfo.Activate(controller, actionContext); + activateInfo.Activate(controller, contexts); } } - private PropertyActivator[] GetPropertiesToActivate(Type type) + private PropertyActivator[] GetPropertiesToActivate(Type type) { - IEnumerable> activators; - activators = PropertyActivator.GetPropertiesToActivate( + IEnumerable> activators; + activators = PropertyActivator.GetPropertiesToActivate( type, typeof(ActionContextAttribute), - p => new PropertyActivator(p, c => c)); + p => new PropertyActivator(p, c => c.ActionContext)); - activators = activators.Concat(PropertyActivator.GetPropertiesToActivate( + activators = activators.Concat(PropertyActivator.GetPropertiesToActivate( type, typeof(ActionBindingContextAttribute), - p => new PropertyActivator(p, GetActionBindingContext))); + p => new PropertyActivator(p, c => c.ActionBindingContext))); return activators.ToArray(); } - private static ActionBindingContext GetActionBindingContext(ActionContext context) + private struct Contexts { - var serviceProvider = context.HttpContext.RequestServices; - var accessor = serviceProvider.GetRequiredService>(); - return accessor.Value; + public ActionBindingContext ActionBindingContext; + public ActionContext ActionContext; } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs index 9d65a4931f..41ff87d837 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs @@ -104,8 +104,8 @@ namespace Microsoft.Framework.DependencyInjection // // Action Invoker // - // These two access per-request services - services.TryAddTransient(); + // The IActionInvokerFactory is cachable + services.TryAddSingleton(); services.TryAddEnumerable( ServiceDescriptor.Transient()); @@ -136,8 +136,9 @@ namespace Microsoft.Framework.DependencyInjection // services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddScoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>)); - services.TryAddScoped(); + services.TryAddSingleton(); + services.TryAddSingleton(); + services.TryAddSingleton(); } private static void ConfigureDefaultServices(IServiceCollection services) diff --git a/src/Microsoft.AspNet.Mvc.Core/FilterActionInvoker.cs b/src/Microsoft.AspNet.Mvc.Core/FilterActionInvoker.cs index 2bb3fbcd70..7700a7c6d3 100644 --- a/src/Microsoft.AspNet.Mvc.Core/FilterActionInvoker.cs +++ b/src/Microsoft.AspNet.Mvc.Core/FilterActionInvoker.cs @@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.Core private readonly IReadOnlyList _outputFormatters; private readonly IReadOnlyList _modelValidatorProviders; private readonly IReadOnlyList _valueProviderFactories; - private readonly IScopedInstance _actionBindingContextAccessor; + private readonly IActionBindingContextAccessor _actionBindingContextAccessor; private readonly ILogger _logger; private readonly int _maxModelValidationErrors; @@ -61,8 +61,8 @@ namespace Microsoft.AspNet.Mvc.Core [NotNull] IReadOnlyList modelBinders, [NotNull] IReadOnlyList modelValidatorProviders, [NotNull] IReadOnlyList valueProviderFactories, - [NotNull] IScopedInstance actionBindingContextAccessor, - [NotNull] ILoggerFactory loggerFactory, + [NotNull] IActionBindingContextAccessor actionBindingContextAccessor, + [NotNull] ILogger logger, int maxModelValidationErrors) { ActionContext = actionContext; @@ -74,7 +74,7 @@ namespace Microsoft.AspNet.Mvc.Core _modelValidatorProviders = modelValidatorProviders; _valueProviderFactories = valueProviderFactories; _actionBindingContextAccessor = actionBindingContextAccessor; - _logger = loggerFactory.CreateLogger(); + _logger = logger; _maxModelValidationErrors = maxModelValidationErrors; } @@ -84,11 +84,11 @@ namespace Microsoft.AspNet.Mvc.Core { get { - return _actionBindingContextAccessor.Value; + return _actionBindingContextAccessor.ActionBindingContext; } private set { - _actionBindingContextAccessor.Value = value; + _actionBindingContextAccessor.ActionBindingContext = value; } } @@ -316,7 +316,22 @@ namespace Microsoft.AspNet.Mvc.Core } else { - // We've reached the end of resource filters, so move on to exception filters. + // We've reached the end of resource filters, so move to setting up state to invoke model + // binding. + ActionBindingContext = new ActionBindingContext(); + ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters; + ActionBindingContext.OutputFormatters = _resourceExecutingContext.OutputFormatters; + ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders); + ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider( + _resourceExecutingContext.ValidatorProviders); + + var valueProviderFactoryContext = new ValueProviderFactoryContext( + ActionContext.HttpContext, + ActionContext.RouteData.Values); + + ActionBindingContext.ValueProvider = CompositeValueProvider.Create( + _resourceExecutingContext.ValueProviderFactories, + valueProviderFactoryContext); // >> ExceptionFilters >> Model Binding >> ActionFilters >> Action await InvokeAllExceptionFiltersAsync(); @@ -465,23 +480,6 @@ namespace Microsoft.AspNet.Mvc.Core { _cursor.SetStage(FilterStage.ActionFilters); - Debug.Assert(_resourceExecutingContext != null); - - ActionBindingContext = new ActionBindingContext(); - ActionBindingContext.InputFormatters = _resourceExecutingContext.InputFormatters; - ActionBindingContext.OutputFormatters = _resourceExecutingContext.OutputFormatters; - ActionBindingContext.ModelBinder = new CompositeModelBinder(_resourceExecutingContext.ModelBinders); - ActionBindingContext.ValidatorProvider = new CompositeModelValidatorProvider( - _resourceExecutingContext.ValidatorProviders); - - var valueProviderFactoryContext = new ValueProviderFactoryContext( - ActionContext.HttpContext, - ActionContext.RouteData.Values); - - ActionBindingContext.ValueProvider = CompositeValueProvider.Create( - _resourceExecutingContext.ValueProviderFactories, - valueProviderFactoryContext); - Instance = CreateInstance(); var arguments = await BindActionArgumentsAsync(ActionContext, ActionBindingContext); diff --git a/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs b/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs index e519f4bb11..374a4c0232 100644 --- a/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs +++ b/src/Microsoft.AspNet.Mvc.Core/FormatFilter.cs @@ -21,11 +21,11 @@ namespace Microsoft.AspNet.Mvc /// Initializes an instance of . /// /// The - /// The - public FormatFilter(IOptions options, IScopedInstance actionContext) + /// The + public FormatFilter(IOptions options, IActionContextAccessor actionContextAccessor) { IsActive = true; - Format = GetFormat(actionContext.Value); + Format = GetFormat(actionContextAccessor.ActionContext); if (string.IsNullOrEmpty(Format)) { diff --git a/src/Microsoft.AspNet.Mvc.Core/IActionBindingContextAccessor.cs b/src/Microsoft.AspNet.Mvc.Core/IActionBindingContextAccessor.cs new file mode 100644 index 0000000000..a2ade26c90 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/IActionBindingContextAccessor.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNet.Mvc +{ + public interface IActionBindingContextAccessor + { + ActionBindingContext ActionBindingContext { get; set; } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/IActionContextAccessor.cs b/src/Microsoft.AspNet.Mvc.Core/IActionContextAccessor.cs new file mode 100644 index 0000000000..ef4cc85cb6 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/IActionContextAccessor.cs @@ -0,0 +1,10 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +namespace Microsoft.AspNet.Mvc +{ + public interface IActionContextAccessor + { + ActionContext ActionContext { get; set; } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/IScopedInstance.cs b/src/Microsoft.AspNet.Mvc.Core/IScopedInstance.cs deleted file mode 100644 index a8b57a81f8..0000000000 --- a/src/Microsoft.AspNet.Mvc.Core/IScopedInstance.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNet.Mvc -{ - public interface IScopedInstance : IDisposable - { - TValue Value { get; set; } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/MvcRouteHandler.cs b/src/Microsoft.AspNet.Mvc.Core/MvcRouteHandler.cs index b761f1a59a..488e2c7cc6 100644 --- a/src/Microsoft.AspNet.Mvc.Core/MvcRouteHandler.cs +++ b/src/Microsoft.AspNet.Mvc.Core/MvcRouteHandler.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; @@ -17,15 +16,19 @@ namespace Microsoft.AspNet.Mvc { public class MvcRouteHandler : IRouter { - private INotifier _notifier; + private IActionContextAccessor _actionContextAccessor; + private IActionInvokerFactory _actionInvokerFactory; + private IActionSelector _actionSelector; private ILogger _logger; + private INotifier _notifier; public VirtualPathData GetVirtualPath([NotNull] VirtualPathContext context) { + EnsureServices(context.Context); + // The contract of this method is to check that the values coming in from the route are valid; // that they match an existing action, setting IsBound = true if the values are OK. - var actionSelector = context.Context.RequestServices.GetRequiredService(); - context.IsBound = actionSelector.HasValidAction(context); + context.IsBound = _actionSelector.HasValidAction(context); // We return null here because we're not responsible for generating the url, the route is. return null; @@ -38,13 +41,9 @@ namespace Microsoft.AspNet.Mvc // Verify if AddMvc was done before calling UseMvc // We use the MvcMarkerService to make sure if all the services were added. MvcServicesHelper.ThrowIfMvcNotRegistered(services); + EnsureServices(context.HttpContext); - EnsureLogger(context.HttpContext); - EnsureNotifier(context.HttpContext); - - var actionSelector = services.GetRequiredService(); - var actionDescriptor = await actionSelector.SelectAsync(context); - + var actionDescriptor = await _actionSelector.SelectAsync(context); if (actionDescriptor == null) { _logger.LogVerbose("No actions matched the current request."); @@ -104,15 +103,10 @@ namespace Microsoft.AspNet.Mvc private async Task InvokeActionAsync(RouteContext context, ActionDescriptor actionDescriptor) { - var services = context.HttpContext.RequestServices; - Debug.Assert(services != null); - var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor); - - var contextAccessor = services.GetRequiredService>(); - contextAccessor.Value = actionContext; - var invokerFactory = services.GetRequiredService(); - var invoker = invokerFactory.CreateInvoker(actionContext); + _actionContextAccessor.ActionContext = actionContext; + + var invoker = _actionInvokerFactory.CreateInvoker(actionContext); if (invoker == null) { throw new InvalidOperationException( @@ -123,17 +117,29 @@ namespace Microsoft.AspNet.Mvc await invoker.InvokeAsync(); } - private void EnsureLogger(HttpContext context) + private void EnsureServices(HttpContext context) { + if (_actionContextAccessor == null) + { + _actionContextAccessor = context.RequestServices.GetRequiredService(); + } + + if (_actionInvokerFactory == null) + { + _actionInvokerFactory = context.RequestServices.GetRequiredService(); + } + + if (_actionSelector == null) + { + _actionSelector = context.RequestServices.GetRequiredService(); + } + if (_logger == null) { var factory = context.RequestServices.GetRequiredService(); _logger = factory.CreateLogger(); } - } - private void EnsureNotifier(HttpContext context) - { if (_notifier == null) { _notifier = context.RequestServices.GetRequiredService(); diff --git a/src/Microsoft.AspNet.Mvc.Core/ObjectResult.cs b/src/Microsoft.AspNet.Mvc.Core/ObjectResult.cs index 061f381c1a..84aae59641 100644 --- a/src/Microsoft.AspNet.Mvc.Core/ObjectResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/ObjectResult.cs @@ -297,8 +297,8 @@ namespace Microsoft.AspNet.Mvc var actionBindingContext = context .HttpContext .RequestServices - .GetRequiredService>() - .Value; + .GetRequiredService() + .ActionBindingContext; // In scenarios where there is a resource filter which directly shortcircuits using an ObjectResult. // actionBindingContext is not setup yet and is null. diff --git a/src/Microsoft.AspNet.Mvc.Core/ScopedInstance.cs b/src/Microsoft.AspNet.Mvc.Core/ScopedInstance.cs deleted file mode 100644 index 0ed1e21e3c..0000000000 --- a/src/Microsoft.AspNet.Mvc.Core/ScopedInstance.cs +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; - -namespace Microsoft.AspNet.Mvc -{ - public class ScopedInstance : IScopedInstance - { - public T Value { get; set; } - - public void Dispose() - { - var disposable = Value as IDisposable; - if (disposable != null) - { - disposable.Dispose(); - } - } - } -} \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs index 97ed3e0096..b379f9f10e 100644 --- a/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/UrlHelper.cs @@ -7,7 +7,6 @@ using System.Diagnostics; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Internal; using Microsoft.AspNet.Routing; -using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.Internal; namespace Microsoft.AspNet.Mvc @@ -18,28 +17,32 @@ namespace Microsoft.AspNet.Mvc /// public class UrlHelper : IUrlHelper { - private readonly HttpContext _httpContext; - private readonly IRouter _router; - private readonly IDictionary _ambientValues; + private readonly IActionContextAccessor _actionContextAccessor; private readonly IActionSelector _actionSelector; /// /// Initializes a new instance of the class using the specified action context and /// action selector. /// - /// The to access the action context + /// The to access the action context /// of the current request. /// The to be used for verifying the correctness of /// supplied parameters for a route. /// - public UrlHelper(IScopedInstance contextAccessor, IActionSelector actionSelector) + public UrlHelper(IActionContextAccessor actionContextAccessor, IActionSelector actionSelector) { - _httpContext = contextAccessor.Value.HttpContext; - _router = contextAccessor.Value.RouteData.Routers[0]; - _ambientValues = contextAccessor.Value.RouteData.Values; + _actionContextAccessor = actionContextAccessor; _actionSelector = actionSelector; } + protected IDictionary AmbientValues => ActionContext.RouteData.Values; + + protected ActionContext ActionContext => _actionContextAccessor.ActionContext; + + protected HttpContext HttpContext => ActionContext.HttpContext; + + protected IRouter Router => ActionContext.RouteData.Routers[0]; + /// public virtual string Action(UrlActionContext actionContext) { @@ -98,8 +101,8 @@ namespace Microsoft.AspNet.Mvc /// The absolute path of the URL. protected virtual string GeneratePathFromRoute(string routeName, IDictionary values) { - var context = new VirtualPathContext(_httpContext, _ambientValues, values, routeName); - var pathData = _router.GetVirtualPath(context); + var context = new VirtualPathContext(HttpContext, AmbientValues, values, routeName); + var pathData = Router.GetVirtualPath(context); if (pathData == null) { return null; @@ -108,7 +111,7 @@ namespace Microsoft.AspNet.Mvc // VirtualPathData.VirtualPath returns string.Empty for null. Debug.Assert(pathData.VirtualPath != null); - var fullPath = _httpContext.Request.PathBase.Add(pathData.VirtualPath).Value; + var fullPath = HttpContext.Request.PathBase.Add(pathData.VirtualPath).Value; if (fullPath.Length == 0) { return "/"; @@ -129,7 +132,7 @@ namespace Microsoft.AspNet.Mvc else if (contentPath[0] == '~') { var segment = new PathString(contentPath.Substring(1)); - var applicationPath = _httpContext.Request.PathBase; + var applicationPath = HttpContext.Request.PathBase; return applicationPath.Add(segment).Value; } @@ -144,8 +147,8 @@ namespace Microsoft.AspNet.Mvc { RouteName = routeName, Values = values, - Protocol = _httpContext.Request.Scheme, - Host = _httpContext.Request.Host.ToUriComponent() + Protocol = HttpContext.Request.Scheme, + Host = HttpContext.Request.Host.ToUriComponent() }); } @@ -174,7 +177,7 @@ namespace Microsoft.AspNet.Mvc else { protocol = string.IsNullOrEmpty(protocol) ? "http" : protocol; - host = string.IsNullOrEmpty(host) ? _httpContext.Request.Host.Value : host; + host = string.IsNullOrEmpty(host) ? HttpContext.Request.Host.Value : host; url = protocol + "://" + host + url; return url; diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs index 263901f481..577dae6013 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ControllerActionInvokerTest.cs @@ -2040,8 +2040,8 @@ namespace Microsoft.AspNet.Mvc new IModelBinder[0], new IModelValidatorProvider[0], new IValueProviderFactory[0], - new MockScopedInstance(), - new NullLoggerFactory(), + new ActionBindingContextAccessor(), + new NullLoggerFactory().CreateLogger(), maxAllowedErrorsInModelState); return invoker; @@ -2102,8 +2102,8 @@ namespace Microsoft.AspNet.Mvc new IModelBinder[] { binder.Object }, new IModelValidatorProvider[0], new IValueProviderFactory[0], - new MockScopedInstance(), - new NullLoggerFactory(), + new ActionBindingContextAccessor(), + new NullLoggerFactory().CreateLogger(), 200); // Act @@ -2202,8 +2202,8 @@ namespace Microsoft.AspNet.Mvc IReadOnlyList modelBinders, IReadOnlyList modelValidatorProviders, IReadOnlyList valueProviderFactories, - IScopedInstance actionBindingContext, - ILoggerFactory loggerFactory, + IActionBindingContextAccessor actionBindingContext, + ILogger logger, int maxAllowedErrorsInModelState) : base( actionContext, @@ -2217,7 +2217,7 @@ namespace Microsoft.AspNet.Mvc modelValidatorProviders, valueProviderFactories, actionBindingContext, - loggerFactory, + logger, maxAllowedErrorsInModelState) { ControllerFactory = controllerFactory; diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs index 27d1f27102..5d2da109ac 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtActionResultTests.cs @@ -102,13 +102,12 @@ namespace Microsoft.AspNet.Mvc services.Setup(s => s.GetService(typeof(ILogger))) .Returns(new Mock>().Object); - var mockContextAccessor = new Mock>(); - mockContextAccessor - .SetupGet(o => o.Value) - .Returns(new ActionBindingContext() { OutputFormatters = optionsAccessor.Options.OutputFormatters }); - - services.Setup(o => o.GetService(typeof(IScopedInstance))) - .Returns(mockContextAccessor.Object); + var actionBindingContext = new ActionBindingContext + { + OutputFormatters = optionsAccessor.Options.OutputFormatters + }; + services.Setup(o => o.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext }); return httpContext; } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs index a53ed5a47d..cec3d740ac 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedAtRouteResultTests.cs @@ -110,14 +110,8 @@ namespace Microsoft.AspNet.Mvc httpContext.Setup(o => o.Response) .Returns(response); - - var mockContextAccessor = new Mock>(); - mockContextAccessor - .SetupGet(o => o.Value) - .Returns((ActionBindingContext)null); - - httpContext.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance))) - .Returns(mockContextAccessor.Object); + httpContext.Setup(o => o.RequestServices.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor()); return httpContext.Object; } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs index 257e2408c0..7b556a8838 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/CreatedResultTests.cs @@ -97,13 +97,13 @@ namespace Microsoft.AspNet.Mvc .Setup(p => p.RequestServices.GetService(typeof(ILogger))) .Returns(new Mock>().Object); - var mockActionBindingContext = new Mock>(); - mockActionBindingContext - .SetupGet(o=> o.Value) - .Returns(new ActionBindingContext() { OutputFormatters = optionsAccessor.Options.OutputFormatters }); + var actionBindingContext = new ActionBindingContext() + { + OutputFormatters = optionsAccessor.Options.OutputFormatters + }; httpContext - .Setup(o => o.RequestServices.GetService(typeof(IScopedInstance))) - .Returns(mockActionBindingContext.Object); + .Setup(o => o.RequestServices.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext }); return httpContext.Object; } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs index 06e3083ddc..593795cff0 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/DefaultControllerFactoryTest.cs @@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.Core var bindingContext = new ActionBindingContext(); var services = GetServices(); - services.GetRequiredService>().Value = bindingContext; + services.GetRequiredService().ActionBindingContext = bindingContext; var httpContext = new DefaultHttpContext { RequestServices = services @@ -255,11 +255,10 @@ namespace Microsoft.AspNet.Mvc.Core .Returns(metadataProvider); services.Setup(s => s.GetService(typeof(IObjectModelValidator))) .Returns(new DefaultObjectValidator(new IExcludeTypeValidationFilter[0], metadataProvider)); - services - .Setup(s => s.GetService(typeof(IScopedInstance))) - .Returns(new MockScopedInstance()); services.Setup(s => s.GetService(typeof(ITempDataDictionary))) .Returns(new Mock().Object); + services.Setup(s => s.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor()); return services.Object; } @@ -268,7 +267,7 @@ namespace Microsoft.AspNet.Mvc.Core controllerActivator = controllerActivator ?? Mock.Of(); var propertyActivators = new IControllerPropertyActivator[] { - new DefaultControllerPropertyActivator(), + new DefaultControllerPropertyActivator(new ActionBindingContextAccessor()), }; return new DefaultControllerFactory(controllerActivator, propertyActivators); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs index ccf368e8be..5f855d6c3a 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/FormatFilterTest.cs @@ -43,7 +43,7 @@ namespace Microsoft.AspNet.Mvc var resultExecutingContext = mockObjects.CreateResultExecutingContext(); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -90,7 +90,7 @@ namespace Microsoft.AspNet.Mvc ac, new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -122,7 +122,7 @@ namespace Microsoft.AspNet.Mvc format, MediaTypeHeaderValue.Parse(contentType)); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -145,7 +145,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(format, place); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -162,7 +162,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -184,7 +184,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(format, place); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { produces }); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -205,7 +205,7 @@ namespace Microsoft.AspNet.Mvc "xml", MediaTypeHeaderValue.Parse("application/xml")); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -226,7 +226,7 @@ namespace Microsoft.AspNet.Mvc "xml", MediaTypeHeaderValue.Parse("application/xml;version=1")); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -252,7 +252,7 @@ namespace Microsoft.AspNet.Mvc "xml", MediaTypeHeaderValue.Parse("application/xml")); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -271,7 +271,7 @@ namespace Microsoft.AspNet.Mvc // Arrange var mockObjects = new MockObjects(format, place); var resourceExecutingContext = mockObjects.CreateResourceExecutingContext(new IFilterMetadata[] { }); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act filter.OnResourceExecuting(resourceExecutingContext); @@ -294,7 +294,7 @@ namespace Microsoft.AspNet.Mvc var mockObjects = new MockObjects(format, place); var resultExecutingContext = mockObjects.CreateResultExecutingContext(); var filterAttribute = new FormatFilterAttribute(); - var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ScopedInstance); + var filter = new FormatFilter(mockObjects.OptionsManager, mockObjects.ActionContextAccessor); // Act and Assert Assert.Equal(expected, filter.IsActive); @@ -322,7 +322,7 @@ namespace Microsoft.AspNet.Mvc public HttpContext MockHttpContext { get; private set; } public ActionContext MockActionContext { get; private set; } - public IScopedInstance ScopedInstance { get; private set; } + public IActionContextAccessor ActionContextAccessor { get; private set; } public IOptions OptionsManager { get; private set; } public MockObjects(string format = null, FormatSource? place = null) @@ -399,9 +399,10 @@ namespace Microsoft.AspNet.Mvc // Setup MVC services on mock service provider MockActionContext = CreateMockActionContext(httpContext, format, place); - var scopedInstance = new Mock>(); - scopedInstance.Setup(s => s.Value).Returns(MockActionContext); - ScopedInstance = scopedInstance.Object; + ActionContextAccessor = new ActionContextAccessor() + { + ActionContext = MockActionContext, + }; } } #endif diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs index 8f6c7f15a4..85f7930b55 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/HttpNotFoundObjectResultTest.cs @@ -91,16 +91,16 @@ namespace Microsoft.AspNet.Mvc optionsAccessor.Options.OutputFormatters.Add(new StringOutputFormatter()); optionsAccessor.Options.OutputFormatters.Add(new JsonOutputFormatter()); optionsAccessor.Options.RespectBrowserAcceptHeader = respectBrowserAcceptHeader; - var mockContextAccessor = new Mock>(); - mockContextAccessor - .SetupGet(o => o.Value) - .Returns(new ActionBindingContext() + var actionBindingContextAccessor = new ActionBindingContextAccessor() + { + ActionBindingContext = new ActionBindingContext() { OutputFormatters = optionsAccessor.Options.OutputFormatters - }); + } + }; - httpContext.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance))) - .Returns(mockContextAccessor.Object); + httpContext.Setup(o => o.RequestServices.GetService(typeof(IActionBindingContextAccessor))) + .Returns(actionBindingContextAccessor); httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions))) .Returns(optionsAccessor); httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger))) diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs index f8e29613bf..06bed410fe 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/HttpOkObjectResultTest.cs @@ -81,11 +81,11 @@ namespace Microsoft.AspNet.Mvc { OutputFormatters = optionsAccessor.Options.OutputFormatters, }; - var bindingContextAccessor = new MockScopedInstance + var bindingContextAccessor = new ActionBindingContextAccessor { - Value = bindingContext, + ActionBindingContext = bindingContext, }; - services.Add(new ServiceDescriptor(typeof(IScopedInstance), bindingContextAccessor)); + services.Add(new ServiceDescriptor(typeof(IActionBindingContextAccessor), bindingContextAccessor)); return services.BuildServiceProvider(); } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/MockScopedInstance.cs b/test/Microsoft.AspNet.Mvc.Core.Test/MockScopedInstance.cs deleted file mode 100644 index 13f1cd2ea6..0000000000 --- a/test/Microsoft.AspNet.Mvc.Core.Test/MockScopedInstance.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using Microsoft.Framework.DependencyInjection; - -namespace Microsoft.AspNet.Mvc -{ - public class MockScopedInstance : IScopedInstance - { - public T Value { get; set; } - - public void Dispose() - { - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs index b2f5f3c0ef..451a3d48bc 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ModelBinding/BodyModelBinderTests.cs @@ -290,25 +290,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding return bindingContext; } - private static IScopedInstance CreateActionContext(HttpContext context) - { - return CreateActionContext(context, (new Mock()).Object); - } - - private static IScopedInstance CreateActionContext(HttpContext context, IRouter router) - { - var routeData = new RouteData(); - routeData.Routers.Add(router); - - var actionContext = new ActionContext(context, - routeData, - new ActionDescriptor()); - var contextAccessor = new Mock>(); - contextAccessor.SetupGet(c => c.Value) - .Returns(actionContext); - return contextAccessor.Object; - } - private class Person { public string Name { get; set; } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/MvcRouteHandlerTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/MvcRouteHandlerTests.cs index 56703aafda..088820ea5f 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/MvcRouteHandlerTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/MvcRouteHandlerTests.cs @@ -205,8 +205,6 @@ namespace Microsoft.AspNet.Mvc IOptions optionsAccessor = null, object notificationListener = null) { - var mockContextAccessor = new Mock>(); - if (actionDescriptor == null) { var mockAction = new Mock(); @@ -252,8 +250,8 @@ namespace Microsoft.AspNet.Mvc } var httpContext = new Mock(); - httpContext.Setup(h => h.RequestServices.GetService(typeof(IScopedInstance))) - .Returns(mockContextAccessor.Object); + httpContext.Setup(h => h.RequestServices.GetService(typeof(IActionContextAccessor))) + .Returns(new ActionContextAccessor()); httpContext.Setup(h => h.RequestServices.GetService(typeof(IActionSelector))) .Returns(actionSelector); httpContext.Setup(h => h.RequestServices.GetService(typeof(IActionInvokerFactory))) diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs index 3629472dee..10d5cb2d38 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/ObjectResultTests.cs @@ -904,20 +904,14 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger))) .Returns(new Mock>().Object); - var mockActionBindingContext = new Mock>(); - - ActionBindingContext bindingContext = null; + ActionBindingContext actionBindingContext = null; if (setupActionBindingContext) { - bindingContext = new ActionBindingContext { OutputFormatters = outputFormatters.ToList() }; + actionBindingContext = new ActionBindingContext { OutputFormatters = outputFormatters.ToList() }; } - - mockActionBindingContext - .SetupGet(o => o.Value) - .Returns(bindingContext); - - httpContext.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance))) - .Returns(mockActionBindingContext.Object); + + httpContext.Setup(o => o.RequestServices.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext }); return new ActionContext(httpContext.Object, new RouteData(), new ActionDescriptor()); } diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs index 4392eab04b..27baa166cd 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs @@ -115,10 +115,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test { var httpContext = new Mock(); var actionContext = GetActionContext(httpContext.Object); - var mockContentAccessor = new Mock>(); - mockContentAccessor.SetupGet(o => o.Value).Returns(actionContext); + var actionContextAccessor = new ActionContextAccessor() { ActionContext = actionContext }; var mockActionSelector = new Mock(); - var urlHelper = new UrlHelper(mockContentAccessor.Object, mockActionSelector.Object); + var urlHelper = new UrlHelper(actionContextAccessor, mockActionSelector.Object); var serviceProvider = GetServiceProvider(urlHelper); httpContext.Setup(o => o.Response) diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/ScopedInstanceTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/ScopedInstanceTest.cs deleted file mode 100644 index a502cde440..0000000000 --- a/test/Microsoft.AspNet.Mvc.Core.Test/ScopedInstanceTest.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) .NET Foundation. All rights reserved. -// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. - -using System; -using Xunit; - -namespace Microsoft.AspNet.Mvc -{ - public class ScopedInstanceTest - { - [Fact] - public void ScopedInstanceDisposesIDisposables() - { - var disposable = new Disposable(); - - // Arrange - var scopedInstance = new ScopedInstance - { - Value = disposable, - }; - - // Act - scopedInstance.Dispose(); - - // Assert - Assert.True(disposable.IsDisposed); - } - - [Fact] - public void ScopedInstanceDoesNotThrowOnNonIDisposable() - { - // Arrange - var scopedInstance = new ScopedInstance() - { - Value = new object(), - }; - - // Act - scopedInstance.Dispose(); - } - - [Fact] - public void ScopedInstanceDoesNotThrowOnNull() - { - // Arrange - var scopedInstance = new ScopedInstance() - { - Value = null, // just making it explicit that there is not value set yet. - }; - - // Act - scopedInstance.Dispose(); - - // Assert - Assert.Null(scopedInstance.Value); - } - - private class Disposable : IDisposable - { - public bool IsDisposed { get; set; } - - public void Dispose() - { - IsDisposed = true; - } - } - } -} \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs index 9794c8e971..1a3b718915 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/UrlHelperTest.cs @@ -820,23 +820,18 @@ namespace Microsoft.AspNet.Mvc return context; } - private static IScopedInstance CreateActionContext(HttpContext context) + private static IActionContextAccessor CreateActionContext(HttpContext context) { return CreateActionContext(context, (new Mock()).Object); } - private static IScopedInstance CreateActionContext(HttpContext context, IRouter router) + private static IActionContextAccessor CreateActionContext(HttpContext context, IRouter router) { var routeData = new RouteData(); routeData.Routers.Add(router); - var actionContext = new ActionContext(context, - routeData, - new ActionDescriptor()); - var contextAccessor = new Mock>(); - contextAccessor.SetupGet(c => c.Value) - .Returns(actionContext); - return contextAccessor.Object; + var actionContext = new ActionContext(context, routeData, new ActionDescriptor()); + return new ActionContextAccessor() { ActionContext = actionContext }; } private static UrlHelper CreateUrlHelper() @@ -874,7 +869,7 @@ namespace Microsoft.AspNet.Mvc return new UrlHelper(actionContext, actionSelector.Object); } - private static UrlHelper CreateUrlHelper(IScopedInstance contextAccessor) + private static UrlHelper CreateUrlHelper(IActionContextAccessor contextAccessor) { var actionSelector = new Mock(MockBehavior.Strict); return new UrlHelper(contextAccessor, actionSelector.Object); diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/ModelBindingTestHelper.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/ModelBindingTestHelper.cs index 65ec766e19..a7fe7139e4 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/ModelBindingTestHelper.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/ModelBindingTestHelper.cs @@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests var httpContext = GetHttpContext(updateRequest, updateOptions); var services = httpContext.RequestServices; - var actionBindingContext = services.GetRequiredService>().Value; + var actionBindingContext = services.GetRequiredService().ActionBindingContext; return new OperationBindingContext() { @@ -77,8 +77,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests var actionContext = new ActionContext(httpContext, new RouteData(), new ControllerActionDescriptor()); var actionContextAccessor = - httpContext.RequestServices.GetRequiredService>(); - actionContextAccessor.Value = actionContext; + httpContext.RequestServices.GetRequiredService(); + actionContextAccessor.ActionContext = actionContext; var options = new TestMvcOptions().Options; if (updateOptions != null) @@ -87,8 +87,8 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests } var actionBindingContextAccessor = - httpContext.RequestServices.GetRequiredService>(); - actionBindingContextAccessor.Value = GetActionBindingContext(options, actionContext); + httpContext.RequestServices.GetRequiredService(); + actionBindingContextAccessor.ActionBindingContext = GetActionBindingContext(options, actionContext); } private static ActionBindingContext GetActionBindingContext(MvcOptions options, ActionContext actionContext) diff --git a/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs b/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs index 07fa780584..f107438e27 100644 --- a/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs +++ b/test/Microsoft.AspNet.Mvc.IntegrationTests/MutableObjectModelBinderIntegrationTest.cs @@ -272,7 +272,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public string Name { get; set; } [FromServices] - public IScopedInstance BindingContext { get; set; } + public IActionBindingContextAccessor BindingContext { get; set; } } [Fact] @@ -1528,7 +1528,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests public Address1 Address { get; set; } [FromServices] - public IScopedInstance BindingContext { get; set; } + public IActionBindingContextAccessor BindingContext { get; set; } } // If a nested POCO object has all properties bound from a greedy source, then it should be populated diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs index 8d6f8ae022..75a87abcc0 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs @@ -536,7 +536,7 @@ namespace Microsoft.AspNet.Mvc return builder; } - private static IScopedInstance GetContextAccessor( + private static IActionContextAccessor GetContextAccessor( IServiceProvider serviceProvider, RouteData routeData = null) { @@ -557,12 +557,12 @@ namespace Microsoft.AspNet.Mvc } var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor()); - var contextAccessor = new Mock>(); - contextAccessor - .SetupGet(accessor => accessor.Value) - .Returns(actionContext); + var contextAccessor = new ActionContextAccessor() + { + ActionContext = actionContext, + }; - return contextAccessor.Object; + return contextAccessor; } private static ServiceCollection GetServiceCollection() diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/BadRequestErrorMessageResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/BadRequestErrorMessageResultTest.cs index a85486005e..33d4c21ba2 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/BadRequestErrorMessageResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/BadRequestErrorMessageResultTest.cs @@ -72,15 +72,10 @@ namespace System.Web.Http var optionsAccessor = new Mock>(); optionsAccessor.SetupGet(o => o.Options) .Returns(options); - - var mockActionBindingContext = new Mock>(); - var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; - mockActionBindingContext - .SetupGet(o => o.Value) - .Returns(bindingContext); - - services.Setup(o => o.GetService(typeof(IScopedInstance))) - .Returns(mockActionBindingContext.Object); + + var actionBindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; + services.Setup(o => o.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext }); services.Setup(s => s.GetService(typeof(IOptions))) .Returns(optionsAccessor.Object); diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/ExceptionResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/ExceptionResultTest.cs index 950c74d48b..bb81c934d0 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/ExceptionResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/ExceptionResultTest.cs @@ -73,14 +73,9 @@ namespace System.Web.Http optionsAccessor.SetupGet(o => o.Options) .Returns(options); - var mockActionBindingContext = new Mock>(); - var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; - mockActionBindingContext - .SetupGet(o => o.Value) - .Returns(bindingContext); - - services.Setup(o => o.GetService(typeof(IScopedInstance))) - .Returns(mockActionBindingContext.Object); + var actionBindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; + services.Setup(o => o.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext }); services.Setup(s => s.GetService(typeof(IOptions))) .Returns(optionsAccessor.Object); diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/InvalidModelStateResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/InvalidModelStateResultTest.cs index b50453f498..96ef43adf0 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/InvalidModelStateResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/InvalidModelStateResultTest.cs @@ -86,15 +86,9 @@ namespace System.Web.Http optionsAccessor.SetupGet(o => o.Options) .Returns(options); - var mockActionBindingContext = new Mock>(); - - var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; - mockActionBindingContext - .SetupGet(o => o.Value) - .Returns(bindingContext); - - services.Setup(o => o.GetService(typeof(IScopedInstance))) - .Returns(mockActionBindingContext.Object); + var actionBindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; + services.Setup(o => o.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext }); services.Setup(s => s.GetService(typeof(IOptions))) .Returns(optionsAccessor.Object); diff --git a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/NegotiatedContentResultTest.cs b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/NegotiatedContentResultTest.cs index acefd3435e..8d2ace76c8 100644 --- a/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/NegotiatedContentResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.WebApiCompatShimTest/ActionResults/NegotiatedContentResultTest.cs @@ -74,14 +74,9 @@ namespace System.Web.Http optionsAccessor.SetupGet(o => o.Options) .Returns(options); - var mockActionBindingContext = new Mock>(); - var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; - mockActionBindingContext - .SetupGet(o => o.Value) - .Returns(bindingContext); - - services.Setup(o => o.GetService(typeof(IScopedInstance))) - .Returns(mockActionBindingContext.Object); + var actionBindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters }; + services.Setup(o => o.GetService(typeof(IActionBindingContextAccessor))) + .Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext }); services.Setup(s => s.GetService(typeof(IOptions))) .Returns(optionsAccessor.Object); diff --git a/test/WebSites/RoutingWebSite/TestResponseGenerator.cs b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs index 26a7c95d22..769f6d0f34 100644 --- a/test/WebSites/RoutingWebSite/TestResponseGenerator.cs +++ b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs @@ -14,9 +14,9 @@ namespace RoutingWebSite { private readonly ActionContext _actionContext; - public TestResponseGenerator(IScopedInstance contextAccessor) + public TestResponseGenerator(IActionContextAccessor contextAccessor) { - _actionContext = contextAccessor.Value; + _actionContext = contextAccessor.ActionContext; if (_actionContext == null) { throw new InvalidOperationException("ActionContext should not be null here."); diff --git a/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs b/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs index a15796d68b..74ebffdb4e 100644 --- a/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs +++ b/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs @@ -4,7 +4,6 @@ using System; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc; -using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.OptionsModel; namespace UrlHelperWebSite @@ -19,12 +18,14 @@ namespace UrlHelperWebSite private readonly IOptions _appOptions; private readonly HttpContext _httpContext; - public CustomUrlHelper(IScopedInstance contextAccessor, IActionSelector actionSelector, - IOptions appOptions) + public CustomUrlHelper( + IActionContextAccessor contextAccessor, + IActionSelector actionSelector, + IOptions appOptions) : base(contextAccessor, actionSelector) { _appOptions = appOptions; - _httpContext = contextAccessor.Value.HttpContext; + _httpContext = contextAccessor.ActionContext.HttpContext; } /// diff --git a/test/WebSites/VersioningWebSite/TestResponseGenerator.cs b/test/WebSites/VersioningWebSite/TestResponseGenerator.cs index 57e2521b0a..808040f235 100644 --- a/test/WebSites/VersioningWebSite/TestResponseGenerator.cs +++ b/test/WebSites/VersioningWebSite/TestResponseGenerator.cs @@ -14,9 +14,9 @@ namespace VersioningWebSite { private readonly ActionContext _actionContext; - public TestResponseGenerator(IScopedInstance contextAccessor) + public TestResponseGenerator(IActionContextAccessor contextAccessor) { - _actionContext = contextAccessor.Value; + _actionContext = contextAccessor.ActionContext; if (_actionContext == null) { throw new InvalidOperationException("ActionContext should not be null here.");