我使用一种方法来处理异常 - 在内部写入数据库,但是当发布到Web时,源代码将不包含写入数据库所需的连接字符串。相反,它应该写入日志文件。
当Foo.Private.dll不存在时,是否可以容纳写入日志,但是当它出现时写入数据库?
//In Foo.Public.dll assembly
public class SimpleLogWriter
{
public virtual void LogError(Exception ex)
{
//Write to log file.
}
}
...
//In Foo.Private.dll assembly
public class ExtendedLogWriter : SimpleLogWriter
{
public override void LogError(Exception ex)
{
//Write to database
}
}
我曾考虑让两个日志类实现共享接口(而不是扩展和覆盖)并创建一些工厂方法来呈现它,但不确定如何验证程序集的存在或使用其类型而不添加引用,在这种情况下,最终项目将有一个循环引用。
答案 0 :(得分:1)
我可以想到几种方法可以实现这一目标。
紧密耦合
使用反射来检测DLL的存在。如果存在,请加载适当的类,并对它们进行额外调用。
为此,请使用Assembly.LoadFile,Assembly.GetType(string)和Activator.CreateInstance(type)。将新实例转换为抽象基本记录器类型/接口。
这或多或少是你所描述的。我不建议这样做,因为它不是很灵活,而且有很好的选择。
松散耦合
创建一个接口或抽象记录器类,并使用Dependency Injection (Inversion of Control)将记录器注入需要记录的组件中。如果选择,可以使用依赖注入库以松散耦合的方式指定所需的实现。配置DI库以从您的额外DLL(如果存在)加载依赖项。
Castle.Windsor有一个松散耦合的日志记录界面(logging facility),您可以查看第二个选项。
这些之间也有一种光谱。
这是将记录器作为依赖项注入的要点(虽然我在这个例子中没有使用任何库):
using System;
using System.IO;
public interface ILogger
{
void WriteDebug(string debug);
void WriteInfo(string info);
void WriteError(string error);
}
public class NullLogger : ILogger
{
private static ILogger instance = new NullLogger();
// This singleton pattern is just here for convenience.
// We do this because pattern has you using null loggers constantly.
// If you use dependency injection elsewhere,
// try to avoid the temptation of implementing more singletons :)
public static ILogger Instance
{
get { return instance; }
}
public void WriteDebug(string debug) { }
public void WriteInfo(string info) { }
public void WriteError(string error) { }
}
public class FileLogger : ILogger, IDisposable
{
private StreamWriter fileWriter;
public FileLogger(string filename)
{
this.fileWriter = File.CreateText(filename);
}
public void Dispose()
{
if (fileWriter != null)
fileWriter.Dispose();
}
public void WriteDebug(string debug)
{
fileWriter.WriteLine("Debug - {0}", debug);
}
// WriteInfo, etc
}
public class SomeBusinessLogic
{
private ILogger logger = NullLogger.Instance;
public SomeBusinessLogic()
{
}
public void DoSomething()
{
logger.WriteInfo("some info to put in the log");
}
public ILogger Logger
{
get { return logger; }
set { logger = value; }
}
}
public class Program
{
static void Main(string[] args)
{
// You're free to use a dependency injection library for this,
// or simply check for a DLL via reflections and load a logger from there
using (var logger = new FileLogger("logfile.txt"))
{
var someBusinessLogic = new SomeBusinessLogic()
{
// The component won't know which logger it is using - it just uses it
Logger = logger,
};
someBusinessLogic.DoSomething();
}
}
}
答案 1 :(得分:1)
这听起来像是{4.0}中可用的Managed Extensibility Framework(MEF)的潜在用例。
答案 2 :(得分:0)
这听起来真的只是你如何创建日志编写器。而不是尝试根据DLL是否存在来执行此操作,只需允许将类实例化为整体配置的一部分。让用户(我指的是安装它的人)如果他们想要的话指定ExtendedLogWriter
,如果他们有Foo.Private.dll,则指定SimpleLogWriter
。有各种各样的IoC容器可以使这很容易。
答案 3 :(得分:0)
这可以通过使用控制反转来解决。
具有LogError(Exception)方法的接口IErrorLogger由以下方法实现:
使用Castle Windsor之类的控制API的一些反转,您可以不同地配置IErrorLogger组件,因为ASP.NET 4.0具有 Web.debug.config 和 Web.release.config 允许为调试和发布到Web场景配置一些Web应用程序。
在一天结束时,当您将编译更改为发布时,FileErrorLogger将是IErrorLogger实现。
点击以下链接了解详情:http://docs.castleproject.org/Windsor.MainPage.ashx