Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/logging/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Constructor Autofac-基于自定义属性的构造函数参数,带有程序集扫描_Constructor_Attributes_Autofac_Code Injection - Fatal编程技术网

Constructor Autofac-基于自定义属性的构造函数参数,带有程序集扫描

Constructor Autofac-基于自定义属性的构造函数参数,带有程序集扫描,constructor,attributes,autofac,code-injection,Constructor,Attributes,Autofac,Code Injection,我遇到了以下问题,即如何配置Autofac容器,但实际上找不到解决方案 假设我有一堆存储库,比如AccountRepository、ContactRepository、LeadRepository等等 每个存储库都有一个IService类型的构造函数参数,它提供基本CRUD方法的实现。在我的例子中,它是到第三方应用程序的通用web服务连接,但这并不重要 比如我有这样的东西: public class AccountRepository { private readonly IServic

我遇到了以下问题,即如何配置Autofac容器,但实际上找不到解决方案

假设我有一堆存储库,比如AccountRepository、ContactRepository、LeadRepository等等

每个存储库都有一个IService类型的构造函数参数,它提供基本CRUD方法的实现。在我的例子中,它是到第三方应用程序的通用web服务连接,但这并不重要

比如我有这样的东西:

public class AccountRepository
{
    private readonly IService service;

    public AccountRepository(IService service)
    {
        this.service = service ?? throw new ArgumentNullException(nameof(service));
    }

    public int GetContactCount(Guid accountId)
    {
        using(DataContext ctx = new DataContext(service))
        {
            return ctx.Contacts.Where(c => c.AccountId == accountId).Count();
        }
    }
}
public class UpdateNrOfContactsCommandHandler : IHandleCommand<UpdateNrOfContactsCommand, Account>
{
    private readonly AccountRepository accountRepo;
    private readonly AccountRepository accountRepoAsUser;

    public UpdateNrOfContactsCommandHandler(AccountRepository accountRepo, [InUserContext] AccountRepository accountRepoAsUser)
    {
        this.accountRepo = accountRepo ?? throw new ArgumentNullException(nameof(accountRepo));
        this.accountRepoAsUser = accountRepoAsUser ?? throw new ArgumentNullException(nameof(accountRepoAsUser));
    }

    public void Execute(Account account)
    {
        account.NrOfContacts = repo.GetContactCount(account.Id);
        account.NrOfContactsSeenByCurrentUser = accountRepoAsUser.GetContactCount(account.Id);
    }
}
我的域代码是通过命令和事件实现的。假设我有一个使用上述存储库的以下命令处理程序:

public class UpdateNrOfContactsCommandHandler : IHandleCommand<UpdateNrOfContactsCommand, Account>
{
    private readonly AccountRepository accountRepo;

    public UpdateNrOfContactsCommandHandler(AccountRepository accountRepo)
    {
        this.accountRepo = accountRepo ?? throw new ArgumentNullException(nameof(accountRepo));
    }

    public void Execute(Account account)
    {
        account.NrOfContacts = repo.GetContactCount(account.Id);
    }
}
管理上下文中的服务应为默认服务

我认为一个优雅的解决方案是这样的:

public class AccountRepository
{
    private readonly IService service;

    public AccountRepository(IService service)
    {
        this.service = service ?? throw new ArgumentNullException(nameof(service));
    }

    public int GetContactCount(Guid accountId)
    {
        using(DataContext ctx = new DataContext(service))
        {
            return ctx.Contacts.Where(c => c.AccountId == accountId).Count();
        }
    }
}
public class UpdateNrOfContactsCommandHandler : IHandleCommand<UpdateNrOfContactsCommand, Account>
{
    private readonly AccountRepository accountRepo;
    private readonly AccountRepository accountRepoAsUser;

    public UpdateNrOfContactsCommandHandler(AccountRepository accountRepo, [InUserContext] AccountRepository accountRepoAsUser)
    {
        this.accountRepo = accountRepo ?? throw new ArgumentNullException(nameof(accountRepo));
        this.accountRepoAsUser = accountRepoAsUser ?? throw new ArgumentNullException(nameof(accountRepoAsUser));
    }

    public void Execute(Account account)
    {
        account.NrOfContacts = repo.GetContactCount(account.Id);
        account.NrOfContactsSeenByCurrentUser = accountRepoAsUser.GetContactCount(account.Id);
    }
}
  • 定义自定义属性,如

    public class InUserContextAttribute : Attribute 
    {
    }    
    
  • 稍后使用此属性,如下所示:

    public class AccountRepository
    {
        private readonly IService service;
    
        public AccountRepository(IService service)
        {
            this.service = service ?? throw new ArgumentNullException(nameof(service));
        }
    
        public int GetContactCount(Guid accountId)
        {
            using(DataContext ctx = new DataContext(service))
            {
                return ctx.Contacts.Where(c => c.AccountId == accountId).Count();
            }
        }
    }
    
    public class UpdateNrOfContactsCommandHandler : IHandleCommand<UpdateNrOfContactsCommand, Account>
    {
        private readonly AccountRepository accountRepo;
        private readonly AccountRepository accountRepoAsUser;
    
        public UpdateNrOfContactsCommandHandler(AccountRepository accountRepo, [InUserContext] AccountRepository accountRepoAsUser)
        {
            this.accountRepo = accountRepo ?? throw new ArgumentNullException(nameof(accountRepo));
            this.accountRepoAsUser = accountRepoAsUser ?? throw new ArgumentNullException(nameof(accountRepoAsUser));
        }
    
        public void Execute(Account account)
        {
            account.NrOfContacts = repo.GetContactCount(account.Id);
            account.NrOfContactsSeenByCurrentUser = accountRepoAsUser.GetContactCount(account.Id);
        }
    }
    
    公共类updateNofContactsCommandHandler:IHandleCommand
    {
    私有只读AccountRepository accountRepo;
    私有只读AccountRepository AccountRepositor;
    公共更新ContactsCommandHandler(AccountRepository accountRepo,[InUserContext]AccountRepository AccountRepasUser)
    {
    this.accountRepo=accountRepo??抛出新的ArgumentNullException(nameof(accountRepo));
    this.accountRepoAsUser=accountRepoAsUser??抛出新的ArgumentNullException(nameof(accountRepoAsUser));
    }
    公共作废执行(账户)
    {
    account.NrOfContacts=repo.GetContactCount(account.Id);
    account.NrOfContactsSeenByCurrentUser=accountrepoasser.GetContactCount(account.Id);
    }
    }
    
  • 我不知道如何做到这一点:)查看了许多示例,但似乎没有一个适合这种情况。另外一个复杂的问题是,这需要通过组件扫描实现动态

    我知道如何通过属性注入(通过使用Autofac的.OnActivated()方法)非常容易地实现类似的东西,但是这些存储库不是可选的,所以应该在构造函数中传递它们

    此外,我希望避免在复合根/命令总线之外引用任何Autofac。我绝对不想在我的业务逻辑中添加任何特定于Autofac的东西

    基本上,我需要做的是以某种方式注册IService的2个实例,如果参数未修饰,它将解析为其中一个,如果它使用InUserContextAttribute属性修饰,则解析为另一个


    我试图实现的目标是可能的吗?怎么做?;)

    你有很多选择来实现你的目标,我更喜欢的是使用

    为了使用命名服务,您需要注册两个
    IService
    实现:

    //使用字符串使事情简单化
    //首先注册您的服务
    builder.RegisterType()。命名为(“admin”);
    builder.RegisterType()。命名为(“用户”);
    //然后注册存储库,两次:
    foreach(assembly.GetTypes.Where(t=>IsRepository(t))中的var repoType)
    {
    builder.RegisterType(repoType)
    .WithParameter(新解析参数(
    (pi,ctx)=>pi.ParameterType==typeof(iSeries设备),
    (pi,ctx)=>ctx.ResolveNamed(“admin”))
    。名为(“管理员”);
    builder.RegisterType(repoType)
    .WithParameter(新解析参数(
    (pi,ctx)=>pi.ParameterType==typeof(iSeries设备),
    (pi,ctx)=>ctx.ResolveNamed(“用户”))
    .指定(“用户”);
    }
    
    在存储库构造函数中,您可以:

    public UpdateNrOfContactsCommandHandler([KeyFilter(“admin”)]accountRepo、[KeyFilter(“user”)]AccountRepository accountrepasuser)
    {
    this.accountRepo=accountRepo??抛出新的ArgumentNullException(nameof(accountRepo));
    this.accountRepoAsUser=accountRepoAsUser??抛出新的ArgumentNullException(nameof(accountRepoAsUser));
    }
    
    您还可以使用其他技术,例如实现解析逻辑的额外类,如下所示:

    public class AccountRepository
    {
        private readonly IService service;
    
        public AccountRepository(IService service)
        {
            this.service = service ?? throw new ArgumentNullException(nameof(service));
        }
    
        public int GetContactCount(Guid accountId)
        {
            using(DataContext ctx = new DataContext(service))
            {
                return ctx.Contacts.Where(c => c.AccountId == accountId).Count();
            }
        }
    }
    
    public class UpdateNrOfContactsCommandHandler : IHandleCommand<UpdateNrOfContactsCommand, Account>
    {
        private readonly AccountRepository accountRepo;
        private readonly AccountRepository accountRepoAsUser;
    
        public UpdateNrOfContactsCommandHandler(AccountRepository accountRepo, [InUserContext] AccountRepository accountRepoAsUser)
        {
            this.accountRepo = accountRepo ?? throw new ArgumentNullException(nameof(accountRepo));
            this.accountRepoAsUser = accountRepoAsUser ?? throw new ArgumentNullException(nameof(accountRepoAsUser));
        }
    
        public void Execute(Account account)
        {
            account.NrOfContacts = repo.GetContactCount(account.Id);
            account.NrOfContactsSeenByCurrentUser = accountRepoAsUser.GetContactCount(account.Id);
        }
    }
    
    公共类工厂
    {
    专用ILifetimeScope\u范围;
    公共RepoFactory(ILifetimeScope范围)
    {
    _范围=范围;
    }
    公共类RepoContext:IDisposable
    {
    公共T实例{get;}
    公共空间处置()
    {
    //实例处理
    }
    }
    公共RepoContext AsAdmin()
    {
    var service=scope.ResolveNamed(“admin”);
    //保持简单,如果需要,您可以利用更多Autofac来提高性能
    var repo=Activator.CreateInstance(typeof(T),service);
    返回新的repo上下文(repo);
    }
    }
    
    回答我自己的问题,因为我找到了一种方法。基本上,解决方案(实际上并不复杂)包括使用Autofac的.Resolve()方法的ResolvedParameter参数

    它允许您将特定参数注入正在解析的对象

    如果有人感兴趣,下面就是我使用的确切代码。 注意-这是在考虑CRM系统的情况下进行的。“服务连接”类型为IOOrganizationService,我上面提到的“存储库”称为“查询”,为使其正常工作,应全部继承自名为CrmQuery的抽象泛型类(这是因为存在一些共享代码,但也在解决方案中使用)

    公共抽象类CrmQuery,其中tenty:Entity
    {
    
    示例查询类如下所示:

    public class AccountRepository
    {
        private readonly IService service;
    
        public AccountRepository(IService service)
        {
            this.service = service ?? throw new ArgumentNullException(nameof(service));
        }
    
        public int GetContactCount(Guid accountId)
        {
            using(DataContext ctx = new DataContext(service))
            {
                return ctx.Contacts.Where(c => c.AccountId == accountId).Count();
            }
        }
    }
    
    public class UpdateNrOfContactsCommandHandler : IHandleCommand<UpdateNrOfContactsCommand, Account>
    {
        private readonly AccountRepository accountRepo;
        private readonly AccountRepository accountRepoAsUser;
    
        public UpdateNrOfContactsCommandHandler(AccountRepository accountRepo, [InUserContext] AccountRepository accountRepoAsUser)
        {
            this.accountRepo = accountRepo ?? throw new ArgumentNullException(nameof(accountRepo));
            this.accountRepoAsUser = accountRepoAsUser ?? throw new ArgumentNullException(nameof(accountRepoAsUser));
        }
    
        public void Execute(Account account)
        {
            account.NrOfContacts = repo.GetContactCount(account.Id);
            account.NrOfContactsSeenByCurrentUser = accountRepoAsUser.GetContactCount(account.Id);
        }
    }
    
    公共类accountquerys:CrmQuery
    {
    公共帐户查询(IOOrganizationService orgService):基本(orgService){}
    public Something[]GetSomething(Guid accountId)
    {
    //...
    }
    }
    
    现在,这个查询在命令处理程序中使用(siml