我正在寻找一种方法将通配符子域路由到ASP MVC 4中的控制器。
这样的事情:
CompanyName.mydomain.com
需要转化为:
mydomain.com/CompanyName
我找不到任何关于如何做到这一点的信息而且我被困住了。这是IIS事物还是ASP MVC路由?
答案 0 :(得分:5)
所以经过一段时间我在应用程序级别上自己解决了这个问题。 IIS重写不起作用,ASP MVC不匹配正确的路线,它将404出。
最终为我工作的解决方案是自己实现路由类,一个在主机名中搜索参数,并将其映射为路径参数。它现在完美无缺,自定义实现很简单。我爱上了灵活的ASP MVC给你的过程:))
因此,自定义路由需要两个覆盖,一个用于匹配传入路由的方法“GetRouteData”,另一个用于写出外路由的“GetVirtualPath”。
以下是整个自定义路线类:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace System.Web.Routing
{
public class WildcardRoute : Route
{
public WildcardRoute(string url, IRouteHandler handler)
: base(url, handler)
{
}
public WildcardRoute(string url, RouteValueDictionary defaults, IRouteHandler handler)
: base(url, defaults, handler)
{
}
public WildcardRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler handler)
: base(url, defaults, constraints, handler)
{
}
public WildcardRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler handler)
: base(url, defaults, constraints, dataTokens, handler)
{
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
// save the original path before we edit it
var orignalPath = HttpContext.Current.Request.Path;
//split the hostname
var split = HttpContext.Current.Request.Url.Host.Split('.');
// fire only if there is more than 2 items in the split (company.mydomain.com) and if the first one is not www
if (split.Count() > 2 && split[0].ToLower() != "www")
{
var split2 = HttpContext.Current.Request.Path.Split('/'); // split everything after the hostname into segments
string newPath = "/" + split[0]; // take the company from company.mydomain.com and rewrite it to mydomain.com/company
foreach (var item in split2) // add all the other segments that come after mydomain.com/company
{ // end result might be for example - mydomain.com/company/Home/Index
newPath = newPath + "/" + item;
}
httpContext.RewritePath(newPath); // rewrite the path into the newone
}
RouteData data = base.GetRouteData(httpContext); // match the route with the new path
if (data == null) // if there is no match in this route write the path back to the original one
{
httpContext.RewritePath(orignalPath);
}
return data;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var data = base.GetVirtualPath(requestContext, values); // do the original url write
var split = requestContext.HttpContext.Request.Url.Host.Split('.'); // split the host by '.'
var item = requestContext.RouteData.Values.FirstOrDefault(x => x.Key == "PermalinkTitle"); // the PermalinkTitle is the name of the "company" route value in mydomain.com/company in my implementation
if (split.Count() > 0 && split[0].ToLower().Contains(item.Value.ToString().ToLower())) // fire only if the hostname contains the "company" route value
{
data.VirtualPath = data.VirtualPath.Replace(item.Value.ToString(), "");
if (data.VirtualPath.StartsWith("/"))
data.VirtualPath = data.VirtualPath.Substring(1);
// this code removes the company part from the path so we dont get company.mydomain.com/company/controller/action rather we just get company.mydomain.com/controller/action
}
return data;
}
}
}
此实施非常灵活,可以使用所有这些路线 - “company.mydomain.com”,“mydomain.com/company”和“www.mydomain.com/company”。
在创建自定义路由类之后,您需要使用映射自定义路由类型的Map方法扩展RouteCollection,如果使用区域,还需要扩展AreaRegistrationContext,因为区域路由映射会通过该方法。这是整个实施:
using System;
using System.Web.Mvc;
using System.Web.Routing;
namespace System.Web.Routing
{
public static class WildcardRoutesExtension
{
public static WildcardRoute MapWildcardRoute(this RouteCollection routes, string name, string url, object defaults)
{
WildcardRoute route = new WildcardRoute(
url,
new RouteValueDictionary(defaults),
new MvcRouteHandler());
routes.Add(name, route);
return route;
}
public static WildcardRoute MapWildcardRoute(this AreaRegistrationContext context, string name, string url, object defaults)
{
WildcardRoute route = new WildcardRoute(
url,
new RouteValueDictionary(defaults),
new RouteValueDictionary(new {}),
new RouteValueDictionary(new {Area = context.AreaName }),
new MvcRouteHandler());
context.Routes.Add(name, route);
return route;
}
public static WildcardRoute MapWildcardRoute(this AreaRegistrationContext context, string name, string url, object defaults, object constraints)
{
WildcardRoute route = new WildcardRoute(
url,
new RouteValueDictionary(defaults),
new RouteValueDictionary(constraints),
new RouteValueDictionary(new {Area = context.AreaName }),
new MvcRouteHandler());
context.Routes.Add(name, route);
return route;
}
public static WildcardRoute MapWildcardRoute(this RouteCollection routes, string name, string url, object defaults, object constraints)
{
WildcardRoute route = new WildcardRoute(
url,
new RouteValueDictionary(defaults),
new RouteValueDictionary(constraints),
new MvcRouteHandler());
routes.Add(name, route);
return route;
}
}
}
当你拥有所有这些时,你现在只需要为RouteConfig类中的常规路线映射这样的自定义路线:
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
// rest of your routes
routes.MapWildcardRoute(
name: "Default",
url: "{PermalinkTitle}/{controller}/{action}",
defaults: new { }
);
//Rest of your routes
}
或类似地区AreaRegistration类中的区域:
public override void RegisterArea(AreaRegistrationContext context)
{
context.MapWildcardRoute(
"MyArea_default",
"{PermalinkTitle}/MyArea/{controller}/{action}/{id}",
new { action = "Index", id = UrlParameter.Optional }
);
}
答案 1 :(得分:0)
尝试将此规则用于IIS:
<rule name="Rule1" stopProcessing="true">
<match url=".*" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(?!www)(.*)\.mydomain\.com$" />
</conditions>
<action type="Rewrite" url="http://mydomain.com/{C:1}/{R:0}" />
</rule>
答案 2 :(得分:0)
我会说,这主要与两者有关。 在大多数情况下,子域实际上是域服务器上根目录下的文件夹。 (即,CompanyName.mydomain.com通常是mydomain.com/CompanyName文件夹(就像你写的一样))。
然后,您可以根据需要设置路由,这取决于您的mvc路由。 使用mvc路由,我使用这个方向:controller / action。
IIS将进行翻译,将您作为子域的根目录进入您的CompanyName文件夹。你的mvc只需要在该文件夹的controllers文件夹中有一个家庭控制器,使用你的任何一个url定义在那里导航。