Support us .Net Basics C# SQL ASP.NET ADO.NET MVC Slides C# Programs Subscribe Buy DVD

Part 34 - Duplex message exchange pattern in WCF

Suggested Videos
Part 31 - WAS hosting in WCF
Part 32 - Message Exchange Patterns in WCF
Part 33 - OneWay Message Exchange Pattern in WCF



In this video we will discuss, the duplex Message Exchange Pattern in WCF.

Duplex messaging pattern can be implemented using Request/Reply or OneWay operations. We discussed Request/Reply messaging pattern in Part 32, and OneWay messaging pattern in Part 33. First we will discuss implementing duplex messaging pattern using Request/Reply operations. We will then modify the example to implement duplex messaging pattern  using oneway operations.



Steps to implement duplex messaging pattern
Step 1: Create a class library project with name = Report Service. Delete the autogenerated class1.cs file and app.config file.

Step 2: Right click on ReportService project in solution explorer and add a WCF service with name = ReportService.

Step 3: Copy and paste the following code in IReportService.cs file
using System.ServiceModel;
namespace ReportService
{
    // Associate callback contract with service contract using CallbackContract attribute
    [ServiceContract(CallbackContract = typeof(IReportServiceCallback))]
    public interface IReportService
    {
        // Since we have not set IsOnway=true, the operation is Request/Reply operation
        [OperationContract]
        void ProcessReport();
    }

    // This is the callback contract
    public interface IReportServiceCallback
    {
        // Since we have not set IsOnway=true, the operation is Request/Reply operation
        [OperationContract]
        void Progress(int percentageComplete);
    }
}

Step 4: Copy and paste the following code in ReportService.cs file
using System.ServiceModel;
using System.Threading;
namespace ReportService
{
    public class ReportService : IReportService
    {
        public void ProcessReport()
        {
            for (int i = 1; i <= 100; i++)
            {
                // some logic to process the report
                Thread.Sleep(100);
                // Get the callback channel to send messages to the client
                OperationContext.Current.
                    GetCallbackChannel<IReportServiceCallback>().Progress(i);
            }
        }
    }
}

Step 5: Right click on ReportService solution in solution explorer and add a console project with name = Host. We will use this project to host the WCF service.

Step 6: Right click on References folder under Host project and add a reference to ReportService project and System.ServiceModel assembly.

Step 7:  Right click on Host project and add Application Configuration file. This should add App.config file.

Step 8: Copy and paste the following configuration in App.config file
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior name="mexBehavior">
          <serviceMetadata httpGetEnabled="true" />
          <serviceDebug includeExceptionDetailInFaults="true"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="mexBehavior" name="ReportService.ReportService">
        <endpoint address="ReportService" binding="netTcpBinding" bindingConfiguration=""
            contract="ReportService.IReportService" />
        <host>
          <baseAddresses>
            <add baseAddress="http://localhost:8080" />
            <add baseAddress="net.tcp://localhost:8090" />
          </baseAddresses>
        </host>
      </service>
    </services>
  </system.serviceModel>
</configuration>

Step 9: Copy and paste the following code in Program.cs file in the Host project.
using System.ServiceModel;
using System;
namespace Host
{
    class Program
    {
        public static void Main()
        {
            using (ServiceHost host = new ServiceHost
                (typeof(ReportService.ReportService)))
            {
                host.Open();
                Console.WriteLine("Host started @ " + DateTime.Now.ToString());
                Console.ReadLine();
            }
        }
    }
}

Step 10: Set Host project as the startup project and run the application by pressing CTRL + F5 key. At this point we have the WCF service up and running.

Step 11: Now let's create a client for the WCF service. Create a new windows forms application with name = DuplexClient

Step 12: Add a service reference to ReportService. Right click on References folder and select Add Service Reference. In the Add Service Reference window type Address = http://localhost:8080/ and click GO button. This should bring up the ReportService. In the Namespace textbox type ReportService and click OK. Also add a reference to System.ServiceModel assembly.

Step 13: Design Form1 as shown below, with a button and a textbox controls. Set the following properties on button1
Name = btnProcessReport
Text  = Process Report
WCF duplex contract

Step 14: Double click on the button to generate the "click event handler" method. Copy and paste the following code in Form1.cs file.
using System;
using System.ServiceModel;
using System.Windows.Forms;
namespace DuplexClient
{
    // The Form1 class implements IReportServiceCallback interface
    public partial class Form1 : Form, ReportService.IReportServiceCallback
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void btnProcessReport_Click(object sender, EventArgs e)
        {
            InstanceContext instanceContext = new InstanceContext(this);
            ReportService.ReportServiceClient client =
                new ReportService.ReportServiceClient(instanceContext);

            client.ProcessReport();
        }

        // This method recevies the progress update from the WCF service
        // Report processing percentage is displayed in the textbox control
        public void Progress(int percentageComplete)
        {
            textBox1.Text = percentageComplete.ToString() + " % completed";
        }
    }
}

Step 15: Run client the application by pressing CTRL + F5 and click on "Process Report" button. At this point we will get the following exception.
This operation would deadlock because the reply cannot be received until the current Message completes processing. If you want to allow out-of-order message processing, specify ConcurrencyMode of Reentrant or Multiple on ServiceBehaviorAttribute.

Step 16: To fix the above error, we need to do 2 things
a) In ReportService.cs file, set ConcurrencyMode to Reentrant as shown below.
      [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Reentrant)]
      public class ReportService : IReportService
b) In Form1.cs file in DuplexClient project, set UseSynchronizationContext to false as shown below.
      [CallbackBehavior(UseSynchronizationContext = false)]
      public partial class Form1 : Form, ReportService.IReportServiceCallback

At this point run the service. Update the service reference in the DuplexClient project. Finally run the client project and click Process Report button. So, we have just seen how to implement Duplex messaging pattern using Request/Reply operations.

Now, let's discuss implementing Duplex messaging pattern using OneWay operations.
Step 1: Remove ServiceBehavior attribute that sets ConcurrencyMode to Reentrant from ReportService.cs file
   [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
   public class ReportService : IReportService

Step 2: Remove CallbackBehavior attribute that sets UseSynchronizationContext to false from Form1.cs file in DuplexClient project.
   [CallbackBehavior(UseSynchronizationContext = false)]
   public partial class Form1 Form, ReportService.IReportServiceCallback

Step 3: Set ProcessReport() and Progress() operation contracts to OneWay in IReportService.cs file in ReportService project
[ServiceContract(CallbackContract = typeof(IReportServiceCallback))]
public interface IReportService
{
    [OperationContract(IsOneWay = true)]
    void ProcessReport();
}

public interface IReportServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void Progress(int percentageComplete);
}

At the point run the service. Update the service reference in the DuplexClient project. Finally run the client project and click Process Report button. With these changes we are now using Duplex messaging pattern using OneWay operations.

wcf tutorial

15 comments:

  1. When i run a client with [OperationContract(IsOneWay=false)] i got an error "Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on." but when i use 'OneWay=true textBox is updated,no error.I can see many solutions using Delegate-Dispatcher-Invoke.. to solve the issue but in your video i can not see any of this and client is working.How ?

    ReplyDelete
    Replies
    1. TextBox.CheckForIllegalCrossThreadCalls = false;
      textBox1.Text = percentageComplete.ToString() + " % completed";

      Delete
    2. Right? I'm also not sure how he doesn't have an App.config file in his service library either, but it all runs lol.

      Delete
    3. [ServiceBehavior(ConcurrencyMode= ConcurrencyMode.Multiple)]

      TextBox.CheckForIllegalCrossThreadCalls = false;

      it will work fine

      Delete
  2. Hi Venkat,

    Many Thanks for sharing this great video. I am getting an error "Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on."

    In oneway operation it is working good. Could you please help me on this.

    ReplyDelete
    Replies
    1. did you resolve this issue, actually i am also getting this issue

      Delete
    2. During OneWay=True remove the attribute [CallbackBehavior(UseSynchronizationContext = false)] from the Form Class declaration.

      Delete
  3. Hi Venkat,
    while doing Step 12 S: Add a service reference to ReportService. with http://localhost:8080/

    i Got error
    There was an error downloading 'http://localhost:8080/'.
    The request failed with the error message:
    --
    Metadata contains a reference that cannot be resolved: 'http://localhost:8080/'.
    There was no endpoint listening at http://localhost:8080/ that could accept the message. This is often caused by an incorrect address or SOAP action. See InnerException, if present, for more details.
    The remote server returned an error: (404) Not Found.
    If the service is defined in the current solution, try building the solution and adding the service reference again

    ReplyDelete
    Replies
    1. I got the same error when I add Server Reference, and I was using VS2012. Could you tell me how to solved the problem? Thanks very much!

      Delete
    2. Change the Port number listed in your computer and Run Application as Administrator

      Delete
  4. When i run a client with [OperationContract(IsOneWay=false)] i got an error "Cross-thread operation not valid: Control 'textBox1' accessed from a thread other than the thread it was created on.

    ReplyDelete
    Replies
    1. TextBox.CheckForIllegalCrossThreadCalls = false;
      textBox1.Text = percentageComplete.ToString() + " % completed";

      Delete
  5. Hello Venkat,

    Thanks for the shared video .
    I'm trying to implement this one.
    My question is when I use http://localhost:8080 in the browser I'm able to see the wsdl document. but why not with the net.tcp://localhost:8090 .
    Can you please let me know ?
    Thanks....

    ReplyDelete
  6. Hello Venkat,

    I really appreciate and thank you for exceptional job you did by creating videos, documentation and presentation slides. I had followed all your videos very closely and it did help to gain tremendous knowledge.

    I was looking for material in web socket, but I didn't find one in your blog. Will it be possible for you to create a blog which explain communication of WCF full duplex web service with web socket client in javascript.

    I'll be really appreciate if you can share web socket blog with us.

    You can reach me at rushabh138@gmail.com.

    Thanks.

    Rushabh.

    ReplyDelete
  7. Hello Venkat,
    Thanks a ton for sharing this great video.
    But I have one doubt for which I have spent almost 4 hours and still nowhere near.
    I am trying to implement this whole functionality but instead of WinForms, I have taken asp.net web forms project as client and implemented exactly the same as ur project but no success till now.
    Please tell me is it possible to use duplex messaging with an asp.net web client?

    ReplyDelete

If you like this website, please share with your friends on facebook and Google+ and recommend us on google using the g+1 button on the top right hand corner.