如何使用 XmlSerializer 和 autofac 注入依赖项?

Kzr*_*tof 1 c# dependency-injection autofac xmlserializer

我有一个名为SomeRule可以以 XML 格式序列化的类。该类使用ISomeService我想通过 autofac 注入的 。

[Serializable]
public class SomeRule 
{
    [XmlAttribute("Attribute1")]
    public string Attribute1 {get;set;}

    [XmlAttribute("Attribute2")]
    public string Attribute2 { get; set; }

    private readonly ISomeService m_someService;

    private SomeRule()
    {
    }

    public SomeRule(ISomeService someService)
    {
        m_someService = someService;
    }

    public void DoSomething()
    {
        m_someService.DoStuff(Attribute1);
    }
}

public interface ISomeService {

    void DoStuff(string param);
}

public class SomeServiceImpl : ISomeService
{
    public void DoStuff(string param)
    {
        //  Do something with the stuff.
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我的程序接收到一个我想要反序列化的 XML 字符串,但同时,autofac 为我注入了依赖项。

void Main()
{
    string serializedRule = "<?xml version=\"1.0\" encoding=\"utf-16\"?><SomeRule xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" Attribute1=\"Huuuuuge\" Attribute2=\"Cofveve\" />";

    XmlSerializer xmlSerializer = new XmlSerializer(typeof(SomeRule));

    var stringBuilder = new StringBuilder(serializedRule);
    var newRule = xmlSerializer.Deserialize(new StringReader(stringBuilder.ToString())) as SomeRule;

    // ISomeService was not injected yet. Is it possible?
}
Run Code Online (Sandbox Code Playgroud)

我可以通过调用 autofac 容器来完成这项工作,获取ISomeService接口的注册实现并将其分配给SomeRule实例的公共属性。我正在寻找一个更好的解决方案,一个不需要类具有公共属性的解决方案。

有没有办法自动注入依赖项XmlSerializer

Ste*_*ven 6

从 DI 的角度来看,具有接受服务依赖项的构造函数的以数据为中心的对象是相当有问题的,应该避免。

在实践 DI 时,我们尝试将应用程序组件(即包含行为并具有自己的依赖项的类)的对象图的组合集中到应用程序中称为Composition Root的集中位置。

然而,包含构造函数依赖关系的以数据为中心的对象使这种做法复杂化,因为它要么强制组合出组合根,要么强制添加工厂抽象来创建这些对象。

相反,您应该使用以下两种替代方法之一:

  1. 分离数据和行为。这意味着将SomeRuleDoSomething方法移动到一个新类,该类SomeRule在其公共方法中作为参数。构造函数依赖项也将移动到这个新类。
  2. 删除 的构造函数依赖项SomeRule,而是将其注入DoSomethingusing 方法注入。

选项 1 可能如下所示:

// SomeRule only contains data. Much simpler
[Serializable]
public class SomeRule 
{
    [XmlAttribute("Attribute1")]
    public string Attribute1 {get;set;}

    [XmlAttribute("Attribute2")]
    public string Attribute2 { get; set; }
}

// Moved behavior to new class. This class can be injected
// into consumers, as usual.
public class SomeRuleHandler : IRuleHandler<SomeRule>
{
    private readonly ISomeService m_someService;

    // There's now just one constructor left
    public SomeRuleHandler(ISomeService someService)
    { 
        m_someService = someService ?? throw new ArgumentNullException("someService");
    }

    public void DoSomething(SomeRule rule)
    {
        m_someService.DoStuff(rule.Attribute1);
    }
}
Run Code Online (Sandbox Code Playgroud)

使用选项 2,结果如下:

[Serializable]
public class SomeRule 
{
    [XmlAttribute("Attribute1")]
    public string Attribute1 {get;set;}

    [XmlAttribute("Attribute2")]
    public string Attribute2 { get; set; }

    // No more constructors. The dependency is supplied in the method,
    // but *not* stored.
    public void DoSomething(ISomeService someService)
    {
        someService.DoStuff(Attribute1);
    }
}
Run Code Online (Sandbox Code Playgroud)