如何在 WPF 应用程序中管理 WCF 客户端的生命周期

本文关键字:客户端 WCF 生命 周期 管理 WPF 应用程序 | 更新日期: 2023-09-27 18:36:49

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

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

我的主要问题不是创建 WCF 客户端通道或工厂,而是使用后的清理。我打算在服务器端使用每个请求的生命周期,因此我需要基于每个请求创建和处置我的客户端。因此,我想到了以下几点:

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不可识别。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 服务中解决此问题的可能务实的解决方案不是一种选择。

如何在 WPF 应用程序中管理 WCF 客户端的生命周期

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

关闭连接的解决方案之一是将接口强制转换为客户端类型并调用 .关闭()-方法:

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

你也可以在你的文章CrudFactory中创建一个静态方法,它将关闭你的IArticleCrud:

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

我已经用 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);
    }
}

只需注册要用WcfServiceCommandHandlerProxy类型实现的IRequestHandler接口,就是这样:

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