问题
I am using the standard MVC template from MVC 2013.
There is a Home controller with actions About, Contact, etc.
There is an Account controller with actions Login, Logout, etc.
The app is deployed at domain website. The url http://website will produce the output of /Home/Index, without changing the url in the browser address box, ie what the browser shows is not the result of a Http redirect.
How do I make the url http://website/X route to /Home/X if X is not another controller in my application? Otherwise it should route to /Home/X/Index.
The reason is that I would like http://website/about, http://website/contact etc without the Home.
回答1:
A naive solution would be to simply define a new route above the default (catch-all) that looks like:
routes.MapRoute(
name: "ShortUrlToHomeActions",
url: "{action}",
defaults: new { controller = "Home" }
);
The problem with this approach is that it will prevent accessing the Index (default action) of other controllers (requesting /Other, when you have OtherContoller with Index action would result in 404, requesting /Other/Index would work).
A better solution would be to create a RouteConstraint that will match our /{action} only in case there is no other controller with the same name:
public class NoConflictingControllerExists : IRouteConstraint
{
private static readonly Dictionary<string, bool> _cache = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
var path = httpContext.Request.Path;
if (path == "/" || String.IsNullOrEmpty(path))
return false;
if (_cache.ContainsKey(path))
return _cache[path];
IController ctrl;
try
{
var ctrlFactory = ControllerBuilder.Current.GetControllerFactory();
ctrl = ctrlFactory.CreateController(httpContext.Request.RequestContext, values["action"] as string);
}
catch
{
_cache.Add(path, true);
return true;
}
var res = ctrl == null;
_cache.Add(path, res);
return res;
}
}
Then applying the constraint:
routes.MapRoute(
name: "ShortUrlToHomeActions",
url: "{action}",
defaults: new { controller = "Home" },
constraints: new { noConflictingControllerExists = new NoConflictingControllerExists() }
);
See MSDN
来源:https://stackoverflow.com/questions/29386170/how-to-make-one-controller-the-default-one-when-only-action-specified