If you have not read about it yet or seen it or used it, please visit Davy Brion’s Blog here and download the Agatha project.  Another link I need to mention is the following, Integrating Strcuture Map With WCF.  Basically what I have attempted to do is create an Agatha.Common.InversionOfControl.IContainer implementation for Agatha which uses StrcutureMap as the IOC Container.  I am also not hosting the WCF Service inside a Web Application but in an actual WCF Service Application which I wanted to use the Service Host Factory as demoed in the above link.

The implementation for the Container was relatively straight forward in most parts and allowed me to use some newer features of StructureMap which I do not currently use yet in my job; well I say newer, newer to me!!.  I have read on Davy Brion’s blog that he is intending to write this Agatha IOC Container for Structure Map, and I look forward to it, but in the mean time I thought I would have a crack at it myself.

While writing the Container for StructureMap I had to make a small change/addition to the Agatha source code, on the interface for the IContainer to make sure that a method had a generic type constraint.  The method:

void Register<TComponent,TImplementation>()

A compile time error was raised which stated that there was no information to allow for boxing/unboxing.  To solve this I added the following constraint:

void Register<TComponent,TImplementation>() where TImplementation : TComponent

Once added the compile time error went, but I was still left with another issue which at this stage of writing this post I am of the opinion that I need to also make a small addition to StructureMap.  I look forward to it, if it is not already available but it would be good to find out that it is already accounted for.  The operation which I am talking about is the removal of an instance from the IOC Container.  The interface for the Agatha IOC IContainer has a method called Release which takes an object instance as a parameter and with the Castle WInsor you can release an instance.

    public interface IContainer
    {
        void Register<TComponent, TImplementation>(Lifestyle lifestyle) where TImplementation : TComponent;
        void Register(Type componentType, Type implementationType, Lifestyle lifeStyle);
        void RegisterInstance<TComponent>(TComponent instance);
        void RegisterInstance(Type componentType, object instance);
        void Release(object component);
        TComponent Resolve<TComponent>();
        object Resolve(Type componentType);
    }

After doing a bit more searching I cannot find a function which fits this criteria exactly.  There is the EjectAllInstancesOf<T> method, but the one I ended up using is the following:

        public void Release(object component)
        {
            //throw new NotImplementedException();
            _strcutureMapContainer.Model.EjectAndRemove(component.GetType());
        }
 

This is a method on the IContainer interface and I am using the component to get its type and releasing all instances of it within the IOC Container.  I am not 100% sure this is what other implementation of IOC are doing with this particular type of function.  Never the less, this does work fine and I am now up and running with the Agatha library inside a WCF Service Application Project using a ServiceHostFactory and configuring a StructureMap IOC Container for use with Agatha.

I have not made the most consistent approach to the StructureMap usage as I have mixed preferred and deprecated methods.  This is because I am not 100% sure how to map the new style of Lifeycle management between Castle Windsor and StructureMap. I look forward to seeing the actual implementation which goes into the Agatha project so I can see where I could have improved my attempt.  Here is the finished code of my attempt.

Hope this is of some help,

Cheers,

Andrew

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using sm = StructureMap;
using Agatha.Common.InversionOfControl;

namespace Agatha.StructureMap
{
    public class Container : Agatha.Common.InversionOfControl.IContainer
    {
        private readonly sm.IContainer _strcutureMapContainer;

        private Dictionary<Lifestyle, sm.InstanceScope> _lifeStyleMappings = new Dictionary<Lifestyle, sm.InstanceScope>
        {
            {Lifestyle.Singleton, sm.InstanceScope.Singleton},
            {Lifestyle.Transient, sm.InstanceScope.Transient}
        };

        private Dictionary<Lifestyle, sm.Pipeline.ILifecycle> _lifeStyleLifeCycleMappings = new Dictionary<Lifestyle, sm.Pipeline.ILifecycle>
        {
             {Lifestyle.Singleton, new sm.Pipeline.SingletonLifecycle()},
            {Lifestyle.Transient, new sm.Pipeline.UniquePerRequestLifecycle()}
        };

        public Container() : this(new sm.Container()) { }

        public Container(sm.IContainer structureMapContainer)
        {
            _strcutureMapContainer = structureMapContainer;
        }

        public void Register(Type componentType, Type implementationType, Lifestyle lifeStyle)
        {
            _strcutureMapContainer.Configure(x => x.For(componentType).LifecycleIs(_lifeStyleMappings[lifeStyle]).Use(implementationType));
        }

        public void Register<TComponent, TImplementation>(Lifestyle lifestyle) where TImplementation:TComponent
        {
            _strcutureMapContainer.Configure(x => x.ForRequestedType<TComponent>()
                .CacheBy(_lifeStyleMappings[lifestyle])
                .TheDefaultIsConcreteType<TImplementation>());
        }

        public void RegisterInstance(Type componentType, object instance)
        {
            _strcutureMapContainer.Configure(x => x.ForRequestedType(componentType).Use(instance));
        }

        public void RegisterInstance<TComponent>(TComponent instance)
        {
            _strcutureMapContainer.Configure(x => x.For<TComponent>().Use(instance));
        }

        public TComponent Resolve<TComponent>()
        {
            return _strcutureMapContainer.GetInstance<TComponent>();
        }

        public object Resolve(Type componentType)
        {
            return _strcutureMapContainer.GetInstance(componentType);
        }

        public void Release(object component)
        {
            //throw new NotImplementedException();
            _strcutureMapContainer.Model.EjectAndRemove(component.GetType());
        }
        
    }
}


.NET | Architecture | C# | WCF
Wednesday, February 10, 2010 10:16:44 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer

An extremely important procedure when working with WCF Services or any remote proxy is to close the service when you are finished using it.  I have been working a lot with Structure Map of late as opposed to Microsoft Unity and one thing which I wanted to have a look at was, injecting an instance of the service proxy into my controllers.  Now before I started one thing was circling in my mind, my normal usage when it came to WCF would be that I wrap the proxy inside a using statement, guaranteeing that it would be disposed of correctly. 

Since I am now injecting this service proxy into the constructor, it became apparent that I now needed a finish line where I could dispose of the service proxy after it had been used. Currently, what seems to be working is, as obvious as this sounds, placing the logic inside an override of the base controller’s Dispose method. 

There were a few ideas going through my head but unfortunately this was not sticking out at all, not sure why.  It was only when my attention was brought to the controller factory that it came clear.  The first attempt, which was successful, was to override the ReleaseController method of the Controller Factory.  Inside here I checked whether the controller could be assigned from IDisposable, and if so, cast and call.  This method meant I needed to implement the IDisposable interface on the Controller, well here is something which I SHOULD HAVE KNOWN:

Controller implements IDisposable –> doh! arrghhh

Yeh, not sure why this was not immediately obvious to me but hey ho, you live and learn , so I now removed the unnecessary override inside the Controller Factory and simply override the Dispose method inside the controller. 

        protected override void Dispose(bool disposing)
        {
            (_forumService as IDisposable).Dispose();
            base.Dispose(disposing);
        }

Great stuff, so now when my controller is released my service proxy is also cleaned up.  This is great timing for me and at present works fine.  I am using request/response objects so any information which needs to be dealt with inside a transaction is encapsulated inside the request object which are flat-ISH data transfer objects which can then be processed on the server.

You will notice, or should anyway that without this call to dispose, you wcf service application will not know that the client connection has been terminated.  I have seen that there is obviously a limit to concurrent connections that the service will handle, and when all are in progress, further requests are queued up. Now I have this, and also the service proxy injected, the controller is nice and slick.

Here is an example of what my controller now looks like using the injection of the service proxy:

    public class ForumController : Controller
    {
        private readonly IForumService _forumService;

        public ForumController(IForumService forumService)
        {
            _forumService = forumService;
        }

        public ActionResult Index(int id, int? pageIndex, int? pagseSize)
        {
            var request = new GetForumRequest
            {
                ForumId = id,
                Query = new PagedQueryDto
                {
                    PageIndex = pageIndex ?? 0,
                    PageSize = pagseSize ?? 10,
                    SortOrder = new SortOrderCollection
                    {
                         new SortOrder
                         {
                              ColumnName = "Id",
                              Ascending = false
                         }
                    }
                }
            };

            GetForumResponse response = (GetForumResponse) _forumService.ProcessRequest(request);

            return View(response);
        }

        protected override void Dispose(bool disposing)
        {
            (_forumService as IDisposable).Dispose();
            base.Dispose(disposing);
        }
    }

Once I am further along with more request/response objects I will be putting this sample application up onto Google Code.  This is a project I am deving for the purposes of helping me learn more about Enterprise Architecture with specific focus on the following:

  • Domain Driven Design
  • Domain Events
  • Services
  • Dependency Injection and Inversion Of Control
  • Messaging Systems

Anyways, hope this is of some help,

Cheers for now,

Andrew


Monday, October 12, 2009 12:03:09 AM (GMT Daylight Time, UTC+01:00)  #    Disclaimer

The first part in this series which I would like to do can be found here:

Part 1 : Socket Programming with C#, JAVA, C++ and Action Script 3.0 – Establishing a base connection and communication with C# Server and AS3

The files for this solution can be downloaded here: WCFCallbackExample

I am looking into how you can work with network communication with sockets using the different languages and this post will use C# and more specifically WCF.  In this post I will look at the bi directional capability of WCF using the NetTcpBinding, I will follow up this post in the near future with an example using the Duplex WS binding (WSDualHttpBinding).  If you are in the area of Application Development and say wanting to use this for example with a chat application, the NetTcpBinding requires that both the client and the service use WCF, so for interoperability that is not really of much use, but there is more than one way to skin a cat for sure.

In this post and the example solution I am making use of threading for the purposes of the example so I can simulate many clients, as opposed to launching the application many times.  I will be making use of the Thread class, ThreadPool class, WaitHandle class, ManualResetEvent class and using a ParamterizedThreadStart and WaitCallBack delegates.  I have also made an extension method which the mode value of an IList<T>.

The theme of this example will be voters casting these vote.  Once all the votes are in, in this case 10, the votes will be counted and all the voters will be informed of the winning candidate.

NetTcpBinding

For the code in this example I am not using the configuration files, I am instantiating and configuring on the fly programmatically as I want to get a feel for accomplishing tasks both programmatically and through xml configuration as both have their benefits dependant on the situation.  The basic idea which I want to demonstrate first of all goes like this.

  1. Instantiate and open a service host to accept incoming messages
  2. Instantiate a client a proxy a call to the listening service
  3. On the server side I want to process the message call from the client and then call-back to the client using the method which I define with an interface(the contract).

The Program

The files which make up this small program include the following:

  • IVote
  • IVoteCallback
  • Client
  • ListExtension
  • Proxy
  • Server
  • ServiceHost

image

I have separated the client from the proxy, first because lol it is a proxy but also each one has a different responsibility, what you end up with though is Client calls Vote on Proxy, Proxy calls Vote on the Service.  So it is exactly that “a proxy,” i.e. the middle person.

I have used the following class for a generic Service Host from the following book, Programming WCF Services.

    public class ServiceHost<T> : ServiceHost
    {
        public ServiceHost()
            : base(typeof(T))
        { }

        public ServiceHost(params string[] baseAddresses)
            : base(typeof(T), Convert(baseAddresses))
        { }

        public ServiceHost(params Uri[] baseAddresses)
            : base(typeof(T), baseAddresses)
        { }

        static Uri[] Convert(string[] baseAddresses)
        {
            Converter<string, Uri> convert = delegate(string address)
            {
                return new Uri(address);
            };

            return Array.ConvertAll(baseAddresses, convert);
        }
    }

The call-back

This is very much an event, and as such many client can subscribe to this event.  It is the service’s responsibility to ensure all subscribers of this event are notified upon the invocation of some trigger, “Don’t call us we shall call you.”

As much as this is an event, the way you program this as opposed to normal CLR Event Subscription and Invocation is different and slightly more management is required with regards to concurrency.

The contract for the call-back is simply the following:

    public interface IVoteCallback
    {
        [OperationContract]
        void OnVotesCounted(string winner);
    }

The server will invoke this method on the clients, and the clients themselves will inherit from this interface so the server can invoke the method on it.  The implementation of this method is up to the client, but it is the responsibility of the Service Host to invoke it.

The Service Contract

The following contract is what the service needs to use, and also any proxy that is made for this service. The client invokes the contract on the proxy and in turn the proxy invokes the contract on the service.

    [ServiceContract(Name = "WCFCallbackExample.Contract.IVote",
        Namespace="uk.co.andrewrea",
        SessionMode=SessionMode.Required,
        CallbackContract=typeof(IVoteCallback))]
    public interface IVote
    {
        [OperationContract(IsOneWay=true)]
        void PlaceVote(string name);
    }

This interface requires some specific attributes for the purposes of:

  1. Being a service contract
  2. Providing operation contracts for a service
  3. Allowing the service to be used in a Duplex hosting scenario, i.e. the service host can send messages to the client as well as the client can send messages to the service
  4. Information for WCF to recognise what call-back it is dealing with.

The session mode is set to required so a call-back can be sent to the client, this is also true of the WSDualHttpBinding.

Also I will mention why I have made the operation in this contract one way below.

The Server

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
        ConcurrencyMode = ConcurrencyMode.Multiple)]
    public class Server : ServiceHost<Server>, IVote
    {
        //A collection of votes from the clients.  
        //The candidate name is the string object value
        private static List<string> _votes
            = new List<string>();

        //A list of the callbacks which the server should invoke
        //allowing the clients to be notified
        private static List<IVoteCallback> _callbacks
            = new List<IVoteCallback>();

        //For the purposes of syncronization
        private static object _syncLock = new Object();

        public Server()
            : base()
        {

        }

        public Server(params string[] addresses)
            : base(addresses)
        {

        }

        #region IVote Members

        /// <summary>
        /// This method will be proxied and called by the client
        /// </summary>
        /// <param name="name"></param>
        public void PlaceVote(string name)
        {
            lock (_syncLock)
            {
                //Get the callback from the client
                IVoteCallback callback = OperationContext.Current
                    .GetCallbackChannel<IVoteCallback>();

                //If the service does not already contain the callback add it
                if (!_callbacks.Contains(callback))
                    _callbacks.Add(callback);

                //Add the vote
                _votes.Add(name);

                //I do not want to block here, so I accept the vote and 
                //call the method to count the votes on another thread
                //
                //I origianlly used the below BUT making the operation IsOneWay
                //Achieves the same thing.  Without this or the IsOneWay,
                //this will block the client thread.
                //ThreadPool.QueueUserWorkItem(new WaitCallback(CheckVoteCount));

                if (_votes.Count == 10)
                {
                    System.Threading.Thread.Sleep(2000);
                    VotesCounted();
                }
            }
        }

        /*
         * 
         * This was called by the ThreadPool, see above
        private void CheckVoteCount(object state)
        {
            if (_votes.Count == 10)
            {
                System.Threading.Thread.Sleep(2000);
                VotesCounted();
            }
        }
         * */

        #endregion

        /// <summary>
        /// This is the callback.  It will loop through all of them and
        /// invoke.  This is the method which updates the clients
        /// </summary>
        private static void VotesCounted()
        {
            Action<IVoteCallback> invoke =
                delegate(IVoteCallback clientCallback)
                {
                    clientCallback.OnVotesCounted(_votes.MostOccurences<string>());
                };

            _callbacks.ForEach(invoke);

        }
    }

The server is keeping a list of:

  • Votes
  • Call-backs

I have plumbed in some thread safety, as each call made to the service will be from a different thread.  You will notice that there is some code I have commented out but left in there.  This is because I wanted to explain the purpose of why I have not used it and what I have used instead.  What I was doing there was ensuring that the method did not block the client thread, so I did the work of the client and then kicked off another thread to check whether or not it should count the votes.  After doing this though, I thought about the IsOneWay attribute property which did exactly what I require.  If you specify this on an operation context, the client will call and forget about the method, i.e. it will not block as it does not care about is outcome so in this way I was able to leave the check for the votes inside the client method and this did not affect the client in terms of time.

Above when I said this was like the CLR Event model in a way, I would now say that through its implementation, it is more like the Java Event Model where you specifically add listeners and the object loops through its subscribers and calls the method the listener has provided as the call-back.  I realise under the covers this is what the clr event model will do, but from a coding point of view, it is more Java’esque – The Observer Pattern.

I will show the source for the extension method, MostOccurences<T> below.

The Proxy

    public class Proxy : DuplexClientBase<IVote>, IVote
    {
        public Proxy(InstanceContext context,
            Binding binding,
            EndpointAddress endpointAddress)
            : base(context, binding, endpointAddress)
        {

        }

        #region IVote Members

        public void PlaceVote(string name)
        {
            Channel.PlaceVote(name);
        }

        #endregion
    }

I have inherited both from the service contract but also from the DuplexClientBase<T> as opposed to the ClientBase<T> which allows the client to accept call-backs from the service.  As a proxy should, the PlaceVote method calls the PlaceVote of the service.  Although I have specified a constructor which allows the supply of a Binding, I am only using NetTcpBinding for this program but I have supplied it, as this is a constructor of the base class.  The InstanceContext is used directly for the call-back, so the service can identify what object instance to use for the call-back method.

The Client

    public class Client : IVoteCallback,IVote
    {
        private Proxy _proxy;
        private string _voterName;
        private ManualResetEvent _handle;

        public Client(string voterName, string serviceEndpointAddress, ManualResetEvent handle)
        {
            _voterName = voterName;
            _handle = handle;
            InstanceContext context = new InstanceContext(this);
            _proxy = new Proxy(context,
                new NetTcpBinding(),
                new EndpointAddress(serviceEndpointAddress));

        }

        #region IVoteCallback Members

        public void OnVotesCounted(string winner)
        {
            Console.WriteLine(String.Format("{0} has been notified the winner is {1}",_voterName, winner ));
            _handle.Set();
        }

        #endregion

        #region IVote Members

        public void PlaceVote(string name)
        {
            _proxy.PlaceVote(name);
            Console.WriteLine(String.Format("From {0}: I have placed my vote for {1}!", _voterName, name));
        }

        #endregion
    }

A lot of this code, is specific just to this example but it is the instantiation of the proxy and in turn the invocation of its method, and the implementation of both the Service Contract and the Call-back contract which are important.  The threading elements are just to provide synchronization and are used so I can test the service with multiple clients(threads). 

The Extension Method (ListExtenions.cs)

        public static T MostOccurences<T>(this IList<T> list)
        {
            Dictionary<T, int> count = new Dictionary<T, int>();
            foreach (T obj in list)
            {
                if (!count.ContainsKey(obj))
                {
                    count.Add(obj, 1);
                }
                else
                {
                    count[obj]++;
                }
            }

            return count.Where(x => x.Value.Equals(count.Max(k=>k.Value))).FirstOrDefault().Key;
        }

This will give me the value of the IList<T> which occurs most often, and its use is so I can see the candidate who won.

Program.cs

This is the main program where I implement the work.  Again the threading stuff is just for the purposes of the example.

    class Program
    {
        private static Server server;

        private static string netServerAddress = "net.tcp://localhost:8000";
        private static string endpointAddress = "net.tcp://localhost:8000/VotingService";
        private static Random rnd;

        private static string[] candidates = new string[]{
            "Candidate 1",
            "Candidate 2",
            "Candidate 3"
        };

        private static ManualResetEvent[] handles = new ManualResetEvent[10];
        private static Thread[] threads = new Thread[10];
        
        static void Main(string[] args)
        {
            rnd = new Random();

            StartService();

            for (int i = 0; i < 10; i++)
            {
                handles[i] = new ManualResetEvent(false);
                threads[i] = new Thread(new ParameterizedThreadStart(CreateClientAndVote));
                threads[i].Start(i);
            }

            Console.WriteLine("Waiting for votes to come in...");

            WaitHandle.WaitAll(handles);

            server.Close();

            Console.WriteLine("Voting has ended");

            Console.ReadLine();
        }

        static void StartService()
        {
            server = new Server(netServerAddress);
            server.AddServiceEndpoint(
                "WCFCallbackExample.Contract.IVote",
                new NetTcpBinding(),
                endpointAddress);
            server.Open();
        }

        static void CreateClientAndVote(object state)
        {
            int number = (int)state;
            Client newClient = new Client(String.Format("Voter #{0}", number + 1), endpointAddress, handles[number]);
            newClient.PlaceVote(candidates[(int)(rnd.Next(candidates.Length))]);
        }
    }

image

And thats it.  I hope this is of some help and/or interest.

Cheers for now,

Andrew.



.NET | C# | WCF
Wednesday, August 26, 2009 6:23:44 PM (GMT Daylight Time, UTC+01:00)  #    Disclaimer

This morning I followed an Adobe Flex tutorial, well 3, about consuming Twitters restful API inside Flex.  After this it got me thinking about WCF and their Rest Starter Kit.  I looked and they are now up to Preview 2, so I downloaded it and in my spare time focused on this recently release white paper:

A Guide to Designing and Building RESTful Web Services with WCF 3.5

Installing the starter kit, which also installs some project templates, gives you a good starting point.  It also introduced me to some new concepts.  The starter kit actually generates a help page for your service which is an xml feed and XSLT Style Sheet e.g.

image

So It provides all the relevant information required i.e. the method, the uri template, the request and response schema.  I tested out a quick code up for the simplest form for consumption by C# and it worked out pretty well.  I focused on the fact that the info can be returned currently in two formats being XML and also JSON.  I wanted an abstract class to hold the URI’s for each method and also abstract methods which each derived object needs to override.

The idea is ultimately to have strongly typed helper methods for consuming restful apis.  So the tool, similar to the WSDL or SVCUTIL could be supplied with the following information:

  • namespace
  • language
  • url of help feed
  • asynchronous

What I would want to build on is the language part, as the interoperability of a rest api is huge.  If you make an implementation of the help generator in C# for example and use a Strategy pattern for the generation then this gives rise to the following:

  • C# Generation Strategy
  • VB.NET Generation Strategy
  • ActionScript Generation Strategy
  • C++ Generation Strategy
  • Pure JavaScript Generation Strategy
  • Jquery Generation Strategy (Yes I differentiated from the JavaScript option)
  • PHP Generation Strategy
  • Java Strategy
  • Python Strategy
  • Ruby on rails strategy

So you get the idea, it could be built then extended over time.  Am I getting ahead of myself here?  Is there one in production? WHO KNOWS? but it is fun never the less to jump in and have a go. 

So the quick Code Up I did is as follows:

Duplicate the type used in the REST Service and decorate with the namespace for XML Serialization needs

    [XmlRoot(Namespace="http://schemas.datacontract.org/2004/07/Swissmod.Service.Model")]
    public class Project
    {
        public string ID { get; set; }
        public string UserID { get; set; }
        public string ClientID { get; set; }
        public string ProjectTitle { get; set; }
        public string ProjectDescription { get; set; }
        public DateTime Created { get; set; }
        public DateTime LastModified { get; set; }
        public string Version { get; set; }

        public override string ToString()
        {
            StringBuilder sb1 = new StringBuilder();

            foreach (PropertyInfo pi in this.GetType().GetProperties())
            {
                sb1.AppendLine(pi.Name + " : " + pi.GetValue(this, null));
            }

            return sb1.ToString();
        }
    }

Define the abstract class for the Project Service

    public abstract class ProjectRestClient
    {
        protected string baseUrl = "http://test.@yoursite.com/ProjectService.svc/";

        public abstract Project GetProject(string id);
    }

Implement an XML Version of the Project Rest Client

    public class ProjectXmlRestClient : ProjectRestClient
    {
        public override Project GetProject(string id)
        {
            WebRequest wr = WebRequest.Create(baseUrl + id);
            wr.Method = "GET";
            wr.ContentType = "text/xml";
            WebResponse wresp = wr.GetResponse();
            XmlSerializer serializer = new XmlSerializer(typeof(Project));
            XmlReaderSettings settings = new XmlReaderSettings();
            settings.ValidationFlags = XmlSchemaValidationFlags.None;
            settings.ValidationType = ValidationType.None;
            settings.ConformanceLevel = ConformanceLevel.Auto;
            settings.IgnoreProcessingInstructions = true;
            settings.NameTable = new NameTable();
            settings.NameTable.Add("http://schemas.datacontract.org/2004/07/Swissmod.Service.Model");
            XmlReader reader = XmlReader.Create(wresp.GetResponseStream(),settings);
            Project p = (Project)serializer.Deserialize(reader);
            return p;
        }
    }

Implement a JSON Version of the Project Rest Client

    public class ProjectJsonRestClient : ProjectRestClient
    {
        public override Project GetProject(string id)
        {
            WebRequest wr = WebRequest.Create(baseUrl + id + "?format=json");
            wr.Method = "GET";
            WebResponse wresp = wr.GetResponse();
            DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Project));
            Project p = (Project)serializer.ReadObject(wresp.GetResponseStream());
            return p;
        }
    }

Give it a whirl

At this point I know what is going to happen, but I am just protyping to give myself ideas for when I come to make a generation tool for the actual complete feed.  IF I CAN OFCOURSE! lol :-)

    public static class Program
    {
        const string XML = "XML";
        const string JSON = "JSON";

        [STAThread]
        public static void Main(string[] args)
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<ProjectRestClient, ProjectXmlRestClient>(XML, new ContainerControlledLifetimeManager());
            container.RegisterType<ProjectRestClient, ProjectJsonRestClient>(JSON, new ContainerControlledLifetimeManager());

            ProjectRestClient xmlCient = container.Resolve<ProjectRestClient>(XML);
            ProjectRestClient jsonCient = container.Resolve<ProjectRestClient>(JSON);

            Console.WriteLine(xmlCient.GetProject("1"));
            Console.WriteLine(jsonCient.GetProject("1"));

            Console.WriteLine("Press any key to exit");
            Console.ReadKey();
        }
    }

P.S. I have used unity here for a few reasons but mainly because I love the idea of Inversion of Control and Dependency Injections.  The above simply allows me to obtain a singleton instance of either class whenever I want to execute a service method.

image

So to summarise, the only reason I am doing this is so that the consumption of the Rest service is strongly typed, I am not doing this because I think it is a necessity, simply because I think it would be extremely helpful for me.  The ability to strongly type things gives me much more happiness when working across language barriers.

Anyways,

Cheers for now,

Andrew



.NET | ASP.NET | C# | WCF
Tuesday, March 17, 2009 4:42:57 PM (GMT Standard Time, UTC+00:00)  #    Disclaimer