2016-04-25 6 views
0

Сначала я использую единицу рабочего шаблона с кодом entityFramework. Теперь я хочу использовать Autofac для регистрации UnitOfWork, Repositories и My dbContext.Autofac using Constructor

Это мой UnitOfWork код:

public class UnitOfWork : IUnitOfWork 
{ 
    private readonly DbContext _context; 

    public UnitOfWork(DbContext context) 
    { 
     _context = context; 

     Contact = new ContractRepository(context); 
    } 

    public void Dispose() 
    { 
     _context.Dispose(); 
     GC.SuppressFinalize(_context); 
    } 

    public IContactRepository Contact { get; private set; } 

    public int Complete() 
    { 
     return _context.SaveChanges(); 
    } 
} 

и это мое хранилище:

public class Repository<Entity> : IRepository<Entity> where Entity : class 
{ 
    protected readonly DbContext _noteBookContext; 
    public Repository(DbContext noteBookContext) 
    { 
     _noteBookContext = noteBookContext; 
    } 
    public void Add(Entity entity) 
    { 
     _noteBookContext.Set<Entity>().Add(entity); 
    } 
} 

и это одна из моих репозиториях:

public class ContractRepository: Repository<Contact>,IContactRepository 
{ 
    public ContractRepository(DbContext noteBookContext) : base(noteBookContext) 
    { 

    } 

    public DbContext NotebookContext 
    { 
     get 
     { 
      return _noteBookContext; 
     } 
    } 
} 

и это мой дб класс контекста:

public class NoteBookContext:DbContext 
{ 
    public NoteBookContext(string connectionstring):base(connectionstring) 
    { 

    } 
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Configurations.Add(new ContactConfig()); 
     modelBuilder.Configurations.Add(new PhoneConfig()); 
     modelBuilder.Configurations.Add(new PhoneTypeConfig()); 
     modelBuilder.Configurations.Add(new GroupConfig()); 
     base.OnModelCreating(modelBuilder); 
    } 
    public DbSet<Contact> Contacts { get; set; } 
    public DbSet<Phone> Phones { get; set; } 

    public DbSet<Group> Groups { get; set; } 

    public DbSet<PhoneType> PhoneTypes { get; set; } 
} 

Теперь я хочу зарегистрировать UnitOfWork с конструктором (конструктором, как это:)

var uow = new UnitOfWork(new NotebookdbContext("connectionstring")); 

Обратите внимание, что NoteBookContext моей структуры сущности модель.

Я пишу регистрацию, но я получил ошибку:

var builder = new ContainerBuilder(); 
builder.RegisterType<NoteBookContext>() 
     .As<DbContext>(); 
builder.RegisterType<UnitOfWork>() 
     .UsingConstructor(typeof(DbContext)) 
     .As<IUnitOfWork>(); 

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

Container container = builder.Build(); 

Это моя ошибка:

An unhandled exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll Additional information: None of the constructors found with 'Autofac.Core.Activators.Reflection.DefaultConstructorFinder' on type 'DataLayer.NoteBookContext' can be invoked with the available services and parameters:

Cannot resolve parameter 'System.String connectionstring' of constructor 'Void .ctor(System.String)'.

Edit 2:

после помощи ответа Кирилла Дюран я пишу следующим регистрирующую конфигурацию:

var builder = new ContainerBuilder(); 
     builder.RegisterType<ConnectionStringProvider>().As<IConnectionStringProvider>(); 
     builder.RegisterType<NoteBookContext>().As<DbContext>().WithParameter((pi, c) => pi.Name == "connectionstring", 
                       (pi, c) => c.Resolve<IConnectionStringProvider>().ConnectionString); 
     builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().WithParameter(ResolvedParameter.ForNamed<DbContext>("connectionstring")); 
     builder.RegisterGeneric(typeof(Repository<>)).As(typeof(IRepository<>)).InstancePerLifetimeScope(); 

и в моем коде:

using (var scope = DependencyInjection.Container.BeginLifetimeScope()) 
     { 
      var ConnectionString = scope.Resolve<IConnectionStringProvider>(); 
      ConnectionString.ConnectionString = "Context"; 

      var uw = scope.Resolve<IUnitOfWork>(); 
      var a =uw.Contact.GetAll(); 

     } 

, но я получил ошибки снова:

An unhandled exception of type 'Autofac.Core.DependencyResolutionException' occurred in Autofac.dll

Additional information: An exception was thrown while invoking the constructor 'Void .ctor(System.String)' on type 'NoteBookContext'.

может все мне помочь?

+1

Не могли бы вы изменить свой пост и включать сообщение об ошибке? –

+0

@CyrilDurand: я включаю ошибку –

ответ

2

Сообщение об ошибке:

An unhandled exception of type Autofac.Core.DependencyResolutionException occurred in Autofac.dll Additional information: None of the constructors found with Autofac.Core.Activators.Reflection.DefaultConstructorFinder on type DataLayer.NoteBookContext can be invoked with the available services and parameters:

Cannot resolve parameter System.String connectionstring of constructor Void .ctor(System.String) .

говорит вам, что Autofac не может создать NoteBookContext, поскольку он может разрешить параметр с именем connectionstring типа String.

Для реализации NoteBookContext требуется соединение, Autofac не может знать об этом, не сообщая об этом.При регистрации NoteBookContext вы должны будете указать этот ConnectionString:

builder.RegisterType<NoteBookContext>() 
     .As<DbContext>() 
     .WithParameter("connectionstring", "XXX"); 

Другое решение с динамическим разрешением и IConnectionStringProvider интерфейс:

public interface IConnectionStringProvider 
{ 
    public String ConnectionString { get; } 
} 

и регистрация:

builder.RegisterType<ConnectionStringProvider>() 
     .As<IConnectionStringProvider>() 
     .InstancePerLifetimeScope(); 
builder.RegisterType<NoteBookContext>() 
     .As<DbContext>() 
     .WithParameter((pi, c) => pi.Name == "connectionstring", 
         (pi, c) => c.Resolve<IConnectionStringProvider>().ConnectionString) 
     .InstancePerLifetimeScope(); 
+0

Как добавить параметр и установить значение во время решения? –

+0

@minamorsali см. Мое редактирование –

+0

большое спасибо за ваши ответы. на самом деле я хочу, чтобы конечный программист в момент времени разрешения передал значение параметра. Является ли это возможным? –

0

Трудно сказать, не видя ошибки. Но вам не нужно использовать UsingConstructor.

//Make DbContext per request, if your app is web app (which has http request). 
builder.RegisterType<NoteBookContext>() 
     .As<DbContext>().WithParameter("connectionstring","ConnectionStringValue").InstancePerLifetimeScope(); 
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope(); 

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

Container = builder.Build(); 
+0

Я тестирую свой код вместо моего, это вызывает следующую ошибку: в Autofac.dll появилось необработанное исключение типа «Autofac.Core.DependencyResolutionException», Дополнительная информация: Ни один из конструкторов, найденных с помощью «Autofac .Core.Activators.Reflection.DefaultConstructorFinder 'on type' BussinessLayer.Repositories.UnitOfWork 'может быть вызван с доступными службами и параметрами: –

+0

Сколько конструкторов у вас на UnitOfWork? –

+0

Только один конструктор –

0

Есть ли причина, по которой вы хотите передать строку подключения в свой контекст? Создайте интерфейс для UnitOfWork и сделать что-то вроде этого:

public class NoteBookContext:DbContext 
{ 
    //Change connectionstring below with the name of your connection string in web.config 
    public NoteBookContext():base("name=connectionstring") 
    { 

    } 
    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     modelBuilder.Configurations.Add(new ContactConfig()); 
     modelBuilder.Configurations.Add(new PhoneConfig()); 
     modelBuilder.Configurations.Add(new PhoneTypeConfig()); 
     modelBuilder.Configurations.Add(new GroupConfig()); 
     base.OnModelCreating(modelBuilder); 
    } 
    public DbSet<Contact> Contacts { get; set; } 
    public DbSet<Phone> Phones { get; set; } 

    public DbSet<Group> Groups { get; set; } 

    public DbSet<PhoneType> PhoneTypes { get; set; } 
} 

И зарегистрироваться как это:

var builder = new ContainerBuilder(); 
builder.RegisterType<NoteBookContext>() 
     .As<DbContext>() 
     .InstancePerLifetimeScope(); 

builder.RegisterType<UnitOfWork>() 
     .As<IUnitOfWork>() 
     .InstancePerLifetimeScope(); 

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

Container container = builder.Build();