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:
parent
ecfbdf2ae1
commit
89a8d0e36c
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
}
|
||||
}
|
||||
|
|
@ -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>();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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>)))
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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; }
|
||||
|
|
|
|||
|
|
@ -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)))
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
|
|
|
|||
Loading…
Reference in New Issue