在控制器中有另一个接口抽象(IConfiguration)以及 IRepository(对我来说看起来很难看) -而且它不起作用,因为 Config 类是静态的并且不能实现接口
大胆的说法并不完全正确。例如:
public interface IManageConfigurations
{
string DefaultFileLocation { get; }
}
public class ConfigurationManagerImpl : IManageConfigurations
{
public string DefaultFileLocation
{
get { return ConfigurationManager.AppSettings["DefaultFileLocation"]; }
}
}
public class MyController : Controller
{
private readonly IRepository _repository;
private readonly IManageConfigurations _config;
public MyController(IRepository repository, IManageConfigurations config)
{
_repository = repository;
_config = config;
}
}
我不认为这是一个丑陋的解决方案,但这主要是一种审美观点,这是主观的。在大多数情况下,我不认为一个类会显示过度注入反模式,直到它具有大约 5 个或更多接口依赖项。
此外,这几乎是单元可测试代码中依赖关系解析的标准解决方案。您可以像模拟存储库一样模拟配置界面。以上是我如何使用 web.config 中保存的值解决依赖关系。
ConfigurationManager.AppSettings["key"]
另一种解决方案是在控制器中对调用进行硬编码。然后,在您的单元测试项目中,您可以在 app.config 文件中设置相同的值。然后,单元测试运行器将在 app.config 中查找值,而 Web 服务器将在 web.config 中查找它们。
public class MyController : Controller
{
public ActionResult Index()
{
// the below will get the value from the unit test project's app.config
// when run as a unit test, but will get the value from web.config in server
var fileLocation = ConfigurationManager.AppSettings["DefaultFileLocation"];
}
}
更新
如果你真的想将字符串保存在静态类中,并且有可单元测试的代码,你可以这样做:
public static class ConfigSettings
{
public static string DefaultFileLocation
{
get { return ConfigurationManager.AppSettings["DefaultFileLocation"]; }
}
}
然后,您可以在Controller
. 但是,为了在作为单元测试运行时提供值,如上所述,您必须appSettings
在单元测试项目的文件中放置一个节点,这与在 Web 项目的文件中放置节点的app.config
方式非常相似。单元测试运行器将从 app.config 中提取值,而 Web 服务器将从 web.config 中提取值。appSettings
web.config
UnitTestProject\app.config
<configuration>
<appSettings>
<!-- use this value when executed in unit test runner -->
<add key="DefaultFileLocation"
value="C:\Users\me\test_files\test_file.png" />
</appSettings>
</configuration>
MvcProject\web.config(默认)
<configuration>
<appSettings>
<!-- use this value when executed locally in IIS Express -->
<add key="DefaultFileLocation"
value="C:\Users\me\Documents\Visual Studio 20xx\Projects\MyProj\App_Data\default_files\default_logo.png" />
</appSettings>
</configuration>
MvcProject\web.Release.config(转换)
<configuration>
<appSettings>
<!-- use this value when executed on live IIS production server -->
<add key="DefaultFileLocation"
value="E:\approot\siteroot\App_Data\default_files\default_logo.png"
xdt:Transform="SetAttributes" xdt:Locator="Match(key)" />
</appSettings>
</configuration>
如果这不能回答你的问题,也许我还没有完全理解你在追求什么。
更新
我在您的解决方案中只缺少一件 - 如何在控制器中使用该公共静态类 ConfigSettings?我应该将此静态类作为参数传递给构造函数吗?
不,你不需要做任何特别的事情。只需将它用作一个类,就像使用 static 一样ConfigurationManager
。
public ActionResult MyAction()
{
var customFilePath = GetCustomFilePath(); // may not be set
if (string.IsNullOrWhiteSpace(customFilePath)) // fall back to default
customFilePath = ConfigSettings.DefaultFilePath;
}
因此,您的控制器操作依赖于静态ConfigSettings
类,但在这种情况下它不是可注入/可交换的依赖项。当单元测试运行器调用此方法,并且 customFilePath 为 null / empty / whitespace 时,它将进入 ConfigSettings get 方法,该方法将调用 ConfigurationManager.AppSettings,该方法将在单元测试项目的 app.config/appSettings 中查找值.