2017-07-27 5 views
3

Was ich erreichen möchte, ist das Folgende. Ich versuche eine neue Lösung zu erstellen mit: MySQL, .NET Core, Autofac, EF Core ... unter Verwendung des (generischen) Repository-Patterns..NET Core (MYSQL) Generisches Repository AutoWinding mit 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(); 
    } 
} 

(Generic) 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; 
    } 

} 

Implementierung, wenn ein Repository:

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

Dann wird die Nutzung innerhalb eines Dienstes oder Controller, oder was Sie haben.

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

Problem:

Wie gehe ich über all dies Verdrahtung ... Ich habe eine ordnungsgemäße Dokumentation auf MySQL + Ef finden gekämpft, und ich bin irgendwie auf der Suche nach dem Gefühl, dass dieser Teil "arbeitet". Aber wie Sie im Fehlerprotokoll sehen können, ist meine Registrierung der Repositories durcheinander.

Fehler:

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

Try Abwurf Bauer in Bezug auf mycontext und sehen, ob Ihr Code ausgeführt und löst richtig.Das Problem, das ich sehe, ist ctor 'Void .ctor (MyApp.Data), was mich in die Richtung zeigt, dass Ihr FooService wegen des ctor, FooRepository nicht instanziiert werden kann. – Programmer

Antwort

1

Die folgende Zeile Repository<Foo> als IRepository<Foo> in Autofac registrieren wird:

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

aber ein IRepository<Foo> ist kein IFooRepository und FooService braucht eine IFooRepository. Deshalb Autofac mit der folgenden Fehlermeldung fehlschlagen:

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

Wenn Sie behalten möchten Ihre FooRepository und IFooRepository werden Sie sie registrieren müssen:

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

Eine andere Lösung wäre, alle Implementierung von IRepository<> registrieren

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

und FooService sollte auf Irepository<Foo> verlassen statt IFooRepository

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

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

    // ... 
} 

Durch die Art und Weise mit Montage Scannen seien Sie vorsichtig, wenn Sie IIS verwenden: Assembly scanning - IIS Hosted application

+0

Hmm ... danke. Es macht Sinn, ich mag den Ansatz, den Sie vorschlagen. Aber es führt immer noch nicht zu einem funktionierenden Build :((versuche nur auszuschließen, wenn es nicht mit diesem spezifischen Problem zusammenhängt, dann akzeptiere ich) –

Verwandte Themen