Friday, October 14, 2011

Creating a WCF Stand Alone Console App

So I had a problem the other day that really annoyed me. I realized that I couldn't spawn processes directly from IIS. The solution was simple, build a wcf stand alone service that IIS app would call to spawn another process...the result was actually really easy. wcf is almost like remoting, in fact it reminds me a lot of java RMI. It's super ez to setup though...

First you have to provide an interface just like java RMI to serve as a contract between the two processes:

using System.ServiceModel;

[ServiceContract]
    public interface IJSXAdapter
    {
        [OperationContract]
        byte[] GetProcessedImageBytes(string jsxTemplatePath, string[] args);
    }

notice the ServiceContract and the OperationContract attributes

you then of course specify the concrete class (you don't need the attributes in the concrete implementation)


here is the server code:

class Program
        {
            static void Main(string[] args)
            {
                using (ServiceHost host = new ServiceHost(typeof(JSXAdapter), new Uri[]{
                        new Uri("http://localhost:8000"),
                        new Uri("net.pipe://localhost")
                    }))
                {
                    host.AddServiceEndpoint(typeof(IJSXAdapter),
                      new BasicHttpBinding(),
                      "Reverse");

                    host.AddServiceEndpoint(typeof(IJSXAdapter),
                      new NetNamedPipeBinding(),
                      "PipeReverse");

                    host.Open();

                    Console.WriteLine("Service is available. " +
                      "Press  to exit.");
                    Console.ReadLine();

                    host.Close();
                }
            }
        }



That's it for the server. In this example I make not one but two ServiceEndpoints or listeners. One http and another net.pipe. In your client you can connect with either..

Now for the client. You specify the same interface (you could potentially share a dll:


[ServiceContract]
    public interface IJSXAdapter
    {
        [OperationContract]
        byte[] GetProcessedImageBytes(string jsxTemplatePath, string[] args);
    }



and the client code (copied from a method)
 XmlDictionaryReaderQuotas readerQuotas = new XmlDictionaryReaderQuotas();
            readerQuotas.MaxArrayLength = 2147483647;



            BasicHttpBinding httpBinding = new BasicHttpBinding();
            httpBinding.MaxReceivedMessageSize = 2147483647;
            httpBinding.MaxBufferSize = 2147483647;
            httpBinding.ReaderQuotas = readerQuotas;
            ChannelFactory httpFactory = new ChannelFactory(httpBinding,
                                                                                      new EndpointAddress("http://localhost:8000/Reverse"));
            NetNamedPipeBinding pipeBinding = new NetNamedPipeBinding();




            pipeBinding.MaxReceivedMessageSize = 2147483647;
            pipeBinding.MaxBufferSize = 2147483647;            
            pipeBinding.ReaderQuotas = readerQuotas;
            ChannelFactory pipeFactory = new ChannelFactory(pipeBinding,
                                                                                      new EndpointAddress("net.pipe://localhost/PipeReverse"));




            IJSXAdapter httpProxy = httpFactory.CreateChannel();
            IJSXAdapter pipeProxy = pipeFactory.CreateChannel();

            
            
            string[] args = new string[1];
            args[0] = "some string";



            byte[] processedImageBytesFromHttp = httpProxy.GetProcessedImageBytes("some string", args);

            byte[] processedImageBytesFromPipe = pipeProxy.GetProcessedImageBytes("some string", args);
            





Though that looks like a lot most of it is extending the size of how much data can come back. Also keep in mind that this is an example of both end points. in practice you would only connect to one...