在不使用 MVC 更改 URL 的情况下为特定 URL 创建路由
Posted
技术标签:
【中文标题】在不使用 MVC 更改 URL 的情况下为特定 URL 创建路由【英文标题】:Create Route for a specific URL without changing the URL with MVC 【发布时间】:2018-07-10 14:21:19 【问题描述】:我有一个在 www.domain.com
上运行的 MVC Web 应用程序,我需要为同一个 Web 应用程序的另一个域 www.domain2.com
配置不同的 URL 绑定。
新域www.domain2.com
必须返回一个特定的控制器操作视图,例如/Category/Cars
:
routes.MapRoute(
name: "www.domain2.com",
url: "www.domain2.com",
defaults: new controller = "Category", action = "Cars", id = UrlParameter.Optional
);
如何在不更改 URL 的情况下实现这一点,因此访问者插入 url www.domain2.com
并接收视图 www.domain.com/category/cars
但 url 仍然是 www.domain2.com
?
编辑:
我已经尝试过这种方法,但它不起作用:
routes.MapRoute(
"Catchdomain2",
"www.domain2.com",
new controller = "Category", action = "Cars"
);
【问题讨论】:
见MVC Custom Routing Subdomain,类似。 嗨!谢谢!这并不容易理解。我总是有一个从 www.domain2.com 到 www.domain.com/Category/Cars 的案例。有没有更简单的方法来做到这一点? @NightOwl888 我尝试了一种基于***.com/questions/1618896/… 的不同方法,但它不起作用:( 【参考方案1】:域通常不是路由的一部分,这就是您的示例不起作用的原因。要使路由仅适用于特定域,您必须自定义路由。
默认情况下,您的路由配置中的所有路由都将在可以访问该网站的所有域上可用。
对此最简单的解决方案是创建一个custom route constraint 并使用它来控制特定 URL 将匹配的域。
域约束
public class DomainConstraint : IRouteConstraint
private readonly string[] domains;
public DomainConstraint(params string[] domains)
this.domains = domains ?? throw new ArgumentNullException(nameof(domains));
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
string domain =
#if DEBUG
// A domain specified as a query parameter takes precedence
// over the hostname (in debug compile only).
// This allows for testing without configuring IIS with a
// static IP or editing the local hosts file.
httpContext.Request.QueryString["domain"];
#else
null;
#endif
if (string.IsNullOrEmpty(domain))
domain = httpContext.Request.Headers["HOST"];
return domains.Contains(domain);
用法
public class RouteConfig
public static void RegisterRoutes(RouteCollection routes)
routes.IgnoreRoute("resource.axd/*pathInfo");
// This ignores Category/Cars for www.domain.com and www.foo.com
routes.IgnoreRoute("Category/Cars", new _ = new DomainConstraint("www.domain.com", "www.foo.com") );
// Matches www.domain2.com/ and sends it to CategoryController.Cars
routes.MapRoute(
name: "HomePageDomain2",
url: "",
defaults: new controller = "Category", action = "Cars" ,
constraints: new _ = new DomainConstraint("www.domain2.com")
);
routes.MapRoute(
name: "Default",
url: "controller/action/id",
defaults: new controller = "Home", action = "Index", id = UrlParameter.Optional ,
// This constraint allows the route to work either
// on "www.domain.com" or "www.domain2.com" (excluding any other domain)
constraints: new _ = new DomainConstraint("www.domain.com", "www.domain2.com")
);
如果您在 Visual Studio 的新项目中启动它,您会注意到它显示错误。这是因为localhost:<port>
不是已配置的域。但是,如果您导航到:
/?domain=www.domain.com
您将看到主页。
这是因为仅对于调试版本,它允许您覆盖“本地”域名以进行测试。您可以configure your local IIS server 使用本地静态IP 地址(添加到您的网卡)并添加本地主机文件条目以在本地测试它没有查询字符串参数。
请注意,在进行“发布”构建时,无法使用查询字符串参数进行测试,因为这会带来潜在的安全漏洞。
如果您使用网址:
/?domain=www.domain2.com
它将运行CategoryController.Cars
操作方法(如果存在)。
请注意,由于Default
路由涵盖了范围广泛的 URL,因此大部分站点将可供www.domain.com
和www.domain2.com
使用。例如,您可以在以下位置访问“关于”页面:
/Home/About?domain=www.domain.com
/Home/About?domain=www.domain2.com
您可以使用IgnoreRoute
extension method 来阻止您不想要的 URL(它接受路由约束,因此该解决方案也可以在那里工作)。
如果您主要希望在域之间共享功能,此解决方案将起作用。如果您希望在一个网站中有 2 个域,但让它们像单独的网站一样,则如果您使用上述路由约束为项目中的每个“网站”使用 Area 会更容易管理区域路线。
public class Domain2AreaRegistration : AreaRegistration
public override string AreaName
get
return "Domain2";
public override void RegisterArea(AreaRegistrationContext context)
context.MapRoute(
name: "Domain2_default",
url: "controller/action/id",
defaults: new action = "Index", id = UrlParameter.Optional ,
constraints: new _ = DomainConstraint("www.domain2.com")
);
上述配置将使www.domain2.com
的每个 URL(即 0、1、2 或 3 段长)路由到 Domain2
区域中的控制器。
【讨论】:
您好,谢谢!从性能的角度来看(我已经能够为我的案例运行 @ArthNRick 解决方案),哪种解决方案效果最好? (你的或 ArthNRick 的) 从性能的角度来看,它们大致相同,因为 ArthNRick 的解决方案将调用级联到另一个操作方法而不是执行重定向(这会向浏览器发出 302 响应并告诉它查找服务器上的新位置 - 额外的网络往返)。但是,如果您最终在www.domain2.com
上拥有多个视图,那么该解决方案将无法很好地扩展,让我们面对现实吧——这可能会发生。路由是一个独立的关注点,而不是动作方法中发生的事情,域名显然属于路由的范围。
另外请记住,来自www.domain.com
的所有 URL 也将在www.domain2.com
上可用(这是默认行为)。如果这是您的意图,您应该使用Canonical Tag 告诉搜索引擎您打算将相同的内容放在 2 个不同的 URL 上。如果这不是您想要的,请使用DomainConstraint
阻止来自您不想看到它们的域的路由。【参考方案2】:
在应用程序的默认操作中确保 url 是第二个域之一,然后返回所需的方法。类似:
public ActionResult Index()
if (Request.Url.Host.Equals("domain2"))
return AnotherAction();
【讨论】:
您好,谢谢!使用简单的路线不是更好吗?关于分析的观点。 我相信这是不可能的,你需要的是一个动作重定向,因为“domain.com”假定了默认路由(通常是“controller/action/id”),依此类推默认路线,您应该更正位置【参考方案3】:同意楼上的回答。
如果您想要更漂亮的实现,请尝试操作过滤器。 来自there 的操作过滤器使用示例。
public override void OnActionExecuting(ActionExecutingContext filterContext)
var controller = (SomeControllerBase) filterContext.Controller;
filterContext.Result = controller.RedirectToAction("index", "home");
从there 获取操作过滤器内的 URL 示例。
var url = filterContext.HttpContext.Request.Url;
把东西放在一起,玩得开心:)
【讨论】:
更漂亮的实现?这甚至没有提供如何将单个操作路由到两个单独的路由的示例,并且根本没有谈论重定向等问题。这应该是一个评论。 @d_petrishin 请不要忽视 *** 的 be nice 政策。 @GrumpyCrouton dick 是誓言的同义词,你是什么意思? @d_petrishin 作为同义词不会使一个词变得更合适或更不合适。你不应该称呼别人的名字。 @GrumpyCrouton 但你也这样做,为什么我不应该这样做?以上是关于在不使用 MVC 更改 URL 的情况下为特定 URL 创建路由的主要内容,如果未能解决你的问题,请参考以下文章
如何在不更改 pvalue 的情况下为 kruskal wallis 测试执行循环比较多列上的 3 个组?
如何在不影响 SYSTEM/IE 代理的情况下为 Webbrowser Control 设置代理