การพึ่งพาการฉีดในไลบรารีของชั้นเรียน

มีวิธีแก้ไขด้วยสองโครงการ ฉันประสบปัญหา DI โซลูชันประกอบด้วยไลบรารีคลาสและแอป WebApi2 (ซึ่งใช้ไลบรารีคลาสและเปิดเผย API)

ฉันได้กำหนด Autofac.module ในไลบรารีคลาสซึ่งตั้งค่า DI ทั้งหมดในโครงการ

ในโครงการ WebApi2 ฉันสร้างคอนเทนเนอร์ DI (โดยใช้ Autofac.WebApi2) และโหลดโมดูลจากไลบรารีคลาส ตอนนี้เมื่อตัวควบคุม api ในโปรเจ็กต์ WepApi2 ร้องขอบริการในคลาสไลบรารีที่พวกเขาสร้างขึ้นโดยมีการขึ้นต่อกันทั้งหมด ทั้งหมดนี้ใช้งานได้ดี!

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

var ruleType = Type.GetType(rule.RuleImplementation.Implementation);
var rule = (IRule)Activator.CreateInstance(ruleType,param1,param2);

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

เป็นไปได้ไหมที่จะใช้การสะท้อนกลับและ autoFac ร่วมกันเพื่อสร้างอินสแตนซ์ของวัตถุ ฉันยังต้องสามารถส่งพารามิเตอร์ของฉันไปยังวัตถุได้เช่นกัน

... หรือมีวิธีการเข้าถึงคอนเทนเนอร์ (ซึ่งสร้างขึ้นในชุดประกอบ webApi2) และใช้สิ่งนั้นเพื่อแก้ไขหรือไม่ ฉันเดาว่านี่จะเป็นรูปแบบการบริการบางอย่างที่ฉันเชื่อว่าถือเป็นรูปแบบการต่อต้าน

ฉันจะดำเนินการต่อได้อย่างไร? ข้อมูลทั้งหมดได้รับการชื่นชมอย่างมาก


person iCediCe    schedule 02.12.2016    source แหล่งที่มา


คำตอบ (2)


การสร้างส่วนประกอบโดยใช้ Activator.CreateInstance ถือเป็นความคิดที่ไม่ดี เนื่องจากโดยพื้นฐานแล้วหมายความว่าคุณกำลังปรับใช้ตรรกะที่คอนเทนเนอร์ทำเพื่อคุณใหม่ แต่ไม่มีฟีเจอร์และตัวป้องกันความปลอดภัยที่ไลบรารี DI จัดเตรียมไว้ให้คุณ

ฉันได้กำหนด Autofac.module ในไลบรารีคลาสซึ่งตั้งค่า DI ทั้งหมดในโครงการ

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

การทำเช่นนี้จะช่วยขจัดปัญหา เนื่องจากคุณมีสิทธิ์เข้าถึงคอนเทนเนอร์อยู่แล้วภายในรากการเรียบเรียงของคุณ

ทางออกที่ดีในการอนุญาตให้สร้างกฎโดยใช้คำจำกัดความบางอย่างที่มาจากฐานข้อมูลคือการกำหนด IRuleActivator abstraction นามธรรมนี้สามารถกำหนดได้ในไลบรารีของคุณและนำไปใช้ภายในรูทการเรียบเรียง สิ่งนี้ทำให้การใช้งานสามารถห่อคอนเทนเนอร์ได้ ในขณะที่ไลบรารียังคงลืมการมีอยู่ของคอนเทนเนอร์:

// Defined in the library
public interface IRuleActivator
{
    IRule GetRule(RuleData rule);
}

// Defined in the Compostion Root
public sealed class AutofacRuleActivator : IRuleActivator
{
    private readonly IComponentContext context;
    public AutofacRuleActivator(IComponentContext context) {
        this.context = context;
    }

    public IRule GetRule(RuleData rule) {
        Type ruleType = Type.GetType(rule.RuleImplementation.Implementation);
        return (IRule)this.context.Resolve(ruleType);
    }
}
person Steven    schedule 02.12.2016

คุณสามารถสร้างโรงงานสำหรับการสร้าง IRule:

public IRuleFactory
{
   IRule CreateRule(params);
}

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

public class RuleFactory : IRuleFactory
{
    public RuleFactory(IParamsProvider provider)
    {
        ...
    }

    public IRule CreateRule()
    {
        return new RuleImpl(provider.Param1, provider.Param2);
    }
}

ลงทะเบียนอินเทอร์เฟซเหล่านี้ลงใน Ioc และฉีดเข้าไปในตัวจัดการบริการ

person Johnny    schedule 02.12.2016
comment
ฉันชอบวิธีแก้ปัญหานี้ เท่าที่ฉันเห็นข้อเสียเพียงอย่างเดียวคือฉันต้องแทรกกฎทั้งหมดลงในบริการของฉันโดยไม่คำนึงว่ากฎเหล่านั้นจำเป็นหรือไม่ เพราะก่อนอื่นฉันรู้ว่าในขณะรันไทม์เมื่อฉันสืบค้นฐานข้อมูล - person iCediCe; 05.12.2016