Мені цікаво дізнатись більше про те, як люди вводять реєстрацію за допомогою платформ для введення залежностей. Незважаючи на те, що посилання нижче та мої приклади стосуються log4net та Unity, я не обов'язково буду використовувати жоден із них. Для введення залежностей / IOC я, ймовірно, буду використовувати MEF, оскільки це стандарт, на якому зупиняється решта проекту (великий).
Я дуже новачок у введенні залежностей / ioc, і я дуже новачок у C # і .NET (написав дуже мало виробничого коду в C # /. NET після останніх 10 років або близько того VC6 і VB6). Я провів багато розслідувань щодо різноманітних рішень для ведення журналів, тому я думаю, що я гідно працюю з їх наборами функцій. Я просто недостатньо обізнаний з фактичною механікою введення однієї залежності (або, можливо, більш «правильно», введення абстрагованої версії однієї залежності).
Я бачив інші публікації, пов'язані з веденням журналу та / або ін'єкцією залежностей, наприклад: інтерфейси ін'єкції залежностей та реєстрації
Найкращі практики ведення журналів
Як би виглядав клас Log4Net Wrapper?
ще раз про log4net та Unity IOC config
Моє запитання не стосується конкретно "Як мені ввести платформу реєстрації xxx за допомогою інструменту ioc yyy?" Швидше, мене цікавить, як люди обробляли обтікання платформи реєстрації (як це часто, але не завжди рекомендується) та конфігурацію (тобто app.config). Наприклад, використовуючи log4net як приклад, я міг налаштувати (в app.config) кількість реєстраторів, а потім отримати ці реєстратори (без введення залежностей) стандартним способом використання коду, як це:
private static readonly ILog logger = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
Як варіант, якщо мій реєстратор названий не для класу, а для функціональної області, я міг би зробити це:
private static readonly ILog logger = LogManager.GetLogger("Login");
private static readonly ILog logger = LogManager.GetLogger("Query");
private static readonly ILog logger = LogManager.GetLogger("Report");
Отже, я думаю, що мої "вимоги" були б приблизно такими:
Я хотів би ізолювати джерело свого продукту від прямої залежності від лісозаготівельної платформи.
Я хотів би мати можливість вирішити конкретний іменований екземпляр журналу (ймовірно, ділившись одним і тим же екземпляром серед усіх запитувачів того самого іменного екземпляра), прямо чи опосередковано за допомогою якоїсь ін’єкції залежностей, можливо, MEF.
Я не знаю, чи назвав би це жорсткою вимогою, але я хотів би отримати можливість іменованого реєстратора (відмінного від реєстратора класів) на вимогу. Наприклад, я можу створити реєстратор для свого класу на основі назви класу, але одному методу потрібна детальна важка діагностика, яку я хотів би контролювати окремо. Іншими словами, я міг би хотіти, щоб один клас "залежав" від двох окремих екземплярів реєстратора.
Почнемо з цифри 1. Я прочитав низку статей, насамперед тут, про stackoverflow, про те, чи є це гарною ідеєю завертати. Дивіться посилання "найкращі практики" вище і перейдіть до коментаря Джеффрі Хантіна , щоб побачити одне уявлення про те, чому погано обертати log4net. Якби ви обгортали (і якщо могли б ефективно обертати), чи обгортали б ви суворо з метою ін’єкції / видалення прямої плідниці? Або ви також спробуєте абстрагувати частину або всю інформацію log4net app.config?
Скажімо, я хочу використовувати System.Diagnostics, я, мабуть, хотів би реалізувати реєстратор на основі інтерфейсу (можливо, навіть використовуючи "загальний" інтерфейс ILogger / ILog), ймовірно, на основі TraceSource, щоб я міг його ввести. Чи могли б ви реалізувати інтерфейс, скажімо через TraceSource, і просто використовувати інформацію System.Diagnostics app.config як є?
Щось на зразок цього:
public class MyLogger : ILogger
{
private TraceSource ts;
public MyLogger(string name)
{
ts = new TraceSource(name);
}
public void ILogger.Log(string msg)
{
ts.TraceEvent(msg);
}
}
І використовуйте його так:
private static readonly ILogger logger = new MyLogger("stackoverflow");
logger.Info("Hello world!")
Перехід до номера 2 ... Як вирішити конкретний примірник журналу? Чи слід просто використовувати інформацію app.config вибраної мною платформи ведення журналу (тобто вирішувати реєстратори на основі схеми імен у app.config)? Отже, у випадку з log4net, чи можу я віддати перевагу "впорскуванню" LogManager (зауважте, що я знаю, що це неможливо, оскільки це статичний об'єкт)? Я міг би обернути LogManager (назвати його MyLogManager), надати йому інтерфейс ILogManager, а потім вирішити інтерфейс MyLogManager.ILogManager. Інші мої об'єкти можуть мати залежність (Імпорт мовою MEF) від ILogManager (Експорт із збірки, де він реалізований). Тепер я міг мати такі об’єкти:
public class MyClass
{
private ILogger logger;
public MyClass([Import(typeof(ILogManager))] logManager)
{
logger = logManager.GetLogger("MyClass");
}
}
Кожного разу, коли викликається ILogManager, він безпосередньо делегує LogManager log4net. Як варіант, може загорнутий LogManager взяти екземпляри ILogger, які він отримує на основі app.config, та додати їх до (a?) Контейнера MEF за іменем. Пізніше, коли запитується журнал з тим самим іменем, обгортаний LogManager запитується щодо цього імені. Якщо там є ILogger, це вирішується таким чином. Якщо це можливо з MEF, чи є якась користь від цього?
У цьому випадку насправді «вводиться» лише ILogManager, і він може передавати екземпляри ILogger так, як це робить log4net. Як цей тип ін’єкції (по суті фабричної) порівнюється з ін’єкцією названих екземплярів реєстратора? Це дозволяє легше використовувати файл log.net (або іншу платформу ведення журналу) app.config.
Я знаю, що можу отримати іменовані екземпляри з контейнера MEF так:
var container = new CompositionContainer(<catalogs and other stuff>);
ILogger logger = container.GetExportedValue<ILogger>("ThisLogger");
Але як мені перенести названі екземпляри в контейнер? Я знаю про модель, засновану на атрибутах, де я міг би мати різні реалізації ILogger, кожна з яких називається (через атрибут MEF), але це насправді мені не допомагає. Чи є спосіб створити щось на зразок app.config (або розділу в ньому), який перелічував би реєстратори (всі однакові реалізації) за назвою та які MEF міг читати? Чи міг / повинен бути центральний "менеджер" (наприклад, MyLogManager), який вирішує іменовані реєстратори за допомогою базового app.config, а потім вставляє вирішений реєстратор у контейнер MEF? Таким чином він буде доступний комусь іншому, хто має доступ до того самого контейнера MEF (хоча без відома MyLogManager про те, як використовувати інформацію app.config log4net,
Це вже сталося досить довго. Я сподіваюся, що це послідовно. Будь ласка, не соромтеся поділитися будь-якою конкретною інформацією про те, як ви залежністю ввели платформу ведення журналу (ми, швидше за все, розглядаємо log4net, NLog або щось (сподіваємося, тонке), побудоване на System.Diagnostics) у вашу програму.
Ви ввели "менеджер" і він повернув екземпляри реєстратора?
Чи додали ви якусь власну інформацію про конфігурацію у своєму власному розділі конфігурації або в конфігураційному розділі вашої платформи DI, щоб полегшити / зробити можливим безпосереднє введення екземплярів реєстратора (тобто зробити так, щоб ваші залежності були на ILogger, а не на ILogManager).
А як щодо наявності статичного або глобального контейнера, в якому є або інтерфейс ILogManager, або набір примірників іменованих ILogger. Отже, замість впорскування в загальноприйнятому розумінні (за допомогою конструктора, властивості або даних-членів), залежність від реєстрації явно вирішується на вимогу. Це хороший чи поганий спосіб введення залежності.
Я позначаю це як спільноту wiki, оскільки це не здається запитанням із чіткою відповіддю. Якщо хтось відчуває інакше, сміливо змінюйте це.
Дякуємо за будь-яку допомогу!
x.Request.ParentContext.Plan.Type.FullName
отримував конкретну назву класу замість імені інтерфейсу.