1

我使用一种方法来处理异常 - 它在内部写入数据库,但是当发布到网络时,源代码将不包含写入数据库所需的连接字符串。相反,它应该写入日志文件。

是否可以在 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
    }
}

我曾考虑让两个日志类实现一个共享接口(而不是扩展和覆盖)并创建一些工厂方法来呈现它,但不确定如何验证程序集的存在或在不添加引用的情况下使用它的类型,在这种情况下最终项目将有一个循环引用。

4

4 回答 4

1

我可以想出几种方法来实现这一点。

紧密耦合

使用反射来检测 DLL 的存在。如果存在,则加载适当的类,并对它们进行额外调用。

为此,请使用Assembly.LoadFileAssembly.GetType(string)Activator.CreateInstance(type)。将新实例转换为您的抽象基本记录器类型/接口。

这或多或少是你所描述的。不过,我不建议这样做,因为它不是很灵活,而且有很好的替代方案。

松耦合

创建一个接口或者抽象的logger类,使用依赖注入(Inversion of Control)将logger注入到需要做日志的组件中。如果您选择,您可以使用依赖注入库以松散耦合的方式指定您想要的实现。配置 DI 库以从额外的 DLL(如果存在)加载依赖项。

Castle.Windsor 有一个松耦合的日志接口(日志工具),您可以查看第二个选项。

在这些之间也有一种光谱。

这是将记录器作为依赖项注入的要点(尽管在此示例中我没有使用任何库):

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();
        }
    }
}
于 2011-06-01T06:26:31.657 回答
1

这听起来像是.NET 4.0 中提供的托管可扩展性框架(MEF) 的一个潜在用例。

于 2011-06-01T06:27:49.743 回答
0

听起来这实际上只是您如何创建日志编写器的问题。与其尝试根据是否存在 DLL 来执行此操作,不如允许将类实例化为整体配置的一部分。让用户(我的意思是安装它的人)指定ExtendedLogWriter他们是否需要以及是否有 Foo.Private.dll,SimpleLogWriter否则。有各种 IoC 容器可以让这变得简单。

于 2011-06-01T06:24:51.467 回答
0

这可以通过使用控制反转来解决。

带有 LogError(Exception) 方法的接口 IErrorLogger 通过以下方式实现:

  • 数据库错误记录器
  • 文件错误记录器

使用诸如 Castle Windsor 之类的控制反转 API,您可以不同地配置 IErrorLogger 组件,因为 ASP.NET 4.0 具有Web.debug.configWeb.release.config允许配置一些 Web 应用程序以进行调试和发布到 Web 方案。

归根结底,当您将编译更改为发布时,FileErrorLogger 将成为 IErrorLogger 实现。

通过以下链接了解更多信息:http: //docs.castleproject.org/Windsor.MainPage.ashx

于 2011-06-01T06:37:46.947 回答