Asp.net MVC RouteBase和IoC

时间:2010-12-27 18:12:10

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

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

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

2 个答案:

答案 0 :(得分:4)

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

我将尝试解释负责用户在运行时创建的纯自定义HTML页面的部分,因此无法拥有自己的Controller / Action。因此路由应该以某种方式在运行时构建,或者使用自定义IRouteConstraint进行“全部捕获”。

首先,让我们说明一些事实和要求。

  • 我们有一些关于存储在DB中的页面的数据和一些元数据;
  • 我们不希望事先为所有现有页面(即在应用程序启动时)生成(假设的)全部百万条路由,因为在应用程序期间某些内容可能会发生变化,我们不希望将更改推送到全局RouteCollection;

所以我们这样做:

1。的PageController

是的,负责我们所有内容页面的特殊控制器。并且唯一的操作是Display(int id)(实际上我们有一个特殊的ViewModel作为参数,但为了简单起见我使用了int id

包含其所有数据的页面由Display()方法中的ID解析。如果找不到页面,该方法本身会返回ViewResult(在PageViewModel后强列入)或NotFoundResult

2。自定义IRouteConstraint

我们必须在某处定义实际请求的URL用户是否引用了我们的一个自定义页面。为此,我们有一个特殊的IsPageConstraint来实现IRouteConstraint接口。在我们约束的Match()方法中,我们只需调用PageRepository来检查是否有与我们请求的网址匹配的网页。我们通过StructureMap注入了PageRepository。如果我们找到该页面,那么我们将“id”参数(带有值)添加到RouteData字典,并由PageController.Display(int id)自动绑定到DefaultModelBinder

但我们需要一个RouteData参数来检查。我们在哪里?来了...

3。使用“catch-all”参数

进行路由映射

重要说明:此路由在路由映射列表的最后定义,因为它非常通用,而不是特定的。我们首先检查所有明确定义的路由,然后检查Page(如果需要,可以轻松更改)。

我们只是简单地映射我们的路线:

routes.MapRoute("ContentPages", 
                "{*pagePath}", 
                new { controller = "Page", action = "Display" }
                new { pagePath = new DependencyRouteConstraint<IsPageConstraint>() });

停止!映射中出现DependencyRouteConstraint的内容是什么?好吧,那就是诀窍。

4。 DependencyRouteConstraint&LT; TConstraint&GT;类

这只是IRouteConstraint的另一个通用实现,只需要“real” IRouteConstraint(IsPageConstraint)并解析它(给定的TConstraint)调用Match()方法。它使用依赖注入,因此我们的IsPageConstraint实例注入了所有实际依赖项!

我们的DependencyRouteConstraint只需调用dependentConstraint.Match()提供所有参数,因此只需将实际的“匹配”委托给“真正的”IRouteConstraint。

注意:此类实际上依赖于ServiceLocator。

摘要

我们有这样的方式:

  • 我们的Route清晰干净;
  • 唯一依赖于服务定位器的类是DependencyRouteConstraint;
  • 任何自定义IRouteConstraint都会在需要时使用依赖注入;
  • ???
  • PROFIT!

希望这有帮助。

答案 1 :(得分:1)

所以,问题是:

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

这就是为什么我没有看到RouteBase类的子代是一些DB工作依赖的好地方。它使一切紧密耦合,不可扩展。实际上不可能执行依赖注入。

从现在起(我猜有一些已经在运行的系统)你实际上只有一个或多或少可行的选项:

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

使用CSL,您只需在GetRouteData内打电话:

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

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

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

你已经完成了。又脏又脏。关键字实际上是“脏”的:)

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