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.Http;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
@ -67,7 +68,13 @@ namespace Microsoft.AspNet.Mvc
base.OnFormatting(context); base.OnFormatting(context);
var request = context.HttpContext.Request; 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( var url = urlHelper.Action(
ActionName, ActionName,

View File

@ -5,6 +5,7 @@ using System;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Net.Http.Headers; using Microsoft.Net.Http.Headers;
@ -69,7 +70,12 @@ namespace Microsoft.AspNet.Mvc
base.OnFormatting(context); 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); var url = urlHelper.Link(RouteName, RouteValues);

View File

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

View File

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

View File

@ -4,6 +4,7 @@
using System; using System;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -98,7 +99,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context) 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 System;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
@ -85,7 +86,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context) 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 System;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -80,7 +81,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context) 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 System;
using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.Logging; using Microsoft.AspNet.Mvc.Logging;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -77,7 +78,14 @@ namespace Microsoft.AspNet.Mvc
private IUrlHelper GetUrlHelper(ActionContext context) 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. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System; using System;
using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.Extensions.Internal;
namespace Microsoft.AspNet.Mvc.Routing namespace Microsoft.AspNet.Mvc.Routing
{ {
@ -17,22 +14,27 @@ namespace Microsoft.AspNet.Mvc.Routing
/// </summary> /// </summary>
public class UrlHelper : IUrlHelper public class UrlHelper : IUrlHelper
{ {
private readonly IActionContextAccessor _actionContextAccessor;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="UrlHelper"/> class using the specified action context and /// Initializes a new instance of the <see cref="UrlHelper"/> class using the specified action context and
/// action selector. /// action selector.
/// </summary> /// </summary>
/// <param name="actionContextAccessor">The <see cref="IActionContextAccessor"/> to access the action context /// <param name="actionContext">
/// of the current request.</param> /// The <see cref="Mvc.ActionContext"/> for the current request.
public UrlHelper(IActionContextAccessor actionContextAccessor) /// </param>
public UrlHelper(ActionContext actionContext)
{ {
_actionContextAccessor = actionContextAccessor; if (actionContext == null)
{
throw new ArgumentNullException(nameof(actionContext));
}
ActionContext = actionContext;
} }
protected RouteValueDictionary AmbientValues => ActionContext.RouteData.Values; protected RouteValueDictionary AmbientValues => ActionContext.RouteData.Values;
protected ActionContext ActionContext => _actionContextAccessor.ActionContext; protected ActionContext ActionContext { get; }
protected HttpContext HttpContext => ActionContext.HttpContext; 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.Infrastructure;
using Microsoft.AspNet.Mvc.Razor.Internal; using Microsoft.AspNet.Mvc.Razor.Internal;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.AspNet.Razor.Runtime.TagHelpers;
using Microsoft.AspNet.Razor.TagHelpers; using Microsoft.AspNet.Razor.TagHelpers;
@ -629,7 +630,9 @@ namespace Microsoft.AspNet.Mvc.Razor
if (_urlHelper == null) 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); return _urlHelper.Content(contentPath);

View File

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

View File

@ -7,6 +7,8 @@ using System.ComponentModel;
using System.Reflection; using System.Reflection;
using System.Text.Encodings.Web; using System.Text.Encodings.Web;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers; using Microsoft.AspNet.Razor.TagHelpers;
namespace Microsoft.AspNet.Mvc.Razor.TagHelpers namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
@ -83,11 +85,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
/// <summary> /// <summary>
/// Creates a new <see cref="UrlResolutionTagHelper"/>. /// Creates a new <see cref="UrlResolutionTagHelper"/>.
/// </summary> /// </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> /// <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; HtmlEncoder = htmlEncoder;
} }
@ -100,10 +102,14 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers
} }
} }
protected IUrlHelper UrlHelper { get; } protected IUrlHelperFactory UrlHelperFactory { get; }
protected HtmlEncoder HtmlEncoder { get; } protected HtmlEncoder HtmlEncoder { get; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
/// <inheritdoc /> /// <inheritdoc />
public override void Process(TagHelperContext context, TagHelperOutput output) 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. // Before doing more work, ensure that the URL we're looking at is app relative.
if (trimmedUrl.Length >= 2 && trimmedUrl[0] == '~' && trimmedUrl[1] == '/') 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) 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 /> /// <inheritdoc />
/// <remarks>Does nothing if user provides an <c>href</c> attribute.</remarks> /// <remarks>Does nothing if user provides an <c>href</c> attribute.</remarks>
/// <exception cref="InvalidOperationException"> /// <exception cref="InvalidOperationException">
@ -177,6 +184,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
if (Route == null) if (Route == null)
{ {
tagBuilder = Generator.GenerateActionLink( tagBuilder = Generator.GenerateActionLink(
ViewContext,
linkText: string.Empty, linkText: string.Empty,
actionName: Action, actionName: Action,
controllerName: Controller, controllerName: Controller,
@ -200,6 +208,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
else else
{ {
tagBuilder = Generator.GenerateRouteLink( tagBuilder = Generator.GenerateRouteLink(
ViewContext,
linkText: string.Empty, linkText: string.Empty,
routeName: Route, routeName: Route,
protocol: Protocol, protocol: Protocol,

View File

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

View File

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

View File

@ -7,6 +7,7 @@ using System.Text.Encodings.Web;
using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Mvc.Razor.TagHelpers; using Microsoft.AspNet.Mvc.Razor.TagHelpers;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TagHelpers.Internal; using Microsoft.AspNet.Mvc.TagHelpers.Internal;
using Microsoft.AspNet.Mvc.TagHelpers.Logging; using Microsoft.AspNet.Mvc.TagHelpers.Logging;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
@ -79,15 +80,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
/// <param name="cache">The <see cref="IMemoryCache"/>.</param> /// <param name="cache">The <see cref="IMemoryCache"/>.</param>
/// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param> /// <param name="htmlEncoder">The <see cref="HtmlEncoder"/>.</param>
/// <param name="javaScriptEncoder">The <see cref="JavaScriptEncoder"/>.</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( public ScriptTagHelper(
ILogger<ScriptTagHelper> logger, ILogger<ScriptTagHelper> logger,
IHostingEnvironment hostingEnvironment, IHostingEnvironment hostingEnvironment,
IMemoryCache cache, IMemoryCache cache,
HtmlEncoder htmlEncoder, HtmlEncoder htmlEncoder,
JavaScriptEncoder javaScriptEncoder, JavaScriptEncoder javaScriptEncoder,
IUrlHelper urlHelper) IUrlHelperFactory urlHelperFactory)
: base(urlHelper, htmlEncoder) : base(urlHelperFactory, htmlEncoder)
{ {
Logger = logger; Logger = logger;
HostingEnvironment = hostingEnvironment; HostingEnvironment = hostingEnvironment;
@ -170,10 +171,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
protected IHostingEnvironment HostingEnvironment { get; } protected IHostingEnvironment HostingEnvironment { get; }
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext ViewContext { get; set; }
protected IMemoryCache Cache { get; } protected IMemoryCache Cache { get; }
protected JavaScriptEncoder JavaScriptEncoder { 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.Filters;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.ModelBinding.Validation;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Routing; using Microsoft.AspNet.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -166,7 +167,8 @@ namespace Microsoft.AspNet.Mvc
{ {
if (_url == null) if (_url == null)
{ {
_url = Resolver?.GetRequiredService<IUrlHelper>(); var factory = Resolver?.GetRequiredService<IUrlHelperFactory>();
_url = factory?.GetUrlHelper(ControllerContext);
} }
return _url; return _url;

View File

@ -199,7 +199,9 @@ namespace Microsoft.AspNet.Mvc
} }
var services = context.ActionContext.HttpContext.RequestServices; 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() var url = urlHelper.RouteUrl(new UrlRouteContext()
{ {
RouteName = this.RouteName, RouteName = this.RouteName,

View File

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

View File

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

View File

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

View File

@ -21,7 +21,31 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
string FormatValue(object value, string format); 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( TagBuilder GenerateActionLink(
ViewContext viewContext,
string linkText, string linkText,
string actionName, string actionName,
string controllerName, string controllerName,
@ -158,7 +182,30 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures
bool? isChecked, bool? isChecked,
object htmlAttributes); 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( TagBuilder GenerateRouteLink(
ViewContext viewContext,
string linkText, string linkText,
string routeName, string routeName,
string protocol, string protocol,

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,13 +1,9 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using ControllersFromServicesWebSite;
using Microsoft.AspNet.Builder;
using Microsoft.Extensions.DependencyInjection;
using Xunit; using Xunit;
namespace Microsoft.AspNet.Mvc.FunctionalTests 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.Abstractions;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.TestCommon; using Microsoft.AspNet.Mvc.TestCommon;
using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
@ -555,17 +556,23 @@ namespace Microsoft.AspNet.Mvc.Razor
// Arrange // Arrange
var expected = "urlhelper-url"; var expected = "urlhelper-url";
var helper = new Mock<IUrlHelper>(); var helper = new Mock<IUrlHelper>();
helper.Setup(h => h.Content("url")) helper
.Returns(expected) .Setup(h => h.Content("url"))
.Verifiable(); .Returns(expected)
.Verifiable();
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(helper.Object);
var page = CreatePage(v => var page = CreatePage(v =>
{ {
v.HtmlEncoder = new HtmlTestEncoder(); v.HtmlEncoder = new HtmlTestEncoder();
v.Write(v.Href("url")); v.Write(v.Href("url"));
}); });
var services = new Mock<IServiceProvider>(); var services = new Mock<IServiceProvider>();
services.Setup(s => s.GetService(typeof(IUrlHelper))) services.Setup(s => s.GetService(typeof(IUrlHelperFactory)))
.Returns(helper.Object); .Returns(factory.Object);
page.Context.RequestServices = services.Object; page.Context.RequestServices = services.Object;
// Act // Act

View File

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

View File

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

View File

@ -13,6 +13,7 @@ using Microsoft.AspNet.Http.Internal;
using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Abstractions;
using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding;
using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.AspNet.Mvc.Routing;
using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Mvc.ViewEngines;
using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures;
using Microsoft.AspNet.Razor.TagHelpers; using Microsoft.AspNet.Razor.TagHelpers;
@ -63,12 +64,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
urlHelper urlHelper
.Setup(urlhelper => urlhelper.Content(It.IsAny<string>())) .Setup(urlhelper => urlhelper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/"))); .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( var helper = new ImageTagHelper(
hostingEnvironment, hostingEnvironment,
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
urlHelper.Object) urlHelperFactory.Object)
{ {
ViewContext = viewContext, ViewContext = viewContext,
AppendVersion = true, AppendVersion = true,
@ -118,7 +123,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) var helper = new ImageTagHelper(
hostingEnvironment,
MakeCache(),
new HtmlTestEncoder(),
MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
Src = "testimage.png", Src = "testimage.png",
@ -159,7 +168,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
Src = "/images/test-image.png", Src = "/images/test-image.png",
@ -195,7 +204,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext(); var viewContext = MakeViewContext();
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
Src = "/images/test-image.png", Src = "/images/test-image.png",
@ -231,7 +240,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
var hostingEnvironment = MakeHostingEnvironment(); var hostingEnvironment = MakeHostingEnvironment();
var viewContext = MakeViewContext("/bar"); var viewContext = MakeViewContext("/bar");
var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
Src = "/bar/images/image.jpg", Src = "/bar/images/image.jpg",
@ -332,7 +341,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return cache.Object; return cache.Object;
} }
private static IUrlHelper MakeUrlHelper() private static IUrlHelperFactory MakeUrlHelperFactory()
{ {
var urlHelper = new Mock<IUrlHelper>(); var urlHelper = new Mock<IUrlHelper>();
@ -340,7 +349,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Setup(helper => helper.Content(It.IsAny<string>())) .Setup(helper => helper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url)); .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 Microsoft.Extensions.WebEncoders.Testing;
using Moq; using Moq;
using Xunit; using Xunit;
using Microsoft.AspNet.Mvc.Routing;
namespace Microsoft.AspNet.Mvc.TagHelpers namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
@ -64,6 +65,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
urlHelper urlHelper
.Setup(urlhelper => urlhelper.Content(It.IsAny<string>())) .Setup(urlhelper => urlhelper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/"))); .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( var helper = new LinkTagHelper(
logger.Object, logger.Object,
@ -71,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
urlHelper.Object) urlHelperFactory.Object)
{ {
ViewContext = viewContext, ViewContext = viewContext,
AppendVersion = true, AppendVersion = true,
@ -170,7 +175,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
FallbackHref = "test.css", FallbackHref = "test.css",
@ -290,7 +295,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -386,7 +391,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -433,7 +438,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
FallbackHref = "test.css", FallbackHref = "test.css",
@ -543,7 +548,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -575,7 +580,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -618,7 +623,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
GlobbingUrlBuilder = globbingUrlBuilder.Object, GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext, ViewContext = viewContext,
@ -663,7 +668,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
GlobbingUrlBuilder = globbingUrlBuilder.Object, GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext, ViewContext = viewContext,
@ -706,7 +711,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
Href = "/css/site.css", Href = "/css/site.css",
@ -746,7 +751,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
Href = "/bar/css/site.css", Href = "/bar/css/site.css",
@ -790,7 +795,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
GlobbingUrlBuilder = globbingUrlBuilder.Object, GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext, ViewContext = viewContext,
@ -897,15 +902,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return cache.Object; return cache.Object;
} }
private static IUrlHelper MakeUrlHelper() private static IUrlHelperFactory MakeUrlHelperFactory()
{ {
var urlHelper = new Mock<IUrlHelper>(); var urlHelper = new Mock<IUrlHelper>();
urlHelper urlHelper
.Setup(helper => helper.Content(It.IsAny<string>())) .Setup(helper => helper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url)); .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 Microsoft.Extensions.WebEncoders.Testing;
using Moq; using Moq;
using Xunit; using Xunit;
using Microsoft.AspNet.Mvc.Routing;
namespace Microsoft.AspNet.Mvc.TagHelpers namespace Microsoft.AspNet.Mvc.TagHelpers
{ {
@ -64,6 +65,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
urlHelper urlHelper
.Setup(urlhelper => urlhelper.Content(It.IsAny<string>())) .Setup(urlhelper => urlhelper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url.Replace("~/", "virtualRoot/"))); .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( var helper = new ScriptTagHelper(
logger.Object, logger.Object,
@ -71,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
urlHelper.Object) urlHelperFactory.Object)
{ {
ViewContext = viewContext, ViewContext = viewContext,
AppendVersion = true, AppendVersion = true,
@ -119,7 +124,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
FallbackSrc = "~/blank.js", FallbackSrc = "~/blank.js",
@ -281,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -378,7 +383,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
GlobbingUrlBuilder = globbingUrlBuilder.Object GlobbingUrlBuilder = globbingUrlBuilder.Object
@ -474,7 +479,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -509,7 +514,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -553,7 +558,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -583,7 +588,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
}; };
@ -635,7 +640,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
FallbackSrc = "~/blank.js", FallbackSrc = "~/blank.js",
@ -677,7 +682,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
GlobbingUrlBuilder = globbingUrlBuilder.Object, GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext, ViewContext = viewContext,
@ -718,7 +723,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
GlobbingUrlBuilder = globbingUrlBuilder.Object, GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext, ViewContext = viewContext,
@ -757,7 +762,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
AppendVersion = true, AppendVersion = true,
@ -794,7 +799,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
AppendVersion = true, AppendVersion = true,
@ -833,7 +838,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
ViewContext = viewContext, ViewContext = viewContext,
FallbackSrc = "fallback.js", FallbackSrc = "fallback.js",
@ -878,7 +883,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
MakeCache(), MakeCache(),
new HtmlTestEncoder(), new HtmlTestEncoder(),
new JavaScriptTestEncoder(), new JavaScriptTestEncoder(),
MakeUrlHelper()) MakeUrlHelperFactory())
{ {
GlobbingUrlBuilder = globbingUrlBuilder.Object, GlobbingUrlBuilder = globbingUrlBuilder.Object,
ViewContext = viewContext, ViewContext = viewContext,
@ -994,7 +999,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return cache.Object; return cache.Object;
} }
private static IUrlHelper MakeUrlHelper() private static IUrlHelperFactory MakeUrlHelperFactory()
{ {
var urlHelper = new Mock<IUrlHelper>(); var urlHelper = new Mock<IUrlHelper>();
@ -1002,7 +1007,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
.Setup(helper => helper.Content(It.IsAny<string>())) .Setup(helper => helper.Content(It.IsAny<string>()))
.Returns(new Func<string, string>(url => url)); .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, IOptions<MvcViewOptions> options,
IUrlHelper urlHelper, IUrlHelper urlHelper,
IDictionary<string, object> validationAttributes) 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; _validationAttributes = validationAttributes;
} }
@ -107,5 +112,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers
return mockOptions.Object; 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) private static ClientModelValidationContext GetValidationContext(IUrlHelper urlHelper)
{ {
var factory = new Mock<IUrlHelperFactory>();
factory
.Setup(f => f.GetUrlHelper(It.IsAny<ActionContext>()))
.Returns(urlHelper);
var serviceCollection = GetServiceCollection(); var serviceCollection = GetServiceCollection();
serviceCollection.AddSingleton<IUrlHelper>(urlHelper); serviceCollection.AddSingleton<IUrlHelperFactory>(factory.Object);
var serviceProvider = serviceCollection.BuildServiceProvider(); var serviceProvider = serviceCollection.BuildServiceProvider();
var actionContext = new ActionContext() var actionContext = new ActionContext()
@ -478,9 +483,15 @@ namespace Microsoft.AspNet.Mvc
routeData.Values["area"] = currentArea; routeData.Values["area"] = currentArea;
} }
var contextAccessor = GetContextAccessor(serviceProvider, routeData); var context = GetActionContext(serviceProvider, routeData);
var urlHelper = new UrlHelper(contextAccessor);
serviceCollection.AddSingleton<IUrlHelper>(urlHelper); 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(); serviceProvider = serviceCollection.BuildServiceProvider();
var actionContext = new ActionContext() var actionContext = new ActionContext()
@ -507,12 +518,17 @@ namespace Microsoft.AspNet.Mvc
}, },
}; };
var contextAccessor = GetContextAccessor(serviceProvider, routeData); var context = GetActionContext(serviceProvider, routeData);
var urlHelper = new UrlHelper(contextAccessor); var urlHelper = new UrlHelper(context);
serviceCollection.AddSingleton<IUrlHelper>(urlHelper); var factory = new Mock<IUrlHelperFactory>();
contextAccessor.ActionContext.HttpContext.RequestServices = serviceCollection.BuildServiceProvider(); 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) private static IRouter GetRouteCollectionWithArea(IServiceProvider serviceProvider)
@ -553,7 +569,7 @@ namespace Microsoft.AspNet.Mvc
return builder; return builder;
} }
private static IActionContextAccessor GetContextAccessor( private static ActionContext GetActionContext(
IServiceProvider serviceProvider, IServiceProvider serviceProvider,
RouteData routeData = null) RouteData routeData = null)
{ {
@ -572,13 +588,7 @@ namespace Microsoft.AspNet.Mvc
}; };
} }
var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor()); return new ActionContext(httpContext, routeData, new ActionDescriptor());
var contextAccessor = new ActionContextAccessor()
{
ActionContext = actionContext,
};
return contextAccessor;
} }
private static ServiceCollection GetServiceCollection() private static ServiceCollection GetServiceCollection()

View File

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

View File

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

View File

@ -1,7 +1,6 @@
// Copyright (c) .NET Foundation. All rights reserved. // 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. // 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;
using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.Routing;
@ -9,29 +8,29 @@ namespace ControllersFromServicesClassLibrary
{ {
public class ConstructorInjectionController public class ConstructorInjectionController
{ {
public ConstructorInjectionController(IUrlHelper urlHelper, public ConstructorInjectionController(IUrlHelperFactory urlHelperFactory, QueryValueService queryService)
QueryValueService queryService)
{ {
UrlHelper = urlHelper; UrlHelperFactory = urlHelperFactory;
QueryService = queryService; QueryService = queryService;
} }
private IUrlHelper UrlHelper { get; }
private QueryValueService QueryService { get; }
[ActionContext] [ActionContext]
public ActionContext ActionContext { get; set; } public ActionContext ActionContext { get; set; }
public HttpRequest Request => ActionContext.HttpContext.Request; private QueryValueService QueryService { get; }
private IUrlHelperFactory UrlHelperFactory { get; }
[HttpGet("/constructorinjection")] [HttpGet("/constructorinjection")]
public IActionResult Index() public IActionResult Index()
{ {
var content = string.Join(" ", var urlHelper = UrlHelperFactory.GetUrlHelper(ActionContext);
UrlHelper.Action(),
QueryService.GetValue(), var content = string.Join(
Request.Headers["Test-Header"]); " ",
urlHelper.Action(),
QueryService.GetValue(),
ActionContext.HttpContext.Request.Headers["Test-Header"]);
return new ContentResult { Content = content }; 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. // 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.Builder;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace RoutingWebSite namespace RoutingWebSite
@ -14,6 +15,7 @@ namespace RoutingWebSite
services.AddMvc(); services.AddMvc();
services.AddScoped<TestResponseGenerator>(); services.AddScoped<TestResponseGenerator>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
} }
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app)

View File

@ -7,7 +7,7 @@ using System.Linq;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Controllers; using Microsoft.AspNet.Mvc.Controllers;
using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection; using Microsoft.AspNet.Mvc.Routing;
namespace RoutingWebSite namespace RoutingWebSite
{ {
@ -15,9 +15,12 @@ namespace RoutingWebSite
public class TestResponseGenerator public class TestResponseGenerator
{ {
private readonly ActionContext _actionContext; private readonly ActionContext _actionContext;
private readonly IUrlHelperFactory _urlHelperFactory;
public TestResponseGenerator(IActionContextAccessor contextAccessor) public TestResponseGenerator(IActionContextAccessor contextAccessor, IUrlHelperFactory urlHelperFactory)
{ {
_urlHelperFactory = urlHelperFactory;
_actionContext = contextAccessor.ActionContext; _actionContext = contextAccessor.ActionContext;
if (_actionContext == null) if (_actionContext == null)
{ {
@ -35,7 +38,7 @@ namespace RoutingWebSite
.Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller") .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]); .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); link = urlHelper.Action(query["link_action"], query["link_controller"], values);
} }

View File

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

View File

@ -3,6 +3,7 @@
using System; using System;
using Microsoft.AspNet.Http; using Microsoft.AspNet.Http;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.OptionsModel; using Microsoft.Extensions.OptionsModel;
@ -16,16 +17,12 @@ namespace UrlHelperWebSite
/// </summary> /// </summary>
public class CustomUrlHelper : UrlHelper public class CustomUrlHelper : UrlHelper
{ {
private readonly IOptions<AppOptions> _appOptions; private readonly AppOptions _options;
private readonly HttpContext _httpContext;
public CustomUrlHelper( public CustomUrlHelper(ActionContext actionContext, AppOptions options)
IActionContextAccessor contextAccessor, : base(actionContext)
IOptions<AppOptions> appOptions)
: base(contextAccessor)
{ {
_appOptions = appOptions; _options = options;
_httpContext = contextAccessor.ActionContext.HttpContext;
} }
/// <summary> /// <summary>
@ -36,12 +33,12 @@ namespace UrlHelperWebSite
/// <returns></returns> /// <returns></returns>
public override string Content(string contentPath) public override string Content(string contentPath)
{ {
if (_appOptions.Value.ServeCDNContent if (_options.ServeCDNContent
&& contentPath.StartsWith("~/", StringComparison.Ordinal)) && contentPath.StartsWith("~/", StringComparison.Ordinal))
{ {
var segment = new PathString(contentPath.Substring(1)); var segment = new PathString(contentPath.Substring(1));
return ConvertToLowercaseUrl(_appOptions.Value.CDNServerBaseUrl + segment); return ConvertToLowercaseUrl(_options.CDNServerBaseUrl + segment);
} }
return ConvertToLowercaseUrl(base.Content(contentPath)); return ConvertToLowercaseUrl(base.Content(contentPath));
@ -60,7 +57,7 @@ namespace UrlHelperWebSite
private string ConvertToLowercaseUrl(string url) private string ConvertToLowercaseUrl(string url)
{ {
if (!string.IsNullOrEmpty(url) if (!string.IsNullOrEmpty(url)
&& _appOptions.Value.GenerateLowercaseUrls) && _options.GenerateLowercaseUrls)
{ {
return url.ToLowerInvariant(); 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. // 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.Builder;
using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Routing;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace UrlHelperWebSite namespace UrlHelperWebSite
@ -22,7 +22,7 @@ namespace UrlHelperWebSite
// Add MVC services to the services container // Add MVC services to the services container
services.AddMvc(); services.AddMvc();
services.AddScoped<IUrlHelper, CustomUrlHelper>(); services.AddSingleton<IUrlHelperFactory, CustomUrlHelperFactory>();
} }
public void Configure(IApplicationBuilder app) 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. // 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.Builder;
using Microsoft.AspNet.Mvc.Infrastructure;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
namespace VersioningWebSite namespace VersioningWebSite
@ -14,6 +15,7 @@ namespace VersioningWebSite
services.AddMvc(); services.AddMvc();
services.AddScoped<TestResponseGenerator>(); services.AddScoped<TestResponseGenerator>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
} }
public void Configure(IApplicationBuilder app) public void Configure(IApplicationBuilder app)

View File

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