Click here to Skip to main content
Click here to Skip to main content
Technical Blog

Invoke Command/queries in the browser, execute them in your app.

, 10 Mar 2015 LGPL3
Rate this:
Please Sign up or sign in to vote.
I've created a small sample project which demonstrates how you can invoke a query using javascript (and execute them in your server). The sample uses authentication, authorization, an inversion of control container and jQuery.

The cool thing (imho) is that this technique obsoletes ASP.NET MVC/WebApi and similar. That is, if you combine command/queries over ajax/websockets you only need static HTML pages and a client side library like angular. To gain performance you could even move all static HTML to a CDN.

Since this architecture doesn’t require a server side view engine, view model binding, controllers or whatever, the logic in the server is pretty slim which also allows more optimizations and performance gains. The HTTP server is functioning more like a service broker which redirects incoming messages to different parts of the system. The CQS Server could for instance route messages to different micro services as I’ve shown in a previous post.

griffin_cqs

Let’s go through all small pieces in my proof of concept. Do note that the library is still in an very early stage. The sample code can be watched in the github repos (link in the bottom of this article).

Authentication/Authorization

To authenticate I’m just using BASIC authentication in this sample. It works great when you have SSL activated (otherwise it’s not secure at all). The user is not requested to authenticate unless requested by your code.

Authentication is divided into two parts. The first part is to do the actual authentication by using a IAuthenticator, once completed a IPrincipalFactory is used to assign a IPrincipal to the current thread.

To activate authentication you assign an authenticator to the listener:

var listener = new CqsHttpListener(builder.BuildMessageProcessor());
listener.Authenticator = CreateAuthenticator();

.. which in this case is built like this..

private static IAuthenticator CreateAuthenticator()
{
    var accountService = new SimpleAccountService();
    accountService.Add("admin", "admin", new[] { "Admin", "User" });
    accountService.Add("user", "user", new []{"User"});
    var basicAuth = new BasicAuthentication(accountService, "localhost");
    return basicAuth;
}

I just got some fake users. The IAccountService interface (implemented by SimpleAccountService) is tiny and easy to implement (using a DB, flat files or whatever).

Finally you need to be able to authorize users.

Start by telling the library to use role based authorization:

GlobalConfiguration.AuthorizationFilter = new RoleAuthorizer();

Then you need to put the [Authorize] attribute either on your CQS class, or on the handler class:

[Authorize("Admin")]
public class GetUsers : Query<GetUsersResult>
{
}

IoC support

In this example I’m using Autofac:

private static AutofacAdapter BuildContainer()
{
    var containerBuilder = new ContainerBuilder();
    containerBuilder.RegisterServices(Assembly.GetExecutingAssembly());

    var container = containerBuilder.Build();
    var adapter = new AutofacAdapter(container);
    return adapter;
}

As you can see, I’m just using a single line to register all command/query handlers. It’s an extension method that is available in the Griffin.Framework.Autofac nuget library. It registers all classes that is decorated with the [ContainerService] attribute like this:

[ContainerService]
class GetUsersHandler : IQueryHandler<GetUsers, GetUsersResult>
{
    public async Task<GetUsersResult> ExecuteAsync(GetUsers query)
    {
        return new GetUsersResult()
        {
            Items = new[]
            {
                new GetUsersResultItem
                {
                    Id = 1,
                    UserName = "arne"
                }
            }
        };
    }
}

Finally I assign the ioc container to the CqsHttpListener

var builder = new IocBusBuilder(adapter);
var listener = new CqsHttpListener(builder.BuildMessageProcessor());

Client side

HTML page which is getting the query result:

<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Demo</title>
    <script type="text/javascript" src="https://code.jquery.com/jquery-2.1.3.min.js"></script>
</head>
<body>
<script type="text/javascript">
    $.ajax({
        type: "POST",
        url: 'http://localhost:8899/cqs',
        data: { /* no query data */ },
        headers: {
            'X-Cqs-Name': "GetUsers"
        },
        dataType: 'json'
    }).done(function (data) {

        // here is the result from the query
        console.log(data.Items);
    });
</script>
</body>
</html>

Result without the [Authorize] attribute:

griffin_cqs_0

.. with the attribute..

griffin_cqs_1

Code

Full sample code can be viewed here.

License

This article, along with any associated source code and files, is licensed under The GNU Lesser General Public License (LGPLv3)

Share

About the Author

jgauffin
Founder Gauffin Interactive AB
Sweden Sweden
Founder of OneTrueError, a .NET service which captures, analyzes and provide possible solutions for exceptions.
 
blog | twitter
Follow on   Twitter   LinkedIn

Comments and Discussions

 
-- There are no messages in this forum --
| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.150327.1 | Last Updated 11 Mar 2015
Article Copyright 2015 by jgauffin
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid