我的目标是实现以下目标。我正在尝试设置一个新的解决方案,使用: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>
不是 IFooRepository
和 FooService
需要 IFooRepository
.这就是 Autofac 失败并显示以下错误消息的原因:
Cannot resolve parameter 'MyApp.Data.Interfaces.IFooRepository repository' of constructor 'Void .ctor(MyApp.Data.Interfaces.IFooRepository)'.
如果你想保留你的 FooRepository
和 IFooRepository
你必须注册他们:
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/