Introduce IUrlHelper.ActionLink (#6775)
Fixes https://github.com/aspnet/AspNetCore/issues/4890
This commit is contained in:
parent
5872af6e61
commit
89a7f3cf77
|
|
@ -530,5 +530,57 @@ namespace Microsoft.AspNetCore.Mvc
|
||||||
host: host,
|
host: host,
|
||||||
fragment: fragment);
|
fragment: fragment);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Generates an absolute URL for an action method, which contains the specified
|
||||||
|
/// <paramref name="action"/> name, <paramref name="controller"/> name, route <paramref name="values"/>,
|
||||||
|
/// <paramref name="protocol"/> to use, <paramref name="host"/> name, and <paramref name="fragment"/>.
|
||||||
|
/// Generates an absolute URL if the <paramref name="protocol"/> and <paramref name="host"/> are
|
||||||
|
/// non-<c>null</c>. See the remarks section for important security information.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="helper">The <see cref="IUrlHelper"/>.</param>
|
||||||
|
/// <param name="action">The name of the action method. When <see langword="null" />, defaults to the current executing action.</param>
|
||||||
|
/// <param name="controller">The name of the controller. When <see langword="null" />, defaults to the current executing controller.</param>
|
||||||
|
/// <param name="values">An object that contains route values.</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 generated URL.</returns>
|
||||||
|
/// <remarks>
|
||||||
|
/// <para>
|
||||||
|
/// The value of <paramref name="host"/> should be a trusted value. Relying on the value of the current request
|
||||||
|
/// can allow untrusted input to influence the resulting URI unless the <c>Host</c> header has been validated.
|
||||||
|
/// See the deployment documentation for instructions on how to properly validate the <c>Host</c> header in
|
||||||
|
/// your deployment environment.
|
||||||
|
/// </para>
|
||||||
|
/// </remarks>
|
||||||
|
public static string ActionLink(
|
||||||
|
this IUrlHelper helper,
|
||||||
|
string action = null,
|
||||||
|
string controller = null,
|
||||||
|
object values = null,
|
||||||
|
string protocol = null,
|
||||||
|
string host = null,
|
||||||
|
string fragment = null)
|
||||||
|
{
|
||||||
|
if (helper == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(helper));
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpContext = helper.ActionContext.HttpContext;
|
||||||
|
|
||||||
|
if (protocol == null)
|
||||||
|
{
|
||||||
|
protocol = httpContext.Request.Protocol;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (host == null)
|
||||||
|
{
|
||||||
|
host = httpContext.Request.Host.ToUriComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Action(helper, action, controller, values, protocol, host, fragment);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,6 @@ using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
namespace Microsoft.AspNetCore.Mvc.Routing
|
namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Mvc.Routing;
|
using Microsoft.AspNetCore.Mvc.Routing;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
|
|
@ -601,6 +602,112 @@ namespace Microsoft.AspNetCore.Mvc.Core.Test.Routing
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ActionLink_WithActionName_Works()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedAction = "TestAction";
|
||||||
|
var expectedProtocol = "testprotocol://";
|
||||||
|
var expectedHost = "www.example.com";
|
||||||
|
UrlActionContext actual = null;
|
||||||
|
|
||||||
|
var httpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
Protocol = expectedProtocol,
|
||||||
|
Host = new HostString(expectedHost),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
|
var urlHelper = CreateMockUrlHelper(actionContext);
|
||||||
|
urlHelper.Setup(h => h.Action(It.IsAny<UrlActionContext>()))
|
||||||
|
.Callback((UrlActionContext context) => actual = context);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
urlHelper.Object.ActionLink(expectedAction);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
urlHelper.Verify();
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
Assert.Equal(expectedAction, actual.Action);
|
||||||
|
Assert.Null(actual.Controller);
|
||||||
|
Assert.Null(actual.Values);
|
||||||
|
|
||||||
|
Assert.Equal(expectedProtocol, actual.Protocol);
|
||||||
|
Assert.Equal(expectedHost, actual.Host);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ActionLink_UsesSpecifiedProtocol()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedProtocol = "testprotocol://";
|
||||||
|
var expectedHost = "www.example.com";
|
||||||
|
UrlActionContext actual = null;
|
||||||
|
|
||||||
|
var httpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
Protocol = "http://",
|
||||||
|
Host = new HostString(expectedHost),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
|
var urlHelper = CreateMockUrlHelper(actionContext);
|
||||||
|
urlHelper.Setup(h => h.Action(It.IsAny<UrlActionContext>()))
|
||||||
|
.Callback((UrlActionContext context) => actual = context);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
urlHelper.Object.ActionLink(protocol: expectedProtocol);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
urlHelper.Verify();
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
Assert.Null(actual.Action);
|
||||||
|
Assert.Null(actual.Controller);
|
||||||
|
Assert.Null(actual.Values);
|
||||||
|
|
||||||
|
Assert.Equal(expectedProtocol, actual.Protocol);
|
||||||
|
Assert.Equal(expectedHost, actual.Host);
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ActionLink_UsesSpecifiedHost()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var expectedProtocol = "testprotocol://";
|
||||||
|
var expectedHost = "www.example.com";
|
||||||
|
UrlActionContext actual = null;
|
||||||
|
|
||||||
|
var httpContext = new DefaultHttpContext
|
||||||
|
{
|
||||||
|
Request =
|
||||||
|
{
|
||||||
|
Protocol = expectedProtocol,
|
||||||
|
Host = new HostString("www.asp.net"),
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var actionContext = new ActionContext(httpContext, new RouteData(), new ActionDescriptor());
|
||||||
|
var urlHelper = CreateMockUrlHelper(actionContext);
|
||||||
|
urlHelper.Setup(h => h.Action(It.IsAny<UrlActionContext>()))
|
||||||
|
.Callback((UrlActionContext context) => actual = context);
|
||||||
|
|
||||||
|
// Act
|
||||||
|
urlHelper.Object.ActionLink(host: expectedHost);
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
urlHelper.Verify();
|
||||||
|
Assert.NotNull(actual);
|
||||||
|
Assert.Null(actual.Action);
|
||||||
|
Assert.Null(actual.Controller);
|
||||||
|
Assert.Null(actual.Values);
|
||||||
|
|
||||||
|
Assert.Equal(expectedProtocol, actual.Protocol);
|
||||||
|
Assert.Equal(expectedHost, actual.Host);
|
||||||
|
}
|
||||||
|
|
||||||
private static Mock<IUrlHelper> CreateMockUrlHelper(ActionContext context = null)
|
private static Mock<IUrlHelper> CreateMockUrlHelper(ActionContext context = null)
|
||||||
{
|
{
|
||||||
if (context == null)
|
if (context == null)
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,6 @@ using Microsoft.AspNetCore.Http.Features;
|
||||||
using Microsoft.AspNetCore.Mvc.Abstractions;
|
using Microsoft.AspNetCore.Mvc.Abstractions;
|
||||||
using Microsoft.AspNetCore.Routing;
|
using Microsoft.AspNetCore.Routing;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.ObjectPool;
|
|
||||||
using Moq;
|
using Moq;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
|
@ -952,6 +951,19 @@ namespace Microsoft.AspNetCore.Mvc.Routing
|
||||||
Assert.Equal("/b/Store/Checkout", url);
|
Assert.Equal("/b/Store/Checkout", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void ActionLink_ReturnsAbsoluteUrlToAction()
|
||||||
|
{
|
||||||
|
// Arrange
|
||||||
|
var urlHelper = CreateUrlHelperWithDefaultRoutes();
|
||||||
|
|
||||||
|
// Act
|
||||||
|
var url = urlHelper.ActionLink("contact", "home");
|
||||||
|
|
||||||
|
// Assert
|
||||||
|
Assert.Equal("http://localhost/app/home/contact", url);
|
||||||
|
}
|
||||||
|
|
||||||
protected abstract IServiceProvider CreateServices();
|
protected abstract IServiceProvider CreateServices();
|
||||||
|
|
||||||
protected abstract IUrlHelper CreateUrlHelper(ActionContext actionContext);
|
protected abstract IUrlHelper CreateUrlHelper(ActionContext actionContext);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue