Частичный / расширенный класс или интерфейс при наличии другой сборки - PullRequest
1 голос
/ 01 июня 2011

Я использую метод для обработки исключений - внутренне он записывает данные в базу данных, но при публикации в Интернете исходный код не будет содержать строку подключения, необходимую для записи в базу данных.Вместо этого он должен записывать в файл журнала.

Возможно ли обеспечить запись в журналы, когда 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 ]

1 голос
/ 01 июня 2011

Я могу подумать о нескольких способах, которыми вы могли бы сделать это.

Плотно связанные

Используйте отражения, чтобы обнаружить присутствие DLL.Если он присутствует, загрузите соответствующие классы и сделайте для них дополнительные вызовы.

Для этого используйте Assembly.LoadFile , Assembly.GetType (string) и Activator.CreateInstance (тип) .Приведите новый экземпляр к вашему абстрактному базовому типу / интерфейсу логгера.

Это более или менее то, что вы описывали.Я не рекомендую это, потому что это не очень гибко, и есть хорошие альтернативы.

Loosly Coupled

создать интерфейс или абстрактный класс регистратораи используйте Внедрение зависимостей (Inversion of Control) , чтобы внедрить регистратор в компоненты, необходимые для ведения журнала.Если вы выберете, вы можете использовать библиотеку внедрения зависимостей, чтобы указать, какие реализации вы хотите в слабосвязанной манере.Сконфигурируйте библиотеку DI для загрузки зависимостей из вашей дополнительной библиотеки DLL (если она есть).

Castle.Windsor имеет слабо связанный интерфейс ведения журнала (средство ведения журнала ), которое вы можете найти для второгоoption.

Также существует своего рода спектр между ними.

Это суть внедрения логгера как зависимости (хотя в этом примере я не использую никаких библиотек):

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 голос
/ 01 июня 2011

Это звучит как случай потенциального использования для Managed Extensibility Framework (MEF), доступного в .NET 4.0.

0 голосов
/ 01 июня 2011

Эту проблему можно решить с помощью инверсии управления .

Интерфейс IErrorLogger с методом LogError (Exception) реализован с помощью:

  • DbErrorLogger
  • FileErrorLogger

Используя некоторую инверсию управляющего API, например Castle Windsor, вы по-разному конфигурируете компонент IErrorLogger, поскольку в ASP.NET 4.0 есть Web.debug.config и Web.release.config , позволяющий настроить некоторые веб-приложения для сценариев отладки и выпуска в веб.

В конце дня, когда вы измените компиляцию на выпуск, FileErrorLogger будетРеализация IErrorLogger.

Подробнее читайте по этой ссылке: http://docs.castleproject.org/Windsor.MainPage.ashx

0 голосов
/ 01 июня 2011

Звучит так, будто на самом деле все зависит от того, как вы создаете свою запись в журнале. Вместо того, чтобы пытаться сделать это в зависимости от того, присутствует ли DLL или нет, просто разрешите создать экземпляр класса, который будет частью общей конфигурации. Пусть пользователь (под которым я имею в виду того, кто его устанавливает) указывает ExtendedLogWriter, если он хочет и если у него есть Foo.Private.dll, и SimpleLogWriter в противном случае. Существуют различные контейнеры IoC, которые облегчили бы эту задачу.

...