diff --git a/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs b/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs index d45d74f4a6..7048da15c0 100644 --- a/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/CreatedAtActionResult.cs @@ -5,6 +5,7 @@ using System; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Routing; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -67,7 +68,13 @@ namespace Microsoft.AspNet.Mvc base.OnFormatting(context); var request = context.HttpContext.Request; - var urlHelper = UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService(); + + var urlHelper = UrlHelper; + if (urlHelper == null) + { + var services = context.HttpContext.RequestServices; + urlHelper = services.GetRequiredService().GetUrlHelper(context); + } var url = urlHelper.Action( ActionName, diff --git a/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs b/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs index 3a63636d3a..a843240e36 100644 --- a/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/CreatedAtRouteResult.cs @@ -5,6 +5,7 @@ using System; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Routing; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -69,7 +70,12 @@ namespace Microsoft.AspNet.Mvc base.OnFormatting(context); - var urlHelper = UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService(); + var urlHelper = UrlHelper; + if (urlHelper == null) + { + var services = context.HttpContext.RequestServices; + urlHelper = services.GetRequiredService().GetUrlHelper(context); + } var url = urlHelper.Link(RouteName, RouteValues); diff --git a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs index 727a7ae229..66d695a6a1 100644 --- a/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/DependencyInjection/MvcCoreServiceCollectionExtensions.cs @@ -137,8 +137,7 @@ namespace Microsoft.Extensions.DependencyInjection // services.TryAddSingleton(); services.TryAddSingleton(); - services.TryAddSingleton(); - services.TryAddSingleton(); + services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton(); services.TryAddSingleton, DefaultArraySegmentPool>(); diff --git a/src/Microsoft.AspNet.Mvc.Core/Infrastructure/MvcRouteHandler.cs b/src/Microsoft.AspNet.Mvc.Core/Infrastructure/MvcRouteHandler.cs index 97e869e2f6..4ff047bb0e 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Infrastructure/MvcRouteHandler.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Infrastructure/MvcRouteHandler.cs @@ -19,6 +19,8 @@ namespace Microsoft.AspNet.Mvc.Infrastructure { public class MvcRouteHandler : IRouter { + private bool _servicesRetrieved; + private IActionContextAccessor _actionContextAccessor; private IActionInvokerFactory _actionInvokerFactory; private IActionSelector _actionSelector; @@ -109,7 +111,11 @@ namespace Microsoft.AspNet.Mvc.Infrastructure private Task InvokeActionAsync(RouteContext context, ActionDescriptor actionDescriptor) { var actionContext = new ActionContext(context.HttpContext, context.RouteData, actionDescriptor); - _actionContextAccessor.ActionContext = actionContext; + + if (_actionContextAccessor != null) + { + _actionContextAccessor.ActionContext = actionContext; + } var invoker = _actionInvokerFactory.CreateInvoker(actionContext); if (invoker == null) @@ -124,31 +130,23 @@ namespace Microsoft.AspNet.Mvc.Infrastructure private void EnsureServices(HttpContext context) { - if (_actionContextAccessor == null) + if (_servicesRetrieved) { - _actionContextAccessor = context.RequestServices.GetRequiredService(); + return; } - if (_actionInvokerFactory == null) - { - _actionInvokerFactory = context.RequestServices.GetRequiredService(); - } + // The IActionContextAccessor is optional. We want to avoid the overhead of using CallContext + // if possible. + _actionContextAccessor = context.RequestServices.GetService(); - if (_actionSelector == null) - { - _actionSelector = context.RequestServices.GetRequiredService(); - } + _actionInvokerFactory = context.RequestServices.GetRequiredService(); + _actionSelector = context.RequestServices.GetRequiredService(); + _diagnosticSource = context.RequestServices.GetRequiredService(); - if (_logger == null) - { - var factory = context.RequestServices.GetRequiredService(); - _logger = factory.CreateLogger(); - } - - if (_diagnosticSource == null) - { - _diagnosticSource = context.RequestServices.GetRequiredService(); - } + var factory = context.RequestServices.GetRequiredService(); + _logger = factory.CreateLogger(); + + _servicesRetrieved = true; } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/LocalRedirectResult.cs b/src/Microsoft.AspNet.Mvc.Core/LocalRedirectResult.cs index 1bed45e0ac..89ef506567 100644 --- a/src/Microsoft.AspNet.Mvc.Core/LocalRedirectResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/LocalRedirectResult.cs @@ -4,6 +4,7 @@ using System; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Logging; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -98,7 +99,14 @@ namespace Microsoft.AspNet.Mvc private IUrlHelper GetUrlHelper(ActionContext context) { - return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService(); + var urlHelper = UrlHelper; + if (urlHelper == null) + { + var services = context.HttpContext.RequestServices; + urlHelper = services.GetRequiredService().GetUrlHelper(context); + } + + return urlHelper; } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs index f4c544e0b6..d28fe88918 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectResult.cs @@ -4,6 +4,7 @@ using System; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Logging; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; @@ -85,7 +86,14 @@ namespace Microsoft.AspNet.Mvc private IUrlHelper GetUrlHelper(ActionContext context) { - return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService(); + var urlHelper = UrlHelper; + if (urlHelper == null) + { + var services = context.HttpContext.RequestServices; + urlHelper = services.GetRequiredService().GetUrlHelper(context); + } + + return urlHelper; } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs index 960b4bf1f6..6cc364639f 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectToActionResult.cs @@ -4,6 +4,7 @@ using System; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Logging; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Routing; using Microsoft.Extensions.DependencyInjection; @@ -80,7 +81,14 @@ namespace Microsoft.AspNet.Mvc private IUrlHelper GetUrlHelper(ActionContext context) { - return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService(); + var urlHelper = UrlHelper; + if (urlHelper == null) + { + var services = context.HttpContext.RequestServices; + urlHelper = services.GetRequiredService().GetUrlHelper(context); + } + + return urlHelper; } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs b/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs index 2a3509cddc..45584fdc71 100644 --- a/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs +++ b/src/Microsoft.AspNet.Mvc.Core/RedirectToRouteResult.cs @@ -4,6 +4,7 @@ using System; using Microsoft.AspNet.Mvc.Core; using Microsoft.AspNet.Mvc.Logging; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Routing; using Microsoft.Extensions.DependencyInjection; @@ -77,7 +78,14 @@ namespace Microsoft.AspNet.Mvc private IUrlHelper GetUrlHelper(ActionContext context) { - return UrlHelper ?? context.HttpContext.RequestServices.GetRequiredService(); + var urlHelper = UrlHelper; + if (urlHelper == null) + { + var services = context.HttpContext.RequestServices; + urlHelper = services.GetRequiredService().GetUrlHelper(context); + } + + return urlHelper; } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/IUrlHelperFactory.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/IUrlHelperFactory.cs new file mode 100644 index 0000000000..1a718182ed --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/IUrlHelperFactory.cs @@ -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 +{ + /// + /// A factory for creating instances. + /// + public interface IUrlHelperFactory + { + /// + /// Gets an for the request associated with . + /// + /// The associated with the current request. + /// An for the request associated with + IUrlHelper GetUrlHelper(ActionContext context); + } +} diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs index 2ee79f1897..ddf1ae51a6 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelper.cs @@ -2,12 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; -using System.Collections.Generic; using System.Diagnostics; using Microsoft.AspNet.Http; -using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Routing; -using Microsoft.Extensions.Internal; namespace Microsoft.AspNet.Mvc.Routing { @@ -17,22 +14,27 @@ namespace Microsoft.AspNet.Mvc.Routing /// public class UrlHelper : IUrlHelper { - private readonly IActionContextAccessor _actionContextAccessor; /// /// Initializes a new instance of the class using the specified action context and /// action selector. /// - /// The to access the action context - /// of the current request. - public UrlHelper(IActionContextAccessor actionContextAccessor) + /// + /// The for the current request. + /// + public UrlHelper(ActionContext actionContext) { - _actionContextAccessor = actionContextAccessor; + if (actionContext == null) + { + throw new ArgumentNullException(nameof(actionContext)); + } + + ActionContext = actionContext; } protected RouteValueDictionary AmbientValues => ActionContext.RouteData.Values; - protected ActionContext ActionContext => _actionContextAccessor.ActionContext; + protected ActionContext ActionContext { get; } protected HttpContext HttpContext => ActionContext.HttpContext; diff --git a/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelperFactory.cs b/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelperFactory.cs new file mode 100644 index 0000000000..06ac87ce95 --- /dev/null +++ b/src/Microsoft.AspNet.Mvc.Core/Routing/UrlHelperFactory.cs @@ -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 +{ + /// + /// A default implementation of . + /// + public class UrlHelperFactory : IUrlHelperFactory + { + /// + public IUrlHelper GetUrlHelper(ActionContext context) + { + return new UrlHelper(context); + } + } +} diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs index 9efe94a876..394888a517 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorPage.cs @@ -15,6 +15,7 @@ using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Mvc.Razor.Internal; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Razor.Runtime.TagHelpers; using Microsoft.AspNet.Razor.TagHelpers; @@ -629,7 +630,9 @@ namespace Microsoft.AspNet.Mvc.Razor if (_urlHelper == null) { - _urlHelper = Context.RequestServices.GetRequiredService(); + var services = Context.RequestServices; + var factory = services.GetRequiredService(); + _urlHelper = factory.GetUrlHelper(ViewContext); } return _urlHelper.Content(contentPath); diff --git a/src/Microsoft.AspNet.Mvc.Razor/RazorPageActivator.cs b/src/Microsoft.AspNet.Mvc.Razor/RazorPageActivator.cs index a0cc2945ab..2cf153d970 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/RazorPageActivator.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/RazorPageActivator.cs @@ -7,6 +7,7 @@ using System.Reflection; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Razor.Internal; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Mvc.ViewFeatures.Internal; using Microsoft.Extensions.DependencyInjection; @@ -111,20 +112,29 @@ namespace Microsoft.AspNet.Mvc.Razor { valueAccessor = context => context.ViewData; } + else if (typeof(IUrlHelper).IsAssignableFrom(property.PropertyType)) + { + valueAccessor = context => + { + var serviceProvider = context.HttpContext.RequestServices; + var factory = (IUrlHelperFactory)serviceProvider.GetRequiredService(typeof(IUrlHelperFactory)); + return factory.GetUrlHelper(context); + }; + } else { valueAccessor = context => - { - var serviceProvider = context.HttpContext.RequestServices; - var value = serviceProvider.GetRequiredService(property.PropertyType); - var canHasViewContext = value as ICanHasViewContext; - if (canHasViewContext != null) - { - canHasViewContext.Contextualize(context); - } + { + var serviceProvider = context.HttpContext.RequestServices; + var value = serviceProvider.GetRequiredService(property.PropertyType); + var canHasViewContext = value as ICanHasViewContext; + if (canHasViewContext != null) + { + canHasViewContext.Contextualize(context); + } - return value; - }; + return value; + }; } return new PropertyActivator(property, valueAccessor); diff --git a/src/Microsoft.AspNet.Mvc.Razor/TagHelpers/UrlResolutionTagHelper.cs b/src/Microsoft.AspNet.Mvc.Razor/TagHelpers/UrlResolutionTagHelper.cs index 689ff37483..a30c793b89 100644 --- a/src/Microsoft.AspNet.Mvc.Razor/TagHelpers/UrlResolutionTagHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Razor/TagHelpers/UrlResolutionTagHelper.cs @@ -7,6 +7,8 @@ using System.ComponentModel; using System.Reflection; using System.Text.Encodings.Web; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; +using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Razor.TagHelpers; namespace Microsoft.AspNet.Mvc.Razor.TagHelpers @@ -83,11 +85,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers /// /// Creates a new . /// - /// The . + /// The . /// The . - public UrlResolutionTagHelper(IUrlHelper urlHelper, HtmlEncoder htmlEncoder) + public UrlResolutionTagHelper(IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder) { - UrlHelper = urlHelper; + UrlHelperFactory = urlHelperFactory; HtmlEncoder = htmlEncoder; } @@ -100,10 +102,14 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers } } - protected IUrlHelper UrlHelper { get; } + protected IUrlHelperFactory UrlHelperFactory { get; } protected HtmlEncoder HtmlEncoder { get; } + [HtmlAttributeNotBound] + [ViewContext] + public ViewContext ViewContext { get; set; } + /// public override void Process(TagHelperContext context, TagHelperOutput output) { @@ -202,7 +208,8 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers // Before doing more work, ensure that the URL we're looking at is app relative. if (trimmedUrl.Length >= 2 && trimmedUrl[0] == '~' && trimmedUrl[1] == '/') { - var appRelativeUrl = UrlHelper.Content(trimmedUrl); + var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext); + var appRelativeUrl = urlHelper.Content(trimmedUrl); if (encodeWebRoot) { diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/AnchorTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/AnchorTagHelper.cs index 83a4a3c3a4..623773775b 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/AnchorTagHelper.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/AnchorTagHelper.cs @@ -115,6 +115,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers } } + /// + /// Gets or sets the for the current request. + /// + [HtmlAttributeNotBound] + [ViewContext] + public ViewContext ViewContext { get; set; } + /// /// Does nothing if user provides an href attribute. /// @@ -177,6 +184,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers if (Route == null) { tagBuilder = Generator.GenerateActionLink( + ViewContext, linkText: string.Empty, actionName: Action, controllerName: Controller, @@ -200,6 +208,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers else { tagBuilder = Generator.GenerateRouteLink( + ViewContext, linkText: string.Empty, routeName: Route, protocol: Protocol, diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/ImageTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/ImageTagHelper.cs index ae411f9041..963f042ec4 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/ImageTagHelper.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/ImageTagHelper.cs @@ -6,6 +6,7 @@ using System.Text.Encodings.Web; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Mvc.Razor.TagHelpers; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.TagHelpers.Internal; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Razor.TagHelpers; @@ -37,13 +38,13 @@ namespace Microsoft.AspNet.Mvc.TagHelpers /// /// The . /// The . - /// The . + /// The . public ImageTagHelper( IHostingEnvironment hostingEnvironment, IMemoryCache cache, HtmlEncoder htmlEncoder, - IUrlHelper urlHelper) - : base(urlHelper, htmlEncoder) + IUrlHelperFactory urlHelperFactory) + : base(urlHelperFactory, htmlEncoder) { HostingEnvironment = hostingEnvironment; Cache = cache; @@ -78,10 +79,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers protected IHostingEnvironment HostingEnvironment { get; } - [HtmlAttributeNotBound] - [ViewContext] - public ViewContext ViewContext { get; set; } - protected IMemoryCache Cache { get; } /// diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs index 6ba1d316c4..fc747bb08a 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/LinkTagHelper.cs @@ -9,6 +9,7 @@ using System.Text.Encodings.Web; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Mvc.Razor.TagHelpers; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.TagHelpers.Internal; using Microsoft.AspNet.Mvc.TagHelpers.Logging; using Microsoft.AspNet.Mvc.ViewFeatures; @@ -94,15 +95,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers /// The . /// The . /// The . - /// The . + /// The . public LinkTagHelper( ILogger logger, IHostingEnvironment hostingEnvironment, IMemoryCache cache, HtmlEncoder htmlEncoder, JavaScriptEncoder javaScriptEncoder, - IUrlHelper urlHelper) - : base(urlHelper, htmlEncoder) + IUrlHelperFactory urlHelperFactory) + : base(urlHelperFactory, htmlEncoder) { Logger = logger; HostingEnvironment = hostingEnvironment; @@ -203,10 +204,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers protected IHostingEnvironment HostingEnvironment { get; } - [HtmlAttributeNotBound] - [ViewContext] - public ViewContext ViewContext { get; set; } - protected IMemoryCache Cache { get; } protected JavaScriptEncoder JavaScriptEncoder { get; } diff --git a/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs b/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs index 303b1548ab..1313059efc 100644 --- a/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs +++ b/src/Microsoft.AspNet.Mvc.TagHelpers/ScriptTagHelper.cs @@ -7,6 +7,7 @@ using System.Text.Encodings.Web; using Microsoft.AspNet.Hosting; using Microsoft.AspNet.Mvc.Razor.TagHelpers; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.TagHelpers.Internal; using Microsoft.AspNet.Mvc.TagHelpers.Logging; using Microsoft.AspNet.Mvc.ViewFeatures; @@ -79,15 +80,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers /// The . /// The . /// The . - /// The . + /// The . public ScriptTagHelper( ILogger logger, IHostingEnvironment hostingEnvironment, IMemoryCache cache, HtmlEncoder htmlEncoder, JavaScriptEncoder javaScriptEncoder, - IUrlHelper urlHelper) - : base(urlHelper, htmlEncoder) + IUrlHelperFactory urlHelperFactory) + : base(urlHelperFactory, htmlEncoder) { Logger = logger; HostingEnvironment = hostingEnvironment; @@ -170,10 +171,6 @@ namespace Microsoft.AspNet.Mvc.TagHelpers protected IHostingEnvironment HostingEnvironment { get; } - [HtmlAttributeNotBound] - [ViewContext] - public ViewContext ViewContext { get; set; } - protected IMemoryCache Cache { get; } protected JavaScriptEncoder JavaScriptEncoder { get; } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs index db0f726613..c7337f907b 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/Controller.cs @@ -13,6 +13,7 @@ using Microsoft.AspNet.Http.Authentication; using Microsoft.AspNet.Mvc.Filters; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Validation; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Routing; using Microsoft.Extensions.DependencyInjection; @@ -166,7 +167,8 @@ namespace Microsoft.AspNet.Mvc { if (_url == null) { - _url = Resolver?.GetRequiredService(); + var factory = Resolver?.GetRequiredService(); + _url = factory?.GetUrlHelper(ControllerContext); } return _url; diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/RemoteAttribute.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/RemoteAttribute.cs index fa407f269a..14b4af2bc3 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/RemoteAttribute.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/RemoteAttribute.cs @@ -199,7 +199,9 @@ namespace Microsoft.AspNet.Mvc } var services = context.ActionContext.HttpContext.RequestServices; - var urlHelper = services.GetRequiredService(); + var factory = services.GetRequiredService(); + var urlHelper = factory.GetUrlHelper(context.ActionContext); + var url = urlHelper.RouteUrl(new UrlRouteContext() { RouteName = this.RouteName, diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponent.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponent.cs index 302cee9e15..c32341ef62 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponent.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewComponent.cs @@ -6,6 +6,7 @@ using System.Security.Principal; using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewComponents; using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Mvc.ViewFeatures; @@ -108,7 +109,8 @@ namespace Microsoft.AspNet.Mvc { // May be null in unit-testing scenarios. var services = ViewComponentContext.ViewContext?.HttpContext?.RequestServices; - _url = services?.GetRequiredService(); + var factory = services?.GetRequiredService(); + _url = factory?.GetUrlHelper(ViewComponentContext.ViewContext); } return _url; diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/DefaultHtmlGenerator.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/DefaultHtmlGenerator.cs index 8215a94599..9627c82d89 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/DefaultHtmlGenerator.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/DefaultHtmlGenerator.cs @@ -14,6 +14,7 @@ using Microsoft.AspNet.Html; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Validation; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewFeatures.Internal; using Microsoft.Extensions.OptionsModel; @@ -28,7 +29,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures private readonly IAntiforgery _antiforgery; private readonly IClientModelValidatorProvider _clientModelValidatorProvider; private readonly IModelMetadataProvider _metadataProvider; - private readonly IUrlHelper _urlHelper; + private readonly IUrlHelperFactory _urlHelperFactory; private readonly HtmlEncoder _htmlEncoder; /// @@ -44,7 +45,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures IAntiforgery antiforgery, IOptions optionsAccessor, IModelMetadataProvider metadataProvider, - IUrlHelper urlHelper, + IUrlHelperFactory urlHelperFactory, HtmlEncoder htmlEncoder) { if (antiforgery == null) @@ -62,9 +63,9 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures throw new ArgumentNullException(nameof(metadataProvider)); } - if (urlHelper == null) + if (urlHelperFactory == null) { - throw new ArgumentNullException(nameof(urlHelper)); + throw new ArgumentNullException(nameof(urlHelperFactory)); } if (htmlEncoder == null) @@ -76,7 +77,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures var clientValidatorProviders = optionsAccessor.Value.ClientModelValidatorProviders; _clientModelValidatorProvider = new CompositeClientModelValidatorProvider(clientValidatorProviders); _metadataProvider = metadataProvider; - _urlHelper = urlHelper; + _urlHelperFactory = urlHelperFactory; _htmlEncoder = htmlEncoder; // Underscores are fine characters in id's. @@ -106,6 +107,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// public virtual TagBuilder GenerateActionLink( + ViewContext viewContext, string linkText, string actionName, string controllerName, @@ -115,12 +117,18 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures object routeValues, object htmlAttributes) { + if (viewContext == null) + { + throw new ArgumentNullException(nameof(viewContext)); + } + if (linkText == null) { throw new ArgumentNullException(nameof(linkText)); } - var url = _urlHelper.Action(actionName, controllerName, routeValues, protocol, hostname, fragment); + var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext); + var url = urlHelper.Action(actionName, controllerName, routeValues, protocol, hostname, fragment); return GenerateLink(linkText, url, htmlAttributes); } @@ -242,7 +250,8 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures } else { - action = _urlHelper.Action(action: actionName, controller: controllerName, values: routeValues); + var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext); + action = urlHelper.Action(action: actionName, controller: controllerName, values: routeValues); } return GenerateFormCore(viewContext, action, method, htmlAttributes); @@ -261,8 +270,8 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures throw new ArgumentNullException(nameof(viewContext)); } - var action = - _urlHelper.RouteUrl(routeName, values: routeValues, protocol: null, host: null, fragment: null); + var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext); + var action = urlHelper.RouteUrl(routeName, routeValues); return GenerateFormCore(viewContext, action, method, htmlAttributes); } @@ -444,6 +453,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures /// public virtual TagBuilder GenerateRouteLink( + ViewContext viewContext, string linkText, string routeName, string protocol, @@ -452,12 +462,18 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures object routeValues, object htmlAttributes) { + if (viewContext == null) + { + throw new ArgumentNullException(nameof(viewContext)); + } + if (linkText == null) { throw new ArgumentNullException(nameof(linkText)); } - var url = _urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment); + var urlHelper = _urlHelperFactory.GetUrlHelper(viewContext); + var url = urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment); return GenerateLink(linkText, url, htmlAttributes); } diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs index 16e9d30190..f71e39c008 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/HtmlHelper.cs @@ -241,6 +241,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures } var tagBuilder = _htmlGenerator.GenerateActionLink( + ViewContext, linkText, actionName, controllerName, @@ -630,6 +631,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures } var tagBuilder = _htmlGenerator.GenerateRouteLink( + ViewContext, linkText, routeName, protocol, diff --git a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/IHtmlGenerator.cs b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/IHtmlGenerator.cs index 2ff06a137e..81379f8f9e 100644 --- a/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/IHtmlGenerator.cs +++ b/src/Microsoft.AspNet.Mvc.ViewFeatures/ViewFeatures/IHtmlGenerator.cs @@ -21,7 +21,31 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures string FormatValue(object value, string format); + /// + /// Generate a <a> element for a link to an action. + /// + /// The instance for the current scope. + /// The text to insert inside the element. + /// The name of the action method. + /// The name of the controller. + /// The protocol (scheme) for the generated link. + /// The hostname for the generated link. + /// The fragment for the genrated link. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route parameters. + /// + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// + /// + /// A instance for the <a> element. + /// TagBuilder GenerateActionLink( + ViewContext viewContext, string linkText, string actionName, string controllerName, @@ -158,7 +182,30 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures bool? isChecked, object htmlAttributes); + /// + /// Generate a <a> element for a link to an action. + /// + /// The instance for the current scope. + /// The text to insert inside the element. + /// The name of the route to use for link generation. + /// The protocol (scheme) for the generated link. + /// The hostname for the generated link. + /// The fragment for the genrated link. + /// + /// An that contains the parameters for a route. The parameters are retrieved through + /// reflection by examining the properties of the . This is typically + /// created using initializer syntax. Alternatively, an + /// instance containing the route parameters. + /// + /// + /// An that contains the HTML attributes for the element. Alternatively, an + /// instance containing the HTML attributes. + /// + /// + /// A instance for the <a> element. + /// TagBuilder GenerateRouteLink( + ViewContext viewContext, string linkText, string routeName, string protocol, diff --git a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs index a79f5c0342..b9e34f6d65 100644 --- a/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs +++ b/src/Microsoft.AspNet.Mvc.WebApiCompatShim/ApiController.cs @@ -9,6 +9,7 @@ using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Validation; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.WebApiCompatShim; using Microsoft.Extensions.DependencyInjection; using Microsoft.Net.Http.Headers; @@ -81,7 +82,7 @@ namespace System.Web.Http { if (_metadataProvider == null) { - _metadataProvider = Context?.RequestServices?.GetRequiredService(); + _metadataProvider = Context?.RequestServices.GetRequiredService(); } return _metadataProvider; @@ -101,7 +102,7 @@ namespace System.Web.Http { if (_objectValidator == null) { - _objectValidator = Context?.RequestServices?.GetRequiredService(); + _objectValidator = Context?.RequestServices.GetRequiredService(); } return _objectValidator; @@ -155,7 +156,8 @@ namespace System.Web.Http { if (_urlHelper == null) { - _urlHelper = Context?.RequestServices?.GetRequiredService(); + var factory = Context?.RequestServices.GetRequiredService(); + _urlHelper = factory?.GetUrlHelper(ActionContext); } return _urlHelper; diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/LocalRedirectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/LocalRedirectResultTest.cs index 60aaa4d69d..053b570df0 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/LocalRedirectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/LocalRedirectResultTest.cs @@ -99,10 +99,10 @@ namespace Microsoft.AspNet.Mvc return new ActionContext(httpContext, routeData, new ActionDescriptor()); } - private static IServiceProvider GetServiceProvider(IUrlHelper urlHelper) + private static IServiceProvider GetServiceProvider() { var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(urlHelper); + serviceCollection.AddSingleton(); serviceCollection.AddTransient(); return serviceCollection.BuildServiceProvider(); } @@ -114,10 +114,7 @@ namespace Microsoft.AspNet.Mvc HttpResponse response) { var httpContext = new Mock(); - var actionContext = GetActionContext(httpContext.Object); - var actionContextAccessor = new ActionContextAccessor() { ActionContext = actionContext }; - var urlHelper = new UrlHelper(actionContextAccessor); - var serviceProvider = GetServiceProvider(urlHelper); + var serviceProvider = GetServiceProvider(); httpContext.Setup(o => o.Response) .Returns(response); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs index be20c92ff6..a8b83ed88f 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectResultTest.cs @@ -107,10 +107,10 @@ namespace Microsoft.AspNet.Mvc new ActionDescriptor()); } - private static IServiceProvider GetServiceProvider(IUrlHelper urlHelper) + private static IServiceProvider GetServiceProvider() { var serviceCollection = new ServiceCollection(); - serviceCollection.AddSingleton(urlHelper); + serviceCollection.AddSingleton(); serviceCollection.AddTransient(); return serviceCollection.BuildServiceProvider(); } @@ -122,10 +122,7 @@ namespace Microsoft.AspNet.Mvc HttpResponse response) { var httpContext = new Mock(); - var actionContext = GetActionContext(httpContext.Object); - var actionContextAccessor = new ActionContextAccessor() { ActionContext = actionContext }; - var urlHelper = new UrlHelper(actionContextAccessor); - var serviceProvider = GetServiceProvider(urlHelper); + var serviceProvider = GetServiceProvider(); httpContext.Setup(o => o.Response) .Returns(response); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs index e8f77f0c98..3c9b97bf5b 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/RedirectToRouteResultTest.cs @@ -90,15 +90,20 @@ namespace Microsoft.AspNet.Mvc // Arrange var routeName = "orders_api"; var locationUrl = "/api/orders/10"; + var urlHelper = new Mock(); - urlHelper.Setup(uh => uh.RouteUrl(It.IsAny())) + urlHelper + .Setup(uh => uh.RouteUrl(It.IsAny())) .Returns(locationUrl) .Verifiable(); - + var factory = new Mock(); + factory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper.Object); var serviceProvider = new Mock(); serviceProvider - .Setup(sp => sp.GetService(typeof(IUrlHelper))) - .Returns(urlHelper.Object); + .Setup(sp => sp.GetService(typeof(IUrlHelperFactory))) + .Returns(factory.Object); serviceProvider .Setup(sp => sp.GetService(typeof(ILoggerFactory))) .Returns(NullLoggerFactory.Instance); diff --git a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs index 9f0446285d..48e3daf9eb 100644 --- a/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.Core.Test/Routing/UrlHelperTest.cs @@ -10,7 +10,6 @@ using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Routing; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging.Testing; using Microsoft.Extensions.OptionsModel; @@ -32,9 +31,9 @@ namespace Microsoft.AspNet.Mvc.Routing string expectedPath) { // Arrange - var context = CreateHttpContext(GetServices(), appRoot); - var contextAccessor = CreateActionContext(context); - var urlHelper = CreateUrlHelper(contextAccessor); + var httpContext = CreateHttpContext(GetServices(), appRoot); + var actionContext = CreateActionContext(httpContext); + var urlHelper = CreateUrlHelper(actionContext); // Act var path = urlHelper.Content(contentPath); @@ -57,9 +56,9 @@ namespace Microsoft.AspNet.Mvc.Routing string expectedPath) { // Arrange - var context = CreateHttpContext(GetServices(), appRoot); - var contextAccessor = CreateActionContext(context); - var urlHelper = CreateUrlHelper(contextAccessor); + var httpContext = CreateHttpContext(GetServices(), appRoot); + var actionContext = CreateActionContext(httpContext); + var urlHelper = CreateUrlHelper(actionContext); // Act var path = urlHelper.Content(contentPath); @@ -754,13 +753,21 @@ namespace Microsoft.AspNet.Mvc.Routing "{first}/{controller}/{action}", new { second = "default", controller = "default", action = "default" }); - var actionContext = services.GetService().ActionContext; + var actionContext = new ActionContext() + { + HttpContext = new DefaultHttpContext() + { + RequestServices = services, + }, + }; + + actionContext.RouteData = new RouteData(); actionContext.RouteData.Values.Add("first", "a"); actionContext.RouteData.Values.Add("controller", "Store"); actionContext.RouteData.Values.Add("action", "Buy"); actionContext.RouteData.Routers.Add(routeBuilder.Build()); - var urlHelper = CreateUrlHelper(services); + var urlHelper = CreateUrlHelper(actionContext); // Act // @@ -791,14 +798,22 @@ namespace Microsoft.AspNet.Mvc.Routing "{first}/{second}/{controller}/{action}", new { second = "default", controller = "default", action = "default" }); - var actionContext = services.GetService().ActionContext; + var actionContext = new ActionContext() + { + HttpContext = new DefaultHttpContext() + { + RequestServices = services, + }, + }; + + actionContext.RouteData = new RouteData(); actionContext.RouteData.Values.Add("first", "a"); actionContext.RouteData.Values.Add("second", "x"); actionContext.RouteData.Values.Add("controller", "Store"); actionContext.RouteData.Values.Add("action", "Buy"); actionContext.RouteData.Routers.Add(routeBuilder.Build()); - var urlHelper = CreateUrlHelper(services); + var urlHelper = CreateUrlHelper(actionContext); // Act // @@ -831,13 +846,21 @@ namespace Microsoft.AspNet.Mvc.Routing "{first}/{controller}/{action}", new { second = "default", controller = "default", action = "default" }); - var actionContext = services.GetService().ActionContext; + var actionContext = new ActionContext() + { + HttpContext = new DefaultHttpContext() + { + RequestServices = services, + }, + }; + + actionContext.RouteData = new RouteData(); actionContext.RouteData.Values.Add("first", "a"); actionContext.RouteData.Values.Add("controller", "Store"); actionContext.RouteData.Values.Add("action", "Buy"); actionContext.RouteData.Routers.Add(routeBuilder.Build()); - var urlHelper = CreateUrlHelper(services); + var urlHelper = CreateUrlHelper(actionContext); // Act // @@ -864,18 +887,17 @@ namespace Microsoft.AspNet.Mvc.Routing return context; } - private static IActionContextAccessor CreateActionContext(HttpContext context) + private static ActionContext CreateActionContext(HttpContext context) { return CreateActionContext(context, (new Mock()).Object); } - private static IActionContextAccessor CreateActionContext(HttpContext context, IRouter router) + private static ActionContext CreateActionContext(HttpContext context, IRouter router) { var routeData = new RouteData(); routeData.Routers.Add(router); - var actionContext = new ActionContext(context, routeData, new ActionDescriptor()); - return new ActionContextAccessor() { ActionContext = actionContext }; + return new ActionContext(context, routeData, new ActionDescriptor()); } private static UrlHelper CreateUrlHelper() @@ -887,9 +909,9 @@ namespace Microsoft.AspNet.Mvc.Routing return new UrlHelper(actionContext); } - private static UrlHelper CreateUrlHelper(IServiceProvider services) + private static UrlHelper CreateUrlHelper(ActionContext context) { - return new UrlHelper(services.GetRequiredService()); + return new UrlHelper(context); } private static UrlHelper CreateUrlHelper(string host) @@ -915,11 +937,6 @@ namespace Microsoft.AspNet.Mvc.Routing return new UrlHelper(actionContext); } - private static UrlHelper CreateUrlHelper(IActionContextAccessor contextAccessor) - { - return new UrlHelper(contextAccessor); - } - private static UrlHelper CreateUrlHelper(string appBase, IRouter router) { var services = GetServices(); @@ -960,20 +977,6 @@ namespace Microsoft.AspNet.Mvc.Routing .Setup(s => s.GetService(typeof(ILoggerFactory))) .Returns(NullLoggerFactory.Instance); - services - .Setup(s => s.GetService(typeof(IActionContextAccessor))) - .Returns(new ActionContextAccessor() - { - ActionContext = new ActionContext() - { - HttpContext = new DefaultHttpContext() - { - RequestServices = services.Object, - }, - RouteData = new RouteData(), - }, - }); - return services.Object; } diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/ControllerFromServicesTests.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/ControllerFromServicesTests.cs index 4fec8cfd04..ed72ae1b50 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/ControllerFromServicesTests.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/ControllerFromServicesTests.cs @@ -1,13 +1,9 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using System; using System.Net; using System.Net.Http; using System.Threading.Tasks; -using ControllersFromServicesWebSite; -using Microsoft.AspNet.Builder; -using Microsoft.Extensions.DependencyInjection; using Xunit; namespace Microsoft.AspNet.Mvc.FunctionalTests diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs index 866322f83a..8e8f1c1874 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/RazorPageTest.cs @@ -12,6 +12,7 @@ using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.TestCommon; using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Mvc.ViewFeatures; @@ -555,17 +556,23 @@ namespace Microsoft.AspNet.Mvc.Razor // Arrange var expected = "urlhelper-url"; var helper = new Mock(); - helper.Setup(h => h.Content("url")) - .Returns(expected) - .Verifiable(); + helper + .Setup(h => h.Content("url")) + .Returns(expected) + .Verifiable(); + var factory = new Mock(); + factory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(helper.Object); + var page = CreatePage(v => { v.HtmlEncoder = new HtmlTestEncoder(); v.Write(v.Href("url")); }); var services = new Mock(); - services.Setup(s => s.GetService(typeof(IUrlHelper))) - .Returns(helper.Object); + services.Setup(s => s.GetService(typeof(IUrlHelperFactory))) + .Returns(factory.Object); page.Context.RequestServices = services.Object; // Act diff --git a/test/Microsoft.AspNet.Mvc.Razor.Test/TagHelpers/UrlResolutionTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.Razor.Test/TagHelpers/UrlResolutionTagHelperTest.cs index 6549530ce0..1cb2e7e20d 100644 --- a/test/Microsoft.AspNet.Mvc.Razor.Test/TagHelpers/UrlResolutionTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.Razor.Test/TagHelpers/UrlResolutionTagHelperTest.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Reflection; using System.Threading.Tasks; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Razor.TagHelpers; using Microsoft.Extensions.WebEncoders.Testing; using Moq; @@ -58,7 +59,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers urlHelperMock .Setup(urlHelper => urlHelper.Content(It.IsAny())) .Returns(new Func(value => "/approot" + value.Substring(1))); - var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, new HtmlTestEncoder()); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelperMock.Object); + var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, new HtmlTestEncoder()); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList( @@ -114,7 +119,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers urlHelperMock .Setup(urlHelper => urlHelper.Content(It.IsAny())) .Returns("approot/home/index.html"); - var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, htmlEncoder: null); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelperMock.Object); + var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, htmlEncoder: null); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList( @@ -143,7 +152,7 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers { "href", true } }, getChildContentAsync: _ => Task.FromResult(null)); - var tagHelper = new UrlResolutionTagHelper(urlHelper: null, htmlEncoder: null); + var tagHelper = new UrlResolutionTagHelper(urlHelperFactory: null, htmlEncoder: null); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList( @@ -184,7 +193,11 @@ namespace Microsoft.AspNet.Mvc.Razor.TagHelpers urlHelperMock .Setup(urlHelper => urlHelper.Content(It.IsAny())) .Returns("UnexpectedResult"); - var tagHelper = new UrlResolutionTagHelper(urlHelperMock.Object, htmlEncoder: null); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelperMock.Object); + var tagHelper = new UrlResolutionTagHelper(urlHelperFactory.Object, htmlEncoder: null); var context = new TagHelperContext( allAttributes: new ReadOnlyTagHelperAttributeList( diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/AnchorTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/AnchorTagHelperTest.cs index 09ca712dd2..ae4fe0be71 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/AnchorTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/AnchorTagHelperTest.cs @@ -71,6 +71,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers { { "name", "value" }, }, + ViewContext = viewContext, }; // Act @@ -109,6 +110,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var generator = new Mock(MockBehavior.Strict); generator .Setup(mock => mock.GenerateRouteLink( + It.IsAny(), string.Empty, "Default", "http", @@ -157,6 +159,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var generator = new Mock(); generator .Setup(mock => mock.GenerateActionLink( + It.IsAny(), string.Empty, "Index", "Home", diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ImageTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ImageTagHelperTest.cs index 8f83923439..b022fffe45 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ImageTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ImageTagHelperTest.cs @@ -13,6 +13,7 @@ using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Razor.TagHelpers; @@ -63,12 +64,16 @@ namespace Microsoft.AspNet.Mvc.TagHelpers urlHelper .Setup(urlhelper => urlhelper.Content(It.IsAny())) .Returns(new Func(url => url.Replace("~/", "virtualRoot/"))); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper.Object); var helper = new ImageTagHelper( hostingEnvironment, MakeCache(), new HtmlTestEncoder(), - urlHelper.Object) + urlHelperFactory.Object) { ViewContext = viewContext, AppendVersion = true, @@ -118,7 +123,11 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) + var helper = new ImageTagHelper( + hostingEnvironment, + MakeCache(), + new HtmlTestEncoder(), + MakeUrlHelperFactory()) { ViewContext = viewContext, Src = "testimage.png", @@ -159,7 +168,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) + var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory()) { ViewContext = viewContext, Src = "/images/test-image.png", @@ -195,7 +204,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext(); - var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) + var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory()) { ViewContext = viewContext, Src = "/images/test-image.png", @@ -231,7 +240,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers var hostingEnvironment = MakeHostingEnvironment(); var viewContext = MakeViewContext("/bar"); - var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelper()) + var helper = new ImageTagHelper(hostingEnvironment, MakeCache(), new HtmlTestEncoder(), MakeUrlHelperFactory()) { ViewContext = viewContext, Src = "/bar/images/image.jpg", @@ -332,7 +341,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers return cache.Object; } - private static IUrlHelper MakeUrlHelper() + private static IUrlHelperFactory MakeUrlHelperFactory() { var urlHelper = new Mock(); @@ -340,7 +349,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers .Setup(helper => helper.Content(It.IsAny())) .Returns(new Func(url => url)); - return urlHelper.Object; + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper.Object); + + return urlHelperFactory.Object; } } } diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs index 3273881e51..ebf2d04ace 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/LinkTagHelperTest.cs @@ -25,6 +25,7 @@ using Microsoft.Extensions.Primitives; using Microsoft.Extensions.WebEncoders.Testing; using Moq; using Xunit; +using Microsoft.AspNet.Mvc.Routing; namespace Microsoft.AspNet.Mvc.TagHelpers { @@ -64,6 +65,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers urlHelper .Setup(urlhelper => urlhelper.Content(It.IsAny())) .Returns(new Func(url => url.Replace("~/", "virtualRoot/"))); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper.Object); var helper = new LinkTagHelper( logger.Object, @@ -71,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - urlHelper.Object) + urlHelperFactory.Object) { ViewContext = viewContext, AppendVersion = true, @@ -170,7 +175,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, FallbackHref = "test.css", @@ -290,7 +295,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, GlobbingUrlBuilder = globbingUrlBuilder.Object @@ -386,7 +391,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, GlobbingUrlBuilder = globbingUrlBuilder.Object @@ -433,7 +438,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, FallbackHref = "test.css", @@ -543,7 +548,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, }; @@ -575,7 +580,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, }; @@ -618,7 +623,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { GlobbingUrlBuilder = globbingUrlBuilder.Object, ViewContext = viewContext, @@ -663,7 +668,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { GlobbingUrlBuilder = globbingUrlBuilder.Object, ViewContext = viewContext, @@ -706,7 +711,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, Href = "/css/site.css", @@ -746,7 +751,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, Href = "/bar/css/site.css", @@ -790,7 +795,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { GlobbingUrlBuilder = globbingUrlBuilder.Object, ViewContext = viewContext, @@ -897,15 +902,19 @@ namespace Microsoft.AspNet.Mvc.TagHelpers return cache.Object; } - private static IUrlHelper MakeUrlHelper() + private static IUrlHelperFactory MakeUrlHelperFactory() { var urlHelper = new Mock(); urlHelper .Setup(helper => helper.Content(It.IsAny())) .Returns(new Func(url => url)); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper.Object); - return urlHelper.Object; + return urlHelperFactory.Object; } } } diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs index 799ed7f82b..38739b4143 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/ScriptTagHelperTest.cs @@ -25,6 +25,7 @@ using Microsoft.Extensions.Primitives; using Microsoft.Extensions.WebEncoders.Testing; using Moq; using Xunit; +using Microsoft.AspNet.Mvc.Routing; namespace Microsoft.AspNet.Mvc.TagHelpers { @@ -64,6 +65,10 @@ namespace Microsoft.AspNet.Mvc.TagHelpers urlHelper .Setup(urlhelper => urlhelper.Content(It.IsAny())) .Returns(new Func(url => url.Replace("~/", "virtualRoot/"))); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper.Object); var helper = new ScriptTagHelper( logger.Object, @@ -71,7 +76,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - urlHelper.Object) + urlHelperFactory.Object) { ViewContext = viewContext, AppendVersion = true, @@ -119,7 +124,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, FallbackSrc = "~/blank.js", @@ -281,7 +286,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, GlobbingUrlBuilder = globbingUrlBuilder.Object @@ -378,7 +383,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, GlobbingUrlBuilder = globbingUrlBuilder.Object @@ -474,7 +479,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, }; @@ -509,7 +514,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, }; @@ -553,7 +558,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, }; @@ -583,7 +588,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, }; @@ -635,7 +640,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, FallbackSrc = "~/blank.js", @@ -677,7 +682,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { GlobbingUrlBuilder = globbingUrlBuilder.Object, ViewContext = viewContext, @@ -718,7 +723,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { GlobbingUrlBuilder = globbingUrlBuilder.Object, ViewContext = viewContext, @@ -757,7 +762,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, AppendVersion = true, @@ -794,7 +799,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, AppendVersion = true, @@ -833,7 +838,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { ViewContext = viewContext, FallbackSrc = "fallback.js", @@ -878,7 +883,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers MakeCache(), new HtmlTestEncoder(), new JavaScriptTestEncoder(), - MakeUrlHelper()) + MakeUrlHelperFactory()) { GlobbingUrlBuilder = globbingUrlBuilder.Object, ViewContext = viewContext, @@ -994,7 +999,7 @@ namespace Microsoft.AspNet.Mvc.TagHelpers return cache.Object; } - private static IUrlHelper MakeUrlHelper() + private static IUrlHelperFactory MakeUrlHelperFactory() { var urlHelper = new Mock(); @@ -1002,7 +1007,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers .Setup(helper => helper.Content(It.IsAny())) .Returns(new Func(url => url)); - return urlHelper.Object; + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper.Object); + + return urlHelperFactory.Object; } } } diff --git a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TestableHtmlGenerator.cs b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TestableHtmlGenerator.cs index 0fe3563e07..94fbdcd459 100644 --- a/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TestableHtmlGenerator.cs +++ b/test/Microsoft.AspNet.Mvc.TagHelpers.Test/TestableHtmlGenerator.cs @@ -43,7 +43,12 @@ namespace Microsoft.AspNet.Mvc.TagHelpers IOptions options, IUrlHelper urlHelper, IDictionary validationAttributes) - : base(Mock.Of(), options, metadataProvider, urlHelper, new HtmlTestEncoder()) + : base( + Mock.Of(), + options, + metadataProvider, + CreateUrlHelperFactory(urlHelper), + new HtmlTestEncoder()) { _validationAttributes = validationAttributes; } @@ -107,5 +112,15 @@ namespace Microsoft.AspNet.Mvc.TagHelpers return mockOptions.Object; } + + private static IUrlHelperFactory CreateUrlHelperFactory(IUrlHelper urlHelper) + { + var factory = new Mock(); + factory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper); + + return factory.Object; + } } } \ No newline at end of file diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs index e73600fc97..4953e6af15 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/RemoteAttributeTest.cs @@ -441,8 +441,13 @@ namespace Microsoft.AspNet.Mvc private static ClientModelValidationContext GetValidationContext(IUrlHelper urlHelper) { + var factory = new Mock(); + factory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper); + var serviceCollection = GetServiceCollection(); - serviceCollection.AddSingleton(urlHelper); + serviceCollection.AddSingleton(factory.Object); var serviceProvider = serviceCollection.BuildServiceProvider(); var actionContext = new ActionContext() @@ -478,9 +483,15 @@ namespace Microsoft.AspNet.Mvc routeData.Values["area"] = currentArea; } - var contextAccessor = GetContextAccessor(serviceProvider, routeData); - var urlHelper = new UrlHelper(contextAccessor); - serviceCollection.AddSingleton(urlHelper); + var context = GetActionContext(serviceProvider, routeData); + + var urlHelper = new UrlHelper(context); + var factory = new Mock(); + factory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper); + + serviceCollection.AddSingleton(factory.Object); serviceProvider = serviceCollection.BuildServiceProvider(); var actionContext = new ActionContext() @@ -507,12 +518,17 @@ namespace Microsoft.AspNet.Mvc }, }; - var contextAccessor = GetContextAccessor(serviceProvider, routeData); - var urlHelper = new UrlHelper(contextAccessor); - serviceCollection.AddSingleton(urlHelper); - contextAccessor.ActionContext.HttpContext.RequestServices = serviceCollection.BuildServiceProvider(); + var context = GetActionContext(serviceProvider, routeData); + var urlHelper = new UrlHelper(context); + var factory = new Mock(); + factory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper); - return new ClientModelValidationContext(contextAccessor.ActionContext, _metadata, _metadataProvider); + serviceCollection.AddSingleton(factory.Object); + context.HttpContext.RequestServices = serviceCollection.BuildServiceProvider(); + + return new ClientModelValidationContext(context, _metadata, _metadataProvider); } private static IRouter GetRouteCollectionWithArea(IServiceProvider serviceProvider) @@ -553,7 +569,7 @@ namespace Microsoft.AspNet.Mvc return builder; } - private static IActionContextAccessor GetContextAccessor( + private static ActionContext GetActionContext( IServiceProvider serviceProvider, RouteData routeData = null) { @@ -572,13 +588,7 @@ namespace Microsoft.AspNet.Mvc }; } - var actionContext = new ActionContext(httpContext, routeData, new ActionDescriptor()); - var contextAccessor = new ActionContextAccessor() - { - ActionContext = actionContext, - }; - - return contextAccessor; + return new ActionContext(httpContext, routeData, new ActionDescriptor()); } private static ServiceCollection GetServiceCollection() diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs index 7bd01614fd..2feed8b4c1 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/Rendering/DefaultTemplatesUtilities.cs @@ -14,6 +14,7 @@ using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.ModelBinding.Validation; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Routing; @@ -232,13 +233,18 @@ namespace Microsoft.AspNet.Mvc.Rendering .SetupGet(o => o.Value) .Returns(options); + var urlHelperFactory = new Mock(); + urlHelperFactory + .Setup(f => f.GetUrlHelper(It.IsAny())) + .Returns(urlHelper); + var serviceProvider = new Mock(); serviceProvider .Setup(s => s.GetService(typeof(ICompositeViewEngine))) .Returns(viewEngine); serviceProvider - .Setup(s => s.GetService(typeof(IUrlHelper))) - .Returns(urlHelper); + .Setup(s => s.GetService(typeof(IUrlHelperFactory))) + .Returns(urlHelperFactory.Object); serviceProvider .Setup(s => s.GetService(typeof(IViewComponentHelper))) .Returns(new Mock().Object); @@ -253,7 +259,7 @@ namespace Microsoft.AspNet.Mvc.Rendering Mock.Of(), optionsAccessor.Object, provider, - urlHelper, + urlHelperFactory.Object, new HtmlTestEncoder()); } diff --git a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultHtmlGeneratorTest.cs b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultHtmlGeneratorTest.cs index 95c4935bbe..1bb6bf9792 100644 --- a/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultHtmlGeneratorTest.cs +++ b/test/Microsoft.AspNet.Mvc.ViewFeatures.Test/ViewFeatures/DefaultHtmlGeneratorTest.cs @@ -11,6 +11,7 @@ using Microsoft.AspNet.Http.Internal; using Microsoft.AspNet.Mvc.Abstractions; using Microsoft.AspNet.Mvc.ModelBinding; using Microsoft.AspNet.Mvc.Rendering; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.AspNet.Mvc.ViewEngines; using Microsoft.AspNet.Routing; using Microsoft.Extensions.OptionsModel; @@ -656,7 +657,7 @@ namespace Microsoft.AspNet.Mvc.ViewFeatures antiforgery, mvcViewOptionsAccessor.Object, metadataProvider, - Mock.Of(), + new UrlHelperFactory(), htmlEncoder); } diff --git a/test/WebSites/ControllersFromServicesClassLibrary/ControllerWithConstructorInjection.cs b/test/WebSites/ControllersFromServicesClassLibrary/ControllerWithConstructorInjection.cs index 080a3aa1c7..39edafda44 100644 --- a/test/WebSites/ControllersFromServicesClassLibrary/ControllerWithConstructorInjection.cs +++ b/test/WebSites/ControllersFromServicesClassLibrary/ControllerWithConstructorInjection.cs @@ -1,7 +1,6 @@ // Copyright (c) .NET Foundation. All rights reserved. // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. -using Microsoft.AspNet.Http; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Routing; @@ -9,29 +8,29 @@ namespace ControllersFromServicesClassLibrary { public class ConstructorInjectionController { - public ConstructorInjectionController(IUrlHelper urlHelper, - QueryValueService queryService) + public ConstructorInjectionController(IUrlHelperFactory urlHelperFactory, QueryValueService queryService) { - UrlHelper = urlHelper; + UrlHelperFactory = urlHelperFactory; QueryService = queryService; } - private IUrlHelper UrlHelper { get; } - - private QueryValueService QueryService { get; } - [ActionContext] public ActionContext ActionContext { get; set; } - public HttpRequest Request => ActionContext.HttpContext.Request; + private QueryValueService QueryService { get; } + + private IUrlHelperFactory UrlHelperFactory { get; } [HttpGet("/constructorinjection")] public IActionResult Index() { - var content = string.Join(" ", - UrlHelper.Action(), - QueryService.GetValue(), - Request.Headers["Test-Header"]); + var urlHelper = UrlHelperFactory.GetUrlHelper(ActionContext); + + var content = string.Join( + " ", + urlHelper.Action(), + QueryService.GetValue(), + ActionContext.HttpContext.Request.Headers["Test-Header"]); return new ContentResult { Content = content }; } diff --git a/test/WebSites/RoutingWebSite/Startup.cs b/test/WebSites/RoutingWebSite/Startup.cs index 15b3f6170f..ed86074c58 100644 --- a/test/WebSites/RoutingWebSite/Startup.cs +++ b/test/WebSites/RoutingWebSite/Startup.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; namespace RoutingWebSite @@ -14,6 +15,7 @@ namespace RoutingWebSite services.AddMvc(); services.AddScoped(); + services.AddSingleton(); } public void Configure(IApplicationBuilder app) diff --git a/test/WebSites/RoutingWebSite/TestResponseGenerator.cs b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs index 4560ea65f2..4005a3c35c 100644 --- a/test/WebSites/RoutingWebSite/TestResponseGenerator.cs +++ b/test/WebSites/RoutingWebSite/TestResponseGenerator.cs @@ -7,7 +7,7 @@ using System.Linq; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Controllers; using Microsoft.AspNet.Mvc.Infrastructure; -using Microsoft.Extensions.DependencyInjection; +using Microsoft.AspNet.Mvc.Routing; namespace RoutingWebSite { @@ -15,9 +15,12 @@ namespace RoutingWebSite public class TestResponseGenerator { private readonly ActionContext _actionContext; + private readonly IUrlHelperFactory _urlHelperFactory; - public TestResponseGenerator(IActionContextAccessor contextAccessor) + public TestResponseGenerator(IActionContextAccessor contextAccessor, IUrlHelperFactory urlHelperFactory) { + _urlHelperFactory = urlHelperFactory; + _actionContext = contextAccessor.ActionContext; if (_actionContext == null) { @@ -35,7 +38,7 @@ namespace RoutingWebSite .Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller") .ToDictionary(kvp => kvp.Key.Substring("link_".Length), kvp => (object)kvp.Value[0]); - var urlHelper = _actionContext.HttpContext.RequestServices.GetRequiredService(); + var urlHelper = _urlHelperFactory.GetUrlHelper(_actionContext); link = urlHelper.Action(query["link_action"], query["link_controller"], values); } diff --git a/test/WebSites/TagHelpersWebSite/TagHelpers/ATagHelper.cs b/test/WebSites/TagHelpersWebSite/TagHelpers/ATagHelper.cs index 5d6d16644b..12d4e50cd2 100644 --- a/test/WebSites/TagHelpersWebSite/TagHelpers/ATagHelper.cs +++ b/test/WebSites/TagHelpersWebSite/TagHelpers/ATagHelper.cs @@ -3,20 +3,26 @@ using System.Linq; using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.Rendering; using Microsoft.AspNet.Mvc.Routing; +using Microsoft.AspNet.Mvc.ViewFeatures; using Microsoft.AspNet.Razor.TagHelpers; namespace TagHelpersWebSite.TagHelpers { public class ATagHelper : TagHelper { - public ATagHelper(IUrlHelper urlHelper) + public ATagHelper(IUrlHelperFactory urlHelperFactory) { - UrlHelper = urlHelper; + UrlHelperFactory = urlHelperFactory; } [HtmlAttributeNotBound] - public IUrlHelper UrlHelper { get; } + public IUrlHelperFactory UrlHelperFactory { get; } + + [ViewContext] + [HtmlAttributeNotBound] + public ViewContext ViewContext { get; set; } public string Controller { get; set; } @@ -33,7 +39,8 @@ namespace TagHelpersWebSite.TagHelpers // be parameters to our final href value. output.Attributes.Clear(); - output.Attributes["href"] = UrlHelper.Action(Action, Controller, methodParameters); + var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext); + output.Attributes["href"] = urlHelper.Action(Action, Controller, methodParameters); output.PreContent.SetContent("My "); } diff --git a/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs b/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs index 93dbc8af37..388593137f 100644 --- a/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs +++ b/test/WebSites/UrlHelperWebSite/CustomUrlHelper.cs @@ -3,6 +3,7 @@ using System; using Microsoft.AspNet.Http; +using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.AspNet.Mvc.Routing; using Microsoft.Extensions.OptionsModel; @@ -16,16 +17,12 @@ namespace UrlHelperWebSite /// public class CustomUrlHelper : UrlHelper { - private readonly IOptions _appOptions; - private readonly HttpContext _httpContext; + private readonly AppOptions _options; - public CustomUrlHelper( - IActionContextAccessor contextAccessor, - IOptions appOptions) - : base(contextAccessor) + public CustomUrlHelper(ActionContext actionContext, AppOptions options) + : base(actionContext) { - _appOptions = appOptions; - _httpContext = contextAccessor.ActionContext.HttpContext; + _options = options; } /// @@ -36,12 +33,12 @@ namespace UrlHelperWebSite /// public override string Content(string contentPath) { - if (_appOptions.Value.ServeCDNContent + if (_options.ServeCDNContent && contentPath.StartsWith("~/", StringComparison.Ordinal)) { var segment = new PathString(contentPath.Substring(1)); - return ConvertToLowercaseUrl(_appOptions.Value.CDNServerBaseUrl + segment); + return ConvertToLowercaseUrl(_options.CDNServerBaseUrl + segment); } return ConvertToLowercaseUrl(base.Content(contentPath)); @@ -60,7 +57,7 @@ namespace UrlHelperWebSite private string ConvertToLowercaseUrl(string url) { if (!string.IsNullOrEmpty(url) - && _appOptions.Value.GenerateLowercaseUrls) + && _options.GenerateLowercaseUrls) { return url.ToLowerInvariant(); } diff --git a/test/WebSites/UrlHelperWebSite/CustomUrlHelperFactory.cs b/test/WebSites/UrlHelperWebSite/CustomUrlHelperFactory.cs new file mode 100644 index 0000000000..7b95ce7b87 --- /dev/null +++ b/test/WebSites/UrlHelperWebSite/CustomUrlHelperFactory.cs @@ -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 options) + { + _options = options.Value; + } + + public IUrlHelper GetUrlHelper(ActionContext context) + { + return new CustomUrlHelper(context, _options); + } + } +} diff --git a/test/WebSites/UrlHelperWebSite/Startup.cs b/test/WebSites/UrlHelperWebSite/Startup.cs index 56b61c761b..d299c79579 100644 --- a/test/WebSites/UrlHelperWebSite/Startup.cs +++ b/test/WebSites/UrlHelperWebSite/Startup.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Builder; -using Microsoft.AspNet.Mvc; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.Extensions.DependencyInjection; namespace UrlHelperWebSite @@ -22,7 +22,7 @@ namespace UrlHelperWebSite // Add MVC services to the services container services.AddMvc(); - services.AddScoped(); + services.AddSingleton(); } public void Configure(IApplicationBuilder app) diff --git a/test/WebSites/VersioningWebSite/Startup.cs b/test/WebSites/VersioningWebSite/Startup.cs index 51cfdcbb66..6d27b596f4 100644 --- a/test/WebSites/VersioningWebSite/Startup.cs +++ b/test/WebSites/VersioningWebSite/Startup.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using Microsoft.AspNet.Builder; +using Microsoft.AspNet.Mvc.Infrastructure; using Microsoft.Extensions.DependencyInjection; namespace VersioningWebSite @@ -14,6 +15,7 @@ namespace VersioningWebSite services.AddMvc(); services.AddScoped(); + services.AddSingleton(); } public void Configure(IApplicationBuilder app) diff --git a/test/WebSites/VersioningWebSite/TestResponseGenerator.cs b/test/WebSites/VersioningWebSite/TestResponseGenerator.cs index 6d6bb6b77e..654c847f0c 100644 --- a/test/WebSites/VersioningWebSite/TestResponseGenerator.cs +++ b/test/WebSites/VersioningWebSite/TestResponseGenerator.cs @@ -7,6 +7,7 @@ using System.Linq; using Microsoft.AspNet.Mvc; using Microsoft.AspNet.Mvc.Controllers; using Microsoft.AspNet.Mvc.Infrastructure; +using Microsoft.AspNet.Mvc.Routing; using Microsoft.Extensions.DependencyInjection; namespace VersioningWebSite @@ -35,7 +36,7 @@ namespace VersioningWebSite .Where(kvp => kvp.Key != "link" && kvp.Key != "link_action" && kvp.Key != "link_controller") .ToDictionary(kvp => kvp.Key.Substring("link_".Length), kvp => (object)kvp.Value[0]); - var urlHelper = _actionContext.HttpContext.RequestServices.GetRequiredService(); + var urlHelper = GetUrlHelper(_actionContext); link = urlHelper.Action(query["link_action"], query["link_controller"], values); } @@ -54,5 +55,12 @@ namespace VersioningWebSite link, }); } + + private IUrlHelper GetUrlHelper(ActionContext context) + { + var services = context.HttpContext.RequestServices; + var urlHelper = services.GetRequiredService().GetUrlHelper(context); + return urlHelper; + } } } \ No newline at end of file