Надо писать собственный обработчик маршрутизации.
Я использовал такой вариант. Исходный вариант нашел на одном из форумов и немного его доработал.
public class SubDomainRoute : Route
{
private Regex domainRegex;
private Regex pathRegex;
private readonly string[] namespaces;
public string Domain { get; set; }
public SubDomainRoute(string domain, string url, object defaults, string[] namespaces)
: base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
{
Domain = domain;
this.namespaces = namespaces;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
// Build regex
domainRegex = CreateRegex(Domain);
pathRegex = CreateRegex(Url);
// Request information
string requestDomain = httpContext.Request.Headers["host"];
if (!string.IsNullOrEmpty(requestDomain))
{
if (requestDomain.IndexOf(":") > 0)
{
requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
}
}
else
{
requestDomain = httpContext.Request.Url.Host;
}
string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;
// Match domain and route
Match domainMatch = domainRegex.Match(requestDomain);
Match pathMatch = pathRegex.Match(requestPath);
if (domainMatch.Success && pathMatch.Success)
{
var routeData = base.GetRouteData(httpContext);
if (this.namespaces != null && this.namespaces.Length > 0)
{
routeData.DataTokens["Namespaces"] = this.namespaces;
}
//тут добавляем поле {host} к маршрутам
routeData.DataTokens["Host"] = routeData.Values["host"];
routeData.DataTokens["UseNamespaceFallback"] = bool.FalseString;
return routeData;
}
return null;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
return base.GetVirtualPath(requestContext, values);
// return null;
}
private Regex CreateRegex(string source)
{
// Perform replacements
source = source.Replace("/", @"\/?");
source = source.Replace(".", @"\.?");
source = source.Replace("-", @"\-?");
source = source.Replace("{", @"(?<");
source = source.Replace("}", @">([a-zA-Z0-9_]*))");
return new Regex("^" + source + "$");
}
}
А в затем описываю маршрут так:
routes.Add("host_default", new SubDomainRoute(
"{host}.web.ru",
"{controller}/{action}/{id}",
new { controller = "User", action = "Index", id = UrlParameter.Optional },
new[] { typeof(Controllers.UserController).Namespace } // Namespaces defaults
));
Надо еще в контроллере User делать проверку на корректность поддомена.