【问题标题】:Asp.net MVC RouteBase and IoCAsp.net MVC RouteBase 和 IoC
【发布时间】:2011-05-31 06:12:05
【问题描述】:

我正在通过子类化 RouteBase 创建自定义路由。我有一个依赖项,我想与 IoC 连接。 GetRouteData 方法只需要 HttpContext,但我也想在我的工作单元中添加....不知何故。

我正在使用 StructureMap,但有关如何使用任何 IoC 框架执行此操作的信息会有所帮助。

【问题讨论】:

  • 您能否提供更多关于您想要实现的目标的信息?因为Route 类似乎不是依赖的好地方。你提到了 UoW,所以我想你会从 DB 那里得到一些东西。我只是想知道为什么Route
  • 有点像 cms....为页面加载数据并将其添加到路由数据中。它工作得很好,只是想清理依赖关系。

标签: asp.net asp.net-mvc structuremap ioc-container


【解决方案1】:

嗯,这是我们的解决方案。许多小细节可能会被省略,但总体思路就在这里。这个答案可能是对原始问题的一种补充,但它描述了问题的一般解决方案。

我将尝试解释负责普通自定义 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 在需要时使用依赖注入;
  • ???
  • 利润!

希望这会有所帮助。

【讨论】:

  • 太好了,谢谢!我基本上在做同样的事情,但是我的路由检查用户是否正在请求自定义页面,如果不是,它返回 null 并落入默认的 mvc 路由。在我的情况下,如果它是一个自定义页面,我正在加载页面数据并将生成的视图模型添加到路由数据中,而不仅仅是像你这样的页面 id。你不同意我们正在做的事情并没有那么不同吗?我的意思是,我们都需要一个服务定位器的用法。
  • 当然,您可以根据需要添加任何其他数据,而不仅仅是页面 ID。正如我所看到的,不同之处在于我们没有为此更改 Route 类,而是使用 IRouteConstraint 代替,这似乎只是这些检查的更合适的地方。对我们来说,Route 只是一个映射数据载体类。它对我们的“页面”或任何东西一无所知(这总是一件好事,因为它不会违反 SRP 并使事情足够解耦)。
【解决方案2】:

所以,问题是:

  • 路由必须在应用程序启动期间预先定义
  • Route 的职责是将传入的 URL 模式映射到正确的 Controller/Action 以根据请求执行某些任务。反之亦然 - 使用该映射数据生成链接。时期。其他一切都是违反“单一职责原则”,实际上导致了您的问题。
  • UoW 依赖项(如 NHibernate ISession 或 EF ObjectContext)必须在运行时解决。

这就是为什么我不认为 RouteBase 类的子类是一些数据库工作依赖的好地方。它使一切都紧密耦合且不可扩展。依赖注入实际上是不可能的。

从现在开始(我猜有某种已经可以工作的系统)你实际上只有一个或多或少可行的选择:

  • 要使用服务定位器模式:在 GetRouteData 方法中解析您的 UoW 实例(使用由 StructureMap IContainer 支持的 CommonServiceLocator)。这很简单,但不是很好,因为这样您就可以在 Route 中获得对静态服务定位器本身的依赖。

使用 CSL,您只需在 GetRouteData 内部调用:

var uow = ServiceLocator.Current.GetService<IUnitOfWork>();

或仅使用 StructureMap(没有 CSL 外观):

var uow = ObjectFactory.GetInstance<IUnitOfWork>();

你就完成了。又快又脏。关键字实际上是“脏”:)

当然,有更灵活的解决方案,但它需要一些架构更改。如果您提供有关您在路由中获得的确切数据的更多详细信息,我可以尝试解释我们如何解决我们的 Pages 路由问题(使用 DI 和自定义 IRouteConstraint)。

【讨论】:

  • 当然,如果可以,请详细说明您的解决方案。我们获取给定页面的所有 html/links/etc 并将其存储在 RouteData 中。基本上是您在网页上看到的所有内容。
  • 显然,Html,链接等Page数据不应该属于RouteData。至少因为RoutePage 有不同的生命周期。我将尝试将我们的解决方案解释为单独的答案。
猜你喜欢
  • 1970-01-01
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 2015-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多