2016-07-12 3 views
0

Я пытаюсь внедрить службу в мои контроллеры, но я хочу добавить другой экземпляр моей службы в зависимости от нескольких параметров. На самом деле для этой части он работает, я в состоянии это сделать.ASP.NET Ядро зависимостей инъекции: разрешена служба во время выполнения с использованием делегата Func

Я хочу загрузить конкретный экземпляр IRepository<Database> на основе некоторой конфигурации, которую мы получаем из файла конфигурации и соблюдения правила DRY (не повторяйте себя).

У меня есть эти 2 класса:

public abstract class FooServicesProvider 
{ 
    public Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider => 
    { 
     return null; 
    }; 
} 

public class FooFileSystemServicesProvider : FooServicesProvider 
{ 
    public new Func<IServiceProvider, IRepository<Database>> DatabaseRepository = provider => 
    { 
     //Specific code determining which database to use and create a new one if needed 
     //our databases are FOLDERS containing some files 
     //knowing how chosenDb.FullName is set is not important here 
     //[...] 
     var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName); 
     databaseRepository.testProperty = "Foo value"; 
     return databaseRepository; 
    }; 
} 

Обратите внимание на новый ключевое слово используется для переопределения код моего Func. Это лучший способ, который я нашел из-за делегата Func, я очень ограничен, я не могу использовать его в интерфейсе и не переопределять его.

Сейчас в моем ConfigureServices метод Startup.cs У меня есть этот код

var fakeConfiguration = "File"; 
FooServicesProvider servicesProvider = null; 
if(fakeConfiguration == "File") 
{ 
    servicesProvider = new FooFileSystemServicesProvider(); 
} 
else 
{ 
    servicesProvider = new AnotherFooServicesProvider(); 
} 
//Here is the tricky part 
//This should call FooFileSystemServicesProvider.DatabaseRepository because of the "new" keyword, but it's NOT 
services.AddScoped<IRepository<Database>>(servicesProvider.DatabaseRepository); 

Моя проблема заключается в том, что нового ключевого слово игнорируется во время выполнения и казненный Func является один объявленным в мой базовый класс вместо полученного.

Если я сделаю это, что он работает

services.AddScoped<IRepository<Database>>((servicesProvider as FooFileSystemServicesProvider).DatabaseRepository); 

Но я не хочу, чтобы бросить его, как я не могу знать, какой типа моего servicesProvider будет, наконец.

Я попытался получить тип моего servicesProvider и бросить его своим типом, но я получаю ошибку компилятора, потому что переменная Type и класс отличаются.

Итак, как я могу получить хороший Func, выполненный во время выполнения? Спасибо

+0

Вам нужно будет создать «DatabaseRepository» базового класса «virtual» и использовать 'override' в производном типе. – Steven

+0

Замените новое ключевое слово, переопределив в объявлении свойства делегата. Это работает ? –

+0

, конечно, игнорируется ключевое слово 'new', потому что' new' только скрывает метод/свойство базовых классов и не заменяет и не отменяет его ... – Tseng

ответ

1

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

Мой код в Startup.cs остается неизменным, но вот новый код моего пользовательского ServicesProvider

public abstract class FooServicesProvider 
{ 
    public Func<IServiceProvider, IRepository<Database>> DatabaseRepository { get; protected set; } 
} 

public class FooFileSystemServicesProvider : FooServicesProvider 
{ 
    public FooFileSystemServicesProvider() 
    { 
     base.DatabaseRepository = GetDatabaseRepository; 
    } 

    private DatabaseFileSystemRepository GetDatabaseRepository(IServiceProvider serviceProvider) 
    { 
     //Specific code determining which database to use and create a new one if needed 
     //our databases are FOLDERS containing some files 
     //knowing how chosenDb.FullName is set is not important here 
     //[...] 
     var databaseRepository = new DatabaseFileSystemRepository(chosenDb.FullName); 
     databaseRepository.testProperty = "Foo value"; 
     return databaseRepository; 
    }   
} 

Только в случае, если люди задаются вопросом: DatabaseFileSystemRepository это класс, который реализует интерфейс IRepository<Database>>

Если любой придумал другое решение, мне очень любопытно это узнать.

Смежные вопросы