2016-03-01 81 views
0

在开发允许编辑文章和载体(托盘,货架)数据(以CRUD方式)的WPF应用程序中,我正在寻找如何管理WPF应用程序的生命周期WCF客户端连接到包含实际数据的服务。如何在WPF应用程序中管理WCF客户端的生命周期

我更喜欢使用使用Caliburn Micro和StructureMap或Castle Windsor的MVVM方法。

我的主要问题不是创建WCF客户端渠道或工厂,而是更重要的是使用后的清理。我打算在服务器端使用per-request生命周期,因此我需要根据每个请求创建和处理我的客户端。这样我心里有以下几点:

public class Article 
{ 
    public int Id { get; set; } 
    public string ArticleId { get; set; } 
} 

[ServiceContract] 
public interface IArticleCrud 
{ 
    [OperationContract] 
    Article CreateArticle(string articleId); 
    [OperationContract] 
    void Delete(int articleId); 
} 

public class ArticlesViewModel 
{ 
    private readonly Func<IArticleCrud> articleCrudFactory; 

    public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory) 
    { 
     this.articleCrudFactory = articleCrudFactory; 
    } 

    public void Delete(int articleId) 
    { 
     // Doesn't work since IArticleCrud is not IDisposable 
     using (var crud = articleCrudFactory()) 
     { 
      crud.Delete(articleId); 
     } 
    } 
} 

正如评论,这将无法工作,因为IArticleCrud不是IDisposable的注意。 IArticleCrud用于在客户端创建ChannelFactory,为实现相同接口的服务生成代理。我会高兴地换出这个代码如下:

public class DeleteArticleCommand : IRequest 
{ 
    public int Id { get; set; } 
} 

public class ArticlesViewModel 
{ 
    private readonly IMediator mediator; 

    public ArticlesViewModel(IMediator mediator) 
    { 
     this.mediator = mediator; 
    } 

    public void Delete(int articleId) 
    { 
     mediator.Send(new DeleteArticleCommand {Id = articleId}); 
    } 
} 

public class DeleteArticleCommandHandler : RequestHandler<DeleteArticleCommand> 
{ 
    private readonly IArticleCrud articleCrud; 

    public DeleteArticleCommandHandler(IArticleCrud articleCrud) 
    { 
     this.articleCrud = articleCrud; 
    } 

    protected override void HandleCore(DeleteArticleCommand message) 
    { 
     articleCrud.Delete(message.Id); 
    } 
} 

但是,因为我还没有处理处置WCF客户端这并没有解决我的问题。然而,我可以让IMediator在发送操作上创建一个新的嵌套容器,并在发送操作完成后将其放置,但它似乎很麻烦。

我是否弄错了所有的错误,还是仅仅需要付出很大的努力才能从WPF应用程序执行WCF调用?

作为一个旁注,我将拥有比这些少数几个CRUD服务更多的服务,所以在我的CRUD服务中解决这个问题的可能实用的解决方案不是一种选择。

+0

讲述的是WCF会话寿命这个问题? – Jasper

+0

不,我想通过会话PerRequest保持WCF层尽可能薄。 – mycroes

回答

0

我已经处理了相同的问题(在WPF应用程序中使用WCF服务),并希望使用ServiceInterface而不是ServiceClient(这是IDisposable,可用于使用块)。

一个解决关闭连接的是接口转换为客户型和调用.Close() - 方法:

public class Article 
{ 
    public int Id { get; set; } 
    public string ArticleId { get; set; } 
} 

public interface IArticleCrud 
{ 
    Article CreateArticle(string articleId); 
    void Delete(int articleId); 
} 

public class ArticlesViewModel 
{ 
    private readonly Func<IArticleCrud> articleCrudFactory; 

    public ArticlesViewModel(Func<IArticleCrud> articleCrudFactory) 
    { 
     this.articleCrudFactory = articleCrudFactory; 
    } 

    public void Delete(int articleId) 
    { 
     //Using-Block doesn't work since IArticleCrud is not IDisposable 
     var crud = articleCrudFactory(); 
     crud.Delete(articleId); 

     if (crud is ArticleCrud) 
      (crud as ArticleCrud).Close(); 
    } 
} 

你还可以创建你articleCrudFactory静态方法将被关闭的IArticleCrud:

public static void CloseInterface(IArticleCrud crud) 
{ 
    if (crud is ArticleCrud) 
     (crud as ArticleCrud).Close(); 
    else { ... } 
} 
+0

我认为你可能意味着转换为'IChannel'或'ICommunicationObject'并关闭它,我没有在'IArticleCrud'上的'Close()',并且我甚至没有客户端中的'ArticleCrud'(记住,它只是一个WCF代理)。另外,'Close()'对我来说不够安全(需要尝试/捕获并在出错时中止)。 – mycroes

+0

请编辑您的问题,并指定您只使用WCF代理或其他人可能认为您正在实施该服务与“右键点击添加新的ServiceReference”,然后生成接口和客户端(IArticleCrud和ArticleCrudClient在你的情况下)。 –

0

我与WCF和MVVM和其非常容易已经完成它(如果我得到正确的您的问题):

public interface IRequest 
{ 
} 

public interface IRequestHandler<in TCommand> where TCommand : IRequest 
{ 
    void HandleCore(TCommand command); 
} 

public class DeleteArticleCommand : IRequest 
{ 
    public int Id { get; set; } 
} 

public class ArticlesViewModel 
{ 
    private readonly IRequestHandler<DeleteArticleCommand> _handler; 

    public ArticlesViewModel(IRequestHandler<DeleteArticleCommand> handler) 
    { 
     _handler = handler; 
    } 

    public void Delete(int articleId) 
    { 
     _handler.HandleCore(new DeleteArticleCommand { Id = articleId }); 
    } 
} 

//On client side 
public sealed class WcfServiceCommandHandlerProxy<TCommand> 
    : IRequestHandler<TCommand> where TCommand : IRequest 
{ 
    public void HandleCore(TCommand command) 
    { 
     using (var service = new ActuaclWcfServiceClient()) 
     { 
      service.Send(command); //Or however you are working with you WCF client 
     } 
    } 
} 

//Somewhere on server side 
public class DeleteArticleCommandHandler : IRequestHandler<DeleteArticleCommand> 
{ 
    private readonly IArticleCrud _articleCrud; 

    public DeleteArticleCommandHandler(IArticleCrud articleCrud) 
    { 
     _articleCrud = articleCrud; 
    } 

    public void HandleCore(DeleteArticleCommand message) 
    { 
     articleCrud.Delete(message.Id); 
    } 
} 

只需注册您的IRequestHandler接口与WcfServiceCommandHandlerProxy类型实现,这就是它:

//May vary :) 
Register(typeof (ICommandHandler<>), typeof (WcfServiceCommandHandlerProxy<>)) 
+0

我打算'IArticleCrud'作为WCF服务的ServiceContract,但更重要的是您的WcfServiceCommandHandlerProxy实现控制着服务的创建,我希望从IoC获得它来从一个地方控制它,这将我带回原始问题。 – mycroes

+0

@mycroes这个'WcfServiceCommandHandlerProxy'只做一件事 - 创建和配置WCF客户端。如果你需要更多的责任装饰它,并与另一个类包装这一个。执行后不应该改变WcfServiceCommandHandlerProxyclass。 IoC现在对生活无所作为。 IoC只知道'WcfServiceCommandHandlerProxyclass'实现'IRequestHandler'。 – Szer

+0

'ActualWcfServiceClient()'在其他地方强加约束,例如我需要为地址/绑定执行XML配置,或者将它们放在这里。此外,我不使用生成的WCF客户端,但我使用服务接口来生成代理。 – mycroes

相关问题