Вы можете получить любое поведение, которое вы желаете, реализовав IRouter
, как в this answer, в том числе основываясь на данных из внешнего источника (например, файла конфигурации или базы данных).
Это гораздо более гибкий, чем универсальный маршрут, поскольку он позволяет вам выбирать контроллер на лету.
public class MyRoute : IRouter
{
private readonly IRouter innerRouter;
public MyRoute(IRouter innerRouter)
{
if (innerRouter == null)
throw new ArgumentNullException("innerRouter");
this.innerRouter = innerRouter;
}
public async Task RouteAsync(RouteContext context)
{
var requestPath = context.HttpContext.Request.Path.Value;
if (!string.IsNullOrEmpty(requestPath) && requestPath[0] == '/')
{
// Trim the leading slash
requestPath = requestPath.Substring(1);
}
if (!requestPath.StartsWith("abcd"))
{
return;
}
//Invoke MVC controller/action
var oldRouteData = context.RouteData;
var newRouteData = new RouteData(oldRouteData);
newRouteData.Routers.Add(this.innerRouter);
newRouteData.Values["controller"] = "Item";
newRouteData.Values["action"] = "View";
newRouteData.Values["id"] = 123;
try
{
context.RouteData = newRouteData;
await this.innerRouter.RouteAsync(context);
}
finally
{
// Restore the original values to prevent polluting the route data.
if (!context.IsHandled)
{
context.RouteData = oldRouteData;
}
}
}
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
VirtualPathData result = null;
var values = context.Values;
var controller = Convert.ToString(values["controller"]);
var action = Convert.ToString(values["action"]);
var id = Convert.ToString(values["id"]);
if ("Item".Equals(controller) && "View".Equals(action))
{
result = new VirtualPathData(this, "abcd?id=" + id);
context.IsBound = true;
}
// IMPORTANT: Always return null if there is no match.
// This tells .NET routing to check the next route that is registered.
return result;
}
}
Использование
// Add MVC to the request pipeline.
app.UseMvc(routes =>
{
routes.Routes.Add(new MyRoute(
innerRouter: routes.DefaultHandler)
);
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
// Uncomment the following line to add a route for porting Web API 2 controllers.
// routes.MapWebApiRoute("DefaultApi", "api/{controller}/{id?}");
});
GetVirtualPath
должна отражать то, что RouteAsync
делает. RouteAsync
преобразует URL в значения маршрута, а GetVirtualPath
должен преобразовывать одни и те же данные маршрута обратно в тот же URL.
Самый простой способ сделать это - использовать структуру данных для создания двустороннего сопоставления между этими двумя точками данных (как в связанном ответе), поэтому вам не нужно постоянно менять логику в этих двух методах , Эта структура данных должна кэшироваться и не делать ничего слишком ресурсоемкой, поскольку каждый запрос будет использовать ее для определения того, куда отправлять каждый URL.
В качестве альтернативы вы можете создать отдельный маршрут для каждой вашей отдельной части логики и зарегистрировать их все при запуске приложения. Однако вам необходимо убедиться, что они зарегистрированы в правильном порядке и что каждый маршрут будет соответствовать только правильному набору URL-адресов и правильному набору RouteValues.
ПРИМЕЧАНИЕ: Для сценария, такие как это вы почти никогда не должны использовать RedirectToAction
. Имейте в виду, что перенаправление отправит HTTP-запрос 302 в браузер, в котором ему будет предложено найти другое местоположение на вашем сервере. В большинстве случаев это лишние накладные расходы, потому что гораздо эффективнее всего направлять первоначальный запрос на требуемый контроллер.
Выполняет [RedirectToAction()] (https://msdn.microsoft.com/en-us/library/system.web.mvc.controller.redirecttoaction (v = vs.118) .aspx) делает то, что вы хотеть? – JosephGarrone
Один контроллер может перенаправлять на другие контроллеры или даже просто попросить их отобразить их содержимое, поскольку это было его собственное представление. Автоматическая маршрутизация может работать, но мы не знаем вашей логики за ней –