c# - .NET Core (MYSQL) Generic Repository AutoWiring 使用 Autofac

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

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

Ultimately I'll be jumping onto a project with an existing db, thus my aim is to somehow make use of (t4) templates & EF to generate some of the models, then it "should" (famous last words) be as easy as making a repo for each model I need to interact with. (Each repo will just be a small lightweight class inherits the base)

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;
    }
}

然后是服务或 Controller 中的用法,或者您有什么。

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 的适当文档,而且我有点直觉地觉得那部分正在“工作”。但是正如您在下面的错误日志中看到的那样,我的存储库注册一团糟。

错误:

An error occurred during the activation of a particular registration.

See the inner exception for details.

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

---> None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyApp.Services.FooService' can be invoked with the available services and parameters:

Cannot resolve parameter 'MyApp.Data.Interfaces.IFooRepository repository' of constructor 'Void .ctor(MyApp.Data.Interfaces.IFooRepository)'. (See inner exception for details.)

--> Autofac.Core.DependencyResolutionException: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'MyApp.Services.FooService' can be invoked with the available services and parameters:

Cannot resolve parameter 'MyApp.Data.Interfaces.IFooRepository repository' of constructor 'Void .ctor(MyApp.Data.Interfaces.IFooRepository)'.

最佳答案

下面一行会注册Repository<Foo>作为IRepository<Foo>Autofac 中:

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

但是一个IRepository<Foo>不是 IFooRepositoryFooService需要 IFooRepository .这就是 Autofac 失败并显示以下错误消息的原因:

Cannot resolve parameter 'MyApp.Data.Interfaces.IFooRepository repository' of constructor 'Void .ctor(MyApp.Data.Interfaces.IFooRepository)'.

如果你想保留你的 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 时要小心程序集扫描:Assembly scanning - IIS Hosted application

关于c# - .NET Core (MYSQL) Generic Repository AutoWiring 使用 Autofac,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45352304/

相关文章:

c# - 是否可以创建使用 C# 或 C++ 代码的 Firefox 插件?如果是这样,如何?

c# - 在 .NET Core 的 Web 请求中使用 NTLM 身份验证

c# - 无法从包含 Union 的 Entity Framework Core 查询中获取完整的 SQL 文本

c# - ASP Web API 和 Autofac 集成异常

C# SQL Server CE 在解析查询时出错

c# - EntityFramework Fluent API 将类映射为组合键

c# - 以编程方式删除 Azure 应用程序注册 API 权限

c# - ASP.NET MVC 2 中的基本 Controller 实现

asp.net-web-api - Webapi DefaultHttpControllerSelector 无法正确解析我的 Controller

c# - xamarin.forms 中带有附件的 ImageCell