Monday 2 June 2014

Simple Standalone WebService/Server

I was noodling around with some other ideas a few weeks ago using some base code that I now have in a number of small projects and thought this would be good for a small post. The initial intention (and you'll see this is interesting for other follow-on work) was to have a small command-line programe that I could serve up some basic web-services to test algorithms and other ideas. It took a bit of searching and playing when I first had a go, so maybe the information is more easily accessible now, however, as I use this quite a bit it's worthwhile getting the thoughts down.

Basically how to make a relatively smallish set of code that can run up as a web-service/server without the need to configure and install IIS using C#.

First of all, you'll need to kick-off a basic console project and set the target framework to .NET Framework 4 (not the Client Profile as is my default). To do this go to Project > SimpleService Properties (or another name for your project) and change the target framework. It'll probably warn that you need to save the project first.













You then need to import a couple of references. So go to the Solution Explorer, right click on References > Add References and then import System.ServiceModel and System.ServiceModel.Web:










You should then have something like this:













Now for some code! This is the boilerplate:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.ServiceModel;
using System.ServiceModel.Web;
using System.ServiceModel.Description;
using System.IO;
using System.Threading;

namespace SimpleService
{
    [ServiceContract]
    public interface ISimpleService
    {
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public partial class SimpleService : ISimpleService
    {
    }

    class Program
    {

        static void Main(string[] args)
        {
            string uripath;

            uripath = "http://localhost/";

            bool live = false;

            SimpleService service = new SimpleService();

            // run service

            WebServiceHost host = new WebServiceHost(service, new Uri(uripath));
            WebHttpBinding binding = new WebHttpBinding();
            binding.MaxBufferSize = 2147483647;
            binding.MaxReceivedMessageSize = 2147483647;
            ServiceEndpoint ep = host.AddServiceEndpoint(typeof(ISimpleService), binding, "");



            host.Open();
            Console.WriteLine("Service is running");
            Console.WriteLine("Press enter to quit...");
            Console.ReadLine();
            host.Close();


        }
    }
}

If you try and run this now you're going to have one of two problems. Firstly if you haven't already then you need to adjust your ACL to allow web services to work on the port of your choice. In this case the default port 80. This took some figuring out! You're gong t need to have administrator privilidges. Firstly start the command-line from the 'start' menu by typing in 'cmd' then hit ctrl+shift+enter. This will start the command-line in administrator mode. Then type the following cryptic line:

netsh http add urlacl url=http://+:80/ user=domain\user

Where domain\user is obviously your domain and user account.

The second (and more positive) problem you will have is that the code as it is does not provide any service entry points. Let's do the classic 'helloworld':



    [ServiceContract]
    public interface ISimpleService
    {
        [OperationContract, WebGet(UriTemplate = "helloworld")]
        Stream GetHelloWorld();
    }

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
    public partial class SimpleService : ISimpleService
    {
        private Stream StringToStream(string result)
        {
            WebOperationContext.Current.OutgoingResponse.ContentType = "text/html";
            return new MemoryStream(Encoding.UTF8.GetBytes(result));
        }

        public Stream GetHelloWorld()
        {
            String response = "<html><body>hello world</body></html>";

            return StringToStream(response);
        }
    }

As we're effectively hi-jacking the C# WCF REST framework this needed another little function StringToStream to enable the response to be sent back as text and to inform the browser that the content type is HTML.

You can test this by running up a browser and putting in 'http://localhost/helloworld which returns back the html formatted string 'hello world'.

So, with very little code a small little server that can provide web pages and other web-services.... in the next couple of posts I'll show some other additions to this that I've been using.

No comments:

Post a Comment