使用 MVC 和 ASP.Net 核心动态 url 重写
Dynamic url rewriting with MVC and ASP.Net Core
我正在使用 ASP.Net Core 和 MVC 6 重写我的 FragSwapper.com 网站(目前在 Asp 2.0!),我正在尝试做一些我通常会做的事情打破 URL 重写工具以及数据库代码和一些重定向,但我想知道在 ASP.Net 核心中是否有 "better" 方法可以使用 MVC 路由和重定向。
这是我的场景...
URL 访问站点:[root]
怎么办: 转到通常的 [Home] Controller 和 [Index] View(无 [ID])。 ...它现在这样做:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
URL 访问站点:[root]/ControllerName/...yada yada...
做什么: 转到控制器,等等...所有这些也都有效。
棘手的一个:URL 访问站点:[root]/SomeString
要做什么: 访问数据库并执行一些逻辑来决定我是否找到事件 ID。如果我这样做,我会转到 [Event] Controller 和 [Index] View 以及我找到的任何内容的 [ID]。如果不是,我会尝试找到一个主机 ID,然后使用我找到的 [ID] 转到 [Home] Controller 和 [Organization] View。如果我没有找到 Event 或 Host,请转到通常的 [Home] Controller 和 [Index] View(无 [ID])。
这里的大问题是我想在 2 个不同的控制器中重定向到三个完全不同的视图之一。
所以最重要的是,当用户访问我网站的根目录并且上面有一个“/Something”时,我想做一些逻辑,并且该逻辑是数据库驱动的。
如果您理解了这个问题,您现在可以停止阅读...如果您觉得有必要理解为什么需要所有这些逻辑,您可以继续阅读以获取更详细的上下文。
My site has basically two modes: Viewing an Event and Not Viewing an
Event! There are usually 4 or 5 events running at an one time but
most users are only interested in one event but it's a DIFFERENT event
every 4 months or so..I have a [Host] entity and each Host holds up to
4 events a year, one at a time. Most users only care about one Host's
events.
I'm trying to avoid making a user always go to an event map and find
the event and click on it since I have a limit to how many times I can
show a map (for free) and it's really not necessary. 99.99% of the
time a user is on my site they are on an Event screen, not my Home
screens, and are interested in only one event at a time. In the
future I want to code it so if they come to my website they go right
to their event or a new event from their favorite host so I can avoid
a LOT of clicks and focus my [Home] controller pages for newbs...but I
don't have auto-login working yet so that's on the back burner.
But for now I want hosts to always have the same url for their events:
FragSwapper.com/[Host Abbreviation] ...and know it will always go to
their current event which has a different ID every 4 months!!!
Crazy...I know...but technically very easy to do, I just don't know
how to do it properly in MVC with how things are done.
更新:ASP.Net核心 1.1
根据release notes, a new RewriteMiddleware
已经创建。
这提供了几种不同的预定义重写选项和实用程序扩展方法,最终可能会修改请求路径,因为它已在此答案中完成。例如,参见 RewriteRule
的实现
具体到 OP 问题,您需要实现自己的 IRule
class(从头开始或扩展现有的 RewriteRule
,它基于正则表达式).您可能会用 RewriteOptions
.
的新 AddMyRule()
扩展方法来补充它
您可以创建自己的 middleware 并将其添加到 MVC 路由之前的请求管道。
这允许您在评估 MVC 路由之前将代码注入管道。这样您将能够:
- 检查传入请求中的路径
- 在数据库中搜索具有相同值的 eventId 或 hostId
- 如果找到事件或主机,请将传入请求路径更新为
Event/Index/{eventId}
或 Home/Organization/{hostId}
- 让下一个中间件(MVC 路由)处理请求。他们会看到之前的中间件对请求路径所做的任何更改
例如,create your own EventIdUrlRewritingMiddleware
中间件将尝试将传入请求路径与数据库中的 eventId 进行匹配。如果匹配,它会将原始请求路径更改为 Event/Index/{eventId}
:
public class EventIdUrlRewritingMiddleware
{
private readonly RequestDelegate _next;
//Your constructor will have the dependencies needed for database access
public EventIdUrlRewritingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var path = context.Request.Path.ToUriComponent();
if (PathIsEventId(path))
{
//If is an eventId, change the request path to be "Event/Index/{path}" so it is handled by the event controller, index action
context.Request.Path = "/Event/Index" + path;
}
//Let the next middleware (MVC routing) handle the request
//In case the path was updated, the MVC routing will see the updated path
await _next.Invoke(context);
}
private bool PathIsEventId(string path)
{
//The real midleware will try to find an event in the database that matches the current path
//In this example I am just using some hardcoded string
if (path == "/someEventId")
{
return true;
}
return false;
}
}
然后按照相同的方法创建另一个 class HostIdUrlRewritingMiddleware
。
最后在 Startup.Configure
方法中将新的中间件添加到管道中,确保它们在路由和 MVC 中间件之前添加:
app.UseMiddleware<EventIdUrlRewritingMiddleware>();
app.UseMiddleware<HostIdUrlRewritingMiddleware>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
使用此配置:
/
转到 HomeController.Index
操作
/Home/About
转到 HomeController.About
操作
/Event/Index/1
转到 EventController.Index
操作 id=1
/someEventId
转到 EventController.Index
操作,id=someEventId
请注意不涉及 http 重定向。当在浏览器中打开 /someEventId
时,有一个 http 请求,浏览器将在地址栏中显示 /someEventId
。 (即使在内部更新了原始路径)
我正在使用 ASP.Net Core 和 MVC 6 重写我的 FragSwapper.com 网站(目前在 Asp 2.0!),我正在尝试做一些我通常会做的事情打破 URL 重写工具以及数据库代码和一些重定向,但我想知道在 ASP.Net 核心中是否有 "better" 方法可以使用 MVC 路由和重定向。
这是我的场景...
URL 访问站点:[root]
怎么办: 转到通常的 [Home] Controller 和 [Index] View(无 [ID])。 ...它现在这样做:
app.UseMvc(routes => { routes.MapRoute( name: "default", template: "{controller=Home}/{action=Index}/{id?}"); });
URL 访问站点:[root]/ControllerName/...yada yada...
做什么: 转到控制器,等等...所有这些也都有效。
棘手的一个:URL 访问站点:[root]/SomeString
要做什么: 访问数据库并执行一些逻辑来决定我是否找到事件 ID。如果我这样做,我会转到 [Event] Controller 和 [Index] View 以及我找到的任何内容的 [ID]。如果不是,我会尝试找到一个主机 ID,然后使用我找到的 [ID] 转到 [Home] Controller 和 [Organization] View。如果我没有找到 Event 或 Host,请转到通常的 [Home] Controller 和 [Index] View(无 [ID])。
这里的大问题是我想在 2 个不同的控制器中重定向到三个完全不同的视图之一。
所以最重要的是,当用户访问我网站的根目录并且上面有一个“/Something”时,我想做一些逻辑,并且该逻辑是数据库驱动的。
如果您理解了这个问题,您现在可以停止阅读...如果您觉得有必要理解为什么需要所有这些逻辑,您可以继续阅读以获取更详细的上下文。
My site has basically two modes: Viewing an Event and Not Viewing an Event! There are usually 4 or 5 events running at an one time but most users are only interested in one event but it's a DIFFERENT event every 4 months or so..I have a [Host] entity and each Host holds up to 4 events a year, one at a time. Most users only care about one Host's events.
I'm trying to avoid making a user always go to an event map and find the event and click on it since I have a limit to how many times I can show a map (for free) and it's really not necessary. 99.99% of the time a user is on my site they are on an Event screen, not my Home screens, and are interested in only one event at a time. In the future I want to code it so if they come to my website they go right to their event or a new event from their favorite host so I can avoid a LOT of clicks and focus my [Home] controller pages for newbs...but I don't have auto-login working yet so that's on the back burner.
But for now I want hosts to always have the same url for their events: FragSwapper.com/[Host Abbreviation] ...and know it will always go to their current event which has a different ID every 4 months!!!
Crazy...I know...but technically very easy to do, I just don't know how to do it properly in MVC with how things are done.
更新:ASP.Net核心 1.1
根据release notes, a new RewriteMiddleware
已经创建。
这提供了几种不同的预定义重写选项和实用程序扩展方法,最终可能会修改请求路径,因为它已在此答案中完成。例如,参见 RewriteRule
具体到 OP 问题,您需要实现自己的 IRule
class(从头开始或扩展现有的 RewriteRule
,它基于正则表达式).您可能会用 RewriteOptions
.
AddMyRule()
扩展方法来补充它
您可以创建自己的 middleware 并将其添加到 MVC 路由之前的请求管道。
这允许您在评估 MVC 路由之前将代码注入管道。这样您将能够:
- 检查传入请求中的路径
- 在数据库中搜索具有相同值的 eventId 或 hostId
- 如果找到事件或主机,请将传入请求路径更新为
Event/Index/{eventId}
或Home/Organization/{hostId}
- 让下一个中间件(MVC 路由)处理请求。他们会看到之前的中间件对请求路径所做的任何更改
例如,create your own EventIdUrlRewritingMiddleware
中间件将尝试将传入请求路径与数据库中的 eventId 进行匹配。如果匹配,它会将原始请求路径更改为 Event/Index/{eventId}
:
public class EventIdUrlRewritingMiddleware
{
private readonly RequestDelegate _next;
//Your constructor will have the dependencies needed for database access
public EventIdUrlRewritingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
var path = context.Request.Path.ToUriComponent();
if (PathIsEventId(path))
{
//If is an eventId, change the request path to be "Event/Index/{path}" so it is handled by the event controller, index action
context.Request.Path = "/Event/Index" + path;
}
//Let the next middleware (MVC routing) handle the request
//In case the path was updated, the MVC routing will see the updated path
await _next.Invoke(context);
}
private bool PathIsEventId(string path)
{
//The real midleware will try to find an event in the database that matches the current path
//In this example I am just using some hardcoded string
if (path == "/someEventId")
{
return true;
}
return false;
}
}
然后按照相同的方法创建另一个 class HostIdUrlRewritingMiddleware
。
最后在 Startup.Configure
方法中将新的中间件添加到管道中,确保它们在路由和 MVC 中间件之前添加:
app.UseMiddleware<EventIdUrlRewritingMiddleware>();
app.UseMiddleware<HostIdUrlRewritingMiddleware>();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
使用此配置:
/
转到HomeController.Index
操作/Home/About
转到HomeController.About
操作/Event/Index/1
转到EventController.Index
操作 id=1/someEventId
转到EventController.Index
操作,id=someEventId
请注意不涉及 http 重定向。当在浏览器中打开 /someEventId
时,有一个 http 请求,浏览器将在地址栏中显示 /someEventId
。 (即使在内部更新了原始路径)