C# 使用DI在WPF应用程序中使用WCF服务的正确方法

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

问题在于,与MVC中的控制器相反,WPF中的MVVM模型是实例化的,并且永远存在。实际上,这对我来说意味着,如果我的VIE模型中有私人财产,我的代理将长期开放,例如:

//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();