嗯,这是我们的解决方案。许多小细节可能会被省略,但总体思路就在这里。这个答案可能是对原始问题的一种补充,但它描述了问题的一般解决方案。
我将尝试解释负责普通自定义 HTML 页面的部分,这些页面由用户在运行时创建,因此无法拥有自己的控制器/动作。因此,路由应该在运行时以某种方式构建,或者使用自定义 IRouteConstraint 进行“包罗万象”。
首先,让我们陈述一些事实和要求。
- 我们有一些关于我们页面的数据和一些元数据存储在 DB 中;
- 我们不想预先为所有现有页面(即在应用程序启动时)生成(假设的)整百万条路由,因为在应用程序期间可能会发生某些变化,我们不想通过将更改推送到全局来解决RouteCollection;
所以我们这样做:
1。页面控制器
是的,负责我们所有内容页面的特殊控制器。唯一的动作是 Display(int id)(实际上我们有一个特殊的 ViewModel 作为参数,但为了简单起见,我使用了 int id。
包含所有数据的页面由Display() 方法中的ID 解析。该方法本身返回ViewResult(强类型在PageViewModel 之后)或NotFoundResult,以防找不到页面。
2。自定义 IRouteConstraint
我们必须在某个地方定义用户实际请求的 URL 是否指向我们的自定义页面之一。为此,我们有一个特殊的IsPageConstraint,它实现了IRouteConstraint 接口。在约束的Match() 方法中,我们只需调用PageRepository 来检查是否存在与我们请求的URL 匹配的页面。我们的 PageRepository 由 StructureMap 注入。如果我们找到该页面,那么我们将那个“id”参数(带有值)添加到 RouteData 字典中,它会被DefaultModelBinder 自动绑定到PageController.Display(int id)。
但是我们需要一个 RouteData 参数来检查。我们从哪里得到的?来了……
3。带有“catch-all”参数的路由映射
重要提示:此路由定义在路由映射列表的最末尾,因为它非常笼统,而不是具体。我们首先检查所有明确定义的路由,然后检查Page(如果需要,可以轻松更改)。
我们只是像这样映射我们的路线:
routes.MapRoute("ContentPages",
"{*pagePath}",
new { controller = "Page", action = "Display" }
new { pagePath = new DependencyRouteConstraint<IsPageConstraint>() });
停下!映射中出现的DependencyRouteConstraint 是什么?嗯,这就是诀窍。
4。 DependencyRouteConstraint 类
这只是IRouteConstraint 的另一个通用实现,它采用“real” IRouteConstraint (IsPageConstraint) 并仅在调用Match() 方法时解析它(给定的TConstraint)。它使用依赖注入,所以我们的IsPageConstraint 实例注入了所有实际的依赖!
我们的DependencyRouteConstraint 然后只需调用dependentConstraint.Match() 提供所有参数,因此只是将实际的“匹配”委托给“真实的”IRouteConstraint。
注意:这个类实际上对ServiceLocator有依赖。
总结
这样我们就有了:
- 我们的
Route 干净整洁;
- 唯一依赖服务定位器的类是
DependencyRouteConstraint;
- 任何自定义
IRouteConstraint 在需要时使用依赖注入;
- ???
- 利润!
希望这会有所帮助。