[英]Proper way of consuming WCF Services in WPF Application using DI
問題在於,與MVC中的控制器相反,WPF中的MVVM模型被實例化並永久存在 。 實際上,這對我而言意味着,如果我在viemodel中擁有私有財產,則我的代理將長期開放,例如:
//Some example after googling for "consuming wcf services in wpf app~"
private FootballerServices.FootballerServiceClient footballersService = null;
private void Window_Loaded(object sender, RoutedEventArgs e)
{
footballersService = new FootballerServices.FootballerServiceClient();
try
{
FootballerBox.ItemsSource = footballersService.GetFootballers();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
如何正確解決該問題?
第一個解決方案:
private void button_Click(object sender, RoutedEventArgs e)
{
MyServicesClient proxy = new MyServicesClient();
try
{
MyServicesData data = proxy.GetDataFromMyService();
proxy.Close();
}
catch (FaultException ex)
{
MessageBox.Show("Fault Exception: " + ex.Message);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
然后,我可以創建一個新類,例如ServiceWrapper,在其中封裝所有方法調用:private void button_Click(object sender,RoutedEventArgs e){var t = serviceWrapper.GetDataFromMyService(); (...)}
在Service Wrapper中:
private void button_Click(object sender, RoutedEventArgs e)
{
MyServicesClient proxy = new MyServicesClient();
try
{
MyServicesData data = proxy.GetDataFromMyService();
proxy.Close();
}
catch (FaultException ex)
{
(...)
}
catch (Exception ex)
{
(...)
}
return data;
}
現在,最后一件事是將DI添加到該解決方案中
第二解決方案
我發現的另一種方法是對DI使用Abstract Factory模式,就像在這里被回答的那樣:
但是,我不完全了解此解決方案。 我的理解是,它是這樣發生的:DI解析了我的ServiceClient的一個實例,執行執行后,使用該解析的實例的方法的作用域之外,DI容器將處置該實例-不需要Abstract工廠模式。 顯然,我的理解是錯誤的。
問題:在這種情況下,正確的做法是什么?
您很可能不想注入WCF客戶端,因為您只需要很短的時間。 您可以注入的工廠將在需要時退還服務。
工廠界面可能如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
假設您要通過構造函數注入該變量,並向類中添加一個私有只讀字段,如下所示:
private readonly IMyServiceFactory _myServiceFactory;
然后,當您需要服務時,請執行以下操作:
var myService = _myServiceFactory.Create();
try
{
// do something with the service
}
finally
{
_myService.Release(myService);
}
一個很大的好處是您的類完全依賴於抽象。 它不“知道”該服務是由WCF客戶端實現的,或者工廠正在調用DI容器。 您可以使用IMyService
的模擬進行IMyService
。 如果您的類直接創建自己的WCF客戶端,那是不可能的。
您沒有提到要使用哪個容器,但是其中許多容器將為您創建WCF客戶端以實現接口。
關於Windsor的另一個不錯的細節是,它還將為您創建抽象工廠 。
以下是構成使用Windsor的示例實現的更多內容。 這假定您具有實現IMyService
的WCF服務。
這是服務接口,工廠接口以及使用它的類:
public interface IMyService
{
IEnumerable<string> GetSomeData();
}
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
public class ClassThatConsumesService
{
private readonly IMyServiceFactory _serviceFactory;
public ClassThatConsumesService(IMyServiceFactory myServiceFactory)
{
_serviceFactory = myServiceFactory;
}
public void MethodThatDoesSomething()
{
var service = _serviceFactory.Create();
try
{
var data = service.GetSomeData();
// do whatever
}
finally
{
_serviceFactory.Release(service);
}
}
}
然后是使用Windsor的一些實現細節的示例。 但是一個重要的細節是,以上所有內容都不取決於溫莎。 您可以使用其他DI容器執行此操作。 您甚至根本不需要DI容器。 您所有的班級都知道,它正在調用工廠來獲取服務的實例。
public class ClassThatConsumesService
{
private readonly IMyServiceFactory _serviceFactory;
public ClassThatConsumesService(IMyServiceFactory myServiceFactory)
{
_serviceFactory = myServiceFactory;
}
public void MethodThatDoesSomething()
{
var service = _serviceFactory.Create();
try
{
var data = service.GetSomeData();
// do whatever
}
finally
{
_serviceFactory.Release(service);
}
}
}
要使用Windsor,您需要添加Windsor WCF Facility nuget軟件包,即Windsor以及一些其他用於處理WCF服務的類。
您的容器注冊可能如下所示:
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
這將執行以下操作:
IMyService
的實現是WCF客戶端。 IMyServiceFactory
的實現是溫莎創建的工廠。 再次是該文檔。 。 這意味着您實際上並沒有創建實現IMyServiceFactory
的類。 容器可以做到這一點。 當您致電Create
工廠時,將創建客戶端。 當您調用Release
它將處置客戶端。 如果您願意,可以編寫自己的工廠實現,如下所示:
public class WcfClientMyServiceFactory : IMyServiceFactory
{
public IMyService Create()
{
return new MyServiceClient();
}
public void Release(IMyService created)
{
var client = (MyServiceClient) created;
try
{
try
{
client.Close();
}
catch
{
client.Abort();
}
}
finally
{
client.Dispose();
}
}
}
(關於如何正確關閉WCF客戶端的詳細信息,請不要引用我。已經有一段時間了,我很生銹。)
但是,習慣了使用Windsor會容易得多。
這樣,假設IMyService
將返回特定數據,如果您想對類進行單元測試,該IMyService
辦? 現在,使用Moq或像這樣編寫測試double類真的很容易:
public class MyServiceDouble : IMyService
{
public IEnumerable<string> GetSomeData()
{
return new [] {"x", "y", "z"};
}
}
public class MyServiceFactoryDouble : IMyServiceFactory
{
public IMyService Create()
{
return new MyServiceDouble();
}
public void Release(IMyService created)
{
// Nothing to clean up.
}
}
因為您的班級對IMyService
-它不知道“正常”實現是WCF客戶端-因此很容易用其他東西替換它。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.