WCF和确认 - 我需要向客户端发送“好的,收到了”吗?

10
如果我有数百/数千台客户端计算机向我的服务器WCP,那么我应该用“200 OK”类型的消息作出响应,指明我已成功接收并将数据存储在数据库中吗?
这个功能是否已经集成到WCF中?
4个回答

18
这里提到了三种消息传递模式:
  1. 同步请求-响应
  2. 异步发送(单向服务的“火并忘”)
  3. 异步请求-响应(具有单向服务的双工服务调用)
这三种模式显示不同的消息行为,应根据您的需求选择要使用的模式。
对于您要求在将数据持久化到数据库后向客户端返回成功的情况,选项1或3是合适的。
选项1:
这是默认配置。
完成所有任务后,此选项会在同一http连接上返回200响应。这意味着调用服务时会阻塞等待响应 - 客户端将挂起,直到服务写入数据库并完成其它任何需要的操作。
选项2:
只要传输层和消息基础设施层成功,就会返回202响应。返回的202表示消息已被接受。从http rfc

请求已被接受进行处理,但尚未完成处理。 (...) 202响应是故意含糊不清的。

这意味着一旦服务基础结构成功启动服务,您的客户端将继续执行,并且您将收到有关数据库调用是否成功的任何信息。
选项3:
类似于选项2,响应是一个HTTP 202,而不是200,但现在当您从客户端调用服务时,提供一个InstanceContext 对象来指定一个处理回调的对象。客户端重新获得控制,一个新线程异步等待服务响应,通知您成功或失败。
以下是有关在WCF中实现这些模式的更多信息。写完后,它相当长,但有一些有用的评论以及代码。
正如Whisk所提到的,Juval Lowy在此处涵盖了很多细节(以及更多!)
选项1
这是WCF中的默认行为,因此您不需要做任何事情-它可以与许多不同的绑定一起使用,包括wsHttpBinding和basicHttpBinding。
需要注意的一件事是,即使您有一个void操作(如下所示),也会发生描述客户端挂起等待200响应的行为:
[ServiceContract]
interface IMyServiceContract
{
    [OperationContract]       
    void DoSomeThing(InputMessage Message);
}

选项2

要将操作设置为单向操作,只需对其进行如下装饰:

[ServiceContract]
interface IMyServiceContract
{
    [OperationContract(IsOneWay = true)]       
    void DoSomeThing(InputMessage Message);
}

用这种方式修饰的方法必须只有void返回类型。一个值得注意的问题是,服务将会很愉快地构建,而且你在连接时不会得到一个异常,说服务配置无效。

选项三

创建双向回调服务的接口代码如下:

[ServiceContract(CallbackContract = typeof(IMyContractCallback))]
interface IMyContract
{
    [OperationContract(IsOneWay=true)]       
    void DoSomeThing(InputMessage Message);
}

public interface IMyContractCallback
{
    [OperationContract(IsOneWay = true)]
    void ServiceResponse(string result);      
}

在客户端,您需要类似这样的东西来设置回调函数:

public class CallbackHandler : IMyContractCallback        
{
    #region IEchoContractCallback Members

    public void ServiceResponse(string result)
    {
        //Do something with the response
    }

    #endregion
}

// And in the client when you set up the service call:

InstanceContext instanceContext = new InstanceContext(new CallbackHandler());
MyContractClient client = new MyContractClient(instanceContext);

InputMessage msg = new InputMessage();

client.DoSomething(msg);           

在服务中,你可能会有一些类似这样的代码:
class MyContractImplementation : IMyContract
{
    public void DoSomeThing(MyMessage Message)
    {

        string responseMessage;

        try
        {
           //Write to the database
           responseMessage = "The database call was good!";
        }
        catch (Exception ex)
        {
            responseMessage = ex.Message;
        }

        Callback.ServiceResponse(responseMessage);
    }
}

需要注意的一件重要的事情是,异常处理非常重要。如果:

  • 消费了一个异常,你将不会收到任何错误警告(但回调函数仍然会执行)

  • 抛出未处理的异常,服务将终止且客户端甚至无法获得回调。

这是与选项1相比这种方法的一个很大的缺点,选项1会在抛出未处理的异常时返回异常信息。


2
默认情况下,即使你的服务方法指定了void返回类型,你的服务也会向客户端返回一个“OK”消息,除非出现异常。在继续执行之前,客户端将等待接收此消息。
因此,根据您的问题,您默认情况下已获得所需的行为。
如果您不希望这样,我同意Whisk的建议,将您的操作标记为单向(在您的操作合同中的设置)。
祝你好运!

1

你可以有两种方法来实现这个 - 从你的wcf调用中返回一个值表示成功或失败,或者假设成功并使用回调告诉客户端是否有问题。

我更喜欢使用单向服务调用和双工服务,并使用回调契约来通知客户端失败。这里有一个很好的回调契约描述这里这里

如果你遵循第二条路线,你会得到一个更好的、更异步的架构,但对于简单的应用程序,只返回成功或失败可能更容易。


在单向通信中,我该如何生成一个错误?这个错误会被客户端和服务器都知道吗? - Mat
抱歉,我的第一次尝试有些匆忙和不太准确(已经有一段时间没有使用WCF了),希望这次会更清晰一些。 - Whisk

0

我认为这个问题需要更详细的阐述才能正确回答。首先,您当前正在使用哪种类型的绑定?

如果您正在使用支持可靠性的绑定,并且仅想要确保从客户端发出的消息确实已被服务器接收,则只需打开可靠性即可。有了此选项,WCF将在幕后自动使每个对话方说: “你收到了吗?” “我收到了,你收到了吗?” “我收到了。”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接