如何配置 WCF 服務以使用依賴注入容器(Castle Windsor)
這個例子有兩部分 - 一些用於將 Castle Windsor 新增到 WCF 服務的樣板步驟,然後是一個簡單,具體的例子來說明我們如何配置和使用 Windsor 的容器。
這使得這個例子有點長。如果你已經瞭解使用 DI 容器,那麼你可能只關心樣板步驟。如果使用 DI 容器是不熟悉的,那麼它需要更多一點 - 看到整個工作從頭到尾 - 在它有意義之前。
鍋爐步驟
-
將 Castle Windsor WCF 整合工具 Nuget 包新增到你的 WCF 服務應用程式。這將新增對 Castle Windsor 的引用以及專門用於 WCF 服務的一些元件。
-
將全域性應用程式類(global.asax)新增到專案中:新增>新項> Visual C#> Web>全域性應用程式類。
必須從Application_Start
方法呼叫配置容器的程式碼。為了保持組織有序,我們可以將所有容器配置放在一個單獨的類中。我們沒有。沒關係。在不同的例子中,你會看到不同的做法。重要的是它是從Application_Start
方法呼叫的,因為那是你的組合根 - 應用程式啟動的地方。我們的想法是在應用程式啟動時配置容器,然後再從不直接觸控它。它只是留在後臺完成它的工作。 -
建立一個類來配置容器。這有兩件事:
ContainerInstance.AddFacility<WcfFacility>()
告訴 Windsor 的 WCF 程式碼在建立 WCF 服務的例項時使用此特定容器。ContainerInstance.Install(FromAssembly.This())
告訴 Windsor 掃描This
程式集(換句話說,你的 WCF 專案),尋找實現IWindsorInstaller
的類。這些類將提供說明,告訴容器如何解決依賴關係。 (我們稍後會建立一個。)
public static class Container
{
private static readonly IWindsorContainer ContainerInstance = new WindsorContainer();
public static void Configure()
{
ContainerInstance.AddFacility<WcfFacility>();
ContainerInstance.Install(FromAssembly.This());
}
}
- 在 global.asax 中從
Application_Start
呼叫此方法:
public class Global : System.Web.HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
Container.Configure();
}
}
- 建立安裝程式。這只是一個實現
IWindsorInstaller
的類。這個是空的。它沒有做任何事情。我們將在幾個步驟中新增到此類。當我們呼叫ContainerInstance.Install(FromAssembly.This())
時,ContainerInstance
會傳遞給Install
方法,以便我們可以在容器中註冊依賴項。
public class WindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
// Nothing here yet!
}
}
- 在你建立的任何 WCF 服務的標記中,新增此指令。這表明應用程式將使用 Windsor 的 WCF 工具來建立服務的例項,這反過來意味著在建立例項時可以注入依賴項。
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration"
這結束了用於設定服務以使用 Castle Windsor 依賴注入容器的樣板步驟
但是除非我們為依賴注入配置至少一個 WCF 服務,否則該示例並不完整。其餘的不是樣板,只是一個簡單,具體的例子。
- 建立一個名為
GreetingService.svc
的新 WCF 服務。 - 編輯標記。它應該如下所示:
<%@ ServiceHost Language="C#" Debug="true"
Service="WcfWindsorDocumentation.GreetingService"
CodeBehind="GreetingService.svc.cs"
Factory="Castle.Facilities.WcfIntegration.DefaultServiceHostFactory, Castle.Facilities.WcfIntegration"
%>
- 用這個代替
IGreetingService
(服務合同):
[ServiceContract]
public interface IGreetingService
{
[OperationContract]
string GetGreeting();
}
- 用此程式碼替換
GreetingService
(在 GreetingService.svc.cs 中)。請注意,建構函式需要一個IGreetingProvider
的例項,我們需要注入容器。
public class GreetingService : IGreetingService
{
private readonly IGreetingProvider _greetingProvider;
public GreetingService(IGreetingProvider greetingProvider)
{
_greetingProvider = greetingProvider;
}
public string GetGreeting()
{
return _greetingProvider.GetGreeting();
}
}
- 新增
IGreetingProvider
的這個實現。它還有一些自己的依賴項,我們需要容器供應。這些類的細節並不太重要。他們只是想創造一些易於理解的東西。
public interface IGreetingProvider
{
string GetGreeting();
}
public interface IComputerNameProvider
{
string GetComputerName();
}
public class ComputerNameGreetingProvider : IGreetingProvider
{
private readonly IComputerNameProvider _computerNameProvider;
public ComputerNameGreetingProvider(IComputerNameProvider computerNameProvider)
{
_computerNameProvider = computerNameProvider;
}
public string GetGreeting()
{
return string.Concat("Hello from ", _computerNameProvider.GetComputerName());
}
}
public class EnvironmentComputerNameProvider : IComputerNameProvider
{
public string GetComputerName()
{
return System.Environment.MachineName;
}
}
- 現在我們擁有了所需的所有類。剩下的就是在我們的容器中註冊依賴項。換句話說,我們將告訴容器需要建立哪些類,因此它知道如何構建
GreetingService
的例項。這段程式碼在我們的IWindsorInstaller
實現中(樣板程式碼的第 5 步)。
public class WindsorInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(
Component.For<IGreetingService, GreetingService>(),
Component.For<IGreetingProvider, ComputerNameGreetingProvider>(),
Component.For<IComputerNameProvider, EnvironmentComputerNameProvider>());
}
}
這告訴容器:
- 它負責在需要時建立
GreetingService
。 - 當它試圖創造
GreetingService
時,它將需要一個IGreetingProvider
。當它需要它應該建立一個ComputerNameGreetingProvider
。 - 當它試圖建立
ComputerNameGreetingProvider
時,該類需要一個IComputerNameProvider
。它應該建立一個EnvironmentComputerNameProvider
例項來滿足這種需求。
如果,在建立 GreetingService
或其中一個依賴項的過程中,它遇到了我們尚未註冊的依賴項的需求,它會讓我們知道一個有用的異常,就像這樣。
缺少依賴性。
元件 WcfWindsorDocumentation.ComputerNameGreetingProvider 依賴於 WcfWindsorDocumentation.IComputerNameProvider,無法解析。
確保依賴項在容器中作為服務正確註冊,或者作為內聯引數提供。
這意味著某些東西取決於 IComputerNameProvider
但是沒有註冊來實現這種依賴。
**這只是讓球滾動。**對於真實場景,正確配置和使用依賴注入容器還有很多其他功能。此示例僅涵蓋將 Windsor 新增到 WCF 服務應用程式的具體內容。如果你使用不同的容器,如 Autofac 或 Unity,你會發現雖然語法和細節各不相同,但原則上它們會做同樣的事情,你很容易發現相似之處。