我有一些单元测试,希望'当前时间'与DateTime不同.现在我不想改变计算机的时间.
实现这一目标的最佳策略是什么?
我试图找出log4net与依赖注入框架的正确模式和用法.
Log4Net使用ILog接口但需要我调用
LogManager.GetLogger(Reflection.MethodBase.GetCurrentMethod().DeclaringType)
Run Code Online (Sandbox Code Playgroud)
在我需要记录信息的每个类或方法中.这似乎违背了IoC原则并让我使用Log4Net.
我应该以某种方式在某处放置另一层抽象?
此外,我需要记录自定义属性,如当前用户名,如下所示:
log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;
Run Code Online (Sandbox Code Playgroud)
我如何封装它,以便我不必记住每次都这样做并仍然保持当前记录的方法.我应该做这样的事情还是我完全错过了标记?
public static class Logger
{
public static void LogException(Type declaringType, string message, Exception ex)
{
log4net.ThreadContext.Properties["userName"] = ApplicationCache.CurrentUserName;
ILog log = LogManager.GetLogger(declaringType);
log.Error(message, ex);
}
}
Run Code Online (Sandbox Code Playgroud) 我不喜欢基于构造函数的依赖注入.
我认为这会增加代码复杂性并降低可维护性,我想知道是否有任何可行的替代方案.
我不是在讨论将实现与接口分离的概念,而是有一种从接口动态解析(递归)一组对象的方法.我完全支持这一点.但是,传统的基于构造函数的方法似乎有一些问题.
1)所有测试都取决于构造函数.
在去年的MVC 3 C#项目中广泛使用DI后,我发现我们的代码中包含以下内容:
public interface IMyClass {
...
}
public class MyClass : IMyClass {
public MyClass(ILogService log, IDataService data, IBlahService blah) {
_log = log;
_blah = blah;
_data = data;
}
...
}
Run Code Online (Sandbox Code Playgroud)
问题:如果我在实现中需要另一个服务,我必须修改构造函数; 这意味着该类的所有单元测试都会中断.
即使与新功能无关的测试也需要至少重构以添加其他参数并为该参数注入模拟.
这似乎是一个小问题,像resharper这样的自动化工具有所帮助,但是当这样的简单改变导致100多个测试中断时,它肯定很烦人.实际上我已经看到人们在做愚蠢的事情以避免更改构造函数而不是咬紧牙关并在发生这种情况时修复所有测试.
2)服务实例不必要地传递,增加了代码复杂性.
public class MyWorker {
public MyWorker(int x, IMyClass service, ILogService logs) {
...
}
}
Run Code Online (Sandbox Code Playgroud)
如果我可以在给定服务可用并且已经自动解析的上下文(例如控制器)内,或者不幸的是,通过将服务实例传递给多个辅助类链来创建此类的实例.
我看到这样的代码,所有的时间:
public class BlahHelper {
// Keep so we can create objects later
var _service = null;
public …Run Code Online (Sandbox Code Playgroud) 我使用Autofac作为我的IoC和一切我已经阅读DI的话题提出使用"构造器注入"明确揭露类的依赖.不过,我也使用日志门面(Common.Logging)与log4net的,并已创建注入它的Autofac模块.现在,在我想要进行一些日志记录的每个类中,我都有额外的构造函数参数(参见示例#1)....
我想知道在使用日志门面时是否需要记录DI?我知道通过构造函数签名显式公开依赖是一个很好的架构. 但是在记录门面的情况下我相信以下是真的:
那么,别人怎么想?注入伐木门面是否过度杀伤?关于这个主题有一些类似的问题,但更笼统地说(基础设施) - 我主要对记录....
// IoC "way"
public class MyController : BaseController
{
private readonly ILog _logger;
public MyController(ILog logger)
{
_logger = logger;
}
public IList<Customers> Get()
{
_logger.Debug("I am injected via constructor using some IoC!");
}
}
// just use the logger "way"
public class MyController : BaseController
{
private static readonly ILog Logger = LogManager.GetCurrentClassLogger();
public IList<Customers> Get()
{
Logger.Debug("Done! I can use it!");
}
}
Run Code Online (Sandbox Code Playgroud) (我最初在这篇评论中提出了这个问题,但Mark Seemann要我改为创建一个新问题.)
我正在开始一个新的应用程序(.NET Core,如果这很重要),现在我正在尝试决定如何进行日志记录.
普遍的共识似乎是日志记录是一个跨领域的问题,因此记录器不应该直接注入应该记录的类.
通常,有一个像下面这样的例子如何不这样做:
public class BadExample : IExample
{
private readonly ILogger logger;
public BadExample(ILogger logger)
{
this.logger = logger;
}
public void DoStuff()
{
try
{
// do the important stuff here
}
catch (Exception e)
{
this.logger.Error(e.ToString());
}
}
}
Run Code Online (Sandbox Code Playgroud)
相反,具有业务逻辑的类不应该知道记录器(SRP),并且应该有一个单独的类来执行日志记录:
public class BetterExample : IExample
{
public void DoStuff()
{
// do the important stuff here
}
}
public class LoggingBetterExample : IExample
{
private readonly IExample betterExample; …Run Code Online (Sandbox Code Playgroud) c# logging dependency-injection inversion-of-control cross-cutting-concerns
我只是想了解PostSharp,说实话,我认为这太棒了.
但有一件事我很难在PostSharp方面无法完成纯依赖注入(不是服务定位器),也许是因为编译时编织的结果.
来自PHP背景,Symfony有JMSAopBundle,它仍然允许依赖注入它的拦截器.
.Net是否有一些具有相同功能的库?
或者我错过了PostSharp的东西?
我试图更好地理解依赖注入模式,我遇到了是否应该注入记录器的问题。
我使用的语言是 Python,但这个概念是不可知的。我现在所做的只是将单例记录器模块导入到作用域中,并在必要时调用它。例如:
import logger
class Television(object):
def __init__(self, colour, inches):
self._colour = colour
self._inches = inches
def turn_on(self):
# do something
logger.message('TV has been turned on')
Run Code Online (Sandbox Code Playgroud)
如果我使用依赖注入,我会做这样的事情:
import logger
class Television(object):
def __init__(self, colour, inches, logger):
self._colour = colour
self._inches = inches
self._logger = logger
def turn_on(self):
# do something
self._logger.message('TV has been turned on')
Run Code Online (Sandbox Code Playgroud)
这使得代码更易于测试(尽管 python 是如此动态,以至于在测试时您可以实时模拟模块中的记录器)。
缺点是我必须通过使用替代构造函数、一些注入框架或服务定位器来处理注入。我不太确定这种努力是否有回报。
我看过其他类似的问题,但我无法真正理解它们,或者答案没有让我满意:
它是最好的(我知道没有银弹,但通过使用一个可能有一些优势) - 登录调用函数,或调用它的函数?
例子:
方法1
module MongoDb =
let tryGetServer connectionString =
try
let server = new MongoClient(connectionString).GetServer()
server.Ping()
Some server
with _ -> None
Run Code Online (Sandbox Code Playgroud)
用法:
match MongoDb.tryGetServer Config.connectionString with
| None ->
logger.Information "Unable to connect to the database server."
// ... code ...
| Some srv ->
logger.Information "Successfully connected to the database server."
// ... code ...
Run Code Online (Sandbox Code Playgroud)
方法2
module MongoDb =
let tryGetServer connectionString =
try
let server = new MongoClient(connectionString).GetServer()
server.Ping()
Some server
with …Run Code Online (Sandbox Code Playgroud) c# ×3
logging ×3
.net ×2
datetime ×1
f# ×1
log4net ×1
mstest ×1
postsharp ×1
systemtime ×1
unit-testing ×1