Simple commanding with Web-Api.

Introduction

OData is a splendid technology, simple in the heart but extremely powerful. Nonetheless, the “commanding” capabilities of Odata are still insufficient.

I have done quite some effort in the past, to find a decent solution for this. I developed an approach for the command table pattern which allows sending a command with a dedicated request parameter class and receiving a response with a dedicated response parameter class. The approach works fine, but you need to setup quite some base infrastructure.

Another interesting approach is using SignalR as command infrastructure. Very powerful stuff. It works more on a web socket level and allows even server initiated communication to the client or even to multiple clients.

This time I’ll come up with something different: Web-Api.

How will we organize the setup of a command with Web-Api?

For simplicity, let’s assume that I want to build a command which allows me to generate server side a big load of test Data. Obviously, this is something that you can do also client side, but it will work much slower when running this from the client. So, we want to inform the server that let’s say 10.000 test records need to be generated.

First install  server side the nuget package Microsoft.AspNet.WebApi.

nuget

 

 

 

 

 

 

 

In the client project we need the nuget package: Newtonsoft.Json.

As you see, a very simple nuget setup this time.

What do we need server side?

Server side, add a global.asax file to your project and include following code:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Web.Security;
using System.Web.SessionState;
using System.Web.Http;
namespace LightSwitchApplication
{
    public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            RouteTable.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{action}/{id}",
                defaults: new { action = "get", id = RouteParameter.Optional }
            );
        }
    }
}

The definition of this route will assure that our commands are routed to the correct controller and action. If you are familiar with Asp.Net MVC, you’ll understand :)

 

Next, add a command controller class, which contains the code for our specific command:

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http;

namespace LightSwitchApplication
{

    public class CommandController : ApiController
    {

        [HttpPost]
        public HttpResponseMessage CreateTestData(TestDataParameters testDataParams)
        {
            using (ServerApplicationContext ls = LightSwitchApplication.Application.CreateContext())
            {
                for (int i = 1; i < 10001; i++)
                {
                    Customer newCustomer = ls.DataWorkspace.ApplicationData.Customers.AddNew();
                    newCustomer.FirstName = string.Format("Customer {0} first Name", i.ToString());
                    newCustomer.LastName = string.Format("Customer {0} Last Name", i.ToString());
                    if (i % 100 == 0)
                        ls.DataWorkspace.ApplicationData.SaveChanges();
                }
                ls.DataWorkspace.ApplicationData.SaveChanges();
            }
            var response = Request.CreateResponse<TestDataParameters>(HttpStatusCode.Accepted, testDataParams);
            return response;
        }
    }
}

You might notice, that I forgot to do something with the incoming parameter, but just put a breakpoint over there, and you’ll see that there is indeed an incoming value.

It is important that our command (in controller terminology this is called an action) is correctly decorated with the HttpPost atttribute. This is because we deviate from the standard convention to call our method “Post”.

Obviously, introducing such a server side web-api is something you could do already in the very first version of LightSwitch, but the usage would be quite limited since you could not communicate with the LightSwitch domain model. The ServerApplicationContext introduced in preview 2 is here stealing the show.

Finally, we need a small class for transporting our command parameters:

public class TestDataParameters
    {
        public int AmountOfRecords { get; set; }
    }

What do we need client side?

Before we forget, we need the above parameter class, also in the client project. The best way to do this, add in the client project the class from the server project as an existing item and add it as a “link”.

Now, let’s first look how we want to trigger the command. Let’s assume that we put a button on a screen, and in the code behind we trigger the command.

It’s as simple as:

partial void CreateTestData_Execute()
        {
            this.StartWebApiCommand<TestDataParameters>("api/Command/CreateTestData",
                new TestDataParameters { AmountOfRecords=10000 },
                (error, responseParams) =>
                {
                    if (error != null)
                    {
                        this.ShowMessageBox("error = " + error.Message);
                    }
                    else
                    {
                        this.ShowMessageBox("result = " + responseParams.AmountOfRecords);
                    }
                }
                );
        }

Yeah, I know, a magic string “api/Command/CreateTestData”. I still need to find an elegant solution for that. Note that we trigger the command via an extension method on the screen object (this.StartWebApiCommand) and we specify the command parameters as a generic. I simplified a bit the usage of parameters in the sense that I don’t make any distinction any longer between request and response parameters. For daily usage that’s just fine :)

It’s clear that the above piece of command invocation is shielded by some piece of base infrastrucutre (now we enter my playground):

using Microsoft.LightSwitch.Client;
using Microsoft.LightSwitch.Threading;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace LightSwitchApplication
{
    public static class LightSwitchCommandProxy
    {
        public static void StartWebApiCommand<T>(this IScreenObject screen, string commandrelativePath, 
            object data, Action<Exception, T> callback)
        {
            Uri baseAddress = null;
            Dispatchers.Main.Invoke(() =>
            {
                baseAddress = new Uri( string.Format("{0}://{1}:{2}", 
                    System.Windows.Application.Current.Host.Source.Scheme,
                    System.Windows.Application.Current.Host.Source.Host,
                    System.Windows.Application.Current.Host.Source.Port));
            });

            var webRequest = WebRequest.Create(new Uri(baseAddress, commandrelativePath));
            webRequest.Method = "POST";
            webRequest.ContentType = "application/json";

            webRequest.BeginGetRequestStream(iar =>
            {
                var requestStream = webRequest.EndGetRequestStream(iar);

                SerializeObject(data, requestStream);

                webRequest.BeginGetResponse(iar2 =>
                {
                    WebResponse webResponse;
                    try
                    {
                        webResponse = webRequest.EndGetResponse(iar2);
                    }
                    catch (Exception ex)
                    {
                        screen.Details.Dispatcher.BeginInvoke(() =>
                        {
                            callback(ex, default(T));
                        });
                        return;
                    }
                    var result = Deserialize<T>(new StreamReader(webResponse.GetResponseStream()));

                    screen.Details.Dispatcher.BeginInvoke(() =>
                        {
                            callback(null, result);
                        });
                }, null);
            }, null);
        }
        private static void SerializeObject(object data, Stream stream)
        {
            var serializer = new JsonSerializer();
            var sw = new StreamWriter(stream);
            serializer.Serialize(sw, data);
            sw.Flush();
            sw.Close();
        }

        private static T Deserialize<T>(TextReader reader)
        {
            var serializer = new JsonSerializer();
            return serializer.Deserialize<T>(new JsonTextReader(reader));
        }
    }
}

Basically, the above extension method takes care of the asynchronous processing and the parameter serialization.

Until now, web-api is my personal favorite when it comes to commanding in LightSwitch. Not only, because it’s my most simple setup so far, but also because of the fact that Web-Api is  first class citizen material in the broader .Net ecosystem. For example, Controllers in the MVC world are in a sense, based on Web-Api. This means also that more web oriented LightSwitch companion apps can participate seamlessly in the whole commanding playground.

Demo app

Be patient, I’m preparing an approach for reporting with web-api. I’ll post the complete sample at that time.