Click here to Skip to main content
15,881,898 members

Dominic Burford - Professional Profile



Summary

Follow on Twitter LinkedIn      Blog RSS
6,554
Author
2,053
Authority
9,852
Debator
8
Editor
100
Enquirer
212
Organiser
2,954
Participant
I am a professional software engineer and technical architect with over twenty years commercial development experience with a strong focus on the design and development of web and mobile applications.

I have experience of architecting scalable, distributed, high volume web applications that are accessible from multiple devices due to their responsive web design, including architecting enterprise service-oriented solutions. I have also developed enterprise mobile applications using Xamarin and Telerik Platform.

I have extensive experience using .NET, ASP.NET, Windows and Web Services, WCF, SQL Server, LINQ and other Microsoft technologies. I am also familiar with HTML, Bootstrap, Javascript (inc. JQuery and Node.js), CSS, XML, JSON, Apache Cordova, KendoUI and many other web and mobile related technologies.

I am enthusiastic about Continuous Integration, Continuous Delivery and Application Life-cycle Management having configured such environments using CruiseControl.NET, TeamCity and Team Foundation Services. I enjoy working in Agile and Test Driven Development (TDD) environments.

Outside of work I have two beautiful daughters. I am also an avid cyclist who enjoys reading, listening to music and travelling.

 

Reputation

Weekly Data. Recent events may not appear immediately. For information on Reputation please see the FAQ.

Privileges

Members need to achieve at least one of the given member levels in the given reputation categories in order to perform a given action. For example, to store personal files in your account area you will need to achieve Platinum level in either the Author or Authority category. The "If Owner" column means that owners of an item automatically have the privilege. The member types column lists member types who gain the privilege regardless of their reputation level.

ActionAuthorAuthorityDebatorEditorEnquirerOrganiserParticipantIf OwnerMember Types
Have no restrictions on voting frequencysilversilversilversilver
Bypass spam checks when posting contentsilversilversilversilversilversilvergoldSubEditor, Mentor, Protector, Editor
Store personal files in your account areaplatinumplatinumSubEditor, Editor
Have live hyperlinks in your profilebronzebronzebronzebronzebronzebronzesilverSubEditor, Protector, Editor
Have the ability to include a biography in your profilebronzebronzebronzebronzebronzebronzesilverSubEditor, Protector, Editor
Edit a Question in Q&AsilversilversilversilverYesSubEditor, Protector, Editor
Edit an Answer in Q&AsilversilversilversilverYesSubEditor, Protector, Editor
Delete a Question in Q&AYesSubEditor, Protector, Editor
Delete an Answer in Q&AYesSubEditor, Protector, Editor
Report an ArticlesilversilversilversilverSubEditor, Mentor, Protector, Editor
Approve/Disapprove a pending ArticlegoldgoldgoldgoldSubEditor, Mentor, Protector, Editor
Edit other members' articlesSubEditor, Protector, Editor
Create an article without requiring moderationplatinumSubEditor, Mentor, Protector, Editor
Approve/Disapprove a pending QuestionProtector
Approve/Disapprove a pending AnswerProtector
Report a forum messagesilversilverbronzeProtector, Editor
Approve/Disapprove a pending Forum MessageProtector
Have the ability to send direct emails to members in the forumsProtector
Create a new tagsilversilversilversilver
Modify a tagsilversilversilversilver

Actions with a green tick can be performed by this member.


 
GeneralBlog updates Pin
Dominic Burford13-May-21 1:37
professionalDominic Burford13-May-21 1:37 
GeneralPublishing events into an ASP.NET Core webhook with Octopus Pin
Dominic Burford13-May-21 1:33
professionalDominic Burford13-May-21 1:33 
GeneralA quick update Pin
Dominic Burford2-Nov-20 8:33
professionalDominic Burford2-Nov-20 8:33 
GeneralHow do you know when it's time to move on? Pin
Dominic Burford19-Aug-20 0:19
professionalDominic Burford19-Aug-20 0:19 
GeneralInitial thoughts on deploying with Octopus Pin
Dominic Burford17-Aug-20 4:25
professionalDominic Burford17-Aug-20 4:25 
GeneralWhat makes for a good DevOps process? Pin
Dominic Burford5-Aug-20 23:00
professionalDominic Burford5-Aug-20 23:00 
GeneralExecuting async code from non async code Pin
Dominic Burford19-Jul-20 23:21
professionalDominic Burford19-Jul-20 23:21 
GeneralPassing dynamic queries between client and backend server Pin
Dominic Burford29-Jun-20 4:55
professionalDominic Burford29-Jun-20 4:55 
To get the most out of this article, you will need a good understanding of creating Expressions with the .NET Framework. If you don't already, then check out this article[^] before going any further.

During the development of our current ASP.NET Core web application, I had a particular set of forms where the client needed to dynamically query one particular dataset. The data being returned related to permission data. The data could be queried in a number of different ways e.g. the permissions for a particular user or the permissions for a particular service. Although the same data was being queried and returned in both cases, they would need to be implemented as two completely separate GET Requests.

All our queries are RESTful GET commands which invoke our ASP.NET Web API backend services. Each new query would involve creating a new controller, service-layer code, data-layer code etc. Much of this code would be very similar as it was effectively querying the same data and returning the same data structures (models).

This got me thinking. Instead of implementing each of these queries separately, that I instead create a dynamically queryable service instead. The client application passes a query to the service. The service executes this query against the data and returns the result back to the client. This would give the client the flexibility to query the data in any way as required.

I wasn't even sure if this was possible. After much investigation, I came across some posts on Stackoverflow confirming that it was indeed possible. The client application would create an Expression tree. This would be serialised and sent to the ASP.NET Web API service where it would be de-serialised and executed.

The first problem would be serialising the Expression. It turns out that .NET Expression trees cannot be serialised / de-serialised. An Expression is not based on a static structure in the same way as a class, and therefore does not contain any definition for its structure. A class can be serialised because it contains type and structure meta data that can used by the serialiser. An Expression tree contains none of this meta data.

It turns out that there is a nuget package called Remote.Linq[^] that is able to handle the serialisation of Expressions. This handles all the serialisation / de-serialisation allowing your Expression to be passed to your backend service from the client application.

The first step is to add two package references to your project in Visual Studio.

1. Remote.Linq
2. Remote.Linq.Newtonsoft.Json

These will add the necessary extension methods and functionality needed to serialise / de-serialise your Expression trees.

You may need to create some helper functions similar to the ones below. These encapsulate the logic involved with serialising / de-serialising your Expression trees.
C#
/// <summary>
/// Deserialise a LINQ expression tree
/// </summary>
public Remote.Linq.Expressions.Expression DeserialiseRemoteExpression<TExpression>(string json) where TExpression : Remote.Linq.Expressions.Expression
{
    JsonSerializerSettings serializerSettings = new JsonSerializerSettings().ConfigureRemoteLinq();
    Remote.Linq.Expressions.Expression result = JsonConvert.DeserializeObject<TExpression>(json, serializerSettings);
    return result;
}

/// <summary>
/// Serialise a remote LINQ expression tree
/// </summary>
public string SerialiseRemoteExpression<TExpression>(TExpression expression) where TExpression : Remote.Linq.Expressions.Expression
{
    JsonSerializerSettings serializerSettings = new JsonSerializerSettings().ConfigureRemoteLinq();
    string json = JsonConvert.SerializeObject(expression, serializerSettings);
    return json;
}

/// <summary>
/// Convert the specified Remote.Linq Expression to a .NET Expression
/// </summary>
public System.Linq.Expressions.Expression<Func<T, TResult>> ToLinqExpression<T, TResult>(Remote.Linq.Expressions.LambdaExpression expression)
{
    var exp = expression.ToLinqExpression();
    var lambdaExpression = System.Linq.Expressions.Expression.Lambda<Func<T, TResult>>(exp.Body, exp.Parameters);
    return lambdaExpression;
}
With those created, the first thing you will need to do is create your Expression and serialise it.

The examples I will use all relate to the scenario I described at the beginning of the article i.e. the ability to dynamically query permissions data.

Here's a simple Expression that returns a list of permissions for the specified permission ID (in reality there would only ever be one permission returned for any given permission ID but for the purposes of this example let's assume that one or more permissions will be returned by the Expression).
C#
const int permissionid = 1;
Expression<Func<PermissionEntities, List<PermissionEntity>>> expr1 = m => m.Permissions.FindAll(q => q.PermissionId == permissionid);
Next we need to convert the Expression into a Remote.Linq expression and serialise it.
C#
var serialised = SerializerManager().SerialiseRemoteExpression(expr1.ToRemoteLinqExpression());
The extension method ToRemoteLinqExpression() is provided by Remote.Linq and converts a .NET Expression into a Remote.Linq expression.

With our Expression now serialised into a string, we can pass it into a function to execute against our permission data. The function will need to perform the following actions.

1. De-serialise the Remote.Linq expression
2. Convert the Remote.Linq Expression into a .NET Expression
3. Invoke and execute the Expression against permissions data

Here's an example of a function that accepts a serialised Remote.Linq expression and executes it against a permissions dataset.
C#
/// <summary>
/// Return the specified permissions from the remote expression
/// </summary>
public PermissionModels GetPermissionsDynamic(string payload)
{
    if (string.IsNullOrEmpty(payload)) return null;
    //create an empty default permission model
    PermissionModels result = new PermissionModels();
    //de-serialise back into a Remote.Linq Expression
    Remote.Linq.Expressions.LambdaExpression expression = 
    SerializerManager().DeserialiseRemoteExpression<Remote.Linq.Expressions.LambdaExpression>(payload) as LambdaExpression;

    //convert the Remote.Linq Expression into a .NET Expression
    var localexpression = SerializerManager().ToLinqExpression<PermissionEntities, List<PermissionEntity>>(expression);

    //grab all the permissions from the DB
    PermissionEntities permissions = this.Data.GetPermissions();
            
    //compile and invoke the expression
    var compiled = localexpression.Compile();
    var matches = compiled.Invoke(permissions);

    //if no matches were found then just return the default object with no items
    if (matches == null || !matches.Any()) return result;

    return matches
}
Putting all the pieces together, here's a simple unit test that demonstrates how to create an Expression and pass this to the above function to execute against actual data.
C#
[TestMethod]
public void GetPermissionsDynamicTests()
{
    //Arrange
    const int permissionid = 1;
    PermissionsService service = new PermissionsService();
    Expression<Func<PermissionEntities, List<PermissionEntity>>> expr1 = m => m.Permissions.FindAll(q => q.PermissionId == permissionid);

    var serialised = SerializerManager().SerialiseRemoteExpression(expr1.ToRemoteLinqExpression());

    //Act
    var results = service.GetPermissionsDynamic(serialised);

    //Assert
    Assert.IsNotNull(results);
    Assert.IsNotNull(results.Permissions);
    Assert.IsTrue(results.Permissions.Any());
    Assert.IsNotNull(results.Permissions.Find(q => q.PermissionId == permissionid));
}
To complete this we would need to write a controller method that invoked the function GetPermissionsDynamic(). It should be noted that although we are creating dynamic queries over HTTP, they will need to be implemented as POST rather than GET. The reason for this (as I found out) is because a GET querystring is limited in length. A serialised Expression will almost certainly break that limit. Therefore place the serialised Expression in the POST body of your Request. It is also more secure to pass your Expressions this way as they are less visible to prying eyes. You may want to consider encoding / encrypting the Expressions you pass from your client to your service for added security.

I wouldn't use this pattern for every query. I would still create a single GET query for each Request for the majority of the queries I implement. However, when you have several queries all acting on the same data and returning the same data structures (models), then this pattern allows you to simply and easily implement those as dynamic queries. Like all patterns, it can solve a very specific problem if used as intended and its usage is clearly understood by the developer.
"There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies. The first method is far more difficult." - C.A.R. Hoare

Home | LinkedIn | Google+ | Twitter

GeneralManaging your Azure resources using Powershell scripting Pin
Dominic Burford13-Mar-20 6:42
professionalDominic Burford13-Mar-20 6:42 
GeneralIntroduction to Azure Cognitive Search Pin
Dominic Burford28-Feb-20 5:39
professionalDominic Burford28-Feb-20 5:39 
GeneralUpdating the version number in your .NET build pipeline Pin
Dominic Burford24-Feb-20 5:33
professionalDominic Burford24-Feb-20 5:33 
GeneralFinding a solution to an Azure web app deployment problem Pin
Dominic Burford23-Jan-20 23:51
professionalDominic Burford23-Jan-20 23:51 
GeneralStructured Logging Pin
Dominic Burford24-Dec-19 1:28
professionalDominic Burford24-Dec-19 1:28 
GeneralEnabling TLS 1.2 on your .NET application Pin
Dominic Burford11-Dec-19 23:11
professionalDominic Burford11-Dec-19 23:11 
GeneralThe new version of the app is (almost) ready for release Pin
Dominic Burford7-Nov-19 23:28
professionalDominic Burford7-Nov-19 23:28 
GeneralChunking your lists into multiple smaller lists Pin
Dominic Burford11-Sep-19 3:40
professionalDominic Burford11-Sep-19 3:40 
GeneralWriting flexible filters for your data using Predicates Pin
Dominic Burford16-Jul-19 6:11
professionalDominic Burford16-Jul-19 6:11 
GeneralRe: Writing flexible filters for your data using Predicates Pin
Slacker00716-Jul-19 22:09
professionalSlacker00716-Jul-19 22:09 
GeneralRe: Writing flexible filters for your data using Predicates Pin
Dominic Burford17-Jul-19 1:17
professionalDominic Burford17-Jul-19 1:17 
GeneralBlocking Asynchronous Code Pin
Dominic Burford4-Jul-19 22:11
professionalDominic Burford4-Jul-19 22:11 
GeneralDesigning and implementing flexible RESTful services Pin
Dominic Burford14-Jun-19 0:50
professionalDominic Burford14-Jun-19 0:50 
GeneralWriting asynchronous code with .NET Pin
Dominic Burford10-Jun-19 3:34
professionalDominic Burford10-Jun-19 3:34 
GeneralWeird Minification Behaviour in ASP.NET Core Pin
Dominic Burford28-May-19 3:54
professionalDominic Burford28-May-19 3:54 
GeneralThe Importance of Structure and Dilligence Pin
Dominic Burford24-May-19 6:14
professionalDominic Burford24-May-19 6:14 
GeneralWhen should you rewrite that legacy application? Pin
Dominic Burford22-May-19 0:03
professionalDominic Burford22-May-19 0:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.