代码之家  ›  专栏  ›  技术社区  ›  mafu

WCF:如何在优雅地关闭连接时发送数据?

wcf
  •  0
  • mafu  · 技术社区  · 14 年前

    我有一个提供登录方法的WCF服务。客户端需要调用此方法(因为它是唯一的IsInitiating=true)。此方法应返回一个描述在任何情况下调用成功的字符串。如果登录失败,则应关闭连接。

    问题在于关闭的时间。我想发送返回值,然后立即关闭连接。

    string Login (string name, string pass)
    {
        if (name != pass) {
            OperationContext.Current.Channel.Close ();
            return "fail";
        }
        else {
            return "yay";
        }
    }
    

    这个 MSDN 声明 Close 在频道上

    使ICommunicationObject 优雅地从开放的过渡 状态转换为关闭状态。关闭 方法允许任何未完成的工作 返回前完成。为了 示例,完成发送任何缓冲区 消息)。

    这对我不起作用(或者我的理解错误),因为close是立即执行的-wcf不等待login方法完成执行并返回字符串,而是提前关闭连接。

    因此,我假设调用close不会等待运行方法完成。现在,我怎么还能返回一个值呢? 然后 关闭?

    在绝望中,我尝试了以下方法,但这并不是一个严肃的解决办法。

    new Thread (() => {
        Thread.Sleep (100);
        OperationContext.Current.Channel.Close ();
    }).Start ();
    
    2 回复  |  直到 14 年前
        1
  •  6
  •   Aaronaught    14 年前

    当文档说“优雅”时,它实际上是在讨论何时调用 ICommunicationObject.Close 客户机 一边。上 服务 另一方面,如果您试图在客户机仍在等待响应时关闭通道,您将遇到不好的情况。

    客户机会感到困惑,不想确认关闭,服务器就会超时。 Close 尝试,在您的情况下,它发生在工作线程上,而工作线程上未处理的异常不利于您的服务健康或您自己的健全性。

    您真正想要的并不是优雅的连接关闭,而是强制断开无法成功登录的客户机。为了做到这一点,您必须在操作完成时为注册一个事件处理程序, 之后 发送响应:

    public string Login(string name, string pass)
    {
        if (name != pass)
        {
            OperationContext.Current.OperationCompleted += LoginFailed;
            return "fail";
        }
        return "yay";
    }
    
    private void LoginFailed(object sender, EventArgs e)
    {
        OperationContext.Current.Channel.Abort();
    }
    

    这将执行我非常确定的操作—将“失败”发送回客户机,清除所有需要清理的内容,然后断开客户机连接,防止在会话中进行任何进一步的活动。

    顺便说一句,我不知道这与实际的服务代码有多接近,但是当您可以使用WCF的内置服务凭证系统时,在服务上使用“登录”方法有点多余。

        2
  •  0
  •   Danthar    14 年前

    为什么要关闭连接服务器端?我知道你想尽快清理资源。但是,为什么不使用WCF提供的可用限制(实例模式等)和超时选项来管理这一点呢?