我创建了一个从 Windows 服务、Windows 窗体和 ASP.NET 程序集引用的 .NET DLL。DLL 中包含相当多的日志记录到文本日志文件。从服务和 winforms 来看,这已经足够直截了当,但显然没有像尝试通过 ASP.NET 写入日志文件那样直截了当。
任何人都可以提供一些关于如何解决这个问题的提示吗?我想将日志记录代码保留在 DLL 中,因此在 Windows 服务和 ASP.NET 应用程序之间共享。
这听起来是个坏主意。每当您尝试创建在所有情况下都能神奇地工作的黑盒类型代码时,从长远来看,它总是会导致难以管理的意大利面条式代码。例如,如果有一天您决定需要两个 Windows 服务,它们都使用相同的通用 DLL,但其中一个需要记录到 Windows 事件日志,另一个需要记录到文本文件,该怎么办。现在,让您的 DLL 自动确定它应该如何记录并不那么容易,并且代码变得更加混乱和复杂。
依赖注入 (DI) 非常优雅地解决了这些问题。记录是一个单独的活动,所以它应该由一个单独的记录器类来处理。如果日志记录是在它自己的类中处理的,那么它就会成为使用它的其他类的依赖项。并且类不应该隐藏它们的依赖关系,而应该要求它们被“注入”到它们中。有用于执行 DI 的工具和框架,但只需在构造函数中请求依赖项也可以。
要以 DI 方式执行此操作,您首先需要为您的记录器创建一个接口,例如:
Public Interface ILogger
Sub WriteEntry(message As String)
End Interface
然后,在每个需要执行日志记录的类中,您会在构造函数中请求记录器,例如:
Public Class MyBusiness
Public Sub New(logger As ILogger)
_logger = logger
End Sub
Private _logger As ILogger
Public Sub DoWork()
_logger.WriteEntry("Doing work")
End Sub
End Class
如您所见,现在您已经从业务类中完全删除了有关日志记录内部工作的任何知识,因此可以将实现该接口的任何类提供给它并且它仍然可以工作。这样做是非常自由的。现在,您可以在任何类型的项目中重用该业务类,无论记录这些应用程序可能有什么要求。您可以给它一个写入文本文件的记录器,以及事件日志、数据库、屏幕和电子邮件,您可以命名它们——所有这些都无需触及使用它的业务类。
现在,您可以轻松地创建两个独立的ILogger
接口实现,一个用于服务,一个用于 ASP.NET 站点:
Public Class MyAspLogger
Implements ILogger
Public Sub WriteEntry(message As String) Implements ILogger.WriteEntry
' Do whatever an ASP project must do to log
End Sub
End Class
Public Class MyServiceLogger
Implements ILogger
Public Sub WriteEntry(message As String) Implements ILogger.WriteEntry
' Do whatever a service project must do to log
End Sub
End Class
然后从您的 ASP 项目中,您可以像这样创建业务对象:
Dim business As New MyBusiness(New MyAspLogger())
从您的服务项目中,您可以像这样创建它:
Dim business As New MyBusiness(New MyServiceLogger())
理想情况下,您将创建一个为您创建业务对象的工厂类,因此您不必在每次需要创建MyBusiness
对象时手动创建记录器(以及所有其他依赖项)。
工厂没有具体的实现要求,只是对类进行分类的通用术语。工厂类只是其唯一/主要目的是从其他类实例化对象的任何类。在理想的世界中,使用 DI,您永远不会New
在代码中的任何地方使用关键字,工厂类除外,但这并不总是实用的。一旦开始声明所有依赖项,您会发现实例化一个对象需要很多行代码,因为您必须首先创建所有依赖项。例如:
Dim fileWriter As IFileWriter = New MyFileWriter()
Dim logger As ILogger = New MyServiceLogger(fileWriter)
Dim dataAccess As IDataAccess = New MyDataAccess()
dim business As IBusiness = New MyBusiness(logger, dataAccess)
' Ta da!! I finally have a business object that I can now use
所以,如果你需要MyBusiness
在同一个项目的多个地方创建对象,那就是大量的复制代码。如果除了方便之外没有其他原因,拥有一个工厂是有意义的,所以你可以这样做:
Dim factory As IBusinessFactory = New MyBusinessFactory()
Dim business As IBusiness = factory.NewMyBusiness()
但是,制作工厂类还有许多其他充分的理由。您可能需要创建多个记录器,例如,按需创建 inside MyBusiness
,因此在这种情况下,MyBusiness
不能简单地ILogger
在其构造函数中请求一个,而是可以请求ILoggerFactory
实现NewLogger
方法的一个。然后你可以有两个独立的记录器工厂:一个MyAspLogger
根据请求返回新对象,另一个创建新MyServiceLogger
对象。因此,这样一来,工厂本身就可以成为其他类的依赖项。
使用工厂的另一个很好的理由是,您会发现实例化所有对象并将它们以不同配置连接在一起的代码本身就是一种特定的业务逻辑,应该以模块化的方式分离出来.