views:

680

answers:

4

Hi,

If I have hundreds/thousands of client computers WCP'ing to my server, should I respond with a '200 OK' type message stating that I received the data and stored it in the db successfully?

Is this already built-into WCF?

+1  A: 

There's 2 ways you could do this - return a value from your wcf call indicating success or failure, or assume success and use a callback to tell the client if there's a problem.

My preference would be to use a one-way service call with a duplex service and use a callback contract for the service to notify the client of a failure. There's a good description of callback contracts here and here.

I think you get a nicer, more asynchronous architecture if you follow the second path, but for simple applications just returning success or failure may be easier.

Whisk
in a one-way, how would I generate an error? Will this be an error that both the client and server will know about?
Sorry, my first effort was a bit hurried and rather inaccurate (it's been a while since I did this with WCF), hopefully this'll be a bit clearer.
Whisk
+2  A: 

Be default your service will return an "OK" message to the client (even if your service method specifies a void return type) unless an exception is thrown. The client will wait until it recieves this message before continuing on with it's life.

So based on your question you are getting the behavior you want by default.

If you don't want that, I would agree with Whisk and mark your operation as One Way (a setting in your operation contract).

Good luck!

James Bender
+11  A: 

There are three messaging patterns mentioned here:

  1. Synchronous request-response
  2. Asynchronous send (fire and forget with one-way service)
  3. Asynchronous request-response (duplex service call with one-way service)

All three display different messaging behaviour, and the pattern to be used should be chosen based on your needs.

For your requirement of returning a success to the client when the data has been persisted to the database, options 1 or 3 are appropriate.

Option 1

This is the default configuration.

This returns a 200 response on the same http connection once the service has completed all its tasks. This means that calls to the service will block while waiting for the response - your client will hang until the service has written to the database and done anything else it needs.

Option 2

Returns a 202 response so long as the transport layer and messaging infrastructure layer succeeds. The 202 returned indicates that the message has been accepted. From the http rfc:

The request has been accepted for processing, but the processing has not been completed. (...) The 202 response is intentionally non-committal.

This means that your client will continue execution as soon as the service infrastructure has successfully started the service, and you will receive no information about whether the database call succeeds or not.

Option 3

Similar to option 2, the response is an http 202, not a 200, but now when you call the service from the client you provide an InstanceContext object that specifies an object to handle the call back. The client regains control and a new thread waits asynchronously for the service response informing you of success or failure.


Below is some more info about implementing these patterns in WCF. After writing it, it is pretty long but there are a couple of useful comments as well as the code.

As Whisk mentioned, Juval Lowy has an article covering a lot this detail (and more!) here

Option 1

This is the default behaviour in WCF so you should not need to do anything - it works with lots of different bindings including wsHttpBinding and basicHttpBinding.

One thing to note is that the behaviour described with your client hanging waiting for the 200 response occurrs even if you have a void Operation like so:


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

Option 2

To set an operation as one-way you simply decorate it as so:


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

Methods decorated in this way must only have a return type of void. One gotcha is that the service will happily build and you won't get an exception saying the service config is invalid until you connect to it.

Option 3

The interface code for creating a duplex callback service is:


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

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

And on the client side you need something like so to set up the callback:


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

In the service you would perhaps have some code like:


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

One important thing to note, that caught me out at first, is to be careful about exceptions. If you:

Consume an exception, you will get no warning of the error (but the callback will happen)

Throw an unhandled exception, the service will terminate the client will not even get the callback.

That is one big disadvantage of this method compared with Option 1, option 1 will return the exception when an unhandled exception is thrown.

David Hall
+1. This is a really good answer. Well done.
RichardOD
A: 

I think the question could use a little more elaboration in order to answer correctly. Primary, which type of binding are you currently using?

If you're using a binding that supports reliability, and you just want to be sure, from the client side, that server did indeed receive the message, then just turn reliability on and you're good. With this on, WCF will, under the hood automatically, have each side of the conversation say: "You got it?" "I got it. You got it?" "I got it."

pettys