C# 使用DI在WPF应用程序中使用WCF服务的正确方法
问题在于,与MVC中的控制器相反,WPF中的MVVM模型是实例化的,并且永远存在。实际上,这对我来说意味着,如果我的VIE模型中有私人财产,我的代理将长期开放,例如:C# 使用DI在WPF应用程序中使用WCF服务的正确方法,c#,wpf,wcf,mvvm,dependency-injection,C#,Wpf,Wcf,Mvvm,Dependency Injection,问题在于,与MVC中的控制器相反,WPF中的MVVM模型是实例化的,并且永远存在。实际上,这对我来说意味着,如果我的VIE模型中有私人财产,我的代理将长期开放,例如: //Some example after googling for "consuming wcf services in wpf app~" private FootballerServices.FootballerServiceClient footballersService = null; private void Win
//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的新类,在其中封装所有方法调用:
私有无效按钮\u单击(对象发送者,路由目标e)
{
var t=serviceWrapper.GetDataFromMyService();
(...)
}
和在用包装器:
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结合使用,就像这里回答的那样:
然而,我并不完全理解这个解决方案。
我的理解是,事情是这样发生的:
DI解析我的ServiceClient的一个实例,在执行超出使用解析实例的方法的范围后,DI容器将处理该实例—不需要抽象工厂模式。
显然,我的理解是错误的
问题:在这种情况下,正确的做法是什么?您很可能不想注入WCF客户端,因为您只需要很短的时间。您可以注入一个工厂,它将在需要时返回服务 工厂界面可能如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
假设您正在通过构造函数注入此字段,并向类中添加一个私有只读字段,如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
然后,当您需要服务时,您可以执行以下操作:
var myService = _myServiceFactory.Create();
try
{
// do something with the service
}
finally
{
_myService.Release(myService);
}
一个很大的好处是类完全依赖于抽象。它不“知道”服务是由WCF客户机实现的,或者工厂正在调用DI容器。您可以使用模拟的IMyService
对其进行测试。如果您的类直接创建自己的WCF客户端,那么这是不可能的
您没有提到您正在使用哪个容器,但其中许多容器将为您创建WCF客户端以实现接口
- -目前缺乏他们的文件。如果你使用温莎,我可以提供更多细节
下面是使用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,您需要添加nuget包,即Windsor加上一些用于处理WCF服务的附加类
您的容器注册可能如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
(不要引用我关于如何正确关闭WCF客户端的详细信息。已经有一段时间了,我已经生锈了。)但习惯了使用温莎之后,就容易多了 这样做之后,假设
IMyService
将返回特定数据,那么如果您想对类进行单元测试,该怎么办?现在,它非常易于使用,或者只需编写测试双类,如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
公共类MyServiceDouble:IMyService
{
公共IEnumerable GetSomeData()
{
返回新的[]{“x”、“y”、“z”};
}
}
公共类MyServiceFactoryDouble:IMyServiceFactory
{
公共IMyService Create()
{
返回新的MyServiceDouble();
}
公共作废发布(已创建IMyService)
{
//没什么要清理的。
}
}
因为您的类不了解任何有关
IMyService
——它不知道“正常”实现是一个WCF客户端——很容易用其他东西替换它。您很可能不想注入WCF客户端,因为您只需要很短的时间。您可以注入一个工厂,它将在需要时返回服务
工厂界面可能如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
假设您正在通过构造函数注入此字段,并向类中添加一个私有只读字段,如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
然后,当您需要服务时,您可以执行以下操作:
var myService = _myServiceFactory.Create();
try
{
// do something with the service
}
finally
{
_myService.Release(myService);
}
一个很大的好处是类完全依赖于抽象。它不“知道”服务是由WCF客户机实现的,或者工厂正在调用DI容器。您可以使用模拟的IMyService
对其进行测试。如果您的类直接创建自己的WCF客户端,那么这是不可能的
您没有提到您正在使用哪个容器,但其中许多容器将为您创建WCF客户端以实现接口
- -目前缺乏他们的文件。如果你使用温莎,我可以提供更多细节
下面是使用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,您需要添加nuget包,即Windsor加上一些用于处理WCF服务的附加类
您的容器注册可能如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
(不要引用我关于如何正确关闭WCF客户端的详细信息。已经有一段时间了,我已经生锈了。)但习惯了使用温莎之后,就容易多了 这样做之后,假设
IMyService
将返回特定数据,那么如果您想对类进行单元测试,该怎么办?现在,它非常易于使用,或者只需编写测试双类,如下所示:
public interface IMyServiceFactory
{
IMyService Create();
void Release(IMyService created);
}
private readonly IMyServiceFactory _myServiceFactory;
container.AddFacility<TypedFactoryFacility>();
container.AddFacility<WcfFacility>();
container.Register(Component.For<IMyService>()
.AsWcfClient(WcfEndpoint.FromConfiguration("MyServiceEndpointName")));
container.Register(Component.For<IMyServiceFactory>().AsFactory());
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();
}
}
}
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.
}
}
公共类MyServiceDouble:IMyService
{
公共IEnumerable GetSomeData()
{
返回新的[]{“x”、“y”、“z”};
}
}
公共类MyServiceFactoryDouble:IMyServiceFactory
{
公共IMyService Create()
{
返回新的MyServiceDouble();