Asp.net MVC RouteBase 和 IoC

发布于 2024-10-09 08:01:01 字数 173 浏览 0 评论 0原文

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

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

I am creating a custom route by subclassing RouteBase. I have a dependency in there that I'd like to wire up with IoC. The method GetRouteData just takes HttpContext, but I want to add in my unit of work as well....somehow.

I am using StructureMap, but info on how you would do this with any IoC framework would be helpful.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

浅黛梨妆こ 2024-10-16 08:01:01

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

我将尝试解释负责用户在运行时创建的普通自定义 HTML 页面的部分,因此不能拥有自己的控制器/操作。因此,路由应该以某种方式在运行时构建,或者使用自定义 IRouteConstraint“包罗万象”。

首先,让我们陈述一些事实和要求。

  • 我们在数据库中存储了有关页面的一些数据和元数据;
  • 我们不想事先(即在应用程序启动时)为所有现有页面生成(假设的)一百万条路由,因为在应用程序期间可能会发生某些变化,并且我们不想通过将更改推送到全局 RouteCollection 来解决;

所以我们这样做:

1. PageController

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

页面及其所有内容数据由 Display() 方法内的 ID 解析。该方法本身返回 ViewResult(在 PageViewModel 之后强类型化)或 NotFoundResult。 以防找不到页面。

2. 自定义 IRouteConstraint

我们必须在某处定义用户实际请求的 URL 是否引用我们的自定义页面之一。为此,我们有一个特殊的 IsPageConstraint 。实现 IRouteConstraint 接口。在约束的 Match() 方法中,我们只需调用 PageRepository 来检查是否存在与我们请求的页面匹配的页面。 URL。如果我们找到该页面,则将“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

只是 IRouteConstraint 的另一个通用实现,它采用 "real" IRouteConstraint (IsPageConstraint) 并解析它(给定的 TConstraint) 仅当调用 Match() 方法时。它使用依赖项注入,因此我们的 IsPageConstraint 实例已注入所有实际依赖项!

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

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

总结

这样我们就有了:

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

希望这有帮助。

Well, here is our solution. Many little details may be omitted but overall idea is here. This answer may be a kind of offtop to original question but it describes the general solution to the problem.

I'll try to explain the part that is responsible for plain custom HTML-pages that are created by users at runtime and therefore can't have their own Controller/Action. So the routes should be either somehow built at runtime or be "catch-all" with custom IRouteConstraint.

First of all, lets state some facts and requirements.

  • We have some data and some metadata about our pages stored in DB;
  • We don't want to generate a (hypothetically) whole million of routes for all of existing pages beforehand (i.e. on Application startup) because something can change during application and we don't want to tackle with pushing the changes to global RouteCollection;

So we do it this way:

1. PageController

Yes, special controller that is responsible for all our content pages. And there is the only action that is Display(int id) (actually we have a special ViewModel as param but I used an int id for simplicity.

The page with all its data is resolved by ID inside that Display() method. The method itself returns either ViewResult (strongly typed after PageViewModel) or NotFoundResult in case when page is not found.

2. Custom IRouteConstraint

We have to somewhere define if the URL user actually requested refers to one of our custom pages. For this we have a special IsPageConstraint that implements IRouteConstraint interface. In the Match() method of our constraint we just call our PageRepository to check whether there is a page that match our requested URL. We have our PageRepository injected by StructureMap. If we find the page then we add that "id" parameter (with the value) to the RouteData dictionary and it is automatically bound to PageController.Display(int id) by DefaultModelBinder.

But we need a RouteData parameter to check. Where we get that? Here comes...

3. Route mapping with "catch-all" parameter

Important note: this route is defined in the very end of route mappings list because it is very general, not specific. We check all our explicitly defined routes first and then check for a Page (that is easily changeable if needed).

We simply map our route like this:

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

Stop! What is that DependencyRouteConstraint thing appeared in mapping? Well, thats what does the trick.

4. DependencyRouteConstraint<TConstraint> class

This is just another generic implementation of IRouteConstraint which takes the "real" IRouteConstraint (IsPageConstraint) and resolves it (the given TConstraint) only when Match() method called. It uses dependency injection so our IsPageConstraint instance has all actual dependencies injected!

Our DependencyRouteConstraint then just calls the dependentConstraint.Match() providing all the parameters thus just delegating actual "matching" to the "real" IRouteConstraint.

Note: this class actually has the dependency on ServiceLocator.

Summary

That way we have:

  • Our Route clear and clean;
  • The only class that has a dependency on Service Locator is DependencyRouteConstraint;
  • Any custom IRouteConstraint uses dependency injection whenever needed;
  • ???
  • PROFIT!

Hope this helps.

栀子花开つ 2024-10-16 08:01:01

所以,问题是:

  • Route 必须事先定义,在应用程序启动期间
  • 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)。

So, the problem is:

  • Route must be defined beforehand, during Application startup
  • Route's responsibility is to map the incoming URL pattern to the right Controller/Action to perform some task on request. And visa versa - to generate links using that mapping data. Period. Everything else is "Single Responsibility Principle" violation which actually led to your problem.
  • But UoW dependencies (like NHibernate ISession, or EF ObjectContext) must be resolved at runtime.

And that is why I don't see the children of RouteBase class as a good place for some DB work dependency. It makes everything closely coupled and non-scalable. It is actually impossible to perform Dependency Injection.

From now (I guess there is some kind of already working system) you actually have just one more or less viable option that is:

  • To use Service Locator pattern: resolve your UoW instance right inside the GetRouteData method (use CommonServiceLocator backed by StructureMap IContainer). That is simple but not really nice thing because this way you get the dependency on static Service Locator itself in your Route.

With CSL you have to just call inside GetRouteData:

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

or with just StructureMap (without CSL facade):

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

and you're done. Quick and dirty. And the keyword is "dirty" actually :)

Sure, there is much more flexible solution but it needs a few architectural changes. If you provide more details on exactly what data you get in your routes I can try to explain how we solved our Pages routing problem (using DI and custom IRouteConstraint).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文