asp.net-mvc - 如何使 ASP.NET Core MVC 路由生成相对?
问题描述
上下文 - 应用程序
我正在使用netcoreapp2.2
(dotnet core 2.2)开发一个 ASP.NET Core 应用程序。此应用程序作为 Docker 映像分发,并且运行良好。它是 HASS.IO 的一个附加组件,一个基于 docker 的Home Assistant自动化环境。一切正常。
我的应用程序中缺少的功能:HASS.IO 的入口
但是......我想使用一个名为Ingress的HASS.IO功能:https ://developers.home-assistant.io/docs/en/next/hassio_addon_presentation.html#ingress
此功能的目标是允许Home Assistant将 http 流量路由到附加组件,而无需管理身份验证部分,也无需系统所有者在其防火墙上设置端口映射以进行通信。所以这是一个非常好的功能。
MVC 路由路径是绝对的
要使用 HASS.IO 入口,应用程序需要提供导航的相对路径。例如,当用户加载 urlhttps://my.hass.io/a0a0a0a0_myaddon/
时,插件容器会收到一个/
http 请求。这意味着应用程序中的所有导航都必须是相对的。
例如,在根页面上(https://my.hass.io/a0a0a0a0_myaddon/
翻译HTTP GET /
为容器的 a ),我们添加以下剃须刀代码:
<a asp-action="myAction" asp-route-id="123">this is a link</a>
我们将得到这样的结果 html,在这种情况下这是错误的:
<a href="/Home/myAction/123">this is a link</a> <!-- THIS IS A WRONG LINK! -->
这是错误的,因为它https://my.hass.io/Home/myAction/123
被浏览器翻译成正确的地址,而正确的地址是https://my.hass.io/a0a0a0a0_myaddon/Home/myAction/123
.
为了解决这个问题,我需要生成的 html 是这样的:
<!-- THIS WOULD BE THE RIGHT LINK [option A] -->
<a href="Home/myAction/123">this is a link</a>
<!-- THIS WOULD BE GOOD TOO [option B] -->
<a href="/a0a0a0a0_myaddon/Home/myAction/123">this is a link</a>
要解决的问题
[选项A]
有没有办法将 MVC 的路由引擎设置为输出相对路径而不是绝对路径?那将解决我的问题。
这也意味着当你在工作https://my.hass.io/a0a0a0a0_myaddon/Home/myAction/123
并且你想回家时,结果应该是
<a href="../..">Return home</a>
- -或者 - -
[选项B]
另一种方法是找到一种方法来发现实际的绝对路径,并找到一种方法将其添加到 MVC 的路由机制中。
解决方案
我找到了自己问题的解决方案。我不知道这是否是最好的方法,但它奏效了!
1.为现有的创建一个包装器IUrlHelper
这个将绝对路径转换为相对路径...
private class RelativeUrlHelper : IUrlHelper
{
private readonly IUrlHelper _inner;
private readonly HttpContext _contextHttpContext;
public RelativeUrlHelper(IUrlHelper inner, HttpContext contextHttpContext)
{
_inner = inner;
_contextHttpContext = contextHttpContext;
}
private string MakeUrlRelative(string url)
{
if (url.Length == 0 || url[0] != '/')
{
return url; // that's an url going elsewhere: no need to be relative
}
if (url.Length > 2 && url[1] == '/')
{
return url; // That's a "//" url, means it's like an absolute one using the same scheme
}
// This is not a well-optimized algorithm, but it works!
// You're welcome to improve it.
var deepness = _contextHttpContext.Request.Path.Value.Split('/').Length - 2;
if (deepness == 0)
{
return url.Substring(1);
}
else
{
for (var i = 0; i < deepness; i++)
{
url = i == 0 ? ".." + url : "../" + url;
}
}
return url;
}
public string Action(UrlActionContext actionContext)
{
return MakeUrlRelative(_inner.Action(actionContext));
}
public string Content(string contentPath)
{
return MakeUrlRelative(_inner.Content(contentPath));
}
public bool IsLocalUrl(string url)
{
if (url?.StartsWith("../") ?? false)
{
return true;
}
return _inner.IsLocalUrl(url);
}
public string RouteUrl(UrlRouteContext routeContext) => _inner.RouteUrl(routeContext);
public string Link(string routeName, object values) => _inner.Link(routeName, values);
public ActionContext ActionContext => _inner.ActionContext;
}
2. 为IUrlHelperFactory
public class RelativeUrlHelperFactory : IUrlHelperFactory
{
private readonly IUrlHelperFactory _previous;
public RelativeUrlHelperFactory(IUrlHelperFactory previous)
{
_previous = previous;
}
public IUrlHelper GetUrlHelper(ActionContext context)
{
var inner = _previous.GetUrlHelper(context);
return new RelativeUrlHelper(inner, context.HttpContext);
}
}
3. 封装IUrlHelper
在 DI/IoC
把它放在ConfigureServices()
文件中Startup.cs
:
services.Decorate<IUrlHelperFactory>((previous, _) => new RelativeUrlHelperFactory(previous));
- 重要提示:您需要
Scrutor
为该https://www.nuget.org/packages/Scrutor/安装 nuget 包。
最后...
我在那里发布了我的解决方案作为 PR:https ://github.com/yllibed/Zigbee2MqttAssistant/pull/2
推荐阅读
- javascript - 小部件在其 URL 的查询字符串中使用键时的过程是什么?安全吗?
- react-native - 如何并排对齐图标和下拉菜单?
- php - 如何限制特定时间?
- angular - Angular 6,加载 svg 不会出现在 chrome 中
- serverless-framework - Swagger 定义的 API 无法在 Serverless 框架上本地执行
- angular - 所需的角度 IOS 年历,如 [https://github.com/MariemChaabeni/angular-calendar-year-view] 用于 angular6
- node.js - 使用 Mongoose 在 MongoDB 中设置的时间后文档不会过期
- mysql - 当 authentication_string 正确时,用户 'root'@'localhost' 的访问被拒绝(使用密码:YES)
- testing - 如何在 JMeter 的单个线程中调用的循环控制器之间添加计时器
- android - 在 android 中获取联系人列表需要时间和崩溃的应用程序