问题
I have the following implementation of my router:
public class TenantUrlResolverRouter : IRouter
{
private readonly IRouter _defaultRouter;
public TenantUrlResolverRouter(IRouter defaultRouter)
{
_defaultRouter = defaultRouter;
}
public VirtualPathData GetVirtualPath(VirtualPathContext context)
{
return _defaultRouter.GetVirtualPath(context);
}
public async Task RouteAsync(RouteContext context)
{
var oldRouteData = context.RouteData;
var newRouteData = new RouteData(oldRouteData);
newRouteData.Values["library"] = "Default";
try
{
context.RouteData = newRouteData;
await _defaultRouter.RouteAsync(context);
}
finally
{
if (!context.IsHandled)
{
context.RouteData = oldRouteData;
}
}
}
}
Then I define it in Startup.cs
:
app.UseMvc(routes =>
{
routes.Routes.Add(
new TenantUrlResolverRouter(routes.DefaultHandler));
routes.MapRoute(
name: "default",
template: "{library=Unknown}/{controller=Home}/{action=Index}/{id?}");
});
But nothing happens, RouteData.Values
in RouteContext
always empty, I always have Unknown, while it's need to be Default. That's not the problem of the predefined template, because it even worked without the {library=Unknown}
and this {library}/{controller=Home}/{action=Index}/{id?}
doesn't work too.
What's the problem with this custom IRouter?
回答1:
You are not providing a complete set of route values. In order to route to an action, you need to provide both controller
and action
.
Also, you don't have a match condition in the route. A match condition will determine whether the incoming request matches the current route. In the built-in routing, the url
and constraints
are match conditions. However, in a custom route, you need to put an if
block to ensure that any request that doesn't match will pass through to the next registered route.
NOTE: This is the most powerful part of custom routing. The built-in routing can only match against URLs. But with custom routing, you can match anything in the request. For example, you could make the route match only for a certain domain or a certain subdomain. You could even make it match things like posted form values or session state.
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);
}
var segments = requestPath.Split('/');
// Required: Match condition to determine if the incoming request
// matches this route. If not, you should allow the framework to
// match another route by doing nothing here.
if (segments.Length > 0 && segments[0].Equals("libraryname", StringComparison.OrdinalIgnoreCase))
{
var oldRouteData = context.RouteData;
var newRouteData = new RouteData(oldRouteData);
newRouteData.Values["library"] = segments[0];
newRouteData.Values["controller"] = segments[1];
newRouteData.Values["action"] = segments[2];
try
{
context.RouteData = newRouteData;
await _defaultRouter.RouteAsync(context);
}
finally
{
if (!context.IsHandled)
{
context.RouteData = oldRouteData;
}
}
}
}
See this question for more info about implementing IRouter
.
来源:https://stackoverflow.com/questions/36724177/nothing-happened-with-custom-irouter-in-asp-net-core