снова про log4net и конфиг Unity IOC

Я столкнулся с несколькими из этих вопросов, лежащих на разных сайтах, и ответы, похоже, были подброшены официальными лицами l4n в сторону ценности легковесной оболочки, которой является log4net (разве вы не понимаете?) и подобных точек зрения. -поразительный факт.

Однако кажется, что пользователи спрашивают (и это мой вопрос), как вписать модель объекта log4net в последовательность типа регистра/регистрационного экземпляра в свободном интерфейсе конфигурации.

Цель здесь не в том, чтобы перепаковать l4n, а просто в том, чтобы получить достойную ссылку, которая не требует захвата плавного потока, так сказать.

бедный ejemplow, я хочу получить ссылку на настроенный экземпляр ILog из метода LogManger.GetLogger и поместить его в свободный поток достаточно рано, чтобы внедрить его в свойства моих нижестоящих объектов.

Итак, в ответ на одно нетерпеливое предложение я попытался создать обычный экземпляр ILog каноническим способом:

log4net.Config.XmlConfigurator.Configure();
static readonly log4Net.Ilog Log = LogManager.GetLogger(thatlongassemblyreflectionstuff);

Так что казалось бы тривиальным (в прямом смысле легким) добавить эту ссылку в контейнер Unity и продолжить свою прекрасную жизнь.

Однако сигнатура для метода RegisterInstance требует «Type», а не интерфейса.

Для тех, кто не искал объектную модель log4net, afficiananderos правы: l4n — это «обертка», и вы не можете получить фактический «тип» для Log штуки.

Так что теперь я должен испытать. И вы знаете, что это значит, это может занять минуту, но, скорее всего, займет час или четыре (сходства, такие как написание «час» и «четыре», никогда не бывают случайными в реальной жизни).

Однако следующее, за исключением пропущенной части о канонической настройке, сработало:

container
  .RegisterInstance("Logger", Log, new ContainerControlledLifetimeManager())
.RegisterType<IControllerContext, ControllerContext>
(
   "CtlrCtx", 
   new ContainerControlledLifetimeManager(), 
   new InjectionConstructor(new ResolvedParameter<IMessageBuilder>("MsgBldr")),
   new InjectionProperty("Log",new ResolvedParameter<ILog>("Logger"))
);

Таким образом, хэш-коды для исходного объекта журнала и объекта журнала, введенного в свойство моего чудесного маленького объекта Context, идентичны.

Тем не мение...

Процесс внедрения требовал, чтобы я открывал свойство Log объекта Context через его интерфейс, а это означало, что он больше не мог быть статическим объектом. И то, является ли объект log4net ILog статическим, по-видимому, является решающим фактором в отношении того, является ли он сериализуемым и может ли он перемещаться между сборками без драматических предупреждений «среда выполнения станет нестабильной» (которые действительно имеют смысл только для поклонников Matrix).

Обескураженный, но не устрашенный, я использовал отличное свойство Resharper «свойство с резервным полем» и установил статическое поле поддержки, в то время как свойство интерфейса оставалось нестатическим. Ну, он построил, и тест прошел зеленый.

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

Так что, возможно, это поможет

Спасибо

Стато


person Stato Machino    schedule 24.08.2009    source источник
comment
Использование регистраторов в качестве переменных экземпляра не является обычной практикой - обычно они являются статическими (т.е. классовыми) переменными и в любом случае реализуются как синглтоны. Поэтому я не думаю, что вы получите какую-то пользу, извлекая их из контейнера Unity — зачем вам это нужно?   -  person Vinay Sajip    schedule 09.10.2009
comment
'Зачем?' безусловно резонный вопрос. Ответ связан с одной точкой конфигурации. использование любого регистратора «везде» становится реальным бременем конфигурации, а техническое обслуживание тяжело для «неактивной» части, когда дело доходит до удовольствия.   -  person Stato Machino    schedule 10.02.2011


Ответы (2)


Поможет ли использование InjectionFactory в Unity 2? (см. этот вопрос). Тогда ваш код конфигурации будет выглядеть примерно так:

IUnityContainer container = new UnityContainer();
container.RegisterType<ILog>(new InjectionFactory(factory => LogManager.GetLogger()));

Затем вы получаете регистратор с помощью обычного вызова Resolve():

ILog logger = container.Resolve<ILog>();
logger.Log(Level.Debug, "Hello world");

Вы также можете настроить время жизни регистратора на ContainerControllerLifetimeManager, чтобы сделать его экземпляром singleton, но я еще не проверял это.

person David Keaveny    schedule 07.02.2011
comment
это похоже на log4net, но полезно для экземпляра объекта, который также создается для запуска. благодаря. - person Nuri YILMAZ; 30.01.2012

ILog logger = container.Resolve<ILog>();
logger.Log(Level.Debug, "Hello world");

действительно работает.

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

ILog logger = container.Resolve<ILog>();

для каждого класса, что дает мне результат, который кажется лишь незначительно отличным от его создания в каждом классе....

Я надеялся, что

private ILog Logger {get;set;} 

можно было просто инжектить но это похоже вообще не работает, так как через log4net все делается через интерфейсы и конкретный логгер прячется за занавеской с Волшебником страны Оз.

person AllenM    schedule 09.06.2011