4

我不想注入行爲依賴關係,而是注入數據依賴關係 - 數據來自數據庫或其他服務調用。爲了達到這個目的,我的第一步是做類型到委託的綁定而不是類型到類型的綁定。到目前爲止,我認爲大多數.net國際奧委會容器可以做到這一點。價值提供者的惰性依賴注入(Unity,結構圖,Ninject ...)

但我期望許多數據注入會產生不需要的延遲,因爲這意味着很多往返數據存儲的往返行程。我寧願所有要注入的數據對象都會在一個請求中獲取。

我想知道是否有一個框架或庫,爲此,或示例代碼。

我相信一個框架或庫將通過不斷髮展我之前的提議,以便委託綁定...

  1. 每個地方的數據請求到線程本地存儲隊列滿足我的需要。
  2. 僅返回類型爲Lazy<T>。 IOC容器完成噴射全部Lazy<T>類型

後,不約而同地執行程序將執行Lazy<T>.Value代表之一。當發生這種情況時,整個數據請求隊列將同時發送並同時填充到TLS中的哈希表或字典中。因此,第一個Lazy<T>.Value命中會很慢,但是作爲IOC容器注入樹一部分的所有其他Lazy<T>項將會很快執行。

關於這種方法的思考?任何圖書館都這樣做?

回答

3

直接向需要它的消費者注入數據可能在某些情況下有效,但在大多數情況下,消費者通過查詢此數據(使用提供的參數詢問數據)確定他需要哪些數據。

對於那些可以直接注入數據的情況(您可以將它們視爲無參數查詢),直接注入數據會使您的DI配置非常複雜。以一個依賴於系統當前時間的消費者爲例。您可以將DateTime注入消費者(或甚至是Lazy<DateTime>)。另一位消費者可能需要當前用戶的出生日期,因此此消費者也取決於DateTime。但是現在你在系統中不明確,因爲DateTime依賴有兩個含義。 DI容器在處理這個問題上不好,爲了解決這個問題,你必須明確地告訴容器什麼DateTime對於每個需要它的消費者意味着什麼。這導致難以容納的脆性結構。

對於後一種情況(無參數查詢),解決方案是定義可以解析的無歧義接口。在上面的示例中,您可以定義一個ITimeProvider接口和一個IUserContext接口。每個消費者可以依賴正確的界面。

對於前一種情況(參數化查詢),您不需要這樣的框架;你需要適當的設計。

您正在討論查詢數據庫和Web服務,並需要緩存返回的數據的方法。因此,您需要的是定義查詢的抽象,並且可以以可插入的方式將緩存和其他cross-cutting concerns應用於其中,並且無需對代碼進行任何更改。

做到這一點的一個有效方法是通過定義限定查詢對象(查詢的輸入參數)+返回類型,和一個接口,定義用於處理該查詢的邏輯接口:

public interface IQuery<TResult> 
{ 
} 

public interface IQueryHandler<TQuery, TResult> 
    where TQuery : IQuery<TResult> 
{ 
    TResult Handle(TQuery query); 
} 

有了這些抽象可以定義一個查詢對象是這樣的:

public class FindUsersBySearchTextQuery : IQuery<User[]> 
{ 
    public string SearchText { get; set; } 
    public bool IncludeInactiveUsers { get; set; } 
} 

此對象定義由搜索文本查找用戶,並允許包含或不活動的用戶的排斥的查詢,並且查詢結果是陣列User個物體。

,執行該查詢可以實現如下的邏輯:

public class FindUsersBySearchTextQueryHandler 
    : IQueryHandler<FindUsersBySearchTextQuery, User[]> 
{ 
    private readonly NorthwindUnitOfWork db; 

    public FindUsersBySearchTextQueryHandler(
     NorthwindUnitOfWork db) 
    { 
     this.db = db; 
    } 

    public User[] Handle(FindUsersBySearchTextQuery query) 
    { 
     return (
      from user in this.db.Users 
      where user.Name.Contains(query.SearchText) 
      where user.IsActive || query.IncludeInactiveUsers 
      select user) 
      .ToArray(); 
    } 
} 

爲什麼究竟該解決你有問題嗎?這解決了您的問題,因爲消費者可以依賴IQueryHandler<FindUsersBySearchTextQuery, User[]>界面,而您可以用decorators包裝IQueryHandler<T>實施,而無需任何人知道。編寫緩存導致胎面局部stogage一個裝飾是一個沒有腦子:

public class TlsCachingQueryHandlerDecorator<TQuery, TResult> 
    : IQueryHandler<TQuery, TResult> 
    where TQuery : IQuery<TResult> 
    where TResult : class 
{ 
    [ThreadStatic] 
    private static TResult cache; 

    private readonly IQueryHandler<TQuery, TResult> decorated; 

    public ValidationQueryHandlerDecorator(
     IQueryHandler<TQuery, TResult> decorated) 
    { 
     this.decorated = decorated; 
    } 

    public TResult Handle(TQuery query) 
    { 
     return cache ?? (cache = this.decorated.Handle(query)); 
    } 
} 

任何固體DI容器,您可以註冊這些裝飾,讓你註冊的裝飾有條件的(基於類型的信息裝飾類型)。這使您可以將此緩存修飾器僅放置在可以安全緩存的類型上(根據您的條件)。

您可以在這篇文章中找到關於此模型的更多信息:Meanwhile… on the query side of my architecture