我面临一个与依赖注入相关的小问题。我有一个程序,它使用了一个asp.net mvc项目的例子中使用的依赖注入的最新规则,以及一些控制台程序。
但它也包含某种“服务定位器”反模式。
我将尝试用一个非常简单的控制台项目来说明它:
using System;
using Autofac;
using System.Collections.Generic;
using System.Linq;
namespace AutofacIssue
{
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterModule<MyModule>();
var container = builder.Build();
using (var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<UserService>();
var users = service.CreateSomeUsers();
var info = users.First().GetSomeInfo;
Console.WriteLine(info.Something);
}
}
}
internal class MyModule : Autofac.Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
builder.RegisterType<UserService>();
builder.RegisterType<UserRelatedInfoService>();
}
}
internal class UserRelatedInfoService
{
public UserInfo GetForUser(int id)
{
return new UserInfo("Various infos for " + id);
}
}
internal class UserService
{
public IEnumerable<User> CreateSomeUsers()
{
return Enumerable.Range(1, 10).Select(r => new User(r)); // Remark "new User()" is called from many various spaces !
}
}
internal class UserInfo
{
// Some things
public string Something;
public UserInfo(string someThings)
{
this.Something = someThings;
}
}
/// <summary>
/// "Service locator" antipattern
/// </summary>
class DependencyLocator
{
public static IContainer Container { get; }
static DependencyLocator()
{
var builder = new ContainerBuilder();
builder.RegisterModule<MyModule>();
Container = builder.Build();
}
}
internal class User
{
public User(int id)
{
this.Id = id;
}
public int Id { get; private set; }
/// <summary>
/// Here's my problematic property using the DependencyLocator
/// </summary>
public UserInfo GetSomeInfo
{
get
{
UserRelatedInfoService userRelatedInfoService = DependencyLocator.Container.Resolve<UserRelatedInfoService>();
return userRelatedInfoService.GetForUser(Id);
}
}
}
}
反模式允许编写非常小的代码,工作得非常好,但违反了di的一些原则(由于“服务定位器”+重复的容器,每个容器都有自己的生命周期)。
此实现还具有实例化
UserRelatedInfoService
只有在实际需要时,如果实际调用了用户的相关属性(请记住,现实世界中的示例要复杂得多,与此相关的一些操作可能会有成本)
在现实世界的例子中,我在许多程序集中都遇到了这种情况,每个程序集都需要能够以相同的方式解析依赖关系。
我的问题是:不需要修改
User
构造函数,以及实例化某些
用户
,有没有干净的方法来避免这种情况?
例如通过某种依赖关系的“动态解析”?
请注意
用户
与我的程序集不在同一程序集中
Program
类,所以我无法访问原始的
Container
作为公共财产。
我想的一个解决办法是让全班
DependencyLocator
但要删除它的内容,只需分配它的
集装箱
属性中创建的属性。
编辑:仅供参考,到目前为止,我只是按照自己的建议和修改的dependencLocator来避免它重新构建自己的容器,并在其上设置在应用程序入口点构建的最终容器。这是一个简单的改变,它避免了原来问题中指出的大多数问题。
至少,代码将始终使用相同的容器。
谢谢你的阅读!