如何在单个 asp.net 网站上模拟两个域? RouteConstraints 是一个选项吗?
How can I mimic two domains on a single asp.net website? Are RouteConstraints an option?
我是 运行 我的网络服务器上的一个 Orchard CMS 实例,有两个自定义模块,ModuleFirst
和 ModuleSecond
。出于某些原因,我希望这两个网站作为独立的网站,拥有自己的域和主页。我无法设置其他网站或使用 Orchard 的内置租户功能。
我有什么
我实现这一目标的方法如下:
- 在 IIS 中向我的网站添加了两个绑定:
first-domain.com
和 second-domain.com
实现了一个 ThemeSelector(我认为它就像一个 ActionFilter),它根据传入请求Url 的主机切换主题
if (host.Contains("second-domain.com"))
{
useSecondTheme = true;
}
- 确保所有路线都是唯一的
这在大多数情况下都运行良好。我可以导航到 first-domain.com/foo
和 second-domain.com/bar
,看起来我在不同的网站上。
问题
对于这两个"homepages"我无法制作唯一的路线,因为我不想添加任何后缀。这两个项目都定义了一条空白路线,应该通向各自的 Home/Index,但我不知道如何进行这项工作。
new RouteDescriptor {
Priority = 90,
Route = new Route(
"",
new RouteValueDictionary { // Defaults
{"area", "ModuleFirst"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary(), // Constraints
new RouteValueDictionary { // Datatokens
{"area", "ModuleFirst"}
},
new MvcRouteHandler())
}
new RouteDescriptor {
Priority = 100,
Route = new Route(
"",
new RouteValueDictionary { // Defaults
{"area", "ModuleSecond"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary(), // Constraints
new RouteValueDictionary { // Datatokens
{"area", "ModuleSecond"}
},
new MvcRouteHandler())
}
我试过的
我尝试实现一个 ActionFilter,当主机 url first-domain.com
的请求到达 ModuleSecond/Home/Index
时重定向到 ModuleFirst/Home/Index
但这显然不起作用,因为它只是一遍又一遍地点击最高优先级的路线并破坏网站。
我还尝试在具有最高优先级的路由上实施自定义 RouteConstraint 以阻止所有不是来自其预期域的传入请求,假设这些请求随后会退回到优先级较低的路由。
public class SecondConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.Url.DnsSafeHost.Contains("second-domain.com");
}
}
使用如下:
new RouteDescriptor {
Priority = 100,
Route = new Route(
"",
new RouteValueDictionary { // Defaults
{"area", "ModuleSecond"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary { // Constraints
{"isSecond", new SecondConstraint()}
},
new RouteValueDictionary { // Datatokens
{"area", "ModuleSecond"}
},
new MvcRouteHandler())
}
我现在可以很好地导航到 second-domain.com
并获得正确的页面,但导航到 first-domain.com
超时。不过,我还没有在 Orchard 中找到 RouteConstraints 的任何示例,所以也许我做错了。
虽然我会建议任何打算从头开始做这样的事情的人尽可能使用租户和 OAuth,正如 Bertrand 在他的评论中建议的那样,但我想到了一种相当干净的方法来完成我想要的。
我没有使用两个单独的模块,而是只使用了一个。
在我的一个模块中,我实现了 IRouteProvider
来覆盖默认路由,它捕获了 first-domain.com/
和 second-domain.com/
public class Routes : IRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
foreach (var routeDescriptor in GetRoutes())
routes.Add(routeDescriptor);
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new RouteDescriptor {
Priority = 100,
Route = new Route(
"",
new RouteValueDictionary {
{"area", "MyModule"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "MyModule"}
},
new MvcRouteHandler())
}
};
}
}
然后我创建了一个只有一个 属性 bool IsHomepage
的自定义部分并将其附加到页面类型
public class SecondHomepagePart : ContentPart<SecondHomepagePartRecord>
{
public bool IsHomepage
{
get { return Retrieve(r => r.IsHomepage); }
set { Store(r => r.IsHomepage, value); }
}
}
在驱动程序中,我确保只有一个 "second homepage"
protected override DriverResult Editor(SecondHomepagePart part, IUpdateModel updater, dynamic shapeHelper)
{
if (updater.TryUpdateModel(part, Prefix, null, null))
{
if (part.IsHomepage)
{
var otherHomepages = _orchardServices.ContentManager.Query<SecondHomepagePart>().Where<SecondHomepagePartRecord>(r => r.IsHomepage && r.Id != part.Id).List();
foreach (var homepagePart in otherHomepages)
{
homepagePart.IsHomepage = false;
}
}
}
return Editor(part, shapeHelper);
}
然后在我的自定义 HomeController
中,我只检查当前域,获取带有空白 AutoroutePart
或 SecondHomepagePart
的 ContentItem,其中 IsHomepage
设置为 true 取决于在域上,构建该项目的详细形状,然后在我的自定义 Index.cshtml
视图中显示该形状。
控制器:
public ActionResult Index()
{
var host = HttpContext.Request.Url.DnsSafeHost;
var model = new IndexViewModel();
IContent homepageItem;
if (host.Contains("first-domain.com"))
{
homepageItem = _homeAliasService.GetHomePage();
}
else
{
homepageItem = _orchardServices.ContentManager.Query<SecondHomepagePart>()
.Where<SecondHomepagePartRecord>(r => r.IsHomepage)
.List()
.FirstOrDefault();
}
model.Homepage = _orchardServices.ContentManager.BuildDisplay(homepageItem, "Detail");
return View(model);
}
查看:
@model MyModule.ViewModels.Home.IndexViewModel
@if (Model.Homepage != null)
{
@Display(Model.Homepage)
}
我在 IConditionProvider
和 IThemeSelector
中使用相同的检查来为每个域设置层规则并自动设置适当的主题。现在我基本上有两个与外界完全不同的网站,但具有共享的内容、小部件、部件、自定义设置等。对于从相同库存但以不同品牌和以下方式销售相同产品的客户来说,这是一个快速简便的解决方案不同的条件,以及一些不同的独家内容。
我是 运行 我的网络服务器上的一个 Orchard CMS 实例,有两个自定义模块,ModuleFirst
和 ModuleSecond
。出于某些原因,我希望这两个网站作为独立的网站,拥有自己的域和主页。我无法设置其他网站或使用 Orchard 的内置租户功能。
我有什么
我实现这一目标的方法如下:
- 在 IIS 中向我的网站添加了两个绑定:
first-domain.com
和second-domain.com
实现了一个 ThemeSelector(我认为它就像一个 ActionFilter),它根据传入请求Url 的主机切换主题
if (host.Contains("second-domain.com")) { useSecondTheme = true; }
- 确保所有路线都是唯一的
这在大多数情况下都运行良好。我可以导航到 first-domain.com/foo
和 second-domain.com/bar
,看起来我在不同的网站上。
问题
对于这两个"homepages"我无法制作唯一的路线,因为我不想添加任何后缀。这两个项目都定义了一条空白路线,应该通向各自的 Home/Index,但我不知道如何进行这项工作。
new RouteDescriptor {
Priority = 90,
Route = new Route(
"",
new RouteValueDictionary { // Defaults
{"area", "ModuleFirst"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary(), // Constraints
new RouteValueDictionary { // Datatokens
{"area", "ModuleFirst"}
},
new MvcRouteHandler())
}
new RouteDescriptor {
Priority = 100,
Route = new Route(
"",
new RouteValueDictionary { // Defaults
{"area", "ModuleSecond"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary(), // Constraints
new RouteValueDictionary { // Datatokens
{"area", "ModuleSecond"}
},
new MvcRouteHandler())
}
我试过的
我尝试实现一个 ActionFilter,当主机 url first-domain.com
的请求到达 ModuleSecond/Home/Index
时重定向到 ModuleFirst/Home/Index
但这显然不起作用,因为它只是一遍又一遍地点击最高优先级的路线并破坏网站。
我还尝试在具有最高优先级的路由上实施自定义 RouteConstraint 以阻止所有不是来自其预期域的传入请求,假设这些请求随后会退回到优先级较低的路由。
public class SecondConstraint : IRouteConstraint
{
public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
return httpContext.Request.Url.DnsSafeHost.Contains("second-domain.com");
}
}
使用如下:
new RouteDescriptor {
Priority = 100,
Route = new Route(
"",
new RouteValueDictionary { // Defaults
{"area", "ModuleSecond"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary { // Constraints
{"isSecond", new SecondConstraint()}
},
new RouteValueDictionary { // Datatokens
{"area", "ModuleSecond"}
},
new MvcRouteHandler())
}
我现在可以很好地导航到 second-domain.com
并获得正确的页面,但导航到 first-domain.com
超时。不过,我还没有在 Orchard 中找到 RouteConstraints 的任何示例,所以也许我做错了。
虽然我会建议任何打算从头开始做这样的事情的人尽可能使用租户和 OAuth,正如 Bertrand 在他的评论中建议的那样,但我想到了一种相当干净的方法来完成我想要的。
我没有使用两个单独的模块,而是只使用了一个。
在我的一个模块中,我实现了 IRouteProvider
来覆盖默认路由,它捕获了 first-domain.com/
和 second-domain.com/
public class Routes : IRouteProvider
{
public void GetRoutes(ICollection<RouteDescriptor> routes)
{
foreach (var routeDescriptor in GetRoutes())
routes.Add(routeDescriptor);
}
public IEnumerable<RouteDescriptor> GetRoutes()
{
return new[] {
new RouteDescriptor {
Priority = 100,
Route = new Route(
"",
new RouteValueDictionary {
{"area", "MyModule"},
{"controller", "Home"},
{"action", "Index"},
},
new RouteValueDictionary(),
new RouteValueDictionary {
{"area", "MyModule"}
},
new MvcRouteHandler())
}
};
}
}
然后我创建了一个只有一个 属性 bool IsHomepage
的自定义部分并将其附加到页面类型
public class SecondHomepagePart : ContentPart<SecondHomepagePartRecord>
{
public bool IsHomepage
{
get { return Retrieve(r => r.IsHomepage); }
set { Store(r => r.IsHomepage, value); }
}
}
在驱动程序中,我确保只有一个 "second homepage"
protected override DriverResult Editor(SecondHomepagePart part, IUpdateModel updater, dynamic shapeHelper)
{
if (updater.TryUpdateModel(part, Prefix, null, null))
{
if (part.IsHomepage)
{
var otherHomepages = _orchardServices.ContentManager.Query<SecondHomepagePart>().Where<SecondHomepagePartRecord>(r => r.IsHomepage && r.Id != part.Id).List();
foreach (var homepagePart in otherHomepages)
{
homepagePart.IsHomepage = false;
}
}
}
return Editor(part, shapeHelper);
}
然后在我的自定义 HomeController
中,我只检查当前域,获取带有空白 AutoroutePart
或 SecondHomepagePart
的 ContentItem,其中 IsHomepage
设置为 true 取决于在域上,构建该项目的详细形状,然后在我的自定义 Index.cshtml
视图中显示该形状。
控制器:
public ActionResult Index()
{
var host = HttpContext.Request.Url.DnsSafeHost;
var model = new IndexViewModel();
IContent homepageItem;
if (host.Contains("first-domain.com"))
{
homepageItem = _homeAliasService.GetHomePage();
}
else
{
homepageItem = _orchardServices.ContentManager.Query<SecondHomepagePart>()
.Where<SecondHomepagePartRecord>(r => r.IsHomepage)
.List()
.FirstOrDefault();
}
model.Homepage = _orchardServices.ContentManager.BuildDisplay(homepageItem, "Detail");
return View(model);
}
查看:
@model MyModule.ViewModels.Home.IndexViewModel
@if (Model.Homepage != null)
{
@Display(Model.Homepage)
}
我在 IConditionProvider
和 IThemeSelector
中使用相同的检查来为每个域设置层规则并自动设置适当的主题。现在我基本上有两个与外界完全不同的网站,但具有共享的内容、小部件、部件、自定义设置等。对于从相同库存但以不同品牌和以下方式销售相同产品的客户来说,这是一个快速简便的解决方案不同的条件,以及一些不同的独家内容。