.NET Core(MYSQL)通用仓储自动装配使用Autofac

4
我想要实现的目标是:使用MySQL、.NET Core、Autofac和EF Core建立一个新的解决方案,利用(通用)仓储模式。最终我将加入一个已有数据库的项目,因此我的目标是通过(t4)模板和EF生成一些模型,然后为需要交互的每个模型创建仓库。每个仓库只是一个小型轻量级类,继承了基类。在Startup.cs中完成配置。
public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
            .AddEnvironmentVariables();
        this.Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; private set; }

    // This method gets called by the runtime. 
    // Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();
        services.
            .AddDbContext<MyContext>(o => o.UseMySQL(
          Configuration.GetConnectionString("MyConnection")));
    }

    public void ConfigureContainer(ContainerBuilder builder)
    {               
        builder.RegisterGeneric(typeof(Repository<>))
            .As(typeof(IRepository<>))
            .InstancePerLifetimeScope();

       // the below works (before adding the repos)
       builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
           .AssignableTo<IService>()
           .AsImplementedInterfaces()
           .InstancePerLifetimeScope();
    }
}

(通用) Repository.cs

public abstract class Repository<T> : IRepository<T>
    where T : class
{
    private readonly MyContext _context;

    protected Repository(MyContext context)
    {
        _context = context;
    }

    public virtual string Add(T entity)
    {
        if (ValidateAdd(ref entity, out var message))
        {
            _context.Set<T>().Add(entity);
        }

        return message;
    }

    public virtual bool ValidateAdd(ref T entity, out string message)
    {
        message = default(string); 
        return true;
    }

}

存储库的实现:

FooRepository.cs

// public interface IFooRepository: IRepository<Foo>

public class FooRepository: Repository<Foo>, IFooRepository
{
    public FooRepository(MyContext context) : base(context)
    {
    }

    public override bool ValidateAdd(ref Foo entity, out string message)
    {
        // just a hook for pre-insert stuff
        message = "All foos shall fail add";
        return false;
    }
}

接下来是在服务或控制器中的使用方法。

FooService.cs

public class FooService: IFooService
{
    private readonly IFooRepository _repository;

    public FooService(IFooRepository repository)
    {
        _repository = repository;
    }

    public void DoSomethingThenAdd()
    {
       // some other business logic specific to this service
        _repository.Add(new Foo()
        {
            Id = 1,
            LastName = "Bar",
            Name = "Foo"
        });
    }
}

问题:

我该如何进行这一切的连接... 我很难找到关于 MySQL + Ef 的适当文档,而且我凭直觉感觉这部分是“工作”的。但是,正如您在下面的错误日志中看到的那样,我的仓库注册有问题。

错误信息:

在特定注册激活期间发生错误。

有关详细信息,请参见内部异常。

注册: Activator = FooService(ReflectionActivator),Services = [MyApp.Services.Interfaces.IFooService,MyApp.Services.Interfaces.IService],Lifetime = Autofac.Core.Lifetime.CurrentScopeLifetime,Sharing = Shared, Ownership = OwnedByLifetimeScope

---> 无法使用类型“MyApp.Services.FooService”上的“Autofac.Core.Activators.Reflection.DefaultConstructorFinder”找到任何构造函数可用于调用可用服务和参数:

无法解析构造函数“Void .ctor(MyApp.Data.Interfaces.IFooRepository repository) ”中的参数“MyApp.Data.Interfaces.IFooRepository repository”。 (有关详细信息,请参见内部异常。)

---> Autofac.Core.DependencyResolutionException: 无法使用类型“MyApp.Services.FooService”上的“Autofac.Core.Activators.Reflection.DefaultConstructorFinder”找到任何构造函数可用于调用可用服务和参数:

无法解析构造函数“Void .ctor(MyApp.Data.Interfaces.IFooRepository repository)”中的参数“MyApp.Data.Interfaces.IFooRepository repository”。


尝试删除与MyContext相关的构造函数,看看您的代码是否可以正确执行和解决。我看到的问题是ctor 'Void .ctor(MyApp.Data),这指向了您的FooService无法实例化的方向,因为它涉及到FooRepository的ctor。 - user4573148
1个回答

1
以下代码将会在 Autofac 中将 Repository<Foo> 注册为 IRepository<Foo>:
builder.RegisterGeneric(typeof(Repository<>))
       .As(typeof(IRepository<>))
       .InstancePerLifetimeScope();

但是IRepository<Foo>并不是IFooRepository,而FooService需要一个IFooRepository。这就是为什么Autofac会出现以下错误信息:

无法解析构造函数的参数'MyApp.Data.Interfaces.IFooRepository repository'。

如果您想保留您的FooRepositoryIFooRepository,您必须注册它们:

builder.RegisterType<FooRepository>()
       .As<IFooRepository>()

另一种解决方案是注册所有实现了 IRepository<> 接口的类。
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
       .AsClosedTypesOf(typeof(IRepository<>))

FooService 应该依赖于 Irepository<Foo> 而不是 IFooRepository

public class FooService: IFooService
{
    private readonly IRepository<Foo> _repository;

    public FooService(IRepository<Foo> repository)
    {
        this._repository = repository;
    }

    // ...
}

顺便提醒一下,在使用IIS时要注意程序集扫描:程序集扫描 - IIS托管应用程序

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