Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>There are three messaging patterns mentioned here:</p> <ol> <li>Synchronous request-response </li> <li>Asynchronous send (fire and forget with one-way service)</li> <li>Asynchronous request-response (duplex service call with one-way service)</li> </ol> <p>All three display different messaging behaviour, and the pattern to be used should be chosen based on your needs. </p> <p>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.</p> <h3>Option 1</h3> <p>This is the default configuration.</p> <p>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.</p> <h3>Option 2</h3> <p>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 <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html" rel="nofollow noreferrer">http rfc</a>: </p> <blockquote> <p>The request has been accepted for processing, but the processing has not been completed. (...) The 202 response is intentionally non-committal.</p> </blockquote> <p>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.</p> <h3>Option 3</h3> <p>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 <code>InstanceContext</code> 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. </p> <hr> <p>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.</p> <p>As Whisk mentioned, Juval Lowy has an article covering a lot this detail (and more!) <a href="http://msdn.microsoft.com/en-us/magazine/cc163537.aspx" rel="nofollow noreferrer">here</a></p> <h3>Option 1</h3> <p>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.</p> <p>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:</p> <pre><code>[ServiceContract] interface IMyServiceContract { [OperationContract] void DoSomeThing(InputMessage Message); } </code></pre> <h3>Option 2</h3> <p>To set an operation as one-way you simply decorate it as so:</p> <pre><code>[ServiceContract] interface IMyServiceContract { [OperationContract(IsOneWay = true)] void DoSomeThing(InputMessage Message); } </code></pre> <p>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.</p> <h3>Option 3</h3> <p>The interface code for creating a duplex callback service is:</p> <pre><code>[ServiceContract(CallbackContract = typeof(IMyContractCallback))] interface IMyContract { [OperationContract(IsOneWay=true)] void DoSomeThing(InputMessage Message); } public interface IMyContractCallback { [OperationContract(IsOneWay = true)] void ServiceResponse(string result); } </code></pre> <p>And on the client side you need something like so to set up the callback:</p> <pre><code>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); </code></pre> <p>In the service you would perhaps have some code like:</p> <pre><code>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); } } </code></pre> <p>One important thing to note, that caught me out at first, is to be careful about exceptions. If you: </p> <ul> <li><p>Consume an exception, you will get no warning of the error (but the callback will happen)</p></li> <li><p>Throw an unhandled exception, the service will terminate and the client will not even get the callback.</p></li> </ul> <p>That is one big disadvantage of this method compared with Option 1, Option 1 will return the exception when an unhandled exception is thrown.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload