2009-12-21 27 views
10

Tôi có giao diện sau:Sử dụng StructureMap với log4net wrapper

public interface ILogger 
{ 
    void Debug(string message, params object[] values); 
    void Info(string message, params object[] values); 
    void Warn(string message, params object[] values); 
    void Error(string message, params object[] values); 
    void Fatal(string message, params object[] values); 
} 

và thực hiện như sau:

public class Log4netLogger : ILogger 
{ 
    private ILog _log; 

    public Log4netLogger(Type type) 
    { 
     _log = LogManager.GetLogger(type); 
    } 

    public void Debug(string message, params object[] values) 
    { 
     _log.DebugFormat(message, values); 
    } 

    // other logging methods here... 

} 

Ý tưởng của tôi là sử dụng StructureMap để nhanh chóng lớp Log4netLogger với việc sử dụng Type của lớp đã đăng nhập. Tuy nhiên, tôi không thể cho cuộc sống của tôi tìm ra cách để vượt qua loại của lớp gọi để structuremap để nó có thể được truyền cho constructor của việc thực hiện đăng nhập. Bất kỳ lời khuyên nào về cách làm điều đó (hoặc một cách tốt hơn) sẽ được đánh giá cao nhất.

Trả lời

1

Nếu tham số kiểu là theo ngữ cảnh cụ thể, tôi không nghĩ rằng điều này sẽ hoạt động như được hiển thị. Nếu bạn cần phải vượt qua một cái gì đó bối cảnh cụ thể trong các nhà xây dựng, bạn có nhiều khả năng sẽ phải tạo ra một giao diện nhà máy và thực hiện trả về một thể hiện của các ILogger:

public interface ILoggerFactory 
{ 
    ILogger Create(Type type); 
} 

public class LoggerFactory : ILoggerFactory 
{ 
    public ILogger Create(Type type) 
    { 
     return new Log4netLogger(type); 
    } 
} 

Nó có thể là có thể bootstrap StructureMap để cung cấp ví dụ bạn muốn dựa trên loại, nhưng điều đó giả định số lượng hạn chế các loại mà bạn biết trước.

+1

Sự cần thiết cho các nhà máy khi sử dụng structuremap thường có thể được loại bỏ bằng cách sử dụng "ConstructedBy" với lambda làm phương pháp nhà máy. http://structuremap.sourceforge.net/InstanceExpression.htm#section13 – KevM

1

Tôi thực sự cần thoát khỏi thói quen trả lời câu hỏi của riêng mình, nhưng đối với những người chạy qua nó, đây là câu trả lời.

return ObjectFactory.With(type).GetInstance<T>(); 

Tôi thực sự có một wrapper để StructureMap (để tránh phơi bày sự phụ thuộc StructureMap để ứng dụng của tôi) trông giống như sau:

public static class ServiceManager 
{ 
    public static T Get<T>() 
    { 
     return ObjectFactory.GetInstance<T>(); 
    } 

    public static T Get<T>(Type type) 
    { 
     return ObjectFactory.With(type).GetInstance<T>(); 
    } 
} 

Bất cứ lúc nào trong mã tôi cần một logger, tôi gọi như sau:

ServiceManager.Get<ILogger>(GetType()).Info("Logging page view..."); 
+1

Tôi thực sự không nghĩ rằng có bất cứ điều gì sai trái khi xem xét logger một dịch vụ toàn cầu (vì nó thường cắt ngang), nhưng điều này tạo ra một phụ thuộc tĩnh trên ServiceManager của bạn. Tôi không nói rằng giải pháp của bạn là sai (xa nó), nhưng nó có vẻ hơi giống nó có thể có xu hướng hướng tới định vị dịch vụ toàn cầu "anti-pattern". Về cơ bản sự phụ thuộc của bạn vào ILogger (hoặc ILoggerFactory) là (hoặc có thể) không còn rõ ràng nữa. –

+0

Điểm thú vị Phil. Tôi không chắc chắn những gì thay thế sẽ được mặc dù (kiến nghị kiến ​​trúc trên IoC là thưa thớt, thực sự). Trong trường hợp của tôi, lớp là một HttpHandler cần truy cập vào ILogger mà nó yêu cầu từ ServiceManager. Tôi sẽ triển khai như thế nào? – Chris

+0

Tôi hoàn toàn đồng ý về đề xuất kiến ​​trúc bị thưa thớt và câu hỏi của bạn IMHO là * * những rào cản phổ biến nhất gặp phải khi họ bắt đầu với khung DI. Tạo một nhà máy trừu tượng là câu trả lời hay nhất mà tôi đã đưa ra, và tôi thường triển khai nhà máy bằng StructureMap (ObjectFactory.GetInstance) để các phụ thuộc tiếp tục xuống chuỗi vẫn có thể được quản lý container. Điều này có thể không * hoàn hảo *, nhưng ít nhất phụ thuộc được giữ rõ ràng. –

23

Chúng tôi sử dụng một trình bao bọc ILogger tương tự quanh log4net và thường sử dụng công cụ xây dựng. Chúng tôi sử dụng một máy đánh chặn như một phương pháp nhà máy chịu trách nhiệm tạo ra Logger. Đây là đăng ký điển hình của chúng tôi để thiết lập đăng nhập.

public class CommonsRegistry : Registry 
{ 
    public CommonsRegistry() 
    { 
     For<ILogger>() 
      .AlwaysUnique() 
      .TheDefault.Is.ConstructedBy(s => 
      { 
       if (s.ParentType == null) 
        return new Log4NetLogger(s.BuildStack.Current.ConcreteType); 

       return new Log4NetLogger(s.ParentType); 
      }); 

     var applicationPath = Path.GetDirectoryName(Assembly.GetAssembly(GetType()).Location); 
     var configFile = new FileInfo(Path.Combine(applicationPath, "log4net.config")); 
     XmlConfigurator.ConfigureAndWatch(configFile); 
    } 
} 

Kiểm tra null kiểu gốc là cần thiết khi có phụ thuộc vào loại cụ thể.

Phần còn lại là công cụ thiết lập log4net tùy chọn.

Một điều tôi thích về thiết lập này là khả năng sử dụng trình ghi nhật ký trống để kiểm tra đơn vị.

+0

Thú vị, tôi sẽ phải thử điều này. Cảm ơn! – Chris

+0

Điều này thực sự thú vị. Tôi cũng thấy bình luận của bạn về câu trả lời của tôi. Điều này có hiệu quả nếu sự phụ thuộc của ctor là bất cứ thứ gì bên ngoài kiểu của lớp gọi? Rất thích nhìn thấy một bài đăng blog về phụ thuộc ctor theo ngữ cảnh cụ thể, vì đây phải là câu hỏi được hỏi nhiều nhất về việc sử dụng khung DI. –

+0

Ngoài ra, tôi đang đấu tranh với việc liệu giải pháp này làm cho sự phụ thuộc ít rõ ràng hơn. Nếu việc xây dựng thực sự đòi hỏi một nhà máy, có nên hay không "ẩn" nhà máy trong mã cấu hình, thay vì làm cho sự phụ thuộc vào một nhà máy trừu tượng rõ ràng? (Tôi có nghĩa là đây là một câu hỏi lý thuyết, không nhất thiết phải là giải pháp tốt nhất cho Chris hoặc cho đăng nhập mỗi lần). –

Các vấn đề liên quan