Remove IScopedInstance - use AsyncLocal for ActionContext and

ActionBindingContext

This change replaces IScopedInstance<T> 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.
This commit is contained in:
Ryan Nowak 2015-07-23 17:30:46 -07:00
parent ecfbdf2ae1
commit 89a8d0e36c
40 changed files with 311 additions and 371 deletions

View File

@ -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<ActionBindingContext> _storage = new AsyncLocal<ActionBindingContext>();
public ActionBindingContext ActionBindingContext
{
get { return _storage.Value; }
set { _storage.Value = value; }
}
#endif
}
}

View File

@ -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<ActionContext> _storage = new AsyncLocal<ActionContext>();
public ActionContext ActionContext
{
get { return _storage.Value; }
set { _storage.Value = value; }
}
#endif
}
}

View File

@ -30,8 +30,8 @@ namespace Microsoft.AspNet.Mvc.Core
[NotNull] IReadOnlyList<IModelBinder> modelBinders,
[NotNull] IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
[NotNull] IReadOnlyList<IValueProviderFactory> valueProviderFactories,
[NotNull] IScopedInstance<ActionBindingContext> 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;

View File

@ -21,16 +21,16 @@ namespace Microsoft.AspNet.Mvc.Core
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
private readonly IScopedInstance<ActionBindingContext> _actionBindingContextAccessor;
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly int _maxModelValidationErrors;
private readonly ILoggerFactory _loggerFactory;
private readonly ILogger _logger;
public ControllerActionInvokerProvider(
IControllerFactory controllerFactory,
IEnumerable<IFilterProvider> filterProviders,
IControllerActionArgumentBinder argumentBinder,
IOptions<MvcOptions> optionsAccessor,
IScopedInstance<ActionBindingContext> 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<ControllerActionInvoker>();
}
public int Order
@ -70,7 +71,7 @@ namespace Microsoft.AspNet.Mvc.Core
_modelValidatorProviders,
_valueProviderFactories,
_actionBindingContextAccessor,
_loggerFactory,
_logger,
_maxModelValidationErrors);
}
}

View File

@ -12,12 +12,15 @@ namespace Microsoft.AspNet.Mvc
{
public class DefaultControllerPropertyActivator : IControllerPropertyActivator
{
private readonly ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]> _activateActions;
private readonly Func<Type, PropertyActivator<ActionContext>[]> _getPropertiesToActivate;
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly ConcurrentDictionary<Type, PropertyActivator<Contexts>[]> _activateActions;
private readonly Func<Type, PropertyActivator<Contexts>[]> _getPropertiesToActivate;
public DefaultControllerPropertyActivator()
public DefaultControllerPropertyActivator(IActionBindingContextAccessor actionBindingContextAccessor)
{
_activateActions = new ConcurrentDictionary<Type, PropertyActivator<ActionContext>[]>();
_actionBindingContextAccessor = actionBindingContextAccessor;
_activateActions = new ConcurrentDictionary<Type, PropertyActivator<Contexts>[]>();
_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<ActionContext>[] GetPropertiesToActivate(Type type)
private PropertyActivator<Contexts>[] GetPropertiesToActivate(Type type)
{
IEnumerable<PropertyActivator<ActionContext>> activators;
activators = PropertyActivator<ActionContext>.GetPropertiesToActivate(
IEnumerable<PropertyActivator<Contexts>> activators;
activators = PropertyActivator<Contexts>.GetPropertiesToActivate(
type,
typeof(ActionContextAttribute),
p => new PropertyActivator<ActionContext>(p, c => c));
p => new PropertyActivator<Contexts>(p, c => c.ActionContext));
activators = activators.Concat(PropertyActivator<ActionContext>.GetPropertiesToActivate(
activators = activators.Concat(PropertyActivator<Contexts>.GetPropertiesToActivate(
type,
typeof(ActionBindingContextAttribute),
p => new PropertyActivator<ActionContext>(p, GetActionBindingContext)));
p => new PropertyActivator<Contexts>(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<IScopedInstance<ActionBindingContext>>();
return accessor.Value;
public ActionBindingContext ActionBindingContext;
public ActionContext ActionContext;
}
}
}

View File

@ -104,8 +104,8 @@ namespace Microsoft.Framework.DependencyInjection
//
// Action Invoker
//
// These two access per-request services
services.TryAddTransient<IActionInvokerFactory, ActionInvokerFactory>();
// The IActionInvokerFactory is cachable
services.TryAddSingleton<IActionInvokerFactory, ActionInvokerFactory>();
services.TryAddEnumerable(
ServiceDescriptor.Transient<IActionInvokerProvider, ControllerActionInvokerProvider>());
@ -136,8 +136,9 @@ namespace Microsoft.Framework.DependencyInjection
//
services.TryAddSingleton<MvcMarkerService, MvcMarkerService>();
services.TryAddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>();
services.TryAddScoped(typeof(IScopedInstance<>), typeof(ScopedInstance<>));
services.TryAddScoped<IUrlHelper, UrlHelper>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.TryAddSingleton<IActionBindingContextAccessor, ActionBindingContextAccessor>();
services.TryAddSingleton<IUrlHelper, UrlHelper>();
}
private static void ConfigureDefaultServices(IServiceCollection services)

View File

@ -22,7 +22,7 @@ namespace Microsoft.AspNet.Mvc.Core
private readonly IReadOnlyList<IOutputFormatter> _outputFormatters;
private readonly IReadOnlyList<IModelValidatorProvider> _modelValidatorProviders;
private readonly IReadOnlyList<IValueProviderFactory> _valueProviderFactories;
private readonly IScopedInstance<ActionBindingContext> _actionBindingContextAccessor;
private readonly IActionBindingContextAccessor _actionBindingContextAccessor;
private readonly ILogger _logger;
private readonly int _maxModelValidationErrors;
@ -61,8 +61,8 @@ namespace Microsoft.AspNet.Mvc.Core
[NotNull] IReadOnlyList<IModelBinder> modelBinders,
[NotNull] IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
[NotNull] IReadOnlyList<IValueProviderFactory> valueProviderFactories,
[NotNull] IScopedInstance<ActionBindingContext> 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<FilterActionInvoker>();
_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);

View File

@ -21,11 +21,11 @@ namespace Microsoft.AspNet.Mvc
/// Initializes an instance of <see cref="FormatFilter"/>.
/// </summary>
/// <param name="options">The <see cref="IOptions{MvcOptions}"/></param>
/// <param name="actionContext">The <see cref="IScopedInstance{ActionContext}"/></param>
public FormatFilter(IOptions<MvcOptions> options, IScopedInstance<ActionContext> actionContext)
/// <param name="actionContextAccessor">The <see cref="IActionContextAccessor"/></param>
public FormatFilter(IOptions<MvcOptions> options, IActionContextAccessor actionContextAccessor)
{
IsActive = true;
Format = GetFormat(actionContext.Value);
Format = GetFormat(actionContextAccessor.ActionContext);
if (string.IsNullOrEmpty(Format))
{

View File

@ -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; }
}
}

View File

@ -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; }
}
}

View File

@ -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<TValue> : IDisposable
{
TValue Value { get; set; }
}
}

View File

@ -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<IActionSelector>();
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<IActionSelector>();
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<IScopedInstance<ActionContext>>();
contextAccessor.Value = actionContext;
var invokerFactory = services.GetRequiredService<IActionInvokerFactory>();
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<IActionContextAccessor>();
}
if (_actionInvokerFactory == null)
{
_actionInvokerFactory = context.RequestServices.GetRequiredService<IActionInvokerFactory>();
}
if (_actionSelector == null)
{
_actionSelector = context.RequestServices.GetRequiredService<IActionSelector>();
}
if (_logger == null)
{
var factory = context.RequestServices.GetRequiredService<ILoggerFactory>();
_logger = factory.CreateLogger<MvcRouteHandler>();
}
}
private void EnsureNotifier(HttpContext context)
{
if (_notifier == null)
{
_notifier = context.RequestServices.GetRequiredService<INotifier>();

View File

@ -297,8 +297,8 @@ namespace Microsoft.AspNet.Mvc
var actionBindingContext = context
.HttpContext
.RequestServices
.GetRequiredService<IScopedInstance<ActionBindingContext>>()
.Value;
.GetRequiredService<IActionBindingContextAccessor>()
.ActionBindingContext;
// In scenarios where there is a resource filter which directly shortcircuits using an ObjectResult.
// actionBindingContext is not setup yet and is null.

View File

@ -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<T> : IScopedInstance<T>
{
public T Value { get; set; }
public void Dispose()
{
var disposable = Value as IDisposable;
if (disposable != null)
{
disposable.Dispose();
}
}
}
}

View File

@ -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
/// </summary>
public class UrlHelper : IUrlHelper
{
private readonly HttpContext _httpContext;
private readonly IRouter _router;
private readonly IDictionary<string, object> _ambientValues;
private readonly IActionContextAccessor _actionContextAccessor;
private readonly IActionSelector _actionSelector;
/// <summary>
/// Initializes a new instance of the <see cref="UrlHelper"/> class using the specified action context and
/// action selector.
/// </summary>
/// <param name="contextAccessor">The <see cref="IScopedInstance{TContext}"/> to access the action context
/// <param name="actionContextAccessor">The <see cref="IActionContextAccessor"/> to access the action context
/// of the current request.</param>
/// <param name="actionSelector">The <see cref="IActionSelector"/> to be used for verifying the correctness of
/// supplied parameters for a route.
/// </param>
public UrlHelper(IScopedInstance<ActionContext> 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<string, object> AmbientValues => ActionContext.RouteData.Values;
protected ActionContext ActionContext => _actionContextAccessor.ActionContext;
protected HttpContext HttpContext => ActionContext.HttpContext;
protected IRouter Router => ActionContext.RouteData.Routers[0];
/// <inheritdoc />
public virtual string Action(UrlActionContext actionContext)
{
@ -98,8 +101,8 @@ namespace Microsoft.AspNet.Mvc
/// <returns>The absolute path of the URL.</returns>
protected virtual string GeneratePathFromRoute(string routeName, IDictionary<string, object> 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;

View File

@ -2040,8 +2040,8 @@ namespace Microsoft.AspNet.Mvc
new IModelBinder[0],
new IModelValidatorProvider[0],
new IValueProviderFactory[0],
new MockScopedInstance<ActionBindingContext>(),
new NullLoggerFactory(),
new ActionBindingContextAccessor(),
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
maxAllowedErrorsInModelState);
return invoker;
@ -2102,8 +2102,8 @@ namespace Microsoft.AspNet.Mvc
new IModelBinder[] { binder.Object },
new IModelValidatorProvider[0],
new IValueProviderFactory[0],
new MockScopedInstance<ActionBindingContext>(),
new NullLoggerFactory(),
new ActionBindingContextAccessor(),
new NullLoggerFactory().CreateLogger<ControllerActionInvoker>(),
200);
// Act
@ -2202,8 +2202,8 @@ namespace Microsoft.AspNet.Mvc
IReadOnlyList<IModelBinder> modelBinders,
IReadOnlyList<IModelValidatorProvider> modelValidatorProviders,
IReadOnlyList<IValueProviderFactory> valueProviderFactories,
IScopedInstance<ActionBindingContext> 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;

View File

@ -102,13 +102,12 @@ namespace Microsoft.AspNet.Mvc
services.Setup(s => s.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
var mockContextAccessor = new Mock<IScopedInstance<ActionBindingContext>>();
mockContextAccessor
.SetupGet(o => o.Value)
.Returns(new ActionBindingContext() { OutputFormatters = optionsAccessor.Options.OutputFormatters });
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.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;
}

View File

@ -110,14 +110,8 @@ namespace Microsoft.AspNet.Mvc
httpContext.Setup(o => o.Response)
.Returns(response);
var mockContextAccessor = new Mock<IScopedInstance<ActionBindingContext>>();
mockContextAccessor
.SetupGet(o => o.Value)
.Returns((ActionBindingContext)null);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.Returns(mockContextAccessor.Object);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IActionBindingContextAccessor)))
.Returns(new ActionBindingContextAccessor());
return httpContext.Object;
}

View File

@ -97,13 +97,13 @@ namespace Microsoft.AspNet.Mvc
.Setup(p => p.RequestServices.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
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<ActionBindingContext>)))
.Returns(mockActionBindingContext.Object);
.Setup(o => o.RequestServices.GetService(typeof(IActionBindingContextAccessor)))
.Returns(new ActionBindingContextAccessor() { ActionBindingContext = actionBindingContext });
return httpContext.Object;
}

View File

@ -102,7 +102,7 @@ namespace Microsoft.AspNet.Mvc.Core
var bindingContext = new ActionBindingContext();
var services = GetServices();
services.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value = bindingContext;
services.GetRequiredService<IActionBindingContextAccessor>().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<ActionBindingContext>)))
.Returns(new MockScopedInstance<ActionBindingContext>());
services.Setup(s => s.GetService(typeof(ITempDataDictionary)))
.Returns(new Mock<ITempDataDictionary>().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<IControllerActivator>();
var propertyActivators = new IControllerPropertyActivator[]
{
new DefaultControllerPropertyActivator(),
new DefaultControllerPropertyActivator(new ActionBindingContextAccessor()),
};
return new DefaultControllerFactory(controllerActivator, propertyActivators);

View File

@ -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<ActionContext> ScopedInstance { get; private set; }
public IActionContextAccessor ActionContextAccessor { get; private set; }
public IOptions<MvcOptions> 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<IScopedInstance<ActionContext>>();
scopedInstance.Setup(s => s.Value).Returns(MockActionContext);
ScopedInstance = scopedInstance.Object;
ActionContextAccessor = new ActionContextAccessor()
{
ActionContext = MockActionContext,
};
}
}
#endif

View File

@ -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<IScopedInstance<ActionBindingContext>>();
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<ActionBindingContext>)))
.Returns(mockContextAccessor.Object);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IActionBindingContextAccessor)))
.Returns(actionBindingContextAccessor);
httpContext.Setup(o => o.RequestServices.GetService(typeof(IOptions<MvcOptions>)))
.Returns(optionsAccessor);
httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger<ObjectResult>)))

View File

@ -81,11 +81,11 @@ namespace Microsoft.AspNet.Mvc
{
OutputFormatters = optionsAccessor.Options.OutputFormatters,
};
var bindingContextAccessor = new MockScopedInstance<ActionBindingContext>
var bindingContextAccessor = new ActionBindingContextAccessor
{
Value = bindingContext,
ActionBindingContext = bindingContext,
};
services.Add(new ServiceDescriptor(typeof(IScopedInstance<ActionBindingContext>), bindingContextAccessor));
services.Add(new ServiceDescriptor(typeof(IActionBindingContextAccessor), bindingContextAccessor));
return services.BuildServiceProvider();
}

View File

@ -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<T> : IScopedInstance<T>
{
public T Value { get; set; }
public void Dispose()
{
}
}
}

View File

@ -290,25 +290,6 @@ namespace Microsoft.AspNet.Mvc.ModelBinding
return bindingContext;
}
private static IScopedInstance<ActionContext> CreateActionContext(HttpContext context)
{
return CreateActionContext(context, (new Mock<IRouter>()).Object);
}
private static IScopedInstance<ActionContext> 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<IScopedInstance<ActionContext>>();
contextAccessor.SetupGet(c => c.Value)
.Returns(actionContext);
return contextAccessor.Object;
}
private class Person
{
public string Name { get; set; }

View File

@ -205,8 +205,6 @@ namespace Microsoft.AspNet.Mvc
IOptions<MvcOptions> optionsAccessor = null,
object notificationListener = null)
{
var mockContextAccessor = new Mock<IScopedInstance<ActionContext>>();
if (actionDescriptor == null)
{
var mockAction = new Mock<ActionDescriptor>();
@ -252,8 +250,8 @@ namespace Microsoft.AspNet.Mvc
}
var httpContext = new Mock<HttpContext>();
httpContext.Setup(h => h.RequestServices.GetService(typeof(IScopedInstance<ActionContext>)))
.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)))

View File

@ -904,20 +904,14 @@ namespace Microsoft.AspNet.Mvc.Core.Test.ActionResults
httpContext.Setup(o => o.RequestServices.GetService(typeof(ILogger<ObjectResult>)))
.Returns(new Mock<ILogger<ObjectResult>>().Object);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
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<ActionBindingContext>)))
.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());
}

View File

@ -115,10 +115,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
{
var httpContext = new Mock<HttpContext>();
var actionContext = GetActionContext(httpContext.Object);
var mockContentAccessor = new Mock<IScopedInstance<ActionContext>>();
mockContentAccessor.SetupGet(o => o.Value).Returns(actionContext);
var actionContextAccessor = new ActionContextAccessor() { ActionContext = actionContext };
var mockActionSelector = new Mock<IActionSelector>();
var urlHelper = new UrlHelper(mockContentAccessor.Object, mockActionSelector.Object);
var urlHelper = new UrlHelper(actionContextAccessor, mockActionSelector.Object);
var serviceProvider = GetServiceProvider(urlHelper);
httpContext.Setup(o => o.Response)

View File

@ -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<Disposable>
{
Value = disposable,
};
// Act
scopedInstance.Dispose();
// Assert
Assert.True(disposable.IsDisposed);
}
[Fact]
public void ScopedInstanceDoesNotThrowOnNonIDisposable()
{
// Arrange
var scopedInstance = new ScopedInstance<object>()
{
Value = new object(),
};
// Act
scopedInstance.Dispose();
}
[Fact]
public void ScopedInstanceDoesNotThrowOnNull()
{
// Arrange
var scopedInstance = new ScopedInstance<Disposable>()
{
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;
}
}
}
}

View File

@ -820,23 +820,18 @@ namespace Microsoft.AspNet.Mvc
return context;
}
private static IScopedInstance<ActionContext> CreateActionContext(HttpContext context)
private static IActionContextAccessor CreateActionContext(HttpContext context)
{
return CreateActionContext(context, (new Mock<IRouter>()).Object);
}
private static IScopedInstance<ActionContext> 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<IScopedInstance<ActionContext>>();
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<ActionContext> contextAccessor)
private static UrlHelper CreateUrlHelper(IActionContextAccessor contextAccessor)
{
var actionSelector = new Mock<IActionSelector>(MockBehavior.Strict);
return new UrlHelper(contextAccessor, actionSelector.Object);

View File

@ -35,7 +35,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
var httpContext = GetHttpContext(updateRequest, updateOptions);
var services = httpContext.RequestServices;
var actionBindingContext = services.GetRequiredService<IScopedInstance<ActionBindingContext>>().Value;
var actionBindingContext = services.GetRequiredService<IActionBindingContextAccessor>().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<IScopedInstance<ActionContext>>();
actionContextAccessor.Value = actionContext;
httpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
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<IScopedInstance<ActionBindingContext>>();
actionBindingContextAccessor.Value = GetActionBindingContext(options, actionContext);
httpContext.RequestServices.GetRequiredService<IActionBindingContextAccessor>();
actionBindingContextAccessor.ActionBindingContext = GetActionBindingContext(options, actionContext);
}
private static ActionBindingContext GetActionBindingContext(MvcOptions options, ActionContext actionContext)

View File

@ -272,7 +272,7 @@ namespace Microsoft.AspNet.Mvc.IntegrationTests
public string Name { get; set; }
[FromServices]
public IScopedInstance<ActionBindingContext> 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<ActionBindingContext> 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

View File

@ -536,7 +536,7 @@ namespace Microsoft.AspNet.Mvc
return builder;
}
private static IScopedInstance<ActionContext> 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<IScopedInstance<ActionContext>>();
contextAccessor
.SetupGet(accessor => accessor.Value)
.Returns(actionContext);
var contextAccessor = new ActionContextAccessor()
{
ActionContext = actionContext,
};
return contextAccessor.Object;
return contextAccessor;
}
private static ServiceCollection GetServiceCollection()

View File

@ -72,15 +72,10 @@ namespace System.Web.Http
var optionsAccessor = new Mock<IOptions<MvcOptions>>();
optionsAccessor.SetupGet(o => o.Options)
.Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.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<MvcOptions>)))
.Returns(optionsAccessor.Object);

View File

@ -73,14 +73,9 @@ namespace System.Web.Http
optionsAccessor.SetupGet(o => o.Options)
.Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.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<MvcOptions>)))
.Returns(optionsAccessor.Object);

View File

@ -86,15 +86,9 @@ namespace System.Web.Http
optionsAccessor.SetupGet(o => o.Options)
.Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.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<MvcOptions>)))
.Returns(optionsAccessor.Object);

View File

@ -74,14 +74,9 @@ namespace System.Web.Http
optionsAccessor.SetupGet(o => o.Options)
.Returns(options);
var mockActionBindingContext = new Mock<IScopedInstance<ActionBindingContext>>();
var bindingContext = new ActionBindingContext { OutputFormatters = options.OutputFormatters };
mockActionBindingContext
.SetupGet(o => o.Value)
.Returns(bindingContext);
services.Setup(o => o.GetService(typeof(IScopedInstance<ActionBindingContext>)))
.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<MvcOptions>)))
.Returns(optionsAccessor.Object);

View File

@ -14,9 +14,9 @@ namespace RoutingWebSite
{
private readonly ActionContext _actionContext;
public TestResponseGenerator(IScopedInstance<ActionContext> contextAccessor)
public TestResponseGenerator(IActionContextAccessor contextAccessor)
{
_actionContext = contextAccessor.Value;
_actionContext = contextAccessor.ActionContext;
if (_actionContext == null)
{
throw new InvalidOperationException("ActionContext should not be null here.");

View File

@ -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> _appOptions;
private readonly HttpContext _httpContext;
public CustomUrlHelper(IScopedInstance<ActionContext> contextAccessor, IActionSelector actionSelector,
IOptions<AppOptions> appOptions)
public CustomUrlHelper(
IActionContextAccessor contextAccessor,
IActionSelector actionSelector,
IOptions<AppOptions> appOptions)
: base(contextAccessor, actionSelector)
{
_appOptions = appOptions;
_httpContext = contextAccessor.Value.HttpContext;
_httpContext = contextAccessor.ActionContext.HttpContext;
}
/// <summary>

View File

@ -14,9 +14,9 @@ namespace VersioningWebSite
{
private readonly ActionContext _actionContext;
public TestResponseGenerator(IScopedInstance<ActionContext> contextAccessor)
public TestResponseGenerator(IActionContextAccessor contextAccessor)
{
_actionContext = contextAccessor.Value;
_actionContext = contextAccessor.ActionContext;
if (_actionContext == null)
{
throw new InvalidOperationException("ActionContext should not be null here.");