整合 ASP.NET MVC 控制器依赖关系 (StructureMap)
我正在查看我的网站中的控制器,它们的大多数构造函数看起来像这样:
public SomeController(
IServiceOne serviceOne,
IServiceTwo serviceTwo,
ILoggingService loggingService,
IGeospatialService geoSpatialService)
{
// copy to class variables.
}
换句话说,它非常毛茸茸并且使重构变得困难。一些控制器有大约 8 个依赖项。
有什么方法可以以某种方式将这些依赖项“分组”到多个存储桶之一中吗?
例如,每个控制器都需要 ILoggingService
,执行空间操作的控制器需要 IGeospatialService
,以及 IServiceOne
和 IServiceTwo
code> 仅在某些情况下才需要。
我希望看到这样的内容:
public SomeController(
ICoreServicesGroup coreGroup,
ISomeNameForServicesGroup serviceGroup)
{
// copy to class variables.
}
我认为引入一些 OO 技术会很好,例如拥有一个“基本”依赖类,它在其受保护的构造函数中采用 ILoggingService
。那么你可能有另一个继承的子依赖项,等等。
以前有人这样做过吗?这是 StructureMap 可以为我做的事情,还是只是我滚动自己的基本代码?
I'm looking at the controllers in my website, and most of their constructors look like this:
public SomeController(
IServiceOne serviceOne,
IServiceTwo serviceTwo,
ILoggingService loggingService,
IGeospatialService geoSpatialService)
{
// copy to class variables.
}
In other words, it's very hairy and makes refactoring difficult. Some controllers have around 8 dependencies.
Is there any way i can somehow "group" these dependencies into one of more buckets?
For example, ILoggingService
is required in every controller, IGeospatialService
is required by controllers who do spatial stuff, and IServiceOne
and IServiceTwo
is only required in certain cases.
I would like to see something like this:
public SomeController(
ICoreServicesGroup coreGroup,
ISomeNameForServicesGroup serviceGroup)
{
// copy to class variables.
}
I'm thinking it would be good to introduce some OO techniques, such as having a "base" depedency class, which takes a ILoggingService
in it's protected ctor. Then you might have another child dependency which inherits, etc.
Has anyone done this before? Is this something StructureMap can do for me, or is it simply me rolling my own basic code?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
日志记录
当每个控制器中都需要依赖项时,就可以肯定地表明它不是“正常”依赖项,而是跨领域关注点< /强>。日志记录是横切关注点的典型示例,因此 ILoggingService 应该像任何其他横切关注点一样处理。
在 OO 中,解决横切问题的适当方法是是使用一个装饰器(其中可以推广到 AOP)。但是,ASP.NET MVC 控制器操作方法不是任何接口的一部分,因此这是一个不太理想的解决方案。
相反,MVC 框架提供操作筛选器出于拦截目的。如果您想实现松散耦合的过滤器,请帮自己一个忙,将其实现为全局过滤器而不是属性。
其他依赖项
对于其他依赖项,将它们重构为外观服务。这涉及识别相关服务的自然集群,因此具体如何完成取决于每个代码库。
Logging
When a dependency is required in each and every Controller it's a pretty certain indicator that it's not a 'normal' dependency, but rather a Cross-cutting Concern. Logging is the archetypical example of a Cross-cutting Concern, so
ILoggingService
should be dealt with like any other Cross-cutting Concern.In SOLID OO the appropriate way to address a Cross-cutting concern would be to employ a Decorator (which can be generalized towards AOP). However, ASP.NET MVC Controller action methods aren't part of any interface, so that's a less ideal solution.
Instead, the MVC framework provides Action Filters for interception purposes. If you want to implement a loosely coupled filter, do yourself a favor and implement it as a global filter instead of an attribute.
Other dependencies
For other dependencies it makes sense to refactor them to Facade Services. This involves identifying natural clusters of related services, so exactly how this is done is specific to each code base.
我知道我不久前接受了@Mark Seeman 的回答,但我现在终于有时间来实现这个,所以我想为了其他人的利益而分享我实际所做的事情。
基本上,我为应用程序中的依赖项“组”创建了包装器接口。
示例:
实现:
确实非常简单。
然后我更新了我的控制器。
示例 ctor 之前:
之后:
实际上没什么特别的,只是一组包装器。在幕后,控制器仍然使用相同的依赖项,但 ctor 签名更小,更具可读性,并且也使单元测试更容易。
I know i accepted @Mark Seeman's answer a while ago, but i only finally got time to implement this now, so thought i'd share what i actually did, for other's benefit.
Basically, i created wrapper interfaces for the "groups" of dependencies in my application.
Example:
And the implementation:
Pretty simple really.
Then i updated my controllers.
Example ctor Before:
After:
Nothing special really, just set of wrappers. Under the hood, the controllers still utilise the same dependencies, but the ctor signature is much smaller, more readable, and it also makes unit testing easier.
我看到了几个选项:
用法:
Logger.Instance().Log(message);
测试:
Logger.Instance = () =>;新的 TestLogger();
I see a few options:
Usage:
Logger.Instance().Log(message);
Testing:
Logger.Instance = () => new TestLogger();