Unity IOC 有时无法解析依赖项。

3
我在使用Unity作为IOC容器时遇到了一个奇怪的问题,已经想不出是什么原因导致的。我的WebAPI控制器中有一个服务依赖项,但它随机无法解析该依赖项。有时我需要启动应用程序3或4次,然后它突然又可以工作了。
我收到的错误消息如下:
"解析依赖关系失败,类型="Base.WebApi.Controllers.ApiUsersController",名称="(none)"。异常发生时:正在解析。异常为:InvalidOperationException - 类型IApiUserService没有可访问的构造函数。----------------------------------------------- 在抛出异常时,容器为:正在解析Base.WebApi.Controllers.ApiUsersController,(none) 正在解析构造函数Base.WebApi.Controllers.ApiUsersController(Base.BLL.Services.User.IApiUserService apiUserService)的参数"apiUserService" 正在解析Base.BLL.Services.User.IApiUserService,(none)"
我使用以下内容初始化和注册我的类型:
public static void RegisterTypes(IUnityContainer container)
{
    var myAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => a.FullName.StartsWith("Base") && !a.FullName.StartsWith("Base.WebApi")).ToArray();

    container.RegisterType(typeof(Startup));

    container.RegisterTypes(
            UnityHelpers.GetTypesWithCustomAttribute<UnityIoCSingletonLifetimedAttribute>(myAssemblies),
            WithMappings.FromMatchingInterface,
            WithName.Default,
            WithLifetime.ContainerControlled,
            null
        ).RegisterTypes(
                UnityHelpers.GetTypesWithCustomAttribute<UnityIoCTransientLifetimedAttribute>(myAssemblies),
                WithMappings.FromMatchingInterface,
                WithName.Default,
                WithLifetime.Transient);

}

正如您所见,我正在使用单例和瞬态命名属性来定义解析我的依赖项的方式。

我的控制器如下所示:

public class ApiUsersController : ODataController
{

    private readonly IApiUserService _apiUserService;

    public ApiUsersController(IApiUserService apiUserService)
    {
        _apiUserService = apiUserService;
    }

    public IQueryable<ApiUserEntity> Get()
    {
        return this._apiUserService.GetUsers();
    }
}

正如您所看到的,它依赖于用户服务,其代码如下:

[UnityIoCTransientLifetimed]
public class ApiUserService : BaseService, IApiUserService
{
    private readonly IUserRepository _userRepository; 

    public ApiUserService(IUserRepository userRepository, IUnitOfWork uow) : base(uow)
    {
        _userRepository = userRepository;
    }
 }

API用户仓库看起来像这样:

[UnityIoCTransientLifetimed]
public class UserRepository :  GenericRepository<ApiUserEntity>, IUserRepository
{
    public UserRepository(IUnitOfWork unitOfWork, IDomainContext context) : base(unitOfWork, context)
    {

    }

扩展以下GenericRepository:

public class GenericRepository<T> : IGenericRepository<T> where T : class
{
    protected readonly BaseContext Context;

    public GenericRepository(IUnitOfWork unitOfWork, IBaseContext context)
    {
        // register this repository with the unit of work.
        unitOfWork.Register(this);

        Context = (BaseContext)context;
    }

使用以下这个工作单元:

[UnityIoCSingletonLifetimed]
public class UnitOfWork : IUnitOfWork
{
    private readonly Dictionary<string, IRepository> _repositories;

    // unit of work class is responsible for creating the repository and then dispossing it when no longer needed.
    public UnitOfWork()
    {
        _repositories = new Dictionary<string, IRepository>();
    }
 }

然而,有时它工作正常,有时却不行,我无法弄清楚为什么或者在哪里查找问题。

可能 IApiUserServiceApiUsersController 之前没有注册,这意味着它没有类型可以注入到该构造函数中。 - Ron Beyer
顺便问一下,你能在调试中重现这个问题吗?如果可以的话,你能检查一下 AppDomain.CurrentDomain.GetAssemblies() 返回了什么吗?我怀疑问题的解释可能是包含 ApiUserService 的程序集还没有被加载。 - Thomas Levesque
@RonBeyer,注册顺序并不重要,只要在解析之前将所有内容都注册即可。 - Thomas Levesque
我刚刚尝试了显式注册它们,自那以后它就没有崩溃过。已经重新启动了大约5/6次。看起来确实是在GetAssemblies部分出了问题。 - Jurgen Welschen
好的伙计们,问题确实在getassemblies中。我再次使用了按约定注册的方式,有时它不会加载Base.BLL程序集(其中包含apiuserservice),有时又会加载。这是怎么回事? - Jurgen Welschen
显示剩余3条评论
1个回答

1
最终得以解决,多亏了一些建议。查看有关文档的信息:

AppDomain.CurrentDomain.GetAssemblies()

它的意思是获取已加载到此应用程序域执行上下文中的程序集。 这基本上意味着只有在需要时才会加载这些程序集。 我解决这个问题的方式是使用更可靠的GetReferencedAssemblies,即使未使用也可加载所有程序集。
var allAssemblies = new ReadOnlyCollection<Assembly>(
BuildManager.GetReferencedAssemblies().Cast<Assembly>().ToList());

已经重新启动了很多次,但都没有解决崩溃的问题 :) 感谢大家! 对于正在寻找更多信息的人,请查看这个 SO 答案: AppDomain.GetAssemblies 和 BuildManager.GetReferencedAssemblies 的区别


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接