Archive for category Web Services

Create a Intra-Application Named Pipe using WCF in .Net using C#; IPC Communications.

Update 07/2009: Update to not use HTTP transport methodology but NetNamedPipeBinding. Updated downloadable code

Update 10/2008: Code downloadable…see comments for link.
A named pipe is a communications method between two disparate applications. This article will show how to use WCF and .Net 3+ with C# to create such named pipe(s). This article is a how-to article showing every step needed and has the code downloadable.
Premise
I have a need to have one application to provide a messages to another application (InterProcess Communication (IPC)) using a unique named pipe between them using WCF.

Named Pipe Library

We will be creating three projects. The first will be a library project (shown below as NamedPipe) and two test projects (not shown in the picture below). The test projects will be the consumers of the library which will be a receiver and a sender talking to each other. The Library will contain the guts of the operations in WCF and once done will look like this in VS2008 Solution Explorer:
image
This library will be all encompassing and contain the code necessary to perform the named pipe between applications. It handles all the core WCF functionality setup/endpoints. All one has to do is have the receiver and sender use the library to communicate by just specifying a name for the pipe.
The receiver and sender will simply consume the classes in Receiver.cs and Sender.cs respectively to achieve the named pipe communication.
Steps:
  1. Create a library project named NamedPipe.
  2. Add two references to the System namespaces Runtime.Serialization and ServiceModel.
  3. Create a folder within the project named Communication, which will be a sub-namespace to NamedPipe. We will place the low level operations and specifications there.
  4. Within the Communication folder add an interface class named IPipeService (as iPipeService.cs in the downloadable code). Within that file is where we will begin to define the service contract which the sending and receive code will adhere to. The interface code will look like this:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.ServiceModel;
    
    namespace NamedPipe.Communication
    {
     [ServiceContract
      (Namespace =
      "http://www.OmegaCoder.com/NamedPipe1")]
     public interface IPipeService
     {
      [OperationContract]
      void PipeIn(List<string> data);
     }
    }
    • Line 04: We will need to add this using so our attributes will be recognized on the interface.
    • Line 08: This is the attribute which will show our interface to be a specialized WCF contract.
    • Line 10: We setup a generic namespace to avoid naming collisions with other WCF services. This namespace does not have anything to do with opening up the ports, which will have a different URL altogether. This url is kind of a throw away url, we are not publishing to this location.
    • Line 13: We will be opening up one port which we will communicate between the processes and this attribute defines that.
    • Line 14: We will be passing a list of strings between the processes and this method is the vector of the operation.
  5. Again within the Communication folder create the second part of the contract, the actual class which will be the catalyst for the data transfer on the receiving side named PipeService (as PipeService.cs in the download code). Let me show the code and explain each line:
    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.ServiceModel;
    
    namespace NamedPipe.Communication
    {
    
    [ServiceBehavior
            (InstanceContextMode = InstanceContextMode.Single)]
     public class PipeService : IPipeService
     {
         public static string URI
             = "net.pipe://localhost/Pipe";
    
         // This is when we used the HTTP bindings.
         // = "http://localhost:8000/Pipe";
    
         #region IPipeService Members
    
         public void PipeIn(List<string> data)
         {
             if (DataReady != null)
                 DataReady(data);
         }
    
         public delegate void DataIsReady(List<string> hotData);
         public DataIsReady DataReady = null;
    
         #endregion
     }
    }
    • Line 04: This is the required using for WCF operations.
    • Line 09: This attribute is self explanatory, for this class will be generated for each endpoint we define. In our case only one endpoint for our pipe.
    • Line 10: This is not the default behavior. In standard WCF processing this object would be created through reflection. We don’t want that to happen, because we have a delegate (call back) which will transfer data to the receiver. Due to that fact, we will be creating the object by hand later and allowing the consumer to subscribe to the delegate. Because of that, we have to specify that this context will be a singleton instance.
    • Line 14: Here is the actual url and port which the operations will be operating on. The named part of the port will be added to this string to give us a unique pipe.  If we want to expand this to other machines on the intranet, we could use an HTTP protocol as shown below in Line 17.
    • Line 20: Here is where the data will be passed in/out.
    • Line 22: Check for a subscriber to the delegate.
    • Line 23: Finally pass the data on to the consumer(s) of the delegate after we have received data from the ether.
    • Line 25/26: Here is where we will transfer the data back and forth by allowing a consumer to subscribe to this delegate.

Receiver Class

  1. Now we will create the top level receiver class (as Receiver.cs in the zip) which will be consumed by the target of the named pipe. That class is created in the top level of the NamedPipe namespace. Here is the code and the line by line explanation.
using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;
using NamedPipe.Communication;

namespace NamedPipe
{
 public class Receiver :  IDisposable
 {

     #region Constructors
     // Default constructor, use this if
     // the default name of the pipe can
     // be used instead of one provided.
     public Receiver() : this(DefaultPipeName) { }

     // Use this constructor to create
     // a pipe with a unique name.
     public Receiver(string PipeName)
     {
         _PipeName = PipeName;
     }
#endregion

     #region Public Operations
     // If the service host can be started,
     // true will be returned. If false is returned
     // another process owns the pipe.
     public bool ServiceOn()
     {
         return ( _operational = HostThisService());
     }

     public void ServiceOff()
     {
      if (_host != null)
          if (_host.State != CommunicationState.Closed)
              _host.Close();

      _operational = false;

     }
#endregion

     #region WCF Operations
    // The thread which will listen for communications
    // from the other side of the pipe.
    private bool HostThisService()
    {

     try
     {

         _host = new ServiceHost(_ps, new Uri(PipeService.URI));

         // Usage BasicHttpBinding can be used if this is
         // not going to be on the local machine.
         _host.AddServiceEndpoint( typeof( IPipeService ),
              new NetNamedPipeBinding(),
              _PipeName );
         _host.Open();

         _operational = true;
     }
     catch (Exception ex)
     {
         error = ex;
         _operational = false;
     }

     return _operational;

    }
#endregion

    #region Public Properties
    // The consumer of this class will subscribe to this delegate to
    // receive data in a callback fashion.
    public PipeService.DataIsReady Data
    {
        get
        {
           return _ps.DataReady;
        }

        set
        {
           _ps.DataReady += value;
        }
    }

    public string CurrentPipeName
    {
        get { return _PipeName; }
    }

    // Any error text will be placed here.
    public Exception error              = null;

    // See the actual name of the pipe for
    // any default operations.
    public const string DefaultPipeName = "Pipe1";
#endregion

#region Private Variables
    private PipeService _ps   = new PipeService();
    private bool _operational = false;
    private ServiceHost _host = null;
    private string _PipeName  = string.Empty;
#endregion

#region IDisposable Members

    // A basic dispose.
    public void Dispose()
    {
        this.ServiceOff();

        if (_ps != null)
            _ps = null;
    }

 #endregion
   }
}
  • Line 04: Even though we have lower level WCF definitions, we will be initiating the WCF functionality in this class.
  • Line 05: Pull in the lower level WCF contract and operations.
  • Line 16: If you know that this is the only named pipe on the system, use a default name for the pipe.
  • Line 20: Otherwise use this constructor to create a named pipe to your specifications.
  • Line 30: Call this after creating the object and after subscribing to the delegate, to start the process of listening. Don’t forget to check for a running status. (Note if the pipe is in use it will throw an exception, so catch any exceptions).
  • Line 35: Turn service off, or it will be done in the dispose automatically.
  • Line 49: This is the function which will do the magic of the WCF port processing.
  • Line 55: The service host will not be creating a generic end point. It will use our singleton pipe service.
  • Line 58: We will open up this URI which is specified in the URI static of PipeService.
  • Line 59: We will have one endpoint and we let it know what type it is.
  • Line 60: We are doing not http communications but netnamed pipe operations.
  • Line 62: Here is the uniqueness of this endpoint. The pipe name.
  • Line 62: Finally we begin listening operations.
  • Line 68: Any errors will be on the public error object for the consumer to check.
  • Line 85: Subscribe to this delegate to pass the information back to the creator of this receiver named pipe.
  • Line 99: Check here for any errors.
  • Line 103: This is the default name of the pipe, if one is not given by the consumer.
  • Line 107: Here we create our singleton WCF service for the one endpoint we will specify.
  • Line 115: Clean up any operations and member variables.

Sender Class

    1. Here is the class which will be consumed by the application which will send the information over. Note this class is not instantiated but used by simply calling the static which will send the data on over:
using System;
using System.Collections.Generic;
using System.Text;

using System.ServiceModel;
using NamedPipe.Communication;

namespace NamedPipe
{
// Create this class to send a message on a
// named pipe.
public class Sender
{
    // Use a default pipe name. Be careful not to reuse
    // this on other applications.
    public static void SendMessage(List<string> messages)
    {
        SendMessage(messages, Receiver.DefaultPipeName);

    }

    // Use this method when we have an actual pipe name.
    public static void SendMessage(List<string> messages, string PipeName)
    {
        EndpointAddress ep
            = new EndpointAddress(
                string.Format("{0}/{1}",
                   PipeService.URI,
                   PipeName));

//      IPipeService proxy = ChannelFactory<IPipeService>.CreateChannel( new BasicHttpBinding(), ep );
        IPipeService proxy = ChannelFactory<IPipeService>.CreateChannel( new NetNamedPipeBinding(), ep );
        proxy.PipeIn( messages );

    }
}
}
  • Line 05: Need to pull in the WCF information to initiate the message.
  • Line 06: We have all the connection contract information which we will need to initiate a message.
  • Line 16: The class and method is a static class so just call this static. No muss no fuss. Note this uses the default named pipe name. If our receiver has specified a name for the pipe do not call this one.
  • Line 21: Call this method with a unique name in for the pipe so a message to us can be sent.
  • Line 23: We will combine the URL and port with the name of the pipe which gives us the uniqueness.
  • Line 29: We create a proxy service to do the transfer and expose the method we need to send the info to the receiver application.
  • Line 30: We send in the list of strings and we are done!

Test Projects

Finally we will create two test projects. A winform which will be the receiver and a console application which will be the sender. All we need to do is reference the Named Pipe Library!

image

Test Receiver

  1. Create a winform project and reference the NamedPipe Project.
  2. Add a richtext box to the form. Here is the code inside:
    using NamedPipe;
    
    public partial class Form1 : Form
    {
        Receiver pipe = new Receiver();
        public Form1()
        {
            InitializeComponent();
            pipe.Data += new NamedPipe.Communication.PipeService.DataIsReady(DataBeingRecieved);
            if (pipe.ServiceOn() == false)
                MessageBox.Show(pipe.error.Message);
    
        }
    
        void DataBeingRecieved(List<string> data)
        {
            this.Invoke(new MethodInvoker(delegate()
            {
                rtb_Status.Text += string.Join(Environment.NewLine, data.ToArray());
                rtb_Status.Text += Environment.NewLine;
            }));
        }
    
        private void button1_Click(object sender, EventArgs e)
        {
            if (pipe != null)
                rtb_Status.Text += "Not Null" + Environment.NewLine;
    
            if (pipe.error != null)
                rtb_Status.Text += pipe.error + Environment.NewLine;
    
        }
    }
  • Line 01: We pull in the Named Pipe namespace.
  • Line 05: Since we will be continuously monitoring, we will instantiate the receiver class on the class, so its lifetime is the same as that of the application.
  • Line 09: Here is where we will subscribe to the delegate which will provide us with the text sent from the sender.
  • Line 11: We have gotten an error, show the exception.
  • Line 15: Here is our subscriber target which will receive the data!
  • Line 17: Since the WCF process is on another thread, we invoke back to the GUI thread to populate the richtext box.
  • Line 19: We add the data to the rich text box!
  • Line 24: I added a button, not in the steps to test out the object. This code is optional.

Test Sender

  1. Create a console application and reference the NamedPipe project.
  2. Copy this code:
    static void Main(string[] args)
    {
        List<string> messages = new List<string>();
    
        messages.Add("Line 1");
        messages.Add("Second Line");
        try
        {
            NamedPipe.Sender.SendMessage(messages);
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    
    }
  • Line 09: We simply send our message. We are using the default pipe name, so we just use the single argument SendMessage. Otherwise we would use the constructor which would allow us to send data on the unique named pipe!

Summary

With that we are finished. Run the winform receiver first. Then run the console sender. If everything has been coded you should see the text on the screen. With the NamedPipe library it is now a toolbox item which we can take with us from project to project.

image

Share

Tags: , , ,

Web Service Consumption and Winform Data Display

This article demonstrates how to consume a foreign webservice with the goals of demonstrating synchronous and asynchronous data extraction against it. Secondly it will show how to do this on another thread with proper winform data invokation to the GUI thread.

The developer who is learning how to consume a webservice and populate data has two hurdles to overcome. The first is working with the webservice and the second is properly populating the data back to the win service. Here are the goals

  1. Asynchronous webservice consumption.
  2. Synchronous webservice consumption.
  3. Threaded webservice consumption with the handling of cancel and background worker thread.
  4. Invoking data back to the winform GUI.

Background: This article will gloss over these topics, so look to learn elsewhere

  1. Basic winform project creation and control handling.
  2. Understanding of the basics on how to connect to a webservice.

Setup

This phase is the initial phase where we create the project foot print.

  1. Create a standard winform project.
  2. Add web reference to http://www.weather.gov/forecasts/xml/DWMLgen/wsdl/ndfdXML.wsdl and change the web reference name to GovWeather. (Note for this web service consumption to work you will need to see my blog Consuming NOAA and Avoiding Protocol Violation in .Net).
  3. Place three buttons on the form labeled Async, Sync and Thread.
  4. Place a RichText Dialog on the screen and name it richTextBoxXmlDisplay. This will display our acquired data or exceptions.

Synchronous Call and Data Display

This one is the easiest to code but it does have a problem. We will simply call the web service directly and then push the data to the RichTextBox. Add this code to the button press for the synchronous event.

try
{
    richTextBoxXmlDisplay.Text = GetDataSynchronously();
}
catch (System.Exception ex)
{
    richTextBoxXmlDisplay.Text = ex.Message;
}

Here is the actual function which gets the data synchronously from the web service, we will actually use it later.

private string GetDataSynchronously()
{

 

    WebServiceConsumer.GovWeather.ndfdXML weather = new WebServiceConsumer.GovWeather.ndfdXML();

 

    return weather.NDFDgenByDay(39.5946m,
                               -105.014m,
                               DateTime.Now,
                               "1",
                               WebServiceConsumer.GovWeather.formatType.Item24hourly);

 

}

But this has a major problem, if the webservice takes a long time to process our user experience will become locked up. This is fine for console applications or background threads but not for true GUI processing.

Asynchronous Call and Data Display

Asynchronous data extraction will play better with GUI thread. First we start by creating a member variable to hold the web service object.


 

WebServiceConsumer.GovWeather.ndfdXML _weather;

We will initialize the _weather object in the button event for async wiring in the asynchronous operations as so:

try
{
    _weather = new WebServiceConsumer.GovWeather.ndfdXML();

 


    _weather.NDFDgenByDayAsync(39.5946m,
                               -105.014m,
                               DateTime.Now,
                               "1",
                               WebServiceConsumer.GovWeather.formatType.Item24hourly);

 

    // Intellisense will be kind and do all the footwork
    // to create the stub for the target.
    _weather.NDFDgenByDayCompleted
        += new WebServiceConsumer.GovWeather.NDFDgenByDayCompletedEventHandler(_weather_NDFDgenByDayCompleted);

 

    richTextBoxXmlDisplay.Text = "Web Service Called...";
}
catch (System.Exception ex)
{
    richTextBoxXmlDisplay.Text = ex.Message;
}

This is the same as the Synchronous except we don’t expect an immediate result. Also we wire in an event for the completion status. By simply typing in _weather.NFDgenByDatCompleted += we can have Visual Studio wire in the actual event call and stub completion. In the stub, remove the throw line and add this information:

if (e.Cancelled == false)
{
    richTextBoxXmlDisplay.Text += "Finished" + Environment.NewLine;

 

    richTextBoxXmlDisplay.Text += e.Result;
}

When the web service is complete, the event is fired, and because it is a winform event, we are guaranteed that the work will be on the GUI thread. That assurance allows us to write directly to the RichTextBox.

Threaded Call and Data Display

The threaded call is a requires a little more preparation and a little more foresight than the other methods. We are going to start with the things we have to declare as member variables

#region Variables
    // The thread to be used to do the work.
    private Thread _weatherThread;

 

    // The result or error message to be written.
    private string _result;

 

    // The delegate used to invoke back to the main GUI thread.
    public delegate void DataAcquired(object sender);

 

    // The invoke event.
    public event DataAcquired OnDataAcquiredEvent;
#endregion

The thread object is obvious, it will hold the worker thread. The result of the operations will be placed on _result. The following two items are required because the worker thread cannot do any GUI writing to the string. Because of that we are going to invoke an event to the main GUI thread to write out the _result.

The first thing we can do is seed the event to write out the _result. We will subscribe to the event OnDataAcquiredEvent in the forms constructor.


 

OnDataAcquiredEvent += new DataAcquired(ThreadReportsDataAquiredEvent);

Then we create the method ThreadReportsDataAquiredEvent for the member variable OnDataAcquiredEvent

private void ThreadReportsDataAquiredEvent(object sender)
{
    richTextBoxXmlDisplay.Text += _result;
}

Pretty basic, we are ignoring the sender object in the example, I am leaving it in if you need to do something special that should be passed in.

The next step is to create the thread _weatherThread to do the actuall work. Wire up the Thread button event with this code:

_weatherThread = new Thread(GetWeather);
// If the user closes the application, the thread will not stay alive
// By placing this as a background thread.
_weatherThread.IsBackground = true;
_weatherThread.Start();

The above code is smart enough to set the thread to be a background status. That does not affect priority or processing. It just ensures that if the application is closing, then this thread won’t continue to work autonomously and hold up the closing of the program.

We now can create the target operation of the thread GetWeather such as

private void GetWeather()
{
    bool InvokeToGui = true;

 

    try
    {
        _result = GetDataSynchronously();
    }

 

    catch (ThreadAbortException)
    {
        // We have handled the exception and will simply return without data.
        // Otherwise the abort will be rethrown out of this block. 
        Thread.ResetAbort();
        InvokeToGui = false; // No sense displaying anything.
    }
    catch (System.Exception ex)
    {
        _result = ex.Message;
    }
    finally
    {
        // We invoke back to the main thread to
        // update the result. We pass in a null, you 
        // may want to change that to pass actual information
        // if running multiple threads.
        if (InvokeToGui)
            this.Invoke(this.OnDataAcquiredEvent, new object[] { null });
    }

 

}

This function does these things

  1. Simply calls the GetDataSynchronously because we are a thread and don’t need to call it asynchronously. Note if you have timeout or cancel issues you may want to rig up an asynchronous call within!
  2. This handles the ThreadAbortException. We use it in this test example, but it is good to handle it if in the future there is need or if it comes from another source.
  3. Simply writes the result to _result. We don’t need to lock result since it is only used by us between this thread and the GUI thread.
  4. Lastly we will invoke to the main thread the event that results are available!

Summary

That wraps it up, you now have three different ways to consume a webservice and safely update the GUI winforms as well.

Share