原文鏈接:https://blazor-university.com/dependency-injection/component-scoped-dependencies/owning-multiple-dependencies-the-right-way/
擁有多個依賴項:正確的方式
在上一節[1]中,我們看到了將多個擁有的依賴項注入組件的錯誤方法。本節將演示解決問題的正確方法。
如前所述,OwningComponentBase<T>
類組件將創建自己的依賴容器并在該容器中解析 T
的實例,因此 T
的實例對于我們的組件是私有的。
如果我們需要我們的組件私有地擁有多種依賴類型的實例,那么我們必須做更多的工作。為此,我們需要使用非泛型 OwningComponentBase
類。與通用版本一樣,此組件將創建自己的依賴容器,該容器將在組件的生命周期內存在。但是,它不會為我們實際解析任何依賴項,而是讓我們訪問其依賴項容器,以便我們可以解析我們需要的任何類型的實例。
示例
源代碼[2]
首先,創建一個新的 Blazor 應用程序。然后,就像我們之前所做的那樣,我們將創建一些可以注入的類,這些類將使用狀態成員來跟蹤已創建的類實例的數量。
創建以下接口
public?interface?IOwnedDependency1
{public?int?InstanceNumber?{?get;?}
}public?interface?IOwnedDependency2
{public?int?InstanceNumber?{?get;?}
}
然后創建實現這些接口的類。我將只顯示第一類的代碼,第二類將是相同的。
public?class?OwnedDependency1?:?IOwnedDependency1
{private?static?volatile?int?PreviousInstanceNumber;public?int?InstanceNumber?{?get;?}public?OwnedDependency1(){InstanceNumber?=System.Threading.Interlocked.Increment(ref?PreviousInstanceNumber);}
}
將接口 + 它們的實現類注冊為 Scoped
(如果需要提醒您,請參閱比較依賴范圍[3])。
接下來,編輯 Index.razor 頁面,以便我們應用程序的用戶可以通過單擊復選框來切換組件。
@page?"/"<input?id="show-component"?type=checkbox?@bind=ShowComponent?/>
<label?for="show-component">Show?component</label>@if?(ShowComponent)
{<MyOwningComponent?/>
}@code
{bool?ShowComponent?=?false;
}
當 ShowComponent
為 true
時,我們的標記將創建 MyOwningComponent
的一個實例并渲染它。接下來,我們將創建 MyOwningComponent
。
OwningComponentBase
在 Shared 文件夾中,創建一個名為 MyOwningComponent
的新 Razor 組件。我們將從 OwningComponentBase
中派生此組件。
@inherits?OwningComponentBase
然后創建一些類字段來保存依賴項。
@code
{private?IOwnedDependency1?OwnedDependency1;private?IOwnedDependency2?OwnedDependency2;
}
解決擁有的依賴關系
OwningComponentBase
創建的私有依賴性容器通過其ScopedServices
屬性提供給我們。
protected?IServiceProvider?ScopedServices?{?get;?}
我們可以使用這個 IServiceProvider
來解析組件所擁有的私有依賴容器中的依賴實例。
@inherits?OwningComponentBase
@using?Microsoft.Extensions.DependencyInjection<div>OwnedDependency1.InstanceNumber?=?@OwnedDependency1.InstanceNumber
</div>
<div>OwnedDependency2.InstanceNumber?=?@OwnedDependency2.InstanceNumber
</div>@code
{private?IOwnedDependency1?OwnedDependency1;private?IOwnedDependency2?OwnedDependency2;protected?override?void?OnInitialized(){OwnedDependency1?=ScopedServices.GetService<IOwnedDependency1>();OwnedDependency2?=ScopedServices.GetService<IOwnedDependency2>();}
}
第 1 行
從
OwningComponentBase
繼承來給我們自己的私有依賴容器。第 2 行
使用
DependencyInjection
命名空間,因此我們可以在IServiceProvider
上使用GetService<T>
擴展方法。第 19 & 21 行
使用
OwningComponentBase.ScopedServices
屬性來解析組件所需的依賴項實例。第 6 & 9 行
顯示為我們創建的依賴項的實例號。
運行示例
如果我們運行示例應用并勾選復選框,我們將看到以下輸出。
OwnedDependency1.InstanceNumber = 1
OwnedDependency2.InstanceNumber = 1
取消勾選該復選框以允許刪除我們的組件,然后再次勾選該復選框以讓 Blazor 創建 MyOwningComponent
的新實例。渲染輸出現在應該如下所示。
OwnedDependency1.InstanceNumber = 2
OwnedDependency2.InstanceNumber = 2
這表明,每次創建組件時,我們在組件的 OnInitialized
方法中解析的兩個依賴項都是新的實例。
依賴生命周期
OwningComponentBase
類實現 IDisposable
接口。當從OwningComponentBase
派生的任何組件不再呈現時,Blazor 將在 OwningComponentBase
上執行 Dispose
方法。
組件上的 Dispose
方法將對其擁有的私有依賴項容器調用Dispose
。反過來,該容器創建的任何實現 IDisposable
的對象實例也將執行其 Dispose
方法。
要演示這種行為,請對應用程序進行以下更改。
首先,在我們的組件上重寫 Dispose(bool isDisposing)
,并讓它在被釋放時輸出日志。
public?void?Dispose()
{System.Diagnostics.Debug.WriteLine("Disposing?"?+?GetType().Name);
}
然后,對于我們的每個依賴類(OwnedDependency1
和 OwnedDependency2
),讓它們實現 IDisposable
,并且再次讓它們在執行 Dispose
時輸出日志。
public?class?OwnedDependency1?:?IOwnedDependency1,?IDisposable{...?Other?code?omitted?for?brevity?...public?void?Dispose(){System.Diagnostics.Debug.WriteLine($"Created?{GetType().Name}?instance?{InstanceNumber}");}}
我們還可以在類的構造函數中添加一些日志記錄。
現在運行應用程序并切換復選框將輸出類似于以下內容的日志文本。
Created MyOwningComponent
Created OwnedDependency1 instance 1
Created OwnedDependency2 instance 1
Disposing OwnedDependency2 instance 1
Disposing OwnedDependency1 instance 1
Disposing MyOwningComponent
Created MyOwningComponent
Created OwnedDependency1 instance 2
Created OwnedDependency2 instance 2
Disposing OwnedDependency2 instance 2
isposing OwnedDependency1 instance 2
Disposing MyOwningComponent
結論
當您的組件只需要擁有一個依賴項時,從 OwningComponentBase<T>
派生;當您的組件需要擁有多個依賴項時,從非泛型 OwningComponentBase
派生。
盡管解析組件依賴項實例的過程是一個手動過程,但不需要處理任何創建的依賴項,因為組件的依賴項容器將在 OwningComponentBase.Dispose
時處理它們。
參考資料
[2]
源代碼: https://github.com/mrpmorris/blazor-university/tree/master/src/DependencyInjection/OwningMultipleDependenciesTheRightWay