Tuesday, September 25, 2012

Simple Web API

The few last months I have been playing around a lot with NodeJS. That has caused me to play with simple Rest API calls.  It's quite neat, you are basically able to do whatever you want with Javascript.  And using JSON you can quite easily communicate with your server.

I've recently installed Visual Studio 2012 ( thought I'd have a play with it), and I immediately wanted to play with the WebAPI.  It had already intrigued me when I had seen a talk by Glen Block about it at tech days.  Although, back then it was still unfinished.  So I was keen to see what it was doing now.  Since I had not played with MVC4, it's basically an intro for me.

When creating a new empty MVC4 project, the wizard will create a project structure.  Most notably for this spike it contains a "App_Start" and a "Controllers" folder.

The "App_Star" folder will contain a class called  WebApiConfig which has already some default routing setup to "/api/{controllerName}".

We can map a controller to this route by adding a new controller inheriting from the ApiController class in the "Controllers" folder.

public class NoteController : ApiController
    {
        public IEnumerable<Note> Get()
        {
            return new Note[] 
            { 
                new Note 
                {
                    Title = "ABC", 
                    Desciption = "value2" 
                } 
            };
        }
    }

The "Get" method basically maps to the Http GET method, it will do the same for POST, PUT, DELETE,...

What's cool is that it will serialize the DTO and output xml or json depending on the accept headers of the request.

If you want to force the output to be of another format you can  configure a querystring to output the correct result when calling the api.


GlobalConfiguration.Configuration
                .Formatters
                .JsonFormatter
                .MediaTypeMappings
                .Add(new QueryStringMapping("json", "true", "application/json"));

Calling "localhost/api/note?json=true" will then return : "[{"Title":"ABC","Desciption":"value2"}]"

To be fair, this does feel like a bulky way to do this, so if anyone knows of a better way, i'd be interested to know.

Wednesday, January 26, 2011

Auto-ViewModel binding with Ninject

I have done a lot of post about binding ViewModels to Views in Silverlight, so can you see that it is really a subject I am quite interested in.  It also allows me to learn more about several technologies all in the context of this domain.

Having said this, lets have a look at using Ninject for Injecting our ViewModels into our Views.  We are going to use the concept of a ViewModelLocator that will be hosting our Ninject kernel in the application scope.

This means we are going to host our Locator as a resource in our App.xaml resource dictionary and bind to it in our views, using the StaticResource as a source.

You would go about doing this as following, and reference it in your code
<Application.Resources> 
<Foo:ViewModelLocator x:Key="viewModelLocator"/>
</Application.Resources>

<UserControl DataContext="{Binding [Bar], Source={StaticResource viewModelLocator}}"/>

You can see that we have defined our ViewModel with the name ‘Bar’ and within square brackets, this means we are binding to an indexer of the ViewModelLocator.  This allows us to do some pretty cool stuff, on the expense of loosing Intelli-Sense.
So lets get started on writing our locator, we first start my setting up our class and initializing some Ninject stuff, creating the Kernel, adding modules,…
public class ViewModelLocator
{       
private readonly IKernel kernel;       
public ViewModelLocator()
{           
kernel = new StandardKernel(GetModules());           
kernel.Load();       
}
}

So the really cool thing we can do now, is create an indexer that will allow us the query our ViewModels setup in our Kernel dynamically without having to type it, and add a new Property for every ViewModel.

The indexer is pretty straightforward, it looks like this :
public object this[string viewModel]
{
get { return GetViewModel(viewModel); }
}

So as you could imagine, the real stuff goes on in the GetViewModel method, so lets have a quick look at that now, I'll explain what we are doing here afterwards.
private object GetViewModel(string viewModel)
{
String viewModelName = viewModel;
if (!viewModel.ToUpper().EndsWith("VIEWMODEL"))
{
viewModelName = viewModelName + "ViewModel";
}
return kernel.Get(GetViewModelType(viewModelName));
}

private Type GetViewModelType(string viewModelname)
{
foreach (string location in GetLocations())
{
Type type = Type.GetType(string.Format("{0}.{1}", location, viewModelname), false, true);
if (type != null)
return type;
}
return null;
}

When we are calling our “Bar” viewmodel, the GetViewModel method will get a string with the value '”Bar”, from this it will need to locate the ViewModel from our kernel which could have a whole bunch of dependency’s injected ( or should I say nInjected ) into it.

Our locator will will take into account a few conventions, it will check the ViewModel string ends with “ViewModel” and if not will append it.  It will then attempt to find the ViewModel Type and return the corresponding instance of that type from the Ninject kernel.

This is where our last convention comes into play, our ViewModels in our application will most likely be located on some very well defined locations (hence the GetLocations method). We can easily define these conventions and possibly even add new ones later, a simple convention for locations might look something like this :
 private IEnumerable GetLocations()
{
string applicationNamespace = GetType().Namespace;
yield return applicationNamespace;
yield return applicationNamespace + ".Shared";
yield return applicationNamespace + ".Shared.ViewModel";
yield return applicationNamespace + ".Views";
yield return applicationNamespace + ".Views.ViewModel";
}

So this way you can add ViewModels with Ninject without having to define any properties to bind to, you just have to type your ViewModel’s name and the locator will do the rest for you.