2017-07-27 55 views
3

我的目標是實現以下內容。我正在嘗試使用MySQL,.NET Core,Autofac,EF Core ...來使用(通用)存儲庫模式來設置新的解決方案。.NET Core(MYSQL)使用Autofac的通用存儲庫自動連線

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

} 

實現,如果存儲庫:

FooReposit ory.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中適當的文件,我有點膽怯,覺得那部分是「工作」的。但是,正如你在下面的錯誤日誌中看到的那樣,我的存儲庫註冊是混亂的。

錯誤:

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)'.

+0

嘗試下探構造與問候MyContext,看看你的代碼執行和正確解析:IFooRepository

public class FooService: IFooService { private readonly IRepository<Foo> _repository; public FooService(IRepository<Foo> repository) { this._repository = repository; } // ... } 

順便說一句,當您使用IIS是小心與組裝掃描。我看到的問題是ctor'Void .ctor(MyApp.Data),它指出我的方向是您的FooService不能實例化,因爲它們分別是Ctor,FooRepository。 – Programmer

回答

1

下面一行將註冊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>代替Assembly scanning - IIS Hosted application

+0

嗯......謝謝。它確實有道理,我喜歡你所建議的方法。但它仍然不會導致構建:((只是試圖排除它與這個特定問題無關,那麼我會接受) –