【问题标题】:Controller class with own configuration class具有自己的配置类的控制器类
【发布时间】:2017-05-10 14:53:17
【问题描述】:

我有几个控制器类,它们使用自己的配置类来设置控制器类的行为。

我有控制器解析器,它可以通过名称获取所需的控制器。

现在我想要另一个解析器将控制器类与其各自的配置类绑定。

我现在拥有的是嵌套在与控制器类同名的部分类中的配置类,因此解析器可以明确地确定配置类,但我对这种可怕的独奏不太满意,因为部分类只包含嵌套配置类必须与控制器类具有相同的命名空间,这让我最困扰,因为它的名称与该类物理所在的文件夹不一致,因为控制器类位于“Controller”文件夹中,它们的命名空间是“Something.Controller " 并且配置类在文件夹 "Configuration" 中,但它们的命名空间也必须是 "Something.Controller"。

//Path: .\Controller
namespace Something.Controller
{
    public partial class MyController : IController
    {
    }
}

//Path: .\Configuration
namespace Something.Controller
{
    public partial class MyController
    {
        public class MyControllerConfiguration : IConfiguration
        {
        }
    }
}

和解析器(没有类型验证,因为它之前完成了,唯一可以传递给这些方法的类型已经实现IController):

public class Resolver
{
    public IController GetController(Type controllerType)
    {
        return (IController)Activator.CreateInstance(controllerType);
    }
    public IConfiguration GetControllerConfiguration(Type controllerType)
    {
        var configurationType = controllerType.GetNestedTypes().FirstOrDefault(t => typeof(IConfiguration).IsAssignableFrom(t));
        if (configurationType != null)
            return (IConfiguration)Activator.CreateInstance(configurationType);
        else
            return null;
    }
}

那么,与在各自的控制器类中嵌套配置类相比,如何以更清晰的方式将控制器类与其配置类耦合?

编辑:

下面是一些用法示例:

假设我有两个控制器。每个都有自己的配置。现在我想让用户选择使用哪个控制器,然后从相应的配置类中向用户显示一组属性。当然,我可以创建控制器实例,它会在用户设置应用程序配置时公开其配置,但我认为这不是一个好主意。

【问题讨论】:

  • 配置类如何控制控制器类的行为?
  • @Orangesandlemons 设置文件控制器正在处理的位置、并发线程数等。

标签: c# class inner-classes partial-classes


【解决方案1】:

此建议基于Dependency Inversion 的原则。 (帖子中的示例实际上与这个确切的问题密切相关。)

这个想法是您的控制器不应该负责确定配置值的来源。它应该依赖于抽象,比如接口。

我要做的第一件事是将您的设置分离到它们自己的界面中,如下所示:(这不是抄袭 - 这是我的博客文章。)

public interface IConfiguration
{
    string SomeSetting { get; }
    int OtherSetting { get; }
}

然后在你的控制器类中,这样做:

public class MyController
{
    private readonly IConfiguration _configuration;

    public MyController(IConfiguration configuration)
    {
        _configuration = configuration;
    }
}

现在,从控制器本身的角度来看,工作已经完成。 IConfiguration 在构造函数中是必需的,因此如果不提供实现IConfiguration东西,就不可能创建MyController 的实例。

这很有帮助,因为它鼓励您在不解决配置设置来自何处的问题的情况下完成控制器的编写。你推迟了。您可以完成手头的任务,然后决定如何实施IConfiguration。它可以防止琐碎的任务让你偏离更重要的任务。

按照设计,MyController 永远不会知道该实现是什么。它不在乎。它只取决于接口。您可以在不更改MyController 的情况下更改设置的来源,只需使用IConfiguration 的不同实现即可。如果您想为MyController 编写单元测试并使用不同的配置设置对其进行测试,您可以使用硬编码值编写IConfiguration 的简短“模拟”实现。

这就留下了IConfiguration 如何传递到构造函数的问题。这通常(或通常)使用 Unity、Autofac 或 Windsor 等依赖注入容器来完成。如果您使用的是 ASP.NET Core,则有一个内置容器。 (我猜这是一个 MVC 控制器,但也许不是——没关系。)

要查找有关如何配置应用程序以使用依赖项注入容器的说明,请在 Google 上搜索您正在使用的技术的名称 +“依赖项注入”,例如“ASP.NET MVC 依赖项注入”。或者,如果您提及您正在使用的内容,我可以为您指出一篇文章。

依赖注入不是灵丹妙药,但对于任何复杂的应用程序,包括 MVC 应用程序,它都非常有用。我发现这是朝着理解和应用其他原则以及学习编写单元测试迈出的一步。它还帮助我避免了走偏。如果我正在编写的类需要依赖其他东西,那么我只需为该依赖项编写一个接口并继续处理我正在处理的类。然后我可以回去决定如何实现那个依赖。

【讨论】:

  • 这是我正在寻找的东西。但主要问题是每个控制器都有自己的配置类。除了接口本身之外,没有什么可以从这些类中提取到接口中,这决定了实现它的类是配置类。请查看问题的编辑,我已经添加了一些解释。
  • 即使每个控制器都有自己的配置类,我也不确定会发生什么变化。如果您使用的是 DI 容器,您将告诉容器要创建任何给定接口的哪个实现。但是“耦合”这两个类是没有好处的。如果你有两个刻意耦合的类并且每个类只与另一个类一起工作,那为什么还要有两个类呢?
  • 实际上有两个类的唯一原因是一个类(实现IController)是“做事”的类,另一个(实现IConfiguration)是一组属性由用户设置并在磁盘上存储/调用。
  • 基于此...我仍然不确定我是否看到将它们耦合在一起的继承优势。避免耦合的原因之一是因为紧密耦合的类在您必须更改某些内容之前一直有效。我不确定单元测试适用于何处,但取决于抽象也使单元测试更容易。例如,如果您的设置始终来自硬盘驱动器,您将如何测试控制器在一种设置下的工作方式与在不同设置下的工作方式?您必须将值实际写入硬盘驱动器以测试您的控制器。
  • 其实是的。我必须写它们并从硬盘读取。或者出于测试目的即时设置值。无论如何,假设我会将配置与控制器分离。控制器仍然需要它的设置,所以它需要做额外的检查,如果传递的配置是它所期望的配置。而且它根本不会解耦。还是应该重新设计控制器以仅使用抽象层?
【解决方案2】:

有很多方法可以做到这一点。

例如在 Spring 框架中,配置可以在单独的 XML 文件中完成,该文件通过“set”方法填充每个控制器属性。

另一种常见的方法是让 Controller 从某种类型的单例 PropertyManager 中查找其属性,该单例 PropertyManager 可以具有文件、数据库或内存实现。

问题是,您真的需要为每个控制器单独配置类吗,或者控制器也可以具有从单独的配置存储库获取其配置的逻辑,但同时不关心该存储库如何读取/写入其配置.

【讨论】:

    猜你喜欢
    • 2016-09-21
    • 2015-05-26
    • 1970-01-01
    • 1970-01-01
    • 2015-07-05
    • 2015-08-02
    • 2016-10-26
    • 2014-08-20
    • 2012-06-14
    相关资源
    最近更新 更多