10

如果我有成百上千的客户端计算机 WCP 连接到我的服务器,我是否应该回复“200 OK”类型的消息,说明我已收到数据并将其成功存储在数据库中?

这已经内置到 WCF 中了吗?

4

4 回答 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 有一篇文章涵盖了很多这个细节(以及更多!)here

选项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。一个问题是该服务将愉快地构建,并且在您连接到它之前,您不会收到一个说明服务配置无效的异常。

选项 3

创建双工回调服务的接口代码为:

[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 将在抛出未处理的异常时返回异常。

于 2008-10-23T00:57:41.247 回答
2

默认情况下,除非抛出异常,否则您的服务将向客户端返回“OK”消息(即使您的服务方法指定了 void 返回类型)。客户端将等到它收到此消息,然后再继续它的生命。

因此,根据您的问题,默认情况下您将获得所需的行为。

如果您不希望这样,我会同意 Whisk 并将您的操作标记为 One Way(您的操作合同中的设置)。

祝你好运!

于 2008-10-22T18:33:48.667 回答
1

有两种方法可以做到这一点 - 从 wcf 调用返回一个值,指示成功或失败,或者假设成功并使用回调告诉客户端是否有问题。

我的偏好是将单向服务调用与双工服务一起使用,并使用服务的回调合同来通知客户端失败。这里这里对回调合约有很好的描述。

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

于 2008-10-22T18:29:13.183 回答
0

我认为这个问题可以使用更多的细节来正确回答。Primary,您当前使用的是哪种类型的绑定?

如果您正在使用支持可靠性的绑定,并且您只想从客户端确定该服务器确实收到了消息,那么只需打开可靠性就可以了。启用此功能后,WCF 将自动在后台自动让对话的每一方说:“你明白了吗?” “我明白了。你明白了吗?” “我知道了。”

于 2008-10-23T03:07:22.077 回答