Remove IActionContextAccessor from UrlHelper

This change removes the IActionContextAccessor as a dependency of
UrlHelper, and shifts UrlHelper to use a factory pattern. Consumers of
IUrlHelper should create an instance using the factory when needed.

This is the last part of MVC that has a dependency on IActionContext
accessor. As part of this change we no longer register it by default, and
treat it as an optional component.
This commit is contained in:
Ryan Nowak 2015-11-18 19:18:04 -08:00
parent 3062eea7d0
commit 9fc3a80056
49 changed files with 552 additions and 252 deletions

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
@ -67,7 +68,13 @@ namespace Microsoft.AspNet.Mvc
base.OnFormatting(context);
var request = context.HttpContext.Request;
var urlHelper = UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = UrlHelper;
if (urlHelper == null)
{
var services = context.HttpContext.RequestServices;
urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
}
var url = urlHelper.Action(
ActionName,

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
@ -69,7 +70,12 @@ namespace Microsoft.AspNet.Mvc
base.OnFormatting(context);
var urlHelper = UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = UrlHelper;
if (urlHelper == null)
{
var services = context.HttpContext.RequestServices;
urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
}
var url = urlHelper.Link(RouteName, RouteValues);

View File

@ -137,8 +137,7 @@ namespace Microsoft.Extensions.DependencyInjection
//
services.TryAddSingleton<MvcMarkerService, MvcMarkerService>();
services.TryAddSingleton<ITypeActivatorCache, DefaultTypeActivatorCache>();
services.TryAddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.TryAddSingleton<IUrlHelper, UrlHelper>();
services.TryAddSingleton<IUrlHelperFactory, UrlHelperFactory>();
services.TryAddSingleton<IHttpRequestStreamReaderFactory, MemoryPoolHttpRequestStreamReaderFactory>();
services.TryAddSingleton<IHttpResponseStreamWriterFactory, MemoryPoolHttpResponseStreamWriterFactory>();
services.TryAddSingleton<IArraySegmentPool<byte>, DefaultArraySegmentPool<byte>>();

View File

@ -19,6 +19,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
{
public class MvcRouteHandler : IRouter
{
private bool _servicesRetrieved;
private IActionContextAccessor _actionContextAccessor;
private IActionInvokerFactory _actionInvokerFactory;
private IActionSelector _actionSelector;
@ -109,7 +111,11 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
private Task InvokeActionAsync(RouteContext context, ActionDescriptor actionDescriptor)
{
var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor);
_actionContextAccessor.ActionContext = actionContext;
if (_actionContextAccessor != null)
{
_actionContextAccessor.ActionContext = actionContext;
}
var invoker = _actionInvokerFactory.CreateInvoker(actionContext);
if (invoker == null)
@ -124,31 +130,23 @@ namespace Microsoft.AspNet.Mvc.Infrastructure
private void EnsureServices(HttpContext context)
{
if (_actionContextAccessor == null)
if (_servicesRetrieved)
{
_actionContextAccessor = context.RequestServices.GetRequiredService<IActionContextAccessor>();
return;
}
if (_actionInvokerFactory == null)
{
_actionInvokerFactory = context.RequestServices.GetRequiredService<IActionInvokerFactory>();
}
// The IActionContextAccessor is optional. We want to avoid the overhead of using CallContext
// if possible.
_actionContextAccessor = context.RequestServices.GetService<IActionContextAccessor>();
if (_actionSelector == null)
{
_actionSelector = context.RequestServices.GetRequiredService<IActionSelector>();
}
_actionInvokerFactory = context.RequestServices.GetRequiredService<IActionInvokerFactory>();
_actionSelector = context.RequestServices.GetRequiredService<IActionSelector>();
_diagnosticSource = context.RequestServices.GetRequiredService<DiagnosticSource>();
if (_logger == null)
{
var factory = context.RequestServices.GetRequiredService<ILoggerFactory>();
_logger = factory.CreateLogger<MvcRouteHandler>();
}
if (_diagnosticSource == null)
{
_diagnosticSource = context.RequestServices.GetRequiredService<DiagnosticSource>();
}
var factory = context.RequestServices.GetRequiredService<ILoggerFactory>();
_logger = factory.CreateLogger<MvcRouteHandler>();
_servicesRetrieved = true;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -98,7 +99,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context)
{
return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = UrlHelper;
if (urlHelper == null)
{
var services = context.HttpContext.RequestServices;
urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
}
return urlHelper;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@ -85,7 +86,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context)
{
return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = UrlHelper;
if (urlHelper == null)
{
var services = context.HttpContext.RequestServices;
urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
}
return urlHelper;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection;
@ -80,7 +81,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context)
{
return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = UrlHelper;
if (urlHelper == null)
{
var services = context.HttpContext.RequestServices;
urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
}
return urlHelper;
}
}
}

View File

@ -4,6 +4,7 @@
using System;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection;
@ -77,7 +78,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context)
{
return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = UrlHelper;
if (urlHelper == null)
{
var services = context.HttpContext.RequestServices;
urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
}
return urlHelper;
}
}
}

View File

@ -0,0 +1,18 @@
// 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.Routing
{
/// <summary>
/// A factory for creating <see cref="IUrlHelper"/> instances.
/// </summary>
public interface IUrlHelperFactory
{
/// <summary>
/// Gets an <see cref="IUrlHelper"/> for the request associated with <paramref name="context"/>.
/// </summary>
/// <param name="context">The <see cref="ActionContext"/> associated with the current request.</param>
/// <returns>An <see cref="IUrlHelper"/> for the request associated with <paramref name="context"/></returns>
IUrlHelper GetUrlHelper(ActionContext context);
}
}

View File

@ -2,12 +2,9 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNet.Mvc.Routing
{
@ -17,22 +14,27 @@ namespace Microsoft.AspNet.Mvc.Routing
/// </summary>
public class UrlHelper : IUrlHelper
{
private readonly IActionContextAccessor _actionContextAccessor;
/// <summary>
/// Initializes a new instance of the <see cref="UrlHelper"/> class using the specified action context and
/// action selector.
/// </summary>
/// <param name="actionContextAccessor">The <see cref="IActionContextAccessor"/> to access the action context
/// of the current request.</param>
public UrlHelper(IActionContextAccessor actionContextAccessor)
/// <param name="actionContext">
/// The <see cref="Mvc.ActionContext"/> for the current request.
/// </param>
public UrlHelper(ActionContext actionContext)
{
_actionContextAccessor = actionContextAccessor;
if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
ActionContext = actionContext;
}
protected RouteValueDictionary AmbientValues => ActionContext.RouteData.Values;
protected ActionContext ActionContext => _actionContextAccessor.ActionContext;
protected ActionContext ActionContext { get; }
protected HttpContext HttpContext => ActionContext.HttpContext;

View File

@ -0,0 +1,17 @@
// 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.Routing
{
/// <summary>
/// A default implementation of <see cref="IUrlHelperFactory"/>.
/// </summary>
public class UrlHelperFactory : IUrlHelperFactory
{
/// <inheritdoc />
public IUrlHelper GetUrlHelper(ActionContext context)
{
return new UrlHelper(context);
}
}
}

View File

@ -15,6 +15,7 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers;
@ -629,7 +630,9 @@ namespace Microsoft.AspNet.Mvc.Razor
if (_urlHelper == null)
{
_urlHelper = Context.RequestServices.GetRequiredService<IUrlHelper>();
var services = Context.RequestServices;
var factory = services.GetRequiredService<IUrlHelperFactory>();
_urlHelper = factory.GetUrlHelper(ViewContext);
}
return _urlHelper.Content(contentPath);

View File

@ -7,6 +7,7 @@ using System.Reflection;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.DependencyInjection;
@ -111,20 +112,29 @@ namespace Microsoft.AspNet.Mvc.Razor
{
valueAccessor = context => context.ViewData;
}
else if (typeof(IUrlHelper).IsAssignableFrom(property.PropertyType))
{
valueAccessor = context =>
{
var serviceProvider = context.HttpContext.RequestServices;
var factory = (IUrlHelperFactory)serviceProvider.GetRequiredService(typeof(IUrlHelperFactory));
return factory.GetUrlHelper(context);
};
}
else
{
valueAccessor = context =>
{
var serviceProvider = context.HttpContext.RequestServices;
var value = serviceProvider.GetRequiredService(property.PropertyType);
var canHasViewContext = value as ICanHasViewContext;
if (canHasViewContext != null)
{
canHasViewContext.Contextualize(context);
}
{
var serviceProvider = context.HttpContext.RequestServices;
var value = serviceProvider.GetRequiredService(property.PropertyType);
var canHasViewContext = value as ICanHasViewContext;
if (canHasViewContext != null)
{
canHasViewContext.Contextualize(context);
}
return value;
};
return value;
};
}
return new PropertyActivator<ViewContext>(property, valueAccessor);

View File

@ -7,6 +7,8 @@ using System.ComponentModel;
using System.Reflection;
using System.Text.Encodings.Web;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
@ -83,11 +85,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
/// <summary>
/// Creates a new <see cref="UrlResolutionTagHelper"/>.
/// </summary>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="urlHelper">The <see cref="IUrlHelperFactory"/>.</param>
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
public UrlResolutionTagHelper(IUrlHelper urlHelper, HtmlEncoder htmlEncoder)
public UrlResolutionTagHelper(IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder)
{
UrlHelper = urlHelper;
UrlHelperFactory = urlHelperFactory;
HtmlEncoder = htmlEncoder;
}
@ -100,10 +102,14 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
}
}
protected IUrlHelper UrlHelper { get; }
protected IUrlHelperFactory UrlHelperFactory { get; }
protected HtmlEncoder HtmlEncoder { get; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
/// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output)
{
@ -202,7 +208,8 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
// Before doing more work, ensure that the URL we're looking at is app relative.
if (trimmedUrl.Length >= 2 && trimmedUrl[0] == '~' && trimmedUrl[1] == '/')
{
var appRelativeUrl = UrlHelper.Content(trimmedUrl);
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
var appRelativeUrl = urlHelper.Content(trimmedUrl);
if (encodeWebRoot)
{

View File

@ -115,6 +115,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
}
}
/// <summary>
/// Gets or sets the <see cref="Rendering.ViewContext"/> for the current request.
/// </summary>
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
/// <inheritdoc />
/// <remarks>Does nothing if user provides an <c>href</c> attribute.</remarks>
/// <exception cref="InvalidOperationException">
@ -177,6 +184,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
if (Route == null)
{
tagBuilder = Generator.GenerateActionLink(
ViewContext,
linkText: string.Empty,
actionName: Action,
controllerName: Controller,
@ -200,6 +208,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
else
{
tagBuilder = Generator.GenerateRouteLink(
ViewContext,
linkText: string.Empty,
routeName: Route,
protocol: Protocol,

View File

@ -6,6 +6,7 @@ using System.Text.Encodings.Web;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor.TagHelpers;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers;
@ -37,13 +38,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// </summary>
/// <param name="hostingEnvironment">The <see cref="IHostingEnvironment"/>.</param>
/// <param name="cache">The <see cref="IMemoryCache"/>.</param>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
public ImageTagHelper(
IHostingEnvironment hostingEnvironment,
IMemoryCache cache,
HtmlEncoder htmlEncoder,
IUrlHelper urlHelper)
: base(urlHelper, htmlEncoder)
IUrlHelperFactory urlHelperFactory)
: base(urlHelperFactory, htmlEncoder)
{
HostingEnvironment = hostingEnvironment;
Cache = cache;
@ -78,10 +79,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
protected IHostingEnvironment HostingEnvironment { get; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
protected IMemoryCache Cache { get; }
/// <inheritdoc />

View File

@ -9,6 +9,7 @@ using System.Text.Encodings.Web;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor.TagHelpers;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Mvc.TagHelpers.Logging;
using Microsoft.AspNet.Mvc.ViewFeatures;
@ -94,15 +95,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <param name="cache">The <see cref="IMemoryCache"/>.</param>
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
/// <param name="javaScriptEncoder">The <see cref="JavaScriptEncoder"/>.</param>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
public LinkTagHelper(
ILogger<LinkTagHelper> logger,
IHostingEnvironment hostingEnvironment,
IMemoryCache cache,
HtmlEncoder htmlEncoder,
JavaScriptEncoder javaScriptEncoder,
IUrlHelper urlHelper)
: base(urlHelper, htmlEncoder)
IUrlHelperFactory urlHelperFactory)
: base(urlHelperFactory, htmlEncoder)
{
Logger = logger;
HostingEnvironment = hostingEnvironment;
@ -203,10 +204,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
protected IHostingEnvironment HostingEnvironment { get; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
protected IMemoryCache Cache { get; }
protected JavaScriptEncoder JavaScriptEncoder { get; }

View File

@ -7,6 +7,7 @@ using System.Text.Encodings.Web;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor.TagHelpers;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Mvc.TagHelpers.Logging;
using Microsoft.AspNet.Mvc.ViewFeatures;
@ -79,15 +80,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <param name="cache">The <see cref="IMemoryCache"/>.</param>
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
/// <param name="javaScriptEncoder">The <see cref="JavaScriptEncoder"/>.</param>
/// <param name="urlHelper">The <see cref="IUrlHelper"/>.</param>
/// <param name="urlHelperFactory">The <see cref="IUrlHelperFactory"/>.</param>
public ScriptTagHelper(
ILogger<ScriptTagHelper> logger,
IHostingEnvironment hostingEnvironment,
IMemoryCache cache,
HtmlEncoder htmlEncoder,
JavaScriptEncoder javaScriptEncoder,
IUrlHelper urlHelper)
: base(urlHelper, htmlEncoder)
IUrlHelperFactory urlHelperFactory)
: base(urlHelperFactory, htmlEncoder)
{
Logger = logger;
HostingEnvironment = hostingEnvironment;
@ -170,10 +171,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
protected IHostingEnvironment HostingEnvironment { get; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
protected IMemoryCache Cache { get; }
protected JavaScriptEncoder JavaScriptEncoder { get; }

View File

@ -13,6 +13,7 @@ using Microsoft.AspNet.Http.Authentication;
using Microsoft.AspNet.Mvc.Filters;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection;
@ -166,7 +167,8 @@ namespace Microsoft.AspNet.Mvc
{
if (_url == null)
{
_url = Resolver?.GetRequiredService<IUrlHelper>();
var factory = Resolver?.GetRequiredService<IUrlHelperFactory>();
_url = factory?.GetUrlHelper(ControllerContext);
}
return _url;

View File

@ -199,7 +199,9 @@ namespace Microsoft.AspNet.Mvc
}
var services = context.ActionContext.HttpContext.RequestServices;
var urlHelper = services.GetRequiredService<IUrlHelper>();
var factory = services.GetRequiredService<IUrlHelperFactory>();
var urlHelper = factory.GetUrlHelper(context.ActionContext);
var url = urlHelper.RouteUrl(new UrlRouteContext()
{
RouteName = this.RouteName,

View File

@ -6,6 +6,7 @@ using System.Security.Principal;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewComponents;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
@ -108,7 +109,8 @@ namespace Microsoft.AspNet.Mvc
{
// May be null in unit-testing scenarios.
var services = ViewComponentContext.ViewContext?.HttpContext?.RequestServices;
_url = services?.GetRequiredService<IUrlHelper>();
var factory = services?.GetRequiredService<IUrlHelperFactory>();
_url = factory?.GetUrlHelper(ViewComponentContext.ViewContext);
}
return _url;

View File

@ -14,6 +14,7 @@ using Microsoft.AspNet.Html;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures.Internal;
using Microsoft.Extensions.OptionsModel;
@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
private readonly IAntiforgery _antiforgery;
private readonly IClientModelValidatorProvider _clientModelValidatorProvider;
private readonly IModelMetadataProvider _metadataProvider;
private readonly IUrlHelper _urlHelper;
private readonly IUrlHelperFactory _urlHelperFactory;
private readonly HtmlEncoder _htmlEncoder;
/// <summary>
@ -44,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
IAntiforgery antiforgery,
IOptions<MvcViewOptions> optionsAccessor,
IModelMetadataProvider metadataProvider,
IUrlHelper urlHelper,
IUrlHelperFactory urlHelperFactory,
HtmlEncoder htmlEncoder)
{
if (antiforgery == null)
@ -62,9 +63,9 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
throw new ArgumentNullException(nameof(metadataProvider));
}
if (urlHelper == null)
if (urlHelperFactory == null)
{
throw new ArgumentNullException(nameof(urlHelper));
throw new ArgumentNullException(nameof(urlHelperFactory));
}
if (htmlEncoder == null)
@ -76,7 +77,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
var clientValidatorProviders = optionsAccessor.Value.ClientModelValidatorProviders;
_clientModelValidatorProvider = new CompositeClientModelValidatorProvider(clientValidatorProviders);
_metadataProvider = metadataProvider;
_urlHelper = urlHelper;
_urlHelperFactory = urlHelperFactory;
_htmlEncoder = htmlEncoder;
// Underscores are fine characters in id's.
@ -106,6 +107,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// <inheritdoc />
public virtual TagBuilder GenerateActionLink(
ViewContext viewContext,
string linkText,
string actionName,
string controllerName,
@ -115,12 +117,18 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
object routeValues,
object htmlAttributes)
{
if (viewContext == null)
{
throw new ArgumentNullException(nameof(viewContext));
}
if (linkText == null)
{
throw new ArgumentNullException(nameof(linkText));
}
var url = _urlHelper.Action(actionName, controllerName, routeValues, protocol, hostname, fragment);
var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext);
var url = urlHelper.Action(actionName, controllerName, routeValues, protocol, hostname, fragment);
return GenerateLink(linkText, url, htmlAttributes);
}
@ -242,7 +250,8 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
else
{
action = _urlHelper.Action(action: actionName, controller: controllerName, values: routeValues);
var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext);
action = urlHelper.Action(action: actionName, controller: controllerName, values: routeValues);
}
return GenerateFormCore(viewContext, action, method, htmlAttributes);
@ -261,8 +270,8 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
throw new ArgumentNullException(nameof(viewContext));
}
var action =
_urlHelper.RouteUrl(routeName, values: routeValues, protocol: null, host: null, fragment: null);
var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext);
var action = urlHelper.RouteUrl(routeName, routeValues);
return GenerateFormCore(viewContext, action, method, htmlAttributes);
}
@ -444,6 +453,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
/// <inheritdoc />
public virtual TagBuilder GenerateRouteLink(
ViewContext viewContext,
string linkText,
string routeName,
string protocol,
@ -452,12 +462,18 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
object routeValues,
object htmlAttributes)
{
if (viewContext == null)
{
throw new ArgumentNullException(nameof(viewContext));
}
if (linkText == null)
{
throw new ArgumentNullException(nameof(linkText));
}
var url = _urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment);
var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext);
var url = urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment);
return GenerateLink(linkText, url, htmlAttributes);
}

View File

@ -241,6 +241,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
var tagBuilder = _htmlGenerator.GenerateActionLink(
ViewContext,
linkText,
actionName,
controllerName,
@ -630,6 +631,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
}
var tagBuilder = _htmlGenerator.GenerateRouteLink(
ViewContext,
linkText,
routeName,
protocol,

View File

@ -21,7 +21,31 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
string FormatValue(object value, string format);
/// <summary>
/// Generate a &lt;a&gt; element for a link to an action.
/// </summary>
/// <param name="viewContext">The <see cref="ViewContext"/> instance for the current scope.</param>
/// <param name="linkText">The text to insert inside the element.</param>
/// <param name="actionName">The name of the action method.</param>
/// <param name="controllerName">The name of the controller.</param>
/// <param name="protocol">The protocol (scheme) for the generated link.</param>
/// <param name="hostname">The hostname for the generated link.</param>
/// <param name="fragment">The fragment for the genrated link.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the route parameters.
/// </param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// A <see cref="TagBuilder"/> instance for the &lt;a&gt; element.
/// </returns>
TagBuilder GenerateActionLink(
ViewContext viewContext,
string linkText,
string actionName,
string controllerName,
@ -158,7 +182,30 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
bool? isChecked,
object htmlAttributes);
/// <summary>
/// Generate a &lt;a&gt; element for a link to an action.
/// </summary>
/// <param name="viewContext">The <see cref="ViewContext"/> instance for the current scope.</param>
/// <param name="linkText">The text to insert inside the element.</param>
/// <param name="routeName">The name of the route to use for link generation.</param>
/// <param name="protocol">The protocol (scheme) for the generated link.</param>
/// <param name="hostname">The hostname for the generated link.</param>
/// <param name="fragment">The fragment for the genrated link.</param>
/// <param name="routeValues">
/// An <see cref="object"/> that contains the parameters for a route. The parameters are retrieved through
/// reflection by examining the properties of the <see cref="object"/>. This <see cref="object"/> is typically
/// created using <see cref="object"/> initializer syntax. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the route parameters.
/// </param>
/// <param name="htmlAttributes">
/// An <see cref="object"/> that contains the HTML attributes for the element. Alternatively, an
/// <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>
/// A <see cref="TagBuilder"/> instance for the &lt;a&gt; element.
/// </returns>
TagBuilder GenerateRouteLink(
ViewContext viewContext,
string linkText,
string routeName,
string protocol,

View File

@ -9,6 +9,7 @@ using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.WebApiCompatShim;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers;
@ -81,7 +82,7 @@ namespace System.Web.Http
{
if (_metadataProvider == null)
{
_metadataProvider = Context?.RequestServices?.GetRequiredService<IModelMetadataProvider>();
_metadataProvider = Context?.RequestServices.GetRequiredService<IModelMetadataProvider>();
}
return _metadataProvider;
@ -101,7 +102,7 @@ namespace System.Web.Http
{
if (_objectValidator == null)
{
_objectValidator = Context?.RequestServices?.GetRequiredService<IObjectModelValidator>();
_objectValidator = Context?.RequestServices.GetRequiredService<IObjectModelValidator>();
}
return _objectValidator;
@ -155,7 +156,8 @@ namespace System.Web.Http
{
if (_urlHelper == null)
{
_urlHelper = Context?.RequestServices?.GetRequiredService<IUrlHelper>();
var factory = Context?.RequestServices.GetRequiredService<IUrlHelperFactory>();
_urlHelper = factory?.GetUrlHelper(ActionContext);
}
return _urlHelper;

View File

@ -99,10 +99,10 @@ namespace Microsoft.AspNet.Mvc
return new ActionContext(httpContext, routeData, new ActionDescriptor());
}
private static IServiceProvider GetServiceProvider(IUrlHelper urlHelper)
private static IServiceProvider GetServiceProvider()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IUrlHelper>(urlHelper);
serviceCollection.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
serviceCollection.AddTransient<ILoggerFactory, LoggerFactory>();
return serviceCollection.BuildServiceProvider();
}
@ -114,10 +114,7 @@ namespace Microsoft.AspNet.Mvc
HttpResponse response)
{
var httpContext = new Mock<HttpContext>();
var actionContext = GetActionContext(httpContext.Object);
var actionContextAccessor = new ActionContextAccessor() { ActionContext = actionContext };
var urlHelper = new UrlHelper(actionContextAccessor);
var serviceProvider = GetServiceProvider(urlHelper);
var serviceProvider = GetServiceProvider();
httpContext.Setup(o => o.Response)
.Returns(response);

View File

@ -107,10 +107,10 @@ namespace Microsoft.AspNet.Mvc
new ActionDescriptor());
}
private static IServiceProvider GetServiceProvider(IUrlHelper urlHelper)
private static IServiceProvider GetServiceProvider()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddSingleton<IUrlHelper>(urlHelper);
serviceCollection.AddSingleton<IUrlHelperFactory, UrlHelperFactory>();
serviceCollection.AddTransient<ILoggerFactory, LoggerFactory>();
return serviceCollection.BuildServiceProvider();
}
@ -122,10 +122,7 @@ namespace Microsoft.AspNet.Mvc
HttpResponse response)
{
var httpContext = new Mock<HttpContext>();
var actionContext = GetActionContext(httpContext.Object);
var actionContextAccessor = new ActionContextAccessor() { ActionContext = actionContext };
var urlHelper = new UrlHelper(actionContextAccessor);
var serviceProvider = GetServiceProvider(urlHelper);
var serviceProvider = GetServiceProvider();
httpContext.Setup(o => o.Response)
.Returns(response);

View File

@ -90,15 +90,20 @@ namespace Microsoft.AspNet.Mvc
// Arrange
var routeName = "orders_api";
var locationUrl = "/api/orders/10";
var urlHelper = new Mock<IUrlHelper>();
urlHelper.Setup(uh => uh.RouteUrl(It.IsAny<UrlRouteContext>()))
urlHelper
.Setup(uh => uh.RouteUrl(It.IsAny<UrlRouteContext>()))
.Returns(locationUrl)
.Verifiable();
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper.Object);
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider
.Setup(sp => sp.GetService(typeof(IUrlHelper)))
.Returns(urlHelper.Object);
.Setup(sp => sp.GetService(typeof(IUrlHelperFactory)))
.Returns(factory.Object);
serviceProvider
.Setup(sp => sp.GetService(typeof(ILoggerFactory)))
.Returns(NullLoggerFactory.Instance);

View File

@ -10,7 +10,6 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Logging.Testing;
using Microsoft.Extensions.OptionsModel;
@ -32,9 +31,9 @@ namespace Microsoft.AspNet.Mvc.Routing
string expectedPath)
{
// Arrange
var context = CreateHttpContext(GetServices(), appRoot);
var contextAccessor = CreateActionContext(context);
var urlHelper = CreateUrlHelper(contextAccessor);
var httpContext = CreateHttpContext(GetServices(), appRoot);
var actionContext = CreateActionContext(httpContext);
var urlHelper = CreateUrlHelper(actionContext);
// Act
var path = urlHelper.Content(contentPath);
@ -57,9 +56,9 @@ namespace Microsoft.AspNet.Mvc.Routing
string expectedPath)
{
// Arrange
var context = CreateHttpContext(GetServices(), appRoot);
var contextAccessor = CreateActionContext(context);
var urlHelper = CreateUrlHelper(contextAccessor);
var httpContext = CreateHttpContext(GetServices(), appRoot);
var actionContext = CreateActionContext(httpContext);
var urlHelper = CreateUrlHelper(actionContext);
// Act
var path = urlHelper.Content(contentPath);
@ -754,13 +753,21 @@ namespace Microsoft.AspNet.Mvc.Routing
"{first}/{controller}/{action}",
new { second = "default", controller = "default", action = "default" });
var actionContext = services.GetService<IActionContextAccessor>().ActionContext;
var actionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = services,
},
};
actionContext.RouteData = new RouteData();
actionContext.RouteData.Values.Add("first", "a");
actionContext.RouteData.Values.Add("controller", "Store");
actionContext.RouteData.Values.Add("action", "Buy");
actionContext.RouteData.Routers.Add(routeBuilder.Build());
var urlHelper = CreateUrlHelper(services);
var urlHelper = CreateUrlHelper(actionContext);
// Act
//
@ -791,14 +798,22 @@ namespace Microsoft.AspNet.Mvc.Routing
"{first}/{second}/{controller}/{action}",
new { second = "default", controller = "default", action = "default" });
var actionContext = services.GetService<IActionContextAccessor>().ActionContext;
var actionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = services,
},
};
actionContext.RouteData = new RouteData();
actionContext.RouteData.Values.Add("first", "a");
actionContext.RouteData.Values.Add("second", "x");
actionContext.RouteData.Values.Add("controller", "Store");
actionContext.RouteData.Values.Add("action", "Buy");
actionContext.RouteData.Routers.Add(routeBuilder.Build());
var urlHelper = CreateUrlHelper(services);
var urlHelper = CreateUrlHelper(actionContext);
// Act
//
@ -831,13 +846,21 @@ namespace Microsoft.AspNet.Mvc.Routing
"{first}/{controller}/{action}",
new { second = "default", controller = "default", action = "default" });
var actionContext = services.GetService<IActionContextAccessor>().ActionContext;
var actionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = services,
},
};
actionContext.RouteData = new RouteData();
actionContext.RouteData.Values.Add("first", "a");
actionContext.RouteData.Values.Add("controller", "Store");
actionContext.RouteData.Values.Add("action", "Buy");
actionContext.RouteData.Routers.Add(routeBuilder.Build());
var urlHelper = CreateUrlHelper(services);
var urlHelper = CreateUrlHelper(actionContext);
// Act
//
@ -864,18 +887,17 @@ namespace Microsoft.AspNet.Mvc.Routing
return context;
}
private static IActionContextAccessor CreateActionContext(HttpContext context)
private static ActionContext CreateActionContext(HttpContext context)
{
return CreateActionContext(context, (new Mock<IRouter>()).Object);
}
private static IActionContextAccessor CreateActionContext(HttpContext context, IRouter router)
private static ActionContext CreateActionContext(HttpContext context, IRouter router)
{
var routeData = new RouteData();
routeData.Routers.Add(router);
var actionContext = new ActionContext(context, routeData, new ActionDescriptor());
return new ActionContextAccessor() { ActionContext = actionContext };
return new ActionContext(context, routeData, new ActionDescriptor());
}
private static UrlHelper CreateUrlHelper()
@ -887,9 +909,9 @@ namespace Microsoft.AspNet.Mvc.Routing
return new UrlHelper(actionContext);
}
private static UrlHelper CreateUrlHelper(IServiceProvider services)
private static UrlHelper CreateUrlHelper(ActionContext context)
{
return new UrlHelper(services.GetRequiredService<IActionContextAccessor>());
return new UrlHelper(context);
}
private static UrlHelper CreateUrlHelper(string host)
@ -915,11 +937,6 @@ namespace Microsoft.AspNet.Mvc.Routing
return new UrlHelper(actionContext);
}
private static UrlHelper CreateUrlHelper(IActionContextAccessor contextAccessor)
{
return new UrlHelper(contextAccessor);
}
private static UrlHelper CreateUrlHelper(string appBase, IRouter router)
{
var services = GetServices();
@ -960,20 +977,6 @@ namespace Microsoft.AspNet.Mvc.Routing
.Setup(s => s.GetService(typeof(ILoggerFactory)))
.Returns(NullLoggerFactory.Instance);
services
.Setup(s => s.GetService(typeof(IActionContextAccessor)))
.Returns(new ActionContextAccessor()
{
ActionContext = new ActionContext()
{
HttpContext = new DefaultHttpContext()
{
RequestServices = services.Object,
},
RouteData = new RouteData(),
},
});
return services.Object;
}

View File

@ -1,13 +1,9 @@
// 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 System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using ControllersFromServicesWebSite;
using Microsoft.AspNet.Builder;
using Microsoft.Extensions.DependencyInjection;
using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests

View File

@ -12,6 +12,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TestCommon;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
@ -555,17 +556,23 @@ namespace Microsoft.AspNet.Mvc.Razor
// Arrange
var expected = "urlhelper-url";
var helper = new Mock<IUrlHelper>();
helper.Setup(h => h.Content("url"))
.Returns(expected)
.Verifiable();
helper
.Setup(h => h.Content("url"))
.Returns(expected)
.Verifiable();
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(helper.Object);
var page = CreatePage(v =>
{
v.HtmlEncoder = new HtmlTestEncoder();
v.Write(v.Href("url"));
});
var services = new Mock<IServiceProvider>();
services.Setup(s => s.GetService(typeof(IUrlHelper)))
.Returns(helper.Object);
services.Setup(s => s.GetService(typeof(IUrlHelperFactory)))
.Returns(factory.Object);
page.Context.RequestServices = services.Object;
// Act

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Razor.TagHelpers;
using Microsoft.Extensions.WebEncoders.Testing;
using Moq;
@ -58,7 +59,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(value => "/approot" + value.Substring(1)));
var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, new HtmlTestEncoder());
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelperMock.Object);
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, new HtmlTestEncoder());
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
@ -114,7 +119,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
.Returns("approot/home/index.html");
var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, htmlEncoder: null);
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelperMock.Object);
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, htmlEncoder: null);
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
@ -143,7 +152,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
{ "href", true }
},
getChildContentAsync: _ => Task.FromResult<TagHelperContent>(null));
var tagHelper = new UrlResolutionTagHelper(urlHelper: null, htmlEncoder: null);
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory: null, htmlEncoder: null);
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(
@ -184,7 +193,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
urlHelperMock
.Setup(urlHelper => urlHelper.Content(It.IsAny<string>()))
.Returns("UnexpectedResult");
var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, htmlEncoder: null);
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelperMock.Object);
var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, htmlEncoder: null);
var context = new TagHelperContext(
allAttributes: new ReadOnlyTagHelperAttributeList<IReadOnlyTagHelperAttribute>(

View File

@ -71,6 +71,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
{
{ "name", "value" },
},
ViewContext = viewContext,
};
// Act
@ -109,6 +110,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var generator = new Mock<IHtmlGenerator>(MockBehavior.Strict);
generator
.Setup(mock => mock.GenerateRouteLink(
It.IsAny<ViewContext>(),
string.Empty,
"Default",
"http",
@ -157,6 +159,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var generator = new Mock<IHtmlGenerator>();
generator
.Setup(mock => mock.GenerateActionLink(
It.IsAny<ViewContext>(),
string.Empty,
"Index",
"Home",

View File

@ -13,6 +13,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers;
@ -63,12 +64,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
urlHelper
.Setup(urlhelper => urlhelper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/")));
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper.Object);
var helper = new ImageTagHelper(
hostingEnvironment,
MakeCache(),
new HtmlTestEncoder(),
urlHelper.Object)
urlHelperFactory.Object)
{
ViewContext = viewContext,
AppendVersion = true,
@ -118,7 +123,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext();
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper())
var helper = new ImageTagHelper(
hostingEnvironment,
MakeCache(),
new HtmlTestEncoder(),
MakeUrlHelperFactory())
{
ViewContext = viewContext,
Src = "testimage.png",
@ -159,7 +168,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext();
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper())
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
{
ViewContext = viewContext,
Src = "/images/test-image.png",
@ -195,7 +204,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext();
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper())
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
{
ViewContext = viewContext,
Src = "/images/test-image.png",
@ -231,7 +240,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext("/bar");
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper())
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
{
ViewContext = viewContext,
Src = "/bar/images/image.jpg",
@ -332,7 +341,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return cache.Object;
}
private static IUrlHelper MakeUrlHelper()
private static IUrlHelperFactory MakeUrlHelperFactory()
{
var urlHelper = new Mock<IUrlHelper>();
@ -340,7 +349,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Setup(helper => helper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url));
return urlHelper.Object;
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper.Object);
return urlHelperFactory.Object;
}
}
}

View File

@ -25,6 +25,7 @@ using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.WebEncoders.Testing;
using Moq;
using Xunit;
using Microsoft.AspNet.Mvc.Routing;
namespace Microsoft.AspNet.Mvc.TagHelpers
{
@ -64,6 +65,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
urlHelper
.Setup(urlhelper => urlhelper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/")));
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper.Object);
var helper = new LinkTagHelper(
logger.Object,
@ -71,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
urlHelper.Object)
urlHelperFactory.Object)
{
ViewContext = viewContext,
AppendVersion = true,
@ -170,7 +175,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
FallbackHref = "test.css",
@ -290,7 +295,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -386,7 +391,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -433,7 +438,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
FallbackHref = "test.css",
@ -543,7 +548,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
};
@ -575,7 +580,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
};
@ -618,7 +623,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext,
@ -663,7 +668,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext,
@ -706,7 +711,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
Href = "/css/site.css",
@ -746,7 +751,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
Href = "/bar/css/site.css",
@ -790,7 +795,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext,
@ -897,15 +902,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return cache.Object;
}
private static IUrlHelper MakeUrlHelper()
private static IUrlHelperFactory MakeUrlHelperFactory()
{
var urlHelper = new Mock<IUrlHelper>();
urlHelper
.Setup(helper => helper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url));
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper.Object);
return urlHelper.Object;
return urlHelperFactory.Object;
}
}
}

View File

@ -25,6 +25,7 @@ using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.WebEncoders.Testing;
using Moq;
using Xunit;
using Microsoft.AspNet.Mvc.Routing;
namespace Microsoft.AspNet.Mvc.TagHelpers
{
@ -64,6 +65,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
urlHelper
.Setup(urlhelper => urlhelper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/")));
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper.Object);
var helper = new ScriptTagHelper(
logger.Object,
@ -71,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
urlHelper.Object)
urlHelperFactory.Object)
{
ViewContext = viewContext,
AppendVersion = true,
@ -119,7 +124,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
FallbackSrc = "~/blank.js",
@ -281,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -378,7 +383,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -474,7 +479,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
};
@ -509,7 +514,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
};
@ -553,7 +558,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
};
@ -583,7 +588,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
};
@ -635,7 +640,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
FallbackSrc = "~/blank.js",
@ -677,7 +682,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext,
@ -718,7 +723,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext,
@ -757,7 +762,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
AppendVersion = true,
@ -794,7 +799,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
AppendVersion = true,
@ -833,7 +838,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
ViewContext = viewContext,
FallbackSrc = "fallback.js",
@ -878,7 +883,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(),
new HtmlTestEncoder(),
new JavaScriptTestEncoder(),
MakeUrlHelper())
MakeUrlHelperFactory())
{
GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext,
@ -994,7 +999,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return cache.Object;
}
private static IUrlHelper MakeUrlHelper()
private static IUrlHelperFactory MakeUrlHelperFactory()
{
var urlHelper = new Mock<IUrlHelper>();
@ -1002,7 +1007,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Setup(helper => helper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url));
return urlHelper.Object;
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper.Object);
return urlHelperFactory.Object;
}
}
}

View File

@ -43,7 +43,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
IOptions<MvcViewOptions> options,
IUrlHelper urlHelper,
IDictionary<string, object> validationAttributes)
: base(Mock.Of<IAntiforgery>(), options, metadataProvider, urlHelper, new HtmlTestEncoder())
: base(
Mock.Of<IAntiforgery>(),
options,
metadataProvider,
CreateUrlHelperFactory(urlHelper),
new HtmlTestEncoder())
{
_validationAttributes = validationAttributes;
}
@ -107,5 +112,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return mockOptions.Object;
}
private static IUrlHelperFactory CreateUrlHelperFactory(IUrlHelper urlHelper)
{
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper);
return factory.Object;
}
}
}

View File

@ -441,8 +441,13 @@ namespace Microsoft.AspNet.Mvc
private static ClientModelValidationContext GetValidationContext(IUrlHelper urlHelper)
{
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper);
var serviceCollection = GetServiceCollection();
serviceCollection.AddSingleton<IUrlHelper>(urlHelper);
serviceCollection.AddSingleton<IUrlHelperFactory>(factory.Object);
var serviceProvider = serviceCollection.BuildServiceProvider();
var actionContext = new ActionContext()
@ -478,9 +483,15 @@ namespace Microsoft.AspNet.Mvc
routeData.Values["area"] = currentArea;
}
var contextAccessor = GetContextAccessor(serviceProvider, routeData);
var urlHelper = new UrlHelper(contextAccessor);
serviceCollection.AddSingleton<IUrlHelper>(urlHelper);
var context = GetActionContext(serviceProvider, routeData);
var urlHelper = new UrlHelper(context);
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper);
serviceCollection.AddSingleton<IUrlHelperFactory>(factory.Object);
serviceProvider = serviceCollection.BuildServiceProvider();
var actionContext = new ActionContext()
@ -507,12 +518,17 @@ namespace Microsoft.AspNet.Mvc
},
};
var contextAccessor = GetContextAccessor(serviceProvider, routeData);
var urlHelper = new UrlHelper(contextAccessor);
serviceCollection.AddSingleton<IUrlHelper>(urlHelper);
contextAccessor.ActionContext.HttpContext.RequestServices = serviceCollection.BuildServiceProvider();
var context = GetActionContext(serviceProvider, routeData);
var urlHelper = new UrlHelper(context);
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper);
return new ClientModelValidationContext(contextAccessor.ActionContext, _metadata, _metadataProvider);
serviceCollection.AddSingleton<IUrlHelperFactory>(factory.Object);
context.HttpContext.RequestServices = serviceCollection.BuildServiceProvider();
return new ClientModelValidationContext(context, _metadata, _metadataProvider);
}
private static IRouter GetRouteCollectionWithArea(IServiceProvider serviceProvider)
@ -553,7 +569,7 @@ namespace Microsoft.AspNet.Mvc
return builder;
}
private static IActionContextAccessor GetContextAccessor(
private static ActionContext GetActionContext(
IServiceProvider serviceProvider,
RouteData routeData = null)
{
@ -572,13 +588,7 @@ namespace Microsoft.AspNet.Mvc
};
}
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor());
var contextAccessor = new ActionContextAccessor()
{
ActionContext = actionContext,
};
return contextAccessor;
return new ActionContext(httpContext, routeData, new ActionDescriptor());
}
private static ServiceCollection GetServiceCollection()

View File

@ -14,6 +14,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing;
@ -232,13 +233,18 @@ namespace Microsoft.AspNet.Mvc.Rendering
.SetupGet(o => o.Value)
.Returns(options);
var urlHelperFactory = new Mock<IUrlHelperFactory>();
urlHelperFactory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper);
var serviceProvider = new Mock<IServiceProvider>();
serviceProvider
.Setup(s => s.GetService(typeof(ICompositeViewEngine)))
.Returns(viewEngine);
serviceProvider
.Setup(s => s.GetService(typeof(IUrlHelper)))
.Returns(urlHelper);
.Setup(s => s.GetService(typeof(IUrlHelperFactory)))
.Returns(urlHelperFactory.Object);
serviceProvider
.Setup(s => s.GetService(typeof(IViewComponentHelper)))
.Returns(new Mock<IViewComponentHelper>().Object);
@ -253,7 +259,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
Mock.Of<IAntiforgery>(),
optionsAccessor.Object,
provider,
urlHelper,
urlHelperFactory.Object,
new HtmlTestEncoder());
}

View File

@ -11,6 +11,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Routing;
using Microsoft.Extensions.OptionsModel;
@ -656,7 +657,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
antiforgery,
mvcViewOptionsAccessor.Object,
metadataProvider,
Mock.Of<IUrlHelper>(),
new UrlHelperFactory(),
htmlEncoder);
}

View File

@ -1,7 +1,6 @@
// 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.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing;
@ -9,29 +8,29 @@ namespace ControllersFromServicesClassLibrary
{
public class ConstructorInjectionController
{
public ConstructorInjectionController(IUrlHelper urlHelper,
QueryValueService queryService)
public ConstructorInjectionController(IUrlHelperFactory urlHelperFactory, QueryValueService queryService)
{
UrlHelper = urlHelper;
UrlHelperFactory = urlHelperFactory;
QueryService = queryService;
}
private IUrlHelper UrlHelper { get; }
private QueryValueService QueryService { get; }
[ActionContext]
public ActionContext ActionContext { get; set; }
public HttpRequest Request => ActionContext.HttpContext.Request;
private QueryValueService QueryService { get; }
private IUrlHelperFactory UrlHelperFactory { get; }
[HttpGet("/constructorinjection")]
public IActionResult Index()
{
var content = string.Join(" ",
UrlHelper.Action(),
QueryService.GetValue(),
Request.Headers["Test-Header"]);
var urlHelper = UrlHelperFactory.GetUrlHelper(ActionContext);
var content = string.Join(
" ",
urlHelper.Action(),
QueryService.GetValue(),
ActionContext.HttpContext.Request.Headers["Test-Header"]);
return new ContentResult { Content = content };
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
namespace RoutingWebSite
@ -14,6 +15,7 @@ namespace RoutingWebSite
services.AddMvc();
services.AddScoped<TestResponseGenerator>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
}
public void Configure(IApplicationBuilder app)

View File

@ -7,7 +7,7 @@ using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.AspNet.Mvc.Routing;
namespace RoutingWebSite
{
@ -15,9 +15,12 @@ namespace RoutingWebSite
public class TestResponseGenerator
{
private readonly ActionContext _actionContext;
private readonly IUrlHelperFactory _urlHelperFactory;
public TestResponseGenerator(IActionContextAccessor contextAccessor)
public TestResponseGenerator(IActionContextAccessor contextAccessor, IUrlHelperFactory urlHelperFactory)
{
_urlHelperFactory = urlHelperFactory;
_actionContext = contextAccessor.ActionContext;
if (_actionContext == null)
{
@ -35,7 +38,7 @@ namespace RoutingWebSite
.Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller")
.ToDictionary(kvp => kvp.Key.Substring("link_".Length), kvp => (object)kvp.Value[0]);
var urlHelper = _actionContext.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContext);
link = urlHelper.Action(query["link_action"], query["link_controller"], values);
}

View File

@ -3,20 +3,26 @@
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers;
namespace TagHelpersWebSite.TagHelpers
{
public class ATagHelper : TagHelper
{
public ATagHelper(IUrlHelper urlHelper)
public ATagHelper(IUrlHelperFactory urlHelperFactory)
{
UrlHelper = urlHelper;
UrlHelperFactory = urlHelperFactory;
}
[HtmlAttributeNotBound]
public IUrlHelper UrlHelper { get; }
public IUrlHelperFactory UrlHelperFactory { get; }
[ViewContext]
[HtmlAttributeNotBound]
public ViewContext ViewContext { get; set; }
public string Controller { get; set; }
@ -33,7 +39,8 @@ namespace TagHelpersWebSite.TagHelpers
// be parameters to our final href value.
output.Attributes.Clear();
output.Attributes["href"] = UrlHelper.Action(Action, Controller, methodParameters);
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
output.Attributes["href"] = urlHelper.Action(Action, Controller, methodParameters);
output.PreContent.SetContent("My ");
}

View File

@ -3,6 +3,7 @@
using System;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.OptionsModel;
@ -16,16 +17,12 @@ namespace UrlHelperWebSite
/// </summary>
public class CustomUrlHelper : UrlHelper
{
private readonly IOptions<AppOptions> _appOptions;
private readonly HttpContext _httpContext;
private readonly AppOptions _options;
public CustomUrlHelper(
IActionContextAccessor contextAccessor,
IOptions<AppOptions> appOptions)
: base(contextAccessor)
public CustomUrlHelper(ActionContext actionContext, AppOptions options)
: base(actionContext)
{
_appOptions = appOptions;
_httpContext = contextAccessor.ActionContext.HttpContext;
_options = options;
}
/// <summary>
@ -36,12 +33,12 @@ namespace UrlHelperWebSite
/// <returns></returns>
public override string Content(string contentPath)
{
if (_appOptions.Value.ServeCDNContent
if (_options.ServeCDNContent
&& contentPath.StartsWith("~/", StringComparison.Ordinal))
{
var segment = new PathString(contentPath.Substring(1));
return ConvertToLowercaseUrl(_appOptions.Value.CDNServerBaseUrl + segment);
return ConvertToLowercaseUrl(_options.CDNServerBaseUrl + segment);
}
return ConvertToLowercaseUrl(base.Content(contentPath));
@ -60,7 +57,7 @@ namespace UrlHelperWebSite
private string ConvertToLowercaseUrl(string url)
{
if (!string.IsNullOrEmpty(url)
&& _appOptions.Value.GenerateLowercaseUrls)
&& _options.GenerateLowercaseUrls)
{
return url.ToLowerInvariant();
}

View File

@ -0,0 +1,24 @@
// 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.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.OptionsModel;
namespace UrlHelperWebSite
{
public class CustomUrlHelperFactory : IUrlHelperFactory
{
private readonly AppOptions _options;
public CustomUrlHelperFactory(IOptions<AppOptions> options)
{
_options = options.Value;
}
public IUrlHelper GetUrlHelper(ActionContext context)
{
return new CustomUrlHelper(context, _options);
}
}
}

View File

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace UrlHelperWebSite
@ -22,7 +22,7 @@ namespace UrlHelperWebSite
// Add MVC services to the services container
services.AddMvc();
services.AddScoped<IUrlHelper, CustomUrlHelper>();
services.AddSingleton<IUrlHelperFactory, CustomUrlHelperFactory>();
}
public void Configure(IApplicationBuilder app)

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection;
namespace VersioningWebSite
@ -14,6 +15,7 @@ namespace VersioningWebSite
services.AddMvc();
services.AddScoped<TestResponseGenerator>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
}
public void Configure(IApplicationBuilder app)

View File

@ -7,6 +7,7 @@ using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection;
namespace VersioningWebSite
@ -35,7 +36,7 @@ namespace VersioningWebSite
.Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller")
.ToDictionary(kvp => kvp.Key.Substring("link_".Length), kvp => (object)kvp.Value[0]);
var urlHelper = _actionContext.HttpContext.RequestServices.GetRequiredService<IUrlHelper>();
var urlHelper = GetUrlHelper(_actionContext);
link = urlHelper.Action(query["link_action"], query["link_controller"], values);
}
@ -54,5 +55,12 @@ namespace VersioningWebSite
link,
});
}
private IUrlHelper GetUrlHelper(ActionContext context)
{
var services = context.HttpContext.RequestServices;
var urlHelper = services.GetRequiredService<IUrlHelperFactory>().GetUrlHelper(context);
return urlHelper;
}
}
}