อีกครั้งเกี่ยวกับการกำหนดค่า log4net และ Unity IOC

ฉันได้เจอกับคำถามเหล่านี้สองสามข้อที่อยู่รอบ ๆ ไซต์ต่าง ๆ และคำตอบดูเหมือนจะถูกปั่นป่วนโดยเจ้าหน้าที่ l4n ไปสู่คุณค่าของกระดาษห่อน้ำหนักเบาที่ log4net 'เป็น' (คุณไม่เข้าใจเหรอ?) และความคิดที่คล้ายกัน - ข้อเท็จจริงที่เหลือเชื่อ

อย่างไรก็ตาม ดูเหมือนว่าสิ่งที่ผู้ใช้ขอ (และนี่คือคำถามของฉัน) คือวิธีปรับโมเดล objet ของ log4net ลงในลำดับ registertype/registerinstance ในอินเทอร์เฟซการกำหนดค่าอย่างคล่องแคล่ว

เป้าหมายในที่นี้จะไม่ใช่การห่อ l4n อีกครั้ง แต่เพียงเพื่อให้ได้ข้อมูลอ้างอิงที่เหมาะสมซึ่งไม่จำเป็นต้องมีการแย่งชิงการไหลอย่างคล่องแคล่วเหมือนเดิม

ตัวอย่างที่ไม่ดี ฉันต้องการรับการอ้างอิงถึงอินสแตนซ์ที่กำหนดค่าของ ILog จากวิธี LogManger.GetLogger และใส่ลงในโฟลว์อย่างคล่องแคล่วเร็วพอที่จะแทรกเข้าไปในคุณสมบัติของอ็อบเจ็กต์ดาวน์สตรีมของฉัน

ดังนั้นเพื่อตอบสนองต่อข้อเสนอแนะที่ใจร้อนข้อหนึ่ง ฉันพยายามสร้างอินสแตนซ์ปกติของ ILog ในลักษณะมาตรฐาน:

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

ดังนั้นจึงดูเหมือนเป็นเรื่องเล็กน้อย (ในความหมายที่แท้จริงของการไม่ต้องพยายามเลย) ตอนนี้เพิ่มการอ้างอิงนั้นไปยังคอนเทนเนอร์ Unity และใช้ชีวิตที่แสนวิเศษของฉันต่อไป

อย่างไรก็ตาม ลายเซ็นสำหรับวิธีการ RegisterInstance ต้องการ 'ประเภท' ไม่ใช่อินเทอร์เฟซ

สำหรับผู้ที่ไม่ได้ค้นหาผ่านโมเดลวัตถุ log4net afficiananderos นั้นถูกต้อง: l4n คือ 'wrapper' และคุณไม่สามารถรับ 'type' ที่แท้จริงสำหรับ Log thingie ได้

ดังนั้นตอนนี้ฉันต้องทดสอบ และคุณรู้ว่านั่นหมายความว่าอย่างไร อาจใช้เวลาหนึ่งนาที แต่มีแนวโน้มว่าจะใช้เวลาประมาณหนึ่งหรือสี่ชั่วโมง (ความคล้ายคลึงกันเช่นการสะกดคำว่า 'ชั่วโมง' และ 'สี่' ไม่เคยเกิดขึ้นโดยบังเอิญในชีวิตจริง)

อย่างไรก็ตาม สิ่งต่อไปนี้ (ลบส่วนที่ยกเว้นเกี่ยวกับการตั้งค่าตามรูปแบบบัญญัติ) ก็ใช้งานได้:

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

ดังนั้นแฮชโค้ดสำหรับวัตถุ Log ดั้งเดิมและวัตถุ Log ที่ฉีดเข้าไปในคุณสมบัติของวัตถุ 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()));

จากนั้นคุณดึงข้อมูล logger ด้วยการเรียกตามปกติเพื่อ Resolve():

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

คุณอาจกำหนดค่าอายุการใช้งานของตัวบันทึกให้เป็น ContainerControllerLifetimeManager ได้เช่นกัน เพื่อให้เป็นอินสแตนซ์แบบซิงเกิลตัน แต่ฉันยังไม่ได้ยืนยันสิ่งนั้น

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 ทุกอย่างทำผ่านอินเทอร์เฟซ และผู้ตัดไม้ที่เป็นรูปธรรมซ่อนอยู่หลังม่านพร้อมกับ Wizard of Oz

person AllenM    schedule 09.06.2011