为了账号安全,请及时绑定邮箱和手机立即绑定

通过上下文解析依赖关系——深入解析树

通过上下文解析依赖关系——深入解析树

C#
RISEBY 2021-11-28 19:38:03
我们有两个应用程序共享一些具有依赖项的公共类。这些依赖项对于两者或特定于应用程序都是相同的。现在为这两个应用程序配置 IoC 很容易 - 使用 ImplementationA 作为一个应用程序的 IDependency,将 ImplementationB 作为另一个应用程序的 IDependency。但是 - 有第三个应用程序,有时在解析界面时需要使用应用程序 A 的依赖项,有时需要使用 B 的依赖项。换句话说,我需要这样的东西:Resolve<ISomething>( when you come accross IDependecy (anywhere in the 'resolve tree') use ImplementationA)Resolve<ISomething>( when you come accross IDependecy (anywhere in the 'resolve tree') use ImplementationB)所以核心问题是:你如何将上下文传递给任何逻辑,从 Resolve 调用中选择实现?具体示例:.NET Core MVC App - 从请求中解析枚举值。现在我需要调用一些 IManagerFactory,将此枚举作为参数传递,并从应用程序 A 或 B 中获取具有所有依赖项的管理器的实现。(再次,深入而不仅仅是管理器本身的依赖项)从请求中获取上下文是时间消耗,所以我只想做一次。这已经在方法的开头完成了。像这样public async Task<Response> ProcessRequest([FromBody] Request request){ var context = _someService.GetContext(request); var appType = ParseAppTypeFromContext(context); ... var manager=  _managerFactory.Resolve(appType); manager.DoSomething(); manager.DoSomethingElse();}可能的解决方案:我可以注册 ISomethingA,使用注册委托并让它通过 ResolvedParameter(Autofac 功能)解析正确的依赖项 - 然后只解析 ISomethingA。但是我必须为每个依赖于 IDependacy 的类以及依赖于该类的每个类等等都这样做 - 继续我的工作。使用工厂。但是您仍然必须以某种方式告诉它您想要哪种实现。所以我必须从上到下传递这些信息 - 这似乎有点......错误,因为这些是不应该知道有一些应用程序 A 或 B 的常见类。所以..我迷路了。我不确定这是否适用于 IoC 或更好的设计。请指教。(我真的不在乎我使用哪个 IoC 容器 - 只要它是好的和维护的)
查看完整描述

1 回答

?
绝地无双

TA贡献1946条经验 获得超4个赞

IMO 使用工厂确实是错误的方法。Factory 使消费者复杂化,IDependency并且引入这个 Factory 抽象可能会导致整个应用程序发生彻底的变化。


相反,我认为最合适的解决方案是应用代理模式。此代理将是 的一个实现,IDependency它将包装这两个IDependency实现,并将根据您指定的条件将任何传入调用分派到正确的实现。


例如:


public class DependencyDispatcher : IDependency

{

    private ImplA a;

    private ImplB b;


    public DependencyDispatcher(ImplA a, ImplB b) {

        this.a = a;

        this.b = b;

    }


    private IDependency Dependency => someCondition ? this.a : this.b;


    // Implement IDependency methods to forward the call to Dependency

    void IDependency.DoSomething() => this.Dependency.DoSomething();

}

您可以将此代理配置为第三个应用程序IDependency的组合根中的默认实现。


您的更新使事情变得更加清晰。您正在为请求提供一些运行时值,您需要根据此值做出决定。


这里有几个解决方案。首先,尝试将此决定从请求正文中移到请求标头中。这样,您的调度员可以执行以下操作:


private IDependency Dependency => 

    HttpContext.Current.Headers["MyHeader"] == "something" ? this.a : this.b;

如果这不是一个选项,并且信息属于请求正文,您也许可以让您的调度员根据其输入做出决定。例如:


public class DependencyDispatcher : IDependency

{

    ...


    private IDependency GetDependency(string appType) =>

        appType == "a" ? this.a : this.b;


    void IDependency.DoSomething(DoSomethingData data) =>

        this.GetDependency(data.AppType).DoSomething(data);

}

这显然只有在将该AppType值(或可以转换为它的值)提供给IDependency的方法时才有可能。只有在这种情况下,有足够的可用信息才能做出此决定。


如果这不是一个选项,另一种选择是定义一个抽象,允许在对象图中设置运行时值,它为调度程序提供该请求的信息。例如:


public interface IApplicationContext

{

    AppType ApplicationType { get; set; }

}

您的控制器可以IApplicationContext注入它并设置AppType属性:


public async Task<Response> ProcessRequest([FromBody] Request request)

{

    var context = _someService.GetContext(request);

    this.applicationContext.ApplicationType = ParseAppTypeFromContext(context);

    this.dependency.DoSomethingElse();

}

或者,您可以添加一些中间件,AppType在调用控制器的 Action 方法之前设置。


您也可以让代理实现IApplicationContext:


public class DependencyDispatcher : IDependency, IApplicationContext

{

    ...

    public AppType ApplicationType { get; set; }


    private IDependency Dependency => ApplicationType == AppType.A ? this.a : this.b;


    // Implement IDependency methods to forward the call to Dependency

    void IDependency.DoSomething() => this.Dependency.DoSomething();

}


查看完整回答
反对 回复 2021-11-28
  • 1 回答
  • 0 关注
  • 244 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信