Making UrlHelper's methods virtual
This commit is contained in:
parent
71964a813c
commit
43c7ddb9b7
15
Mvc.sln
15
Mvc.sln
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.22013.1
|
||||
VisualStudioVersion = 14.0.22115.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DAAE4C74-D06F-4874-A166-33305D2643CE}"
|
||||
EndProject
|
||||
|
|
@ -78,6 +78,8 @@ Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "FiltersWebSite", "test\WebS
|
|||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "XmlSerializerWebSite", "test\WebSites\XmlSerializerWebSite\XmlSerializerWebSite.kproj", "{96107AC0-18E2-474D-BAB4-2FFF2185FBCD}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "UrlHelperWebSite", "test\WebSites\UrlHelperWebSite\UrlHelperWebSite.kproj", "{A192E504-2881-41DC-90D1-B7F1DD1134E8}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
|
@ -398,6 +400,16 @@ Global
|
|||
{96107AC0-18E2-474D-BAB4-2FFF2185FBCD}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{96107AC0-18E2-474D-BAB4-2FFF2185FBCD}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{96107AC0-18E2-474D-BAB4-2FFF2185FBCD}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8}.Release|x86.ActiveCfg = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
@ -435,5 +447,6 @@ Global
|
|||
{6A0B65CE-6B01-40D0-840D-EFF3680D1547} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{1976AC4A-FEA4-4587-A158-D9F79736D2B6} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{96107AC0-18E2-474D-BAB4-2FFF2185FBCD} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
{A192E504-2881-41DC-90D1-B7F1DD1134E8} = {16703B76-C9F7-4C75-AE6C-53D92E308E3C}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
|
|
|
|||
|
|
@ -3,14 +3,52 @@
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the contract for the helper to build URLs for ASP.NET MVC within an application.
|
||||
/// </summary>
|
||||
public interface IUrlHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Generates a fully qualified or absolute URL for an action method by using the specified action name,
|
||||
/// controller name, route values, protocol to use, host name and fragment.
|
||||
/// </summary>
|
||||
/// <param name="action">The name of the action method.</param>
|
||||
/// <param name="controller">The name of the controller.</param>
|
||||
/// <param name="values">An object that contains the parameters for a route.</param>
|
||||
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
|
||||
/// <param name="host">The host name for the URL.</param>
|
||||
/// <param name="fragment">The fragment for the URL.</param>
|
||||
/// <returns>The fully qualified or absolute URL to an action method.</returns>
|
||||
string Action(string action, string controller, object values, string protocol, string host, string fragment);
|
||||
|
||||
/// <summary>
|
||||
/// Converts a virtual (relative) path to an application absolute path.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the specified content path does not start with the tilde (~) character,
|
||||
/// this method returns <paramref name="contentPath"/> unchanged.
|
||||
/// </remarks>
|
||||
/// <param name="contentPath">The virtual path of the content.</param>
|
||||
/// <returns>The application absolute path.</returns>
|
||||
string Content(string contentPath);
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a value that indicates whether the URL is local.
|
||||
/// </summary>
|
||||
/// <param name="url">The URL.</param>
|
||||
/// <returns>true if the URL is local; otherwise, false.</returns>
|
||||
bool IsLocalUrl(string url);
|
||||
|
||||
/// <summary>
|
||||
/// Generates a fully qualified or absolute URL for the specified route values by
|
||||
/// using the specified route name, protocol to use, host name and fragment.
|
||||
/// </summary>
|
||||
/// <param name="routeName">The name of the route that is used to generate URL.</param>
|
||||
/// <param name="values">An object that contains the parameters for a route.</param>
|
||||
/// <param name="protocol">The protocol for the URL, such as "http" or "https".</param>
|
||||
/// <param name="host">The host name for the URL.</param>
|
||||
/// <param name="fragment">The fragment for the URL.</param>
|
||||
/// <returns>The fully qualified or absolute URL.</returns>
|
||||
string RouteUrl(string routeName, object values, string protocol, string host, string fragment);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,10 @@ using Microsoft.Framework.DependencyInjection;
|
|||
|
||||
namespace Microsoft.AspNet.Mvc
|
||||
{
|
||||
/// <summary>
|
||||
/// An implementation of <see cref="IUrlHelper"/> that contains methods to
|
||||
/// build URLs for ASP.NET MVC within an application.
|
||||
/// </summary>
|
||||
public class UrlHelper : IUrlHelper
|
||||
{
|
||||
private readonly HttpContext _httpContext;
|
||||
|
|
@ -18,6 +22,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
private readonly IDictionary<string, object> _ambientValues;
|
||||
private readonly IActionSelector _actionSelector;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="UrlHelper"/> class using the specified action context and action selector.
|
||||
/// </summary>
|
||||
/// <param name="contextAccessor">The <see cref="IContextAccessor{TContext}"/> to access the action context
|
||||
/// of the current request.</param>
|
||||
/// <param name="actionSelector">The <see cref="IActionSelector"/> to be used for verifying the correctness of
|
||||
/// supplied parameters for a route.
|
||||
/// </param>
|
||||
public UrlHelper(IContextAccessor<ActionContext> contextAccessor, IActionSelector actionSelector)
|
||||
{
|
||||
_httpContext = contextAccessor.Value.HttpContext;
|
||||
|
|
@ -26,12 +38,13 @@ namespace Microsoft.AspNet.Mvc
|
|||
_actionSelector = actionSelector;
|
||||
}
|
||||
|
||||
public string Action(
|
||||
string action,
|
||||
string controller,
|
||||
object values,
|
||||
string protocol,
|
||||
string host,
|
||||
/// <inheritdoc />
|
||||
public virtual string Action(
|
||||
string action,
|
||||
string controller,
|
||||
object values,
|
||||
string protocol,
|
||||
string host,
|
||||
string fragment)
|
||||
{
|
||||
var valuesDictionary = TypeHelper.ObjectToDictionary(values);
|
||||
|
|
@ -55,6 +68,7 @@ namespace Microsoft.AspNet.Mvc
|
|||
return GenerateUrl(protocol, host, path, fragment);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsLocalUrl(string url)
|
||||
{
|
||||
return
|
||||
|
|
@ -67,9 +81,11 @@ namespace Microsoft.AspNet.Mvc
|
|||
(url.Length > 1 && url[0] == '~' && url[1] == '/'));
|
||||
}
|
||||
|
||||
public string RouteUrl(string routeName, object values, string protocol, string host, string fragment)
|
||||
/// <inheritdoc />
|
||||
public virtual string RouteUrl(string routeName, object values, string protocol, string host, string fragment)
|
||||
{
|
||||
var valuesDictionary = TypeHelper.ObjectToDictionary(values);
|
||||
|
||||
var path = GeneratePathFromRoute(routeName, valuesDictionary);
|
||||
if (path == null)
|
||||
{
|
||||
|
|
@ -84,7 +100,14 @@ namespace Microsoft.AspNet.Mvc
|
|||
return GeneratePathFromRoute(routeName: null, values: values);
|
||||
}
|
||||
|
||||
private string GeneratePathFromRoute(string routeName, IDictionary<string, object> values)
|
||||
/// <summary>
|
||||
/// Generates the absolute path of the url for the specified route values by
|
||||
/// using the specified route name.
|
||||
/// </summary>
|
||||
/// <param name="routeName">The name of the route that is used to generate the URL.</param>
|
||||
/// <param name="values">A dictionary that contains the parameters for a route.</param>
|
||||
/// <returns>The absolute path of the URL.</returns>
|
||||
protected virtual string GeneratePathFromRoute(string routeName, IDictionary<string, object> values)
|
||||
{
|
||||
var context = new VirtualPathContext(_httpContext, _ambientValues, values, routeName);
|
||||
var path = _router.GetVirtualPath(context);
|
||||
|
|
@ -110,7 +133,8 @@ namespace Microsoft.AspNet.Mvc
|
|||
}
|
||||
}
|
||||
|
||||
public string Content([NotNull] string contentPath)
|
||||
/// <inheritdoc />
|
||||
public virtual string Content([NotNull] string contentPath)
|
||||
{
|
||||
return GenerateClientUrl(_httpContext.Request.PathBase, contentPath);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,10 +38,9 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
[InlineData(null, "~/Home/About", "/Home/About")]
|
||||
[InlineData("/", "~/Home/About", "/Home/About")]
|
||||
[InlineData("/", "~/", "/")]
|
||||
[InlineData("", "~/Home/About", "/Home/About")]
|
||||
[InlineData("/myapproot", "~/", "/myapproot/")]
|
||||
[InlineData("", "~/Home/About", "/Home/About")]
|
||||
[InlineData("/myapproot", "~/", "/myapproot/")]
|
||||
[InlineData("/myapproot", "~/Content/bootstrap.css", "/myapproot/Content/bootstrap.css")]
|
||||
public void Content_ReturnsAppRelativePath_WhenItStartsWithToken(string appRoot,
|
||||
string contentPath,
|
||||
string expectedPath)
|
||||
|
|
@ -382,11 +381,11 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
// Act
|
||||
var url = urlHelper.RouteUrl(routeName: "namedroute",
|
||||
values: new
|
||||
{
|
||||
Action = "newaction",
|
||||
Controller = "home2",
|
||||
id = "someid"
|
||||
},
|
||||
{
|
||||
Action = "newaction",
|
||||
Controller = "home2",
|
||||
id = "someid"
|
||||
},
|
||||
protocol: "https");
|
||||
|
||||
// Assert
|
||||
|
|
@ -436,19 +435,74 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
// Act
|
||||
var url = urlHelper.RouteUrl(routeName: "namedroute",
|
||||
values: new
|
||||
{
|
||||
Action = "newaction",
|
||||
Controller = "home2",
|
||||
id = "someid"
|
||||
});
|
||||
{
|
||||
Action = "newaction",
|
||||
Controller = "home2",
|
||||
id = "someid"
|
||||
});
|
||||
|
||||
// Assert
|
||||
Assert.Equal("/app/named/home2/newaction/someid", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UrlAction_RouteValuesAsDictionary_CaseSensitive()
|
||||
{
|
||||
// Arrange
|
||||
var urlHelper = CreateUrlHelperWithRouteCollection("/app");
|
||||
|
||||
// We're using a dictionary with a case-sensitive comparer and loading it with data
|
||||
// using casings differently from the route. This should still successfully generate a link.
|
||||
var dict = new Dictionary<string, object>();
|
||||
var id = "suppliedid";
|
||||
var isprint = "true";
|
||||
dict["ID"] = id;
|
||||
dict["isprint"] = isprint;
|
||||
|
||||
// Act
|
||||
var url = urlHelper.Action(
|
||||
action: "contact",
|
||||
controller: "home",
|
||||
values: dict);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(2, dict.Count);
|
||||
Assert.Same(id, dict["ID"]);
|
||||
Assert.Same(isprint, dict["isprint"]);
|
||||
Assert.Equal("/app/home/contact/suppliedid?isprint=true", url);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UrlRouteUrl_RouteValuesAsDictionary_CaseSensitive()
|
||||
{
|
||||
// Arrange
|
||||
var urlHelper = CreateUrlHelperWithRouteCollection("/app");
|
||||
|
||||
// We're using a dictionary with a case-sensitive comparer and loading it with data
|
||||
// using casings differently from the route. This should still successfully generate a link.
|
||||
var dict = new Dictionary<string, object>();
|
||||
var action = "contact";
|
||||
var controller = "home";
|
||||
var id = "suppliedid";
|
||||
|
||||
dict["ACTION"] = action;
|
||||
dict["Controller"] = controller;
|
||||
dict["ID"] = id;
|
||||
|
||||
// Act
|
||||
var url = urlHelper.RouteUrl(routeName: "namedroute", values: dict);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(3, dict.Count);
|
||||
Assert.Same(action, dict["ACTION"]);
|
||||
Assert.Same(controller, dict["Controller"]);
|
||||
Assert.Same(id, dict["ID"]);
|
||||
Assert.Equal("/app/named/home/contact/suppliedid", url);
|
||||
}
|
||||
|
||||
private static HttpContext CreateHttpContext(string appRoot, ILoggerFactory factory = null)
|
||||
{
|
||||
if(factory == null)
|
||||
if (factory == null)
|
||||
{
|
||||
factory = NullLoggerFactory.Instance;
|
||||
}
|
||||
|
|
@ -553,7 +607,7 @@ namespace Microsoft.AspNet.Mvc.Core.Test
|
|||
serviceProviderMock.Setup(o => o.GetService(typeof(IInlineConstraintResolver)))
|
||||
.Returns(new DefaultInlineConstraintResolver(serviceProviderMock.Object,
|
||||
accessorMock.Object));
|
||||
|
||||
|
||||
rt.ServiceProvider = serviceProviderMock.Object;
|
||||
rt.MapRoute(string.Empty,
|
||||
"{controller}/{action}/{id}",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.TestHost;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNet.Mvc.FunctionalTests
|
||||
{
|
||||
/// <summary>
|
||||
/// The tests here verify the extensibility of <see cref="UrlHelper"/>.
|
||||
///
|
||||
/// Following are some of the scenarios exercised here:
|
||||
/// 1. Based on configuration, generate Content urls pointing to local or a CDN server
|
||||
/// 2. Based on configuration, generate lower case urls
|
||||
/// </summary>
|
||||
public class CustomUrlHelperTests
|
||||
{
|
||||
private readonly IServiceProvider _services = TestHelper.CreateServices("UrlHelperWebSite");
|
||||
private readonly Action<IApplicationBuilder> _app = new UrlHelperWebSite.Startup().Configure;
|
||||
private const string _cdnServerBaseUrl = "http://cdn.contoso.com";
|
||||
|
||||
[Fact]
|
||||
public async Task CustomUrlHelper_GeneratesUrlFromController()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Home/UrlContent");
|
||||
|
||||
string responseData = await response.Content.ReadAsStringAsync();
|
||||
|
||||
//Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(_cdnServerBaseUrl + "/bootstrap.min.css", responseData);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task CustomUrlHelper_GeneratesUrlFromView()
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync("http://localhost/Home/Index");
|
||||
|
||||
string responseData = await response.Content.ReadAsStringAsync();
|
||||
|
||||
//Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Contains(_cdnServerBaseUrl + "/bootstrap.min.css", responseData);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("http://localhost/Home/LinkByUrlRouteUrl", "/api/simplepoco/10")]
|
||||
[InlineData("http://localhost/Home/LinkByUrlAction", "/home/urlcontent")]
|
||||
public async Task LowercaseUrls_LinkGeneration(string url, string expectedLink)
|
||||
{
|
||||
// Arrange
|
||||
var server = TestServer.Create(_services, _app);
|
||||
var client = server.CreateClient();
|
||||
|
||||
// Act
|
||||
var response = await client.GetAsync(url);
|
||||
|
||||
string responseData = await response.Content.ReadAsStringAsync();
|
||||
|
||||
//Assert
|
||||
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
|
||||
Assert.Equal(expectedLink, responseData, ignoreCase: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -9,7 +9,7 @@
|
|||
"BasicWebSite": "",
|
||||
"CompositeViewEngine": "",
|
||||
"ConnegWebsite": "",
|
||||
"FiltersWebSite": "",
|
||||
"FiltersWebSite": "",
|
||||
"FormatterWebSite": "",
|
||||
"InlineConstraintsWebSite": "",
|
||||
"Microsoft.AspNet.TestHost": "1.0.0-*",
|
||||
|
|
@ -27,6 +27,7 @@
|
|||
"RazorWebSite": "",
|
||||
"ValueProvidersSite": "",
|
||||
"XmlSerializerWebSite": "",
|
||||
"UrlHelperWebSite": "",
|
||||
"Xunit.KRunner": "1.0.0-*"
|
||||
},
|
||||
"commands": {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
using System;
|
||||
|
||||
namespace UrlHelperWebSite
|
||||
{
|
||||
public class AppOptions
|
||||
{
|
||||
public bool ServeCDNContent { get; set; }
|
||||
|
||||
public string CDNServerBaseUrl { get; set; }
|
||||
|
||||
public bool GenerateLowercaseUrls { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"ServeCDNContent": "true",
|
||||
"CDNServerBaseUrl" : "http://cdn.contoso.com",
|
||||
"GenerateLowercaseUrls": "true"
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,30 @@
|
|||
// Copyright (c) Microsoft Open Technologies, Inc. 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;
|
||||
|
||||
namespace UrlHelperWebSite.Controllers
|
||||
{
|
||||
public class HomeController : Controller
|
||||
{
|
||||
public IActionResult Index()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
public string UrlContent()
|
||||
{
|
||||
return Url.Content("~/Bootstrap.min.css");
|
||||
}
|
||||
|
||||
public string LinkByUrlAction()
|
||||
{
|
||||
return Url.Action("UrlContent", "Home", null);
|
||||
}
|
||||
|
||||
public string LinkByUrlRouteUrl()
|
||||
{
|
||||
return Url.RouteUrl("SimplePocoApi", new { id = 10 });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
|
||||
namespace UrlHelperWebSite.Controllers
|
||||
{
|
||||
[Route("api/[controller]/{id?}", Name = "SimplePocoApi")]
|
||||
public class SimplePocoController
|
||||
{
|
||||
private readonly IUrlHelper _urlHelper;
|
||||
|
||||
public SimplePocoController(IUrlHelper urlHelper)
|
||||
{
|
||||
_urlHelper = urlHelper;
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
public string GetById(int id)
|
||||
{
|
||||
return "value:" + id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
using Microsoft.Framework.OptionsModel;
|
||||
|
||||
namespace UrlHelperWebSite
|
||||
{
|
||||
/// <summary>
|
||||
/// Following are some of the scenarios exercised here:
|
||||
/// 1. Based on configuration, generate Content urls pointing to local or a CDN server
|
||||
/// 2. Based on configuration, generate lower case urls
|
||||
/// </summary>
|
||||
public class CustomUrlHelper : UrlHelper
|
||||
{
|
||||
private readonly IOptionsAccessor<AppOptions> _appOptions;
|
||||
private readonly HttpContext _httpContext;
|
||||
|
||||
public CustomUrlHelper(IContextAccessor<ActionContext> contextAccessor, IActionSelector actionSelector,
|
||||
IOptionsAccessor<AppOptions> appOptions)
|
||||
: base(contextAccessor, actionSelector)
|
||||
{
|
||||
_appOptions = appOptions;
|
||||
_httpContext = contextAccessor.Value.HttpContext;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Depending on config data, generates an absolute url pointing to a CDN server
|
||||
/// or falls back to the default behavior
|
||||
/// </summary>
|
||||
/// <param name="contentPath"></param>
|
||||
/// <returns></returns>
|
||||
public override string Content(string contentPath)
|
||||
{
|
||||
if (_appOptions.Options.ServeCDNContent
|
||||
&& contentPath.StartsWith("~/", StringComparison.Ordinal))
|
||||
{
|
||||
var segment = new PathString(contentPath.Substring(1));
|
||||
|
||||
return ConvertToLowercaseUrl(_appOptions.Options.CDNServerBaseUrl + segment);
|
||||
}
|
||||
|
||||
return ConvertToLowercaseUrl(base.Content(contentPath));
|
||||
}
|
||||
|
||||
public override string RouteUrl(string routeName, object values, string protocol, string host, string fragment)
|
||||
{
|
||||
return ConvertToLowercaseUrl(base.RouteUrl(routeName, values, protocol, host, fragment));
|
||||
}
|
||||
|
||||
public override string Action(string action, string controller, object values, string protocol, string host, string fragment)
|
||||
{
|
||||
return ConvertToLowercaseUrl(base.Action(action, controller, values, protocol, host, fragment));
|
||||
}
|
||||
|
||||
private string ConvertToLowercaseUrl(string url)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(url)
|
||||
&& _appOptions.Options.GenerateLowercaseUrls)
|
||||
{
|
||||
return url.ToLowerInvariant();
|
||||
}
|
||||
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using Microsoft.AspNet.Builder;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Routing;
|
||||
using Microsoft.Framework.ConfigurationModel;
|
||||
using Microsoft.Framework.DependencyInjection;
|
||||
|
||||
namespace UrlHelperWebSite
|
||||
{
|
||||
public class Startup
|
||||
{
|
||||
public void Configure(IApplicationBuilder app)
|
||||
{
|
||||
var configuration = app.GetTestConfiguration();
|
||||
configuration.AddJsonFile("config.json");
|
||||
|
||||
// Set up application services
|
||||
app.UseServices(services =>
|
||||
{
|
||||
services.SetupOptions<AppOptions>(optionsSetup =>
|
||||
{
|
||||
optionsSetup.ServeCDNContent = Convert.ToBoolean(configuration.Get("ServeCDNContent"));
|
||||
optionsSetup.CDNServerBaseUrl = configuration.Get("CDNServerBaseUrl");
|
||||
optionsSetup.GenerateLowercaseUrls = Convert.ToBoolean(configuration.Get("GenerateLowercaseUrls"));
|
||||
});
|
||||
|
||||
// Add MVC services to the services container
|
||||
services.AddMvc(configuration);
|
||||
|
||||
services.AddScoped<IUrlHelper, CustomUrlHelper>();
|
||||
});
|
||||
|
||||
// Add MVC to the request pipeline
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
routes.MapRoute("Default", "{controller=Home}/{action=Index}");
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="__ToolsVersion__" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">12.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>a192e504-2881-41dc-90d1-b7f1dd1134e8</ProjectGuid>
|
||||
<OutputType>Web</OutputType>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(OutputType) == 'Console'">
|
||||
<DebuggerFlavor>ConsoleDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="$(OutputType) == 'Web'">
|
||||
<DebuggerFlavor>WebDebugger</DebuggerFlavor>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'" Label="Configuration">
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
<DevelopmentServerPort>35856</DevelopmentServerPort>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\AspNet\Microsoft.Web.AspNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
||||
|
|
@ -0,0 +1 @@
|
|||
@Url.Content("~/Bootstrap.min.css")
|
||||
|
|
@ -0,0 +1 @@
|
|||
@Url.Content("~/Bootstrap.min.css")
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"Microsoft.AspNet.Mvc": "",
|
||||
"Microsoft.AspNet.Server.IIS": "1.0.0-*",
|
||||
"Microsoft.AspNet.Mvc.TestConfiguration": "",
|
||||
"Microsoft.Framework.ConfigurationModel.Json": "1.0.0-*",
|
||||
"Microsoft.Framework.OptionsModel": "1.0.0-*"
|
||||
},
|
||||
"frameworks": {
|
||||
"aspnet50": { },
|
||||
"aspnetcore50": { }
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue