ASP.NET, C#, MVC

ASP.NET MVC Test

UPDATE: This article is rather old now – MVC Preview 3 is out and I suggest looking at the new testing stuff in that 🙂 http://weblogs.asp.net/scottgu/archive/2008/05/27/asp-net-mvc-preview-3-release.aspx

I’ve been playing with MVC for a couple of days now as part of my professional development at Readify – and this afternoon it was time to attack a bit of testing.

So I cracked open Scott’s post on MVC and zoomed in on the unit testing code he posted.

Now, because ASP.NET MVC is quite new (its CTP, not beta, not anything, just a preview – so its *real new*) the dev community is still poking around trying out this and that and in the case of testing, not having a real smooth ride.

In Scott’s post he uses a class called TestViewEngine, which allows him to instantiate and test the views defined in the test web app project, running asserts etc on the output. But this class doesn’t exist in the MVC stuff yet – that I can see anyway (or my Googling).

So I set out on a Google fest to try to get this test code to run… and it turns out it was just a little more difficult than just creating a TestViewEngine class. The final result make use of the excellent Rhino mocking framework and my own TestViewEngine implementation.

I got the mocking code from here: http://haacked.com/archive/2007/12/09/writing-unit-tests-for-controller-actions.aspx a great article on the initial state of MVC testing. I then combine this code with Scott’s and some of my own for the final result. You can download Rhino Mocks from here: http://www.ayende.com/projects/rhino-mocks/downloads.aspx.

There are also some great posts here http://www.persistall.com/ which may help you out a bit.

Basically the code is as on haacked for the most part:

 
 [TestMethod]
        public void AllForUser()
        {

            RouteTable.Routes.Add(new Route
            {
                Url = "Snippet/Detail/[id]",
                RouteHandler = typeof(MvcRouteHandler)
            });

            SnippetController controller = new SnippetController();

            MockRepository mocks = new MockRepository();
            IHttpContext httpContextMock = mocks.DynamicMock();
            IHttpRequest requestMock = mocks.DynamicMock();
            IHttpResponse responseMock = mocks.DynamicMock();
            SetupResult.For(httpContextMock.Request).Return(requestMock);
            SetupResult.For(httpContextMock.Response).Return(responseMock);
            SetupResult.For(requestMock.ApplicationPath).Return("/");

            responseMock.Redirect("/Snippet/Detail/1");

            RouteData routeData = new RouteData();
            routeData.Values.Add("Action", "SnippetDetail");
            routeData.Values.Add("Controller", "Snippet");

            ControllerContext contextMock = new
              ControllerContext(httpContextMock, routeData, controller);
            mocks.ReplayAll();

            controller.GetType().GetProperty("TempData").SetValue(controller, new TempDataDictionary(httpContextMock), null);

            controller.ControllerContext = contextMock;

            TestViewEngine tve = new TestViewEngine();

            controller.ViewFactory = tve;

            controller.SnippetDetail(1);

            Assert.AreEqual(typeof(Snippet), tve.View.ViewData.GetType(), "Snippet object passed to view");
            Assert.AreEqual(1, tve.View.GetViewData().SnippetId, "Correct Snippet ID Processed");
            Assert.AreEqual("SnippetDetail", tve.View.ViewName, "Correct view rendered");
        }

    }

The only thing I had to add here was the following line:

</pre>
<pre>controller.GetType().GetProperty("TempData").SetValue(controller, new TempDataDictionary(httpContextMock), null);

The problem was that the RenderView call in my ControllerAction was throwing a null argument exception because TempData on the object was null and is not allowed to be – thanks to a comment by Alexey on haacked for this!

Then I created my own little TestViewEngine class to keep in line with what Scott was doing in his post:

 

 public class TestViewEngine : IViewFactory
    {

        TestView _view;

        #region IView Members

        #endregion

        #region IViewFactory Members

        public IView CreateView(ControllerContext controllerContext, string viewName, string masterName, object viewData)
        {
            _view = new TestView(controllerContext, viewName, masterName, viewData);
            return _view;
        }

        public TestView View
        {
            get
            {
                return _view;
            }
        }

        #endregion
    }

    public class TestView : IView, IViewDataContainer
    {
        ControllerContext _controllerContext;
        string _viewName;
        string _masterName;
        object _viewData;

        public TestView(ControllerContext controllerContext, string viewName, string masterName, object viewData)
        {
            _controllerContext = controllerContext;
            _viewName = viewName;
            _masterName = masterName;
            _viewData = viewData;
        }

        public T GetViewData()
        {
            return (T)_viewData;
        }

        public string ViewName
        {
            get
            {
                return _viewName;
            }
        }

        #region IView Members

        public void RenderView(ViewContext viewContext)
        {
            //throw new NotImplementedException();
        }

        #endregion

        #region IViewDataContainer Members

        public object ViewData
        {
            get
            {
                return _viewData;
            }
        }

        #endregion
    }

With this code in place you should be able to correctly run the asserts as in Scott’s article.

From what I have read there are going to be a lot of additions in the coming versions that will assist with testing – hopefully this includes things to assist with mocking the View requests etc. For now at least we can run some testing code to get us through.

C#, CLR

CLR Boxing Demystified

One area of programming that many developers do not fully understand is boxing and this can lead to some interesting bugs and poor performance. A firm grasp of boxing is very important for any programmer who works with .NET and the CLR. I will attempt to demystify boxing from a C# perspective.

What? Why?

Firstly it’s important to understand some of the fundamentals of how types are allocated in memory on a CLR based system. There are two main categories of types in any CLR system, C# included: reference types and value types. Reference types are allocated on the managed heap, where as value types are allocated on a thread’s stack. Value types are the more lightweight of the two. When designing types its very important that you understand this difference for a range of reasons, mostly to do with memory management and performance. Reference types (being on the managed heap) are subject to garbage collection (and allocation could force a gc operation) and items on the heap have some overhead memory usage associated with them per instance. Value types on the other hand are allocated on the thread’s stack and are not subject to garbage collection – their memory is freed as soon as the method that defines the variable ends.

Some examples of value types are stucts, enums, int, bool etc.

It’s also important to understand that a value type variable will store its value directly, where as reference types will store a pointer to the object on the managed heap. Also another important point is that value types are sealed and cannot be inherited from. Value types all derive from System.ValueType which itself is derived from System.Object (all types both reference and value end up being derived from System.Object – important to remember when thinking about boxing).

Important: When designing a value type, it must be immutable, which means that no members update any of its fields – this is very important to save you confusion one day.

You only should use a value type when the following statements are true:

  • Type is simple and immutable (i.e. it acts as a primitive type)
  • Does not need to inherit from another type
  • No types will need to derived from it
  • Data will be relatively small in the type or the type will never be passed into or returned from methods (this is important because each time a value type is assigned to a new variable its entire value will be copied – where as a reference type will simply have its reference to the object on the heap copied.

So why do we need boxing?

A boxing operation occurs when ever a reference of a value type is required, for example in a method that takes an object as a parameter. It also occurs when value types are created using any interfaces they may inherit from (oh yeah, value types can implement interfaces :)). As I mentioned earlier, value types all inherit from System.Object in the end, but System.Object is a reference type… so for a value type to become a System.Object type it must be turned into a reference and placed on the managed heap. This is called boxing. Once the value type is converted to Object, it becomes a reference type.

Why is this important to understand? Because boxing is very expensive… creating objects on the managed heap etc causes more work in assigning the object and for the garbage collector. A boxed value type’s life will extend the life of the unboxed version. It also means you can end up with more than one copy of the object (on on stack and one on heap). Working with boxed objects can also be a little strange to the uninitiated.

So what does a box operation look like? Simple:

int x = 5;
Object o = x;

Done. The variable x has now been placed onto the managed heap. The original variable x will stay on the stack until the current method exits.

How can I tell when a box or unbox operation happens easily?

It’s very handy to know when a boxing or unboxing operation is happening, and it may not always be apparent (especially when you start overloading methods and implementing type safe versions of default methods etc). A very easy way to see this is by using ILDasm and looking at the IL version of your code. The IL code for the code above would look like this:

.locals init ([0] int32 x,
          [1] object o,
          [2] int32 y)
 IL_0000:  nop
 IL_0001:  ldc.i4.5
 IL_0002:  stloc.0
 IL_0003:  ldloc.0
 IL_0004:  box        [mscorlib]System.Int32
 IL_0009:  stloc.1
 IL_000a:  ldloc.1
 IL_000b:  unbox.any  [mscorlib]System.Int32
 IL_0010:  stloc.2

You can clearly see the box and unbox IL calls here… you don’t need to fully understand Intermediary Language to gain benefits from this.

Okay, so what are the traps – this seems pretty easy

Well, aside from the performance issues associated with unwanted boxing and unboxing operations, there is a really big gotcha when dealing with boxed versions of types.

Imagine this code:

A test structure

struct TestStruct
    {
        private int value;           	public TestStruct(int initVar)
        {
            this.value = initVar;
        }           	public override string ToString()
        {
            return value.ToString();
        }           	public void ChangeVal(int newVal)
        {
            value = newVal;
        }          }

A test main method

static void Main(string[] args)
       {
        TestStruct ts = new TestStruct(10);              	 	Object boxedObj = ts;              	 	((TestStruct)boxedObj).ChangeVal(20);              	 	Console.WriteLine(string.Format("Boxed version: {0}", boxedObj.ToString()));
        Console.WriteLine(string.Format("Normal version: {0}", ts.ToString()));
        Console.ReadLine();
       }

What will this code display? We first create the test struct and initiate it to 10. Then we box it into object. Then we cast the boxed object back into a TestStruct type and change its value to 20. Then we write out the two values. The output:

Boxed version: 10
Normal version: 10

What happened? Well first, Object knows nothing about TestStruct’s ChangeVal method, so it needs to be cast back to a TestStruct, which creates a temporary TestStruct value on the stack. Then we change the value to 20. However the boxed version doesn’t get updated! Oh and by the way, C# prevents you from altering the fields on the boxed version of a value type.

So be very careful when dealing with boxing and unboxing it could cause you some headaches one day!

Linq

How to do a join between two XML files with Linq

Linq is still a relatively new concept, but with the release of Visual Studio 2008 beta 2 and talk of a release candidate version it is about to become available for production use.

I’ve been knocking around with Linq for a little while now, and so far I really like what I see. There is plenty of talk about it around the internet and some excellent tutorials kicking around also. For a great look into Linq to SQL and also an overview of lambda expressions and extension methods check out Scott Guthrie’s blog.

First let me begin by saying that I make no pretences to being any form of Linq expert. My linq skills are still very much in their infancy… but I’m going to have a go at talking you through a little problem I had to solve the other day.

The Problem

You have two XML files, or a single XML file with two distinct tree’s. The first file/tree contains some records with primary keys of sorts. The second file/tree contains some joining information. The example I will use here is a list of words and synonyms.

File A may look like this:

<words>       <word>          <id>1</id>
         <text>Accident</text>      </word>      <word>          <id>2</id>
         <text>Mistake</text>      </word>   </words>

File B may look like this (linking the word and its synonyms):

<links>       <link>          <id>1</id>
         <refId>2</refId>      </link>   </links>

A little disclaimer here: Obviously given the chance you would use the hierarchical nature of XML to store the relationships, but because the source of the data I had to deal with was flat I had no choice.

When using linq to SQL you get lovely typed data and all the relationships are mapped out for you (or you map them out using the linq to SQL designer if they are not present in the source data). Unfortunately with linq to XML we can’t explicitly map these relationships *yet*.

Enter stage left the linq join functionality. The join keyword available in linq basically lets you write similar joins to what you might be used to with SQL (left, inner, outer etc).

An SQL query to select a word and find all the synonyms using the ref table might look something like this:

SELECT words_1.word
FROM links INNER JOIN
words ON links.id = words.id INNER JOIN
words AS words_1 ON links.refId = words_1.id

Pretty simple in SQL… but in linq to XML how to you achieve the same result? Using the join keyword of course.

Start off by loading the two XDocuments – one for the words and the other for the linking information:

XDocument wordDoc = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "\\words.xml");
XDocument linkDoc = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "\\links.xml");

Then start the linkq query in the usual way.

 var wordMatched = from w in wordDoc.Elements("words").Elements("word")

This will iterate all the elements in words/word, and place them into the w variable.

Next we can start populating the return var with information on the currently selected word element.

 select new
 {
 id = w.Element("id").Value,
 term = w.Element("text").Value,

Basically each item in the wordMatched IEnumerable object will contain .id and .term when you iterate them. That’s all really interesting but it doesn’t really do much yet, we want each wordMatched element to contain multiple child synonym words.

 syns = from refIds in linkDoc.Elements("links").Elements("link")
        join synLinkedWord in wordDoc.Elements("words").Elements("word") on refIds.Element("refId").Value equals synLinkedWord.Element("id").Value
        where refIds.Element("id").Value == w.Element("id").Value
        select new
        {
           id = synLinkedWord.Element("id").Value,
           term = synLinkedWord.Element("text").Value
        }

The join here is selecting words from the same XML file first up… this is because the final data we want resides in the same XML file as the words (i.e. words and their synonyms are identical, its the linking table that joins them up). The next part of the join says: we want to make the refIds in the other XML file match the ids of words in the original table.

Next is the where clause, which places a restraint on the query, or the join will return all items that are referenced in the links table… so only return items from the links table that have an id the same as the id on the original “w” object.

Finally we select some data from the original table again (this time using the word that our linking XML gave us).

To read this data is quite simple:

 foreach (var word in wordMatched)
 {
     txtOutput.AppendText("\r\nWord: " + word.term);
     foreach (var syn in word.syns)
     {
          txtOutput.AppendText("\r\n\t->Syn: " + syn.term);
     }
 }

As you can see each word contains the id and term properties, but also contains another IEnumerable properly called syns, each one containing the details of the syns!

Problems

There is one problem which I cannot solve as yet, and this is due to my total lack of depth in linq… Iterating through the wordMatch enumeable will return words which were listed as syns in other words… i.e. in our example mistake will be listed as a syn under accident, but it will also be listed by itself as a main word. This can probably be solved with some more where clauses and possibly another join… comments would be greatly appreciated on this!

Edit 9 Movember (sic) 2007

I solved my own problem whilst working on another problem… Insert the following line below the first from w in wordDoc xxxxx line:

where linkDoc.Elements("links").Elements("link").Where(p=>p.Element("refId").Value==w.Element("id").Value).Any() == false

This line adds a where clause that runs a scan on the links XML document searching for items that have a refId that is the same as the current id. The lambda expression in the .Where checks all elements in the linkDoc.Elements(“links”).Elements(“link”) enumerable to see if their ids match. The .Any() method returns true when the returned enumerable contains one or more items. So if an items id is a refId in the links table we assume that it is a synonym.

Full Listing

XDocument wordDoc = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "\\words.xml");
            XDocument linkDoc = XDocument.Load(AppDomain.CurrentDomain.BaseDirectory + "\\links.xml");

            var wordMatched = from w in wordDoc.Elements("words").Elements("word")
                              where linkDoc.Elements("links").Elements("link").Where(p=>p.Element("refId").Value==w.Element("id").Value).Any() == false 			      select new
                              {
                                  id = w.Element("id").Value,
                                  term = w.Element("text").Value,
                                  syns = from refIds in linkDoc.Elements("links").Elements("link")
                                         join synLinkedWord in wordDoc.Elements("words").Elements("word") on refIds.Element("refId").Value equals synLinkedWord.Element("id").Value
                                         where refIds.Element("id").Value == w.Element("id").Value
                                         select new
                                         {
                                             id = synLinkedWord.Element("id").Value,
                                             term = synLinkedWord.Element("text").Value
                                         }
                              };

            foreach (var word in wordMatched)
            {
                txtOutput.AppendText("\r\nWord: " + word.term);
                foreach (var syn in word.syns)
                {
                    txtOutput.AppendText("\r\n\t->Syn: " + syn.term);
                }
            }
Web Services

Encrypting and securing web service traffic without SSL

Sometimes the need arises to have secured web service traffic without depending on SSL. The web service in a windows service without IIS from the previous post cannot use SSL anyway (well not that I know – any comments on this). There also may be a need to authenticate to the web service, either through the usual user and pass system, or my preferred method of using AES and pre-shared keys. Security experts agree the world over that AES is a very tough security standard. This method is great for two reasons:

  • No need to type in a user and pass, just ensure the keyfile is on each machine – if they keys match then the data is readable
  • Very high security

It does have a couple of downsides however:

  • Each client must have the same key – unless we use soap headers to first identify the user, the server will use this info to load the appropriate key
  • Keys cannot distinguish users without the soap header above or something similar, so user accounting is a smidge more tricky than straight user and pass

Of course on IIS you can use both the pre-shared key and user/pass authentication for extra security – NTLM kerberos and pre-shared AES key… pretty damn secure in my book.

A basic outline of the steps involved in this little project is:

  • Create webservice
  • Create encryption class
  • Create SOAP header class to provide a secondary layer of security
  • Maybe some user/pass authentication if I get time (for IIS only)

I’m going to use the web service created in the previous post, but this should work with any web service, WSE or not.

First we will get the basic encryption stuff out of the way, so create a new public class called Crypto… mine is in a class library. This class will create a key if one doesn’t exist, and will provide the encryption and decryption duties. This article isn’t focused on encryption, so I’m going to just dump the encryption class code in one blob.


using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Xml;

namespace Web_Service_inside_a_Windows_Service
{
    public class Crypto
    {
        byte[] key;
        byte[] iv;

        public Crypto()
        {
            keyInit();
        }

        //pretty much a straight copy of MSDN
        public byte[] Encrypt(string input)
        {
            UTF8Encoding textConverter = new UTF8Encoding();
            RijndaelManaged rijndael = new RijndaelManaged();
            byte[] toEncrypt;         

            ICryptoTransform encryptor = rijndael.CreateEncryptor(key, iv);

            MemoryStream msEncrypt = new MemoryStream();
            CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);

            toEncrypt = textConverter.GetBytes(input);

            csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
            csEncrypt.FlushFinalBlock();

            return msEncrypt.ToArray();
        }

        public string Decrypt(byte[] input)
        {
            UTF8Encoding textConverter = new UTF8Encoding();
            RijndaelManaged rijndael = new RijndaelManaged();

            byte[] fromEncrypt;
            int discarded = 0;

            ICryptoTransform decryptor = rijndael.CreateDecryptor(key, iv);

            MemoryStream msDecrypt = new MemoryStream(input);
            CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read);

            fromEncrypt = new byte[input.Length];

            csDecrypt.Read(fromEncrypt, 0, fromEncrypt.Length);

            return textConverter.GetString(fromEncrypt);
        }

        //check for keys and if not present the create them
        //load keys into local vars
        void keyInit()
        {
            //place the keys in a nicely accessible location so other applications that use this class can use them - note this location is probably
            //not secure on most machines
            FileInfo keyFile = new FileInfo(System.Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData) + "\\CryptoKeys");

            string sKey;
            string sIv;

            if (!keyFile.Exists)
            {
                sKey = generateHexKey();//set the keys into the local vars as they are created
                sIv = generateHexIV();
                XmlDocument doc = new XmlDocument();
                doc.LoadXml("");

                XmlNode keyNode = doc.CreateElement("key");
                keyNode.InnerText = sKey;
                doc.DocumentElement.AppendChild(keyNode);

                XmlNode ivNode = doc.CreateElement("iv");
                ivNode.InnerText = sIv;
                doc.DocumentElement.AppendChild(ivNode);

                if (!keyFile.Directory.Exists)
                {
                    keyFile.Directory.Create();
                }

                doc.Save(keyFile.FullName);
            }
            else
            {
                XmlDocument doc = new XmlDocument();
                doc.Load(keyFile.FullName);
                sKey = doc.DocumentElement.SelectSingleNode("key").InnerText;
                sIv = doc.DocumentElement.SelectSingleNode("iv").InnerText;
            }

            key = Convert.FromBase64String(sKey);
            iv = Convert.FromBase64String(sIv);
        }

        string generateHexKey()
        {
            //Rijndael *is* AES
            RijndaelManaged rijndael = new RijndaelManaged();
            rijndael.GenerateKey();
            return Convert.ToBase64String(rijndael.Key);
        }

        string generateHexIV()
        {
            RijndaelManaged rijndael = new RijndaelManaged();
            rijndael.GenerateIV();
            return Convert.ToBase64String(rijndael.IV);
        }
    }
}

There. Nothing fancy, pretty much the default encryption stuff from MSDN, except i change the ASCIIEncoder to a UTF one so that way it will support any character we throw at it. Oh and the comments are poor as you can see.

Okay, so now we can encrypt stuff, lets use it and get some secure web service action happening. First we need to update the web service. In your web service code behind make the following adjustments.


using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "http://myURI/MyLittleWebService")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebServiceCodeEncrypted : System.Web.Services.WebService
{
    Web_Service_inside_a_Windows_Service.Crypto crypto = new Web_Service_inside_a_Windows_Service.Crypto();
    public WebServiceCodeEncrypted()
    {
    }

    [WebMethod]
    [SoapHeader("AuthKey", Direction = SoapHeaderDirection.In)]
    public string GetMessages(string sGuid)
    {
        string guid = decString(sGuid);
        return encString("At the third stroke the time will be " + DateTime.Now.ToString() + ". Your guid was " + guid);
    }

    string encString(string input)
    {
        //convert the byte array that comes out for easy transport.
        return Convert.ToBase64String(crypto.Encrypt(input));
    }

    string decString(string input)
    {
        return crypto.Decrypt(Convert.FromBase64String(input));
    }

    public class AuthorisationKey : SoapHeader
    {
        public byte[] EncData = null;

        public AuthorisationKey()
        {

        }

        public bool Validate(System.Web.HttpContext context, string WSMethodName)
        {
            try
            {
                //EncData should contain the ticks of the date time that hte request was made...
                //by checking this we are doing two things a) the key is right if we get a valid date time and
                //b) the request is only valid for 5 minutes, cause after that runDate will be less than now - 5 mins.
                string ticks = crypto.Decrypt(EncData);
                DateTime runDate = new DateTime(Convert.ToInt64(ticks));
                return runDate > DateTime.Now.AddMinutes(-5);
            }
            catch (Exception ex)
            {
                //maybe throw a nice exception here - like the key was bad or something.
                throw ex;
            }
        }
    }

}

A few notes:

  • Added decrypt and encrypt string methods. They user the base64encoding stuff in the Convert class library to turn the byte array into a string.
  • We could have just put return type of byte[] on the GetMessages web method (.NET will base64 encode it anyway), but I like strings better because they are easily stored in formats like XML.
  • We added in the soap header authorisation class. More on this a bit later.
  • Changed the web service class name to WebServiceCodeEncrypted because you need to include a reference to your main project to bring in the new crypto class library, and there would have been two classes named the same (the original copy of the webservice is in the other class remember)
  • Note that any unsafe string (i.e. un encrypted) should always be named in a way that indicates its status. For example, you could call your safe encrypted string sSomeName and your un-encrypted ones uSomeName… then hopefully you wont ever accidentally transmit around an unsecured string.

Ensure you copy this updated webservice code into an IIS based “real” web service and update the reference in your project.

Now accessing the webservice is the fun part. Update the code in your WebServiceQuery class:


WebServiceCodeReference.WebServiceCodeWse wsc = new WebServiceCodeReference.WebServiceCodeWse();
WebServiceCodeReference.AuthorisationKey key = new WebServiceCodeReference.AuthorisationKey();

Crypto crypto = new Crypto();
key.EncData = crypto.Encrypt(DateTime.Now.Ticks.ToString());

wsc.AuthorisationKeyValue = key;

IPHostEntry ip = Dns.GetHostEntry(targetMachineName);
wsc.Url = "soap.tcp://" + ip.AddressList[0].ToString() + "/MyLittleWebService";

string result = wsc.GetMessages(Convert.ToBase64String(crypto.Encrypt("This here is a test string")));

string decResult = crypto.Decrypt(Convert.FromBase64String(result));</pre>
<pre>return decResult;

First and foremost if you run this from your test application or service, the data will be encrypted! Secondly you can see we are creating an object to implement the call to the soap security header… we put the current date time in there, so the server can get *its* current date time, take off five minutes, and compare it to the one passed in… this means that each message is only valid for five minutes (so no nefarious beings can pinch your packets and spoof another request to the server – well not after five minutes anyway).

If you are running your web service on IIS then you can add in the following code to authenticate with user and pass while still using the pre-shared key system:


	if (user != null && user!=string.Empty)
            {
                if (user.ToLower() == "integrated")
                {
                    wsc.Credentials = System.Net.CredentialCache.DefaultCredentials;
                }
                else
                {
                    NetworkCredential netCred = new NetworkCredential(user, pass);
                    wsc.Credentials = netCred;
                }
            }

Pass the user and pass variables into your method. Set the user the integrated to use the NTLM based single sign on authentication of the current windows user.

Update: 31 October 2007

Another reason why using built in encryption rather than SSL etc is that SSL is transport level encryption, meaning you cannot access the encrypted version of the content. With the AES inbuilt version you could save off your messages to DB or filesystem without the need to re-encrypt them.

Update: 16 May 2008

Added missing soap attribute from GetMessages method.

Web Services

Web service inside a Windows service without IIS

Update: If you have any questions about this article or any other web-services related queries then please ask! I see alot of traffic coming from Google about web-services and related issues/problems which this text doesn’t cover but I can probably help with! Leave a comment and I will respond quickly – if I don’t have the answers then I bet I know someone that does.

Skip to the Ramble End section to get into the guts of the article… the first part is just me talking too much as usual.

I’ve decided I need to get out more (it was either me or my shrink – I cant remember. Ed.); see the sights, expand my horizons, meet new media dissemination platforms.

I find myself writing and documenting code for my team mates at Objectify – tidbits of information here and there, how-to’s, faq, code snippets, my secret pasta recipe etc. – all usually transmitted in email form, with the occasional Word or PDF doc if they are lucky. If they are really lucky I may enter it into our internal FAQ system… for a fee.

Why not blog about some stuff too? See just for interests sake if anybody is interested in anything I say.

I thought I would start off nice and easy – ease into the Blogoshere nice and slowly (note to self – blog about hating the word “Blogoshere”… oh someone already did, damn). So I’m opening up the innings with a little ditty about hosting web services inside a windows service without the need for IIS. I wrote this doco about a year and a half ago, so its basically a translation of some old stuff… Sure its nothing too technical, its not ahead of the curve so to speak, and its probably been done a thousand times but we all gotta start somewhere. If we get time we may even throw in some SOAP headers and AES encryption for good measure – nothing like a pre-shared key to brighten your day. Okay well maybe in the next entry.

I first came across the need for a web service inside a windows service when thinking about ways to decentralise the Objectify CMS debugging system. Basically the debugging system goes way back to the days of the first CMS, all written in VB6 mind you, and uses mail slots to transfer messages from an array of COM objects to the debugger output application. Problem was that clients (and internal testers etc.) had to log into the server and run the application to see the messages. Now I know what you are going to say – you can pipe mailslot data between machines, problem solved… but I wanted to try something new, so web services it was.

Ramble End

We will end up with a simple web service windows service (WSWS?) with an interface to query which will do some simple processing for posterity’s sake and return a message to the client.
Firstly, you are going to need Web Services Enhancements 3.0 from Microsoft. Hop along to http://msdn2.microsoft.com/en-gb/webservices/Aa740663.aspx and grab a copy – make sure you install the developer option (the Visual Studio developer option if you are using VS). It will distribute itself with your app when you build the installer (if you choose to) so no need to install the MSI on your target machine.

Start your new project by creating a class library. I called mine something original – Web Service inside a Windows Service. This is where we will be placing the bulk of the code. Create a new public class called HostWebService.

Add in references to Microsoft.Web.Services3 and System.Web.Services.

Begin your code by adding the following namespace includes:

using Microsoft.Web.Services3;
using Microsoft.Web.Services3.Addressing;
using Microsoft.Web.Services3.Messaging;
using System.Net;

Okay so we are ready to go. Too easy. In the constructor we need to do some things to start our little web service listener. First, we need to know the local machine’s DNS address, and use this address to create a URI for our new Web Service (i.e. the address that will be used in the client application to query the service).

 string hostName = Dns.GetHostName();
 IPHostEntry ipEntry = Dns.GetHostEntry(hostName);
 Uri address = new Uri("soap.tcp://" + ipEntry.AddressList[0].ToString() + "/MyLittleWebService");

By the way, did I mention that if you know a better way to do any of this the please feel free to comment – i.e. is that the best way to get the IP of the local machine?

You can see above that the Uri address=xxxxx line is where you set the actual URI of the service, you can change the last part from MyLittleWebService to something more fitting if you like.

Now we need to create the actual web service code… It’s basically the same code that is generated by Visual Studio when you create a web service (the code behind in the Service.asmx file). Create a new class called WebServiceCode.cs and paste in the following:

using System;
using System.Web;
using System.Web.Services;
using System.Web.Services.Protocols;

[WebService(Namespace = "http://myURI/MyLittleWebService")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class WebServiceCode : System.Web.Services.WebService
{
    public WebServiceCode()
    {
    }

    [WebMethod]
    public string GetMessages(string guid)
    {
        return "At the third stroke the time will be " + DateTime.Now.ToString();
    }

}

Nothing too tricky there, stock standard web service stuff. Next we go back into the HostWebService class and add the following just below the URI stuff:

 SoapReceivers.Add(new EndpointReference(address), typeof(WebServiceCode));

And we’re done… almost. Well we’re done to the point that if you run that code (from a test app or something) then you will have a windows app that is hosting a web service. Thats great, but how do you query said service?

Accessing the new service

Before we can access the new web service we need to add it as a Web Reference to our project. Normally this is nice and easy, just right click and add a Web Reference in Visual Studio and let WDSL do the work. Problem is this new web service isn’t published anywhere yet, and even when its installed on the target machine and running, its URI will be unknown to the client.

Lets start by getting the web reference. Create a new ASP.NET web service project (call it tempservice or something, you wont need to keep it for long) go to the Service.asmx code behind and paste in the code from your WebServiceCode.cs file. Then right click the Service.asmx file and View in Browser. Copy the URL from the browser window that pops up, and add it as a web reference to your main project (right click References, Add Web Reference, paste into field, click Go, click Add Reference).

Great we have a description of our web service for the client app to use when querying.

Create another class called WebServiceQuery. Add the following to the namespace references section:

 using System.Net;

Now create a public method called Query that returns a string (or you can just paste in the following code):

 public string Query(string targetMachineName)
   {
      Web_Service_inside_a_Windows_Service.WebServiceCodeReference.WebServiceCodeWSE wsc = new Web_Service_inside_a_Windows_Service.WebServiceCodeReference.WebServiceCodeWSE();

      IPHostEntry ip = Dns.GetHostEntry(targetMachineName);
      wsc.Url = "soap.tcp://" + ip.AddressList[0].ToString() + "/MyLittleWebService";
      string result = wsc.GetMessages("some guid");

      return result;
   }

NOTE: The object we create is the WSE version (WebServiceCodeWSE), without this the calls to soap.tcp will not work.

Simple – first we instantiate our web reference object. Then we set the URI of the newly instantiated object the same way we did for the service itself. Finally we query the service and return the value. Note the GUID parameter on the service call – this is just in there to demonstrate calling methods and passing in parameters, but you already knew how to do that.

Now you can create a test application, start the service and then query it! All that’s left is to create a Windows service and create an instance of your calling class.

Just a note on the URI creation parts – if you are getting an error do do with port parsing, check that the IP address its getting isn’t and IPV6 address…

Okay so that’s it, my first post. Its long and boring.

Next time I will visit security using SOAP headers and how to encrypt the SOAP data using AES (Rijndael).

Cheers.