依赖注入-如何注册Unity容器的泛型类型



我正在努力使用Unity将通用类型存储库注入我的服务类。至少,我认为这个通用存储库是造成麻烦的原因。有人能指出我做错了什么吗?请原谅我,因为我是Unity的新手。首先,这里是我收到以下错误的错误信息。

解析依赖项失败,type = "TestUnity.Services.Contracts. "ICustBillingTypeService", name = "(none)"。解析。

时发生异常

异常是:InvalidOperationException -类型String不能被构造。您必须配置容器来提供这个值。

异常发生时,容器为:

解析testunity . services . implementations . custbillingtypesservice,(none)(从TestUnity.Services.Contracts映射)。ICustBillingTypeService (none))解析构造函数的参数"repo"。IRepository 1[[TestUnity.DAL.CustBillingType, TestUnity.DAL, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] repo) Resolving TestUnity.Repositories.Implementations.Repository [TestUnity.DAL. custbillingtype],(none)(映射自TestUnity.Repositories.Contracts.IRepository 1[TestUnity.DAL.CustBillingType], (none)) Resolving parameter "ctx" of constructor TestUnity.Repositories.Implementations.Repository 1[[TestUnity.DAL. custbillingtype])。CustBillingType TestUnity。[0], Version=1.0.0.0, Culture=neutral, PublicKeyToken=null。IDataContext ctx)解析TestUnity.Repositories.Implementations.DataContext,(none)(从testunories . repositories . contracts .映射)。IDataContext (none))解析构造函数的参数"nameOrConnectionString"。字符串nameOrConnectionString)system . string,解决(没有)

这是我的Unity引导类,它在一个单独的类库

    public static class UnityBootstrap
{
    private static IUnityContainer container;
    public static IUnityContainer Container
    {
        get
        {
            if (container == null)
                InitializeContainer();
            return container;
        }
    }
    public static void InitializeContainer()
    {
        container = new UnityContainer();
        container.RegisterType<ICustBillingTypeService, CustBillingTypeService>();
        container.RegisterType<IDataContext, DataContext>();
        container.RegisterType(typeof(IRepository<>), typeof(Repository<>));
    }
}
    public interface IRepository<T> where T : class, IObjectState
{
    T FindOne(Expression<Func<T, bool>> predicate);
}
    public class Repository<T> : IRepository<T> where T : class, IObjectState
{
    private readonly IDataContext context;
    private readonly IDbSet<T> dbSet;
    public Repository() { }
    public Repository(IDataContext ctx)
    {
        this.context = ctx;
        var dbContext = context as DbContext;
        dbSet = dbContext.Set<T>();
    }
    public virtual T FindOne(Expression<Func<T, bool>> predicate)
    {
        return dbSet.SingleOrDefault(predicate);
    }
}
public interface ICustBillingTypeService
{
    CustBillingType GetCustBillingTypeByPKId(int pkId);
}
public class CustBillingTypeService : ICustBillingTypeService
{
    IRepository<CustBillingType> custBillingTypeRepo;
    public CustBillingTypeService() { }
    public CustBillingTypeService(IRepository<CustBillingType> repo)
    {
        custBillingTypeRepo = repo;
    }
    public CustBillingType GetCustBillingTypeByPKId(int pkId)
    {
        var cbt = custBillingTypeRepo.FindOne(x => x.PKId == pkId);
        return cbt;
    }
}
public interface IDataContext : IDisposable
{
    int SaveChanges();
    void SyncObjectState<TEntity>(TEntity entity) where TEntity : class, IObjectState;
    void SyncObjectsStatePostCommit();
}

public class DataContext : DbContext, IDataContext
{
    private readonly Guid _instanceId;
    bool _disposed;
    public DataContext(string nameOrConnectionString) : base(nameOrConnectionString)
    {
        _instanceId = Guid.NewGuid();
        Configuration.LazyLoadingEnabled = false;
        Configuration.ProxyCreationEnabled = false;
    }
    public Guid InstanceId { get { return _instanceId; } }
    public override int SaveChanges()
    {
        SyncObjectsStatePreCommit();
        var changes = base.SaveChanges();
        SyncObjectsStatePostCommit();
        return changes;
    }
    protected override void Dispose(bool disposing)
    {
        if (!_disposed)
        {
            if (disposing)
            {
            }
            _disposed = true;
        }
        base.Dispose(disposing);
    }
}
public partial class TestModel : DataContext
{
    public TestModel() : base("name=TestModel") {}
    public virtual DbSet<CustBillingType> CustBillingTypes { get; set; }
    protected override void OnModelCreating(DbModelBuilder modelBuilder)
    {
        CustBillingTypeModelBuilder.Map(modelBuilder);
    }
}
[TestClass]
public class UnityTestCases
{
    private IUnityContainer uContainer;
    private ICustBillingTypeService icbService;
    public UnityTestCases()
    {
        uContainer = UnityBootstrap.Container;
        icbService = uContainer.Resolve<ICustBillingTypeService>();
    }
    [TestMethod]
    public void GetCustBillingTypeByPKId_return_ValidObj()
    {
        var obj = icbService.GetCustBillingTypeByPKId(pkId: 15);
        Assert.IsNotNull(obj);
    }
}

请注意,在我的测试用例中,我没有嘲笑任何东西。这是一种集成测试

如果要我猜的话,我会认为泛型类型注册有问题。也可能完全是别的原因。

先生。

IDataContext映射到DataContext:

container.RegisterType<IDataContext, DataContext>();

DataContext构造函数需要一个连接字符串/名称作为参数,但您没有提供。

像这样提供这个值:

container.RegisterType<IDataContext, DataContext>(
    new InjectionConstructor("name=TestModel"));

或者使用TestModel代替DataContext。我猜这就是你想要做的。TestModel已经有一个默认构造函数,所以你不需要提供连接字符串:

container.RegisterType<IDataContext, TestModel>();

在我看来,在组合根(在你的例子中是UnityBootstrap类)中有可见的连接字符串是有意义的,而不是在TestModel的默认构造函数中硬编码。连接字符串基本上是一个基本依赖项,您可能希望在将来更改它。