2017-07-27 4 views
3

Ce que je vise à réaliser est le suivant. J'essaie de configurer une nouvelle solution en utilisant: MySQL, .NET Core, Autofac, EF Core ... en utilisant le modèle de référentiel (générique)..NET Core (MYSQL) Référentiel générique AutoWiring utilisant 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(); 
    } 
} 

(générique) 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; 
    } 

} 

Mise en œuvre si un dépôt:

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

Ensuite, l'utilisation au sein d'un service ou d'un contrôleur, ou ce que vous avez.

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

Problème:

Comment puis-je aller sur le câblage tout cela ... J'ai eu du mal à trouver de la documentation appropriée sur MySQL + Ef, et je suis un peu aller sur l'intestin sentir que cette partie est "travail". Mais comme vous pouvez le voir dans le journal des erreurs ci-dessous, mon enregistrement des dépôts est foiré.

Erreur:

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

essayer d'enlever les constructeurs en ce qui concerne MyContext et voir si votre code est exécuté et résout correctement.Le problème que je vois est ctor 'Void .ctor (MyApp.Data), qui me pointe dans la direction que votre FooService ne peut pas être instancié à cause du ctor, FooRepository respectivement. – Programmer

Répondre

1

La ligne suivante enregistrera Repository<Foo> comme IRepository<Foo> dans Autofac:

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

mais IRepository<Foo> n'est pas un IFooRepository et FooService a besoin d'un IFooRepository. Voilà pourquoi Autofac échouer avec le message d'erreur suivant:

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

Si vous voulez garder votre FooRepository et IFooRepository vous devrez les enregistrer:

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

Une autre solution serait d'enregistrer toute la mise en œuvre de IRepository<>

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

et FooService devrait compter sur Irepository<Foo> au lieu de IFooRepository

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

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

    // ... 
} 

Par ailleurs être prudent avec l'analyse d'assemblage lorsque vous utilisez IIS: Assembly scanning - IIS Hosted application

+0

Hmm ... merci. Cela a du sens, j'aime vraiment l'approche que vous suggérez. Mais il ne résulte toujours pas en une construction de travail :((essayant juste d'exclure si elle n'est pas liée à ce problème spécifique, alors je vais accepter) –