ASP.NET MVC IoC 可用性

发布于 2024-08-31 11:59:54 字数 337 浏览 5 评论 0原文

在实际项目中,您多久将 IoC 用于控制器/DAL?

IoC 允许通过应实现的附加接口层从具体实现中抽象出应用程序。但具体实施的变化频率如何?如果实现几乎不会改变,我们真的应该做两次向接口添加方法然后实现的工作吗?我参与了大约 10 个 ASP.NET 项目,并且 DAL(类似 ORM 或非 ORM)从未被完全重写。

观看大量视频后,我清楚地了解到 IoC“很酷”,并且是一种非常好的编程方式,但它真的需要吗?

后来补充了一点: 是的,IoC 允许准备更好的测试环境,但我们也有很好的方法在没有 IoC 的情况下测试 DAL。我们将对数据库的 DAL 调用包装到未提交的事务中,而不存在导致数据不稳定的风险。

How often do you use IoC for controllers/DAL in real projects?

IoC allows to abstract application from concrete implementation with additional layer of interfaces that should be implemented. But how often concrete implementation changes? Should we really have to do job twice adding method to interface then the implementation if implementation hardly will ever be changed? I took part in about 10 asp.net projects and DAL (ORM-like and not) was never rewritten completely.

Watching lots of videos I clearly understand that IoC "is cool" and the really nice way to program, but does it really needed?

Added a bit later:
Yes, IoC allows prepare better testing environment, but we also have nice way to test DAL without IoC. We wrap DAL calls to database into uncommited transactions without risk to make data unstable.

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

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

发布评论

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

评论(4

吃颗糖壮壮胆 2024-09-07 11:59:54

IoC 不仅仅用于编写模块化程序;它也是一种模式。它还允许更容易的测试,通过能够交换实现与它们所代表的组件相同的接口的模拟对象。

另外,它实际上使代码更容易维护。

IoC isn't a pattern only for writing modular programs; it also allows for easier testing, by being able to swap in mock objects that implement the same interface as the components they stand in for.

Plus, it actually makes code much easier to maintain down the road.

邮友 2024-09-07 11:59:54

它不是 IOC,它允许您使用附加的接口层从具体实现中抽象应用程序,这就是您应该如何设计应用程序以使其更加模块化和可重用。另一个重要的好处是,一旦您以这种方式设计了应用程序,就可以更轻松地单独测试不同的部分,而无需依赖于具体的数据库访问等。

It's not IOC that allows you to abstract application from concrete implementation with additional layer of interfaces, this is how you should design your application in order to be more modular and reusable. Another important benefit is that once you've designed your application this way it will be much easier to test the different parts in isolation without depending on concrete database access for example.

一指流沙 2024-09-07 11:59:54

除了更改实现的能力之外,还有更多关于 IoC 的内容:

  • 测试
  • 显式依赖项 - 不隐藏在私有 DataContext
  • 自动实例化中 - 您在构造函数中声明您需要某些东西,然后您就得到了它 - 所有深层嵌套依赖项都解决了
  • 程序集的分离 - 看看在 S#arp Architecture 中了解 IoC 如何允许避免引用 NHibernate 和其他特定程序集,否则您将不得不引用
  • 生命周期管理 - 能够指定对象的每个请求/单例/传递生命周期并在一处更改它,而不是在数十个控制器中
  • 执行动态操作的能力,例如在模型绑定程序中获取正确的数据上下文,因为使用 IoC,您现在拥有有关依赖项的元数据;这表明也许 IoC 对你的对象依赖关系的作用就像反射对 C# 编程的作用一样 - 很多新的可能性,你甚至从未想过等等

,我确信我错过了很多积极的东西。虽然我能想到的唯一“坏”的事情(以及你提到的)是接口的重复,但这对于现代 IDE 对重构的支持来说不是问题。

好吧,如果您的数据接口每天都在变化,并且您有数百个数据接口 - 您可能希望避免 IoC。

但是,您是否仅仅因为遵循良好的设计实践更困难而回避它们?您是否复制并粘贴代码而不是提取方法/类,只是因为这样做需要更多时间和更多代码?您是否将业务逻辑放在视图中只是因为创建视图模型并将其与域模型同步更困难?如果是,那么你可以避免 IoC,没问题。

There's much more about IoC except ability to change implementation:

  • testing
  • explicit dependencies - not hidden inside private DataContext
  • automatic instantiation - you declare in constructor that you need something, and you get it - with all deep nested dependencies resolved
  • separation of assemblies - take a look at S#arp Architecture to see how IoC allows to avoid referencing NHibernate and other specific assemblies, which otherwise you'll have to reference
  • management of lifetime - ability to specify per request / singleton / transitive lifetime of objects and change it in one place, instead of in dozens of controllers
  • ability to do dynamic stuff, like, getting correct data context in model binders, because with IoC you now have metadata about your dependencies; and this shows that maybe IoC does to your object dependencies what reflection does to C# programming - a lot of new possibilities, that you never even thought about

And so on, I'm sure I missed a lot of positive stuff. While the only "bad" thing that I can think about (and that you mentioned) is duplication of interface, which is non-issue with modern IDEs support for refactoring.

Well, if your data interfaces change every day, and you have hundreds of them - you may want to avoid IoC.

But, do you avoid good design practices just because it's harder to follow them? Do you copy and paste code instead of extracting a method/class, just because it takes more time and more code to do so? Do you place business logic in views just because it's harder to create view models and sync them with domain models? If yes, then you can avoid IoC, no problem.

别挽留 2024-09-07 11:59:54

您认为使用 IOC 比不使用它需要更多代码。我不同意。

以下是我使用 LinqToSql 的项目之一的完整 DAL IOC 配置。 ContextProvider 类只是一个线程安全的 LinqToSql 上下文工厂。

container.Register(Component.For<IContextProvider<LSDataContext>, IContextProvider>().LifeStyle.PerWebRequest.ImplementedBy<ContextProvider<LSDataContext>>();
container.Register(Component.For<IContextProvider<WorkSheetDataContext>, IContextProvider>().LifeStyle.PerWebRequest.ImplementedBy<ContextProvider<WorkSheetDataContext>>();
container.Register(Component.For<IContextProvider<OffersReadContext>, IContextProvider>().LifeStyle.PerWebRequest.ImplementedBy<ContextProvider<OffersReadContext>>();

以下是我的一个使用 NHibernate 和存储库模式的项目的完整 DAL 配置:

container.Register(Component.For<NHSessionBuilder>().LifeStyle.Singleton);
container.Register(Component.For(typeof(IRepository<>)).ImplementedBy(typeof(NHRepositoryBase<>)));

以下是我在 BLL 中使用 DAL 的方式(使用依赖注入):

public class ClientService
{
    private readonly IRepository<Client> _Clients;

public ClientService(IRepository<Client> clients)
{
    _Clients = clients;
}

public IEnumerable<Client> GetClientsWithGoodCredit()
{
    return _Clients.Where(c => c.HasGoodCredit);
}

}

请注意,我的 IRepository<>接口继承IQueryable<>;所以这段代码非常简单!

以下是我在不连接数据库的情况下测试 BLL 的方法:

public void GetClientsWithGoodCredit_ReturnsClientWithGoodCredit()
{
    var clientWithGoodCredit = new Client() {HasGoodCredit = true};
    var clientWithBadCredit = new Client() {HasGoodCredit = false};
    var clients = new List<Client>() { clientWithGoodCredit, clientWithBadCredit }.ToTestRepository();
    var service = new ClientService(clients);

var clientsWithGoodCredit = service.GetClientsWithGoodCredit();

Assert(clientsWithGoodCredit.Count() == 1);
Assert(clientsWithGoodCredit.First() == clientWithGoodCredit);

}

ToTestRepository() 是一个扩展方法,它返回一个假的 IRepository<> 。使用内存列表。

您不可能认为这比在 BLL 上更新 DAL 更复杂。

编写上述测试的唯一方法是连接到数据库,保存一些测试客户端,然后进行查询。我保证执行时间比这个长 100 倍以上。 (经过 1000 次测试,您就可以在等待时去喝杯咖啡了。)

此外,通过使用未提交的事务进行测试,您会引入由于 ORM 不查询未提交的实体而导致的调试噩梦。

You're arguing that using IOC takes MORE code than not using it. I disagree.

Here is the entire DAL IOC configuration for one of my projects using LinqToSql. The ContextProvider class is simply a thread safe LinqToSql context factory.

container.Register(Component.For<IContextProvider<LSDataContext>, IContextProvider>().LifeStyle.PerWebRequest.ImplementedBy<ContextProvider<LSDataContext>>();
container.Register(Component.For<IContextProvider<WorkSheetDataContext>, IContextProvider>().LifeStyle.PerWebRequest.ImplementedBy<ContextProvider<WorkSheetDataContext>>();
container.Register(Component.For<IContextProvider<OffersReadContext>, IContextProvider>().LifeStyle.PerWebRequest.ImplementedBy<ContextProvider<OffersReadContext>>();

Here is the entire DAL configuration for one of my projects using NHibernate and the repository pattern:

container.Register(Component.For<NHSessionBuilder>().LifeStyle.Singleton);
container.Register(Component.For(typeof(IRepository<>)).ImplementedBy(typeof(NHRepositoryBase<>)));

Here is how I consume the DAL in my BLL (w/ dependency injection):

public class ClientService
{
    private readonly IRepository<Client> _Clients;

public ClientService(IRepository<Client> clients)
{
    _Clients = clients;
}

public IEnumerable<Client> GetClientsWithGoodCredit()
{
    return _Clients.Where(c => c.HasGoodCredit);
}

}

Note that my IRepository<> interface inherits IQueryable<> so this code is very trivial!

Here's how I can test my BLL without connecting to a DB:

public void GetClientsWithGoodCredit_ReturnsClientWithGoodCredit()
{
    var clientWithGoodCredit = new Client() {HasGoodCredit = true};
    var clientWithBadCredit = new Client() {HasGoodCredit = false};
    var clients = new List<Client>() { clientWithGoodCredit, clientWithBadCredit }.ToTestRepository();
    var service = new ClientService(clients);

var clientsWithGoodCredit = service.GetClientsWithGoodCredit();

Assert(clientsWithGoodCredit.Count() == 1);
Assert(clientsWithGoodCredit.First() == clientWithGoodCredit);

}

ToTestRepository() is an extension method that returns a fake IRepository<> that uses an in-memory list.

There is no possible way you can argue that this is more complicated than newing up your DAL all over your BLL.

The only way you could have ever written the above test is by connecting to a DB, saving some test clients, and then querying. I guarantee that takes 100+ times longer to execute than this did. (Times that by 1000 tests and you can go get some coffee while you're waiting.)

Also, by using uncommitted transactions for testing you introduce debugging nightmares resulting from ORMs that don't query over uncommitted entities.

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