Reputation: 6081
I am working on an .NET Core MVC application which requires alternative controller/action names to be allowed. To accomplish this, I am using my own Router on a MapRoute:
app.UseMvc(routes =>
{
routes.Routes.Add(new CustomRouter(routes.DefaultHandler));
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
My custom router observes the requested controller and action, and based on it places a new value into the RouteData in the request:
public async Task RouteAsync(RouteContext context)
{
[...]
if (requestedAction == "fakeAction")
context.RouteData.Values["action"] = "realAction";
However, to determine the value of the requestedAction
, I am basically taking the requested path, splitting it and getting the value of it that way. This seems suboptimal.
What I would like to do would look something like this:
var rr = new RouteBuilder(app);
var myRoute = rr.MapRoute(...).Build();
var myRouteData = myRoute.GetRouteData(context);
myRouteData["action"] == "fakeAction";
Another solution to this problem which I would very much enjoy is if I could do the following:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "something",
template: "{controller=Home}/{action=Index}/{id?}");
routes.Routes.Add(new CustomRouter(routes.DefaultHandler));
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
But NOT have my something
route actually route anything and only serve as a way to define the RouteData for my CustomRouter.
Is either of these possible? I do not like the idea us uncleanly implementing existing functionality as it is a both a code smell and a potential maintenance difficulty in the future.
Upvotes: 1
Views: 736
Reputation: 3113
I hope this help you:
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);
}
// Get the page that matches.
var page = GetPageList()
.Where(x => x.VirtualPath.Equals(requestPath))
.FirstOrDefault();
// If we got back a null value set, that means the URI did not match
if (page == null)
{
return;
}
//Invoke MVC controller/action
var oldRouteData = context.RouteData;
var newRouteData = new RouteData(oldRouteData);
newRouteData.Routers.Add(this.target);
// TODO: You might want to use the page object (from the database) to
// get both the controller and action, and possibly even an area.
// Alternatively, you could create a route for each table and hard-code
// this information.
if (context.RouteData.Values["action"] == "fakeAction")
newRouteData.Values["controller"] = "realController";
newRouteData.Values["action"] = "realAction";
// This will be the primary key of the database row.
// It might be an integer or a GUID.
newRouteData.Values["id"] = page.Id;
try
{
context.RouteData = newRouteData;
await this.target.RouteAsync(context);
}
finally
{
// Restore the original values to prevent polluting the route data.
if (!context.IsHandled)
{
context.RouteData = oldRouteData;
}
}
}
app.UseMvc(routes =>
{
routes.Routes.Add(
new CustomRoute(routes.ServiceProvider.GetRequiredService<IMemoryCache>(),
routes.DefaultHandler));
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Upvotes: 1