【问题标题】:.NET Core (MYSQL) Generic Repository AutoWiring using Autofac.NET Core (MYSQL) 通用存储库自动装配使用 Autofac
【发布时间】:2018-01-03 06:32:38
【问题描述】:

我的目标是实现以下目标。我正在尝试使用 MySQL、.NET Core、Autofac、EF Core 设置一个新的解决方案...利用(通用)存储库模式。

最终我会跳到一个有现有数据库的项目,因此我的目标是以某种方式利用 (t4) 模板和 EF 来生成一些模型,然后它“应该”(最后著名话)就像为我需要与之交互的每个模型创建一个 repo 一样简单。 (每个 repo 将只是一个小的轻量级继承基类)

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], 生命周期 = Autofac.Core.Lifetime.CurrentScopeLifetime,共享 = 共享, 所有权 = OwnedByLifetimeScope

---> 没有找到类型为 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' 的构造函数 'MyApp.Services.FooService' 可以用可用的调用 服务和参数:

无法解析参数'MyApp.Data.Interfaces.IFooRepository 构造函数 'Void 的存储库' .ctor(MyApp.Data.Interfaces.IFooRepository)'。 (见内部异常 详情。)

--> Autofac.Core.DependencyResolutionException: 没有找到任何构造函数 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' 类型 'MyApp.Services.FooService' 可以用可用的调用 服务和参数:

无法解析参数'MyApp.Data.Interfaces.IFooRepository 构造函数 'Void 的存储库' .ctor(MyApp.Data.Interfaces.IFooRepository)'。

【问题讨论】:

  • 尝试删除有关 MyContext 的构造函数,看看您的代码是否正确执行和解析。我看到的问题是 ctor 'Void .ctor(MyApp.Data),这为我指明了您的 FooService 无法实例化的方向,因为分别是 ctor 和 FooRepository。

标签: c# .net-core autofac ioc-container entity-framework-core


【解决方案1】:

以下行将在Autofac中将Repository&lt;Foo&gt;注册为IRepository&lt;Foo&gt;

builder.RegisterGeneric(typeof(Repository<>))
       .As(typeof(IRepository<>))
       .InstancePerLifetimeScope();

但是IRepository&lt;Foo&gt; 不是IFooRepository 并且FooService 需要IFooRepository。这就是 Autofac 失败并显示以下错误消息的原因:

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

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

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

另一种解决方案是注册IRepository&lt;&gt;的所有实现

builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
       .AsClosedTypesOf(typeof(IRepository<>))

FooService 应该依赖Irepository&lt;Foo&gt; 而不是IFooRepository

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

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

    // ...
}

顺便说一句,使用 IIS 时要小心程序集扫描:Assembly scanning - IIS Hosted application

【讨论】:

    猜你喜欢
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-12-06
    • 2015-03-20
    • 2010-12-10
    • 1970-01-01
    相关资源
    最近更新 更多