Thursday, 13 November 2008

Testable LINQ to Entities with Table Joins

I’m enjoying LINQ to Entities and the Entity Framework, but sometimes it feels like someone forgot to write up the documentation.  It’s nice to have the product, but it can be very hard to use without adequate training or documentation.  But I suppose it’s very new and I’ll just have to wait for more people to jump on board.

In the mean time, I came across a problem.  We are following the repository model design pattern in our data access objects and when using LINQ to Entities we define the table that the model is concerned with as a private member from the Entity Model.  This allows us to use TDD and override this private member with our own queryable datasets for testing.

So your data repository will look something like this:

public class SecurityUserRepository : ISecurityUserRepository
{
    private IQueryable<rfSysAction> _rfSysActionData;
    private MyEntities _Entities;
 
    public SecurityUserRepository()
    {
        _Entities = new MyEntities();
        _rfSysActionData = _Entities.rfSysAction;
    }
 
    public SecurityUserRepository(IQueryable<rfSysAction> sysAction)
    {
        _rfSysActionData = sysAction;
    }
}

Nice code, easy to test, but what if I want to join several tables together to get a set of data back?  For example, my user is part of several security groups, my security groups are linked to my MVC actions and my actions are defined in a table specifying their names. 

Well it’s actually not that hard.

Most often when trying to write this join you’ll get examples that make you reference the entity model to get all the tables you want to join.  This works fine, but it’s not good for me because I have only mocked up a copy of my root object.

Then I found this great example showing how it can be done.  So if I want to return an action table record for a specific action, controller and user my LINQ should look like this:

IQueryable<rfSysAction> query = 
    from sa in _rfSysActionData
        from sas in sa.rfSysActionSecurity
        from usg in sas.rfSecurityGroup.UserSecurityGroup
    where usg.UserID == userIdparam 
        && sa.Controller == controller
        && sa.Name == action
    select sa;

This query will find all security actions and then limit the selection to those for the user, controller and action specified.  This is what my model looks like for the tables in the above query:

image

The code is simple and makes sense when you know what to do, but now that I have it, how do I test it.  With rfSysAction as my base table, all I have to do is mock this up and add in the child table data like this:

private IQueryable<rfSysAction> GetTestUserSecurityGroupData()
{
    List<rfSysAction> data = new List<rfSysAction>
    {
        new rfSysAction()
        {
            ActionID = 1,
            Controller = "controllera",
            Name = "actiona",
            rfSysActionSecurity = new EntityCollection<rfSysActionSecurity>()
            {
                new rfSysActionSecurity()
                {
                    rfSecurityGroup = new rfSecurityGroup()
                    {
                        Name = "groupa",
                        UserSecurityGroup = new EntityCollection<UserSecurityGroup>()
                        {
                            new UserSecurityGroup()
                            {
                                UserID = 1
                            }
                        }
                    }
                }
            }
        }
    };
 
    return data.AsQueryable();
}

And then use the override constructor to set the data:

ISecurityRepository target = new SecurityRepository(GetTestUserSecurityData());

There you have it, testable LINQ to Entities and I haven’t had to overwrite several table object. 

Monday, 10 November 2008

Localization with ASP.NET MVC

When investigating the subject of Areas I came across some recent posts from Phil Haack and Steve Sanderson that made great use of areas to provide exactly what I wanted.  But it got me to thinking, in our application we wish to implement localisation as well as areas where the views have their own sub directories depending on the browser language selection, defaulting to English when no supported language is chosen.

I came up with a very simple solution, and while it’s not the most elegant it works very well.  Using Phil Haack’s code, I implemented my view engine, however I subdivided my views into separate directories for English and Japanese like so:

image

Setting up for English in my view engine was very easy, I just changed the view engine’s constructor to specifically point to my EN views like so in the AreaViewEngine.cs.

public AreaViewEngine() : base() 
{
    ViewLocationFormats = new[] 
    { 
        "~/{0}.aspx",
        "~/{0}.ascx",
        "~/Views/EN/{1}/{0}.aspx",
        "~/Views/EN/{1}/{0}.ascx",
        "~/Views/EN/Shared/{0}.aspx",
        "~/Views/EN/Shared/{0}.ascx",
    };
 
    MasterLocationFormats = new[] 
    {
        "~/{0}.master",
        "~/Shared/{0}.master",
        "~/Views/EN/{1}/{0}.master",
        "~/Views/EN/Shared/{0}.master",
    };
 
    PartialViewLocationFormats = ViewLocationFormats;
}

And made sure the formatting functions in Phil’s view engine looked specifically for my views.

private static string FormatViewName(ControllerContext controllerContext, string viewName) 
{
    string controllerName = controllerContext.RouteData.GetRequiredString("controller");
 
    string area = controllerContext.RouteData.Values["area"].ToString();
    return "Areas/" + area + "/Views/EN/" + controllerName + "/" + viewName;
}
 
private static string FormatSharedViewName(ControllerContext controllerContext, string viewName) 
{
    string area = controllerContext.RouteData.Values["area"].ToString();
    return "Areas/" + area + "/Views/EN/Shared/" + viewName;
}

But how do I tell the system that when Japanese is the default language to look into the JP folder?

There are two ways that I can see.  Phil’s source uses the base.FindView from within the FindView method of his custom view engine.  By completely overriding the FindView method you could specify the language directories to look into depending on the language selection.  This seemed like quite a difficult task and quite a lot of code.

I went down the very simple path of redirecting to the Japanese views once the view selection is complete.

protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
    viewPath = viewPath.Replace("/EN/", "/JP/");
    return base.CreateView(controllerContext, viewPath, masterPath);
}

I do realise that this code will ALWAYS route from English into Japanese, it’s just an example.  And before anyone jumps up and down and shouts “Bad Developer” I realise this is not the prettiest way to do it, but it is exactly ideal for our purposes and it is very simple.

The view must exist in the English language for it to be routable to in any other language and must exist in exactly the same location in the Japanese folders.

If anyone reading this knows a better way this should be done, please let me know. 

Asynchronous Data Loading in ASP.NET MVC Components

I recently came across a problem when designing my ASP.NET MVC enterprise application where I needed a user control to hit the database to load some information dynamically without refreshing the page.  I did a bit of searching and found a few possible ways of doing it, but when I asked the question on Stack Overflow I got a great answer.

The example uses jQuery, if you’re not familiar with it try this site as I found it quite helpful.  Your controllers are not restricted to returning views only, action results can be in the form of Json data if you wish or many other types of data.  Using System.Web.Mvc you can find the JsonResult action result.

If we call an action that returns a JsonResult from an Ajax control using java script we can asynchronously get the data we need and not have to worry about postbacks on the page.

For my example I’m going to do almost exactly the same as my answer from stackoverflow, but I found a few things that didn’t work for me so I’ll repair them.  I want a text box to auto complete.  When I type the first letter I want it to fill out the remainder for me and select the whole text.

My action looks something like this

public ActionResult GetSuggestions(string searchText)
{
    return Json(new { SearchText = searchText + "completestring"});
}

No checking of the database here, it’s out of the scope of this post, just return the letter or letters entered and add “completestring” to the end. 

Now all I need to do is use some javascript inside my HTML link so.

function startAutoComplete() {
    var searchText = $("#inputText").val();
    $.getJSON("/Search/GetSuggestions?searchText=" + searchText, null, autoCompleteResponse);
}
 
function autoCompleteResponse(data) {
    if (data.SearchText) {
        $("#inputText").val(data.SearchText);
        $("#inputText").select();
    }
}

This code will input component called inputText and set the value of the text box to the output of the JSON based action.  The data is returned via an event handler (autoCompleteResponse(data)) so that it is handled asynchronously.

This example is the simplest use case I could think of, and it’s not terribly useful.  But this same method is going to be very useful for me when searching for data to complete entry fields (user search for a user field for example) and when creating other asynchronous components.

Friday, 7 November 2008

Encrypting Password Fields in C#

This is probably nothing new to many people, but for me it was something new so I’m blogging about it.  There is often the need to encrypt password fields (or any other field for that matter) when storing it in the database.  There are a few ways to do it in the database too, but if you’re using an ORM like LINQ to SQL or NHibernate for .NET then you’ll find that the SQL used to encrypt and decrypt can add un-necessary complexity to your application.  Instead .NET provides you with many means to encrypt and decrypt data using cryptography.

Don’t Decrypt Passwords

The first lesson I’ve learned when dealing with cryptography is that you should never decrypt a password.  If you need to validate a password then you should re-encrypt the password and then validate the two encrypted passwords against each other.

.NET provides encryption by the System.Security.Cryptography namespace and uses the provider model that’s so prominent in .NET.  The different encryption types I won’t go into here, that’s something you’ll have to find out for yourself, however the most popular seems to be MD5 or SHA1.

The code to encrypt a string field is very simple.

MD5CryptoServiceProvider md5crypto = new MD5CryptoServiceProvider();
byte[] data = System.Text.Encoding.ASCII.GetBytes(inputString);
data = md5crypto.ComputeHash(data);
return System.Text.Encoding.ASCII.GetString(data);

Convert the string to a byte array, compute the hash, return the encrypted hash.  This can be used by any type of data that allows conversion into a byte array.

I would highly recommend wrapping up the MD5 encryption in an interface so you can plug in other encryption types that are appropriate for your security concerns.

Tuesday, 4 November 2008

Faking HTTPContext in Unit Tests

You may often come across some area of your application where you need to test using the HTTPContext values.  Thing is that HTTPContext doesn’t exist in a test application and you probably don’t want to mess around with HostType() variables or trying to create a “real” context in code.  So here’s a snippet that will create a simple worker request context for your application to test with

TextWriter tw = new StringWriter();
HttpWorkerRequest wr = new SimpleWorkerRequest("/webapp", "c:\\inetpub\\wwwroot\\webapp\\", "default.aspx", "", tw);
HttpContext.Current = new HttpContext(wr);

I can’t take credit for it, I found it here on Jeff’s Junk (good on ya Jeff!).  Once you have put your HttpContext in place you can setup whatever information you need for your unit test.  In my case I wanted to test a user called “usernotfound” so my unit test starts off like so;

// Setup the user account for testing.
IIdentity identify = new System.Security.Principal.GenericIdentity("usernotfound");
IPrincipal currentUser = new System.Security.Principal.GenericPrincipal(identify, null);
 
TextWriter tw = new StringWriter();
HttpWorkerRequest wr = new SimpleWorkerRequest("/webapp", "c:\\inetpub\\wwwroot\\webapp\\", "default.aspx", "", tw);
HttpContext.Current = new HttpContext(wr);
 
System.Web.HttpContext.Current.User = currentUser;

And away I go….

Validating Entity Framework Objects Using Reflection and Generics and the Validation Application Block

I’ve spent much of today trying to minimise the amount of work I’m going to be required to do during my project and this is what I’ve come up with.  We are working with the Entity Framework and Linq to Entities, however we also want to implement some custom validation of fields where instead of writing validation rules.

We found this to be a little difficult.  One thing about the validation application block, it does not support inheritance.  If you have a number of objects that inherit from a base object you may want to define a type for the  base object so that it will pick up all seven types in validation time and validate them against the base type.  But it doesn’t work.  For example in the code below.

BaseClass objectToValidate = new SuperClass();
Validation.Validate(objectToValidate)

This code will not validate against the type BaseClass (assuming BaseClass is the base type of SuperClass).  You can modify your code so that you tell it which class to validate against like so:

SuperClass objectToValidate = new SuperClass();
Validation.Validate<BaseClass>(objectToValidate)

But this is quite difficult if you’re trying to remain generic.  For example in our application we are wrapping up the Validation application block in an Object Method design pattern to hide the implementation from the user and allow simple unit testing.

In our case, this method will not work because it thinks that the object type is System.Object.

public ValidationResults Validate(object toValidate)
{
    ValidationResults msResults = Validation.Validate(toValidate);
    return returnList;
}

I wouldn't recommend that you use the validation application block directly as it will make unit testing quite difficult.  To unit test effectively you will need to mock out an interface into validation for the rest of your code where the testing of validation is not relevant.  You can work around this with Generics.

Using Generics implementation, the method above turns into this.

public ValidationResults Validate<T>(T toValidate)
{
    ValidationResults msResults = Validation.Validate(toValidate);
    return returnList;
}

This will work and your object will remain of its own type.  It also allows you to validate against other object types (like base classes) by defining the object type in the method call using angle brackets.

How does this relate to the entity framework?  Well all objects in the entity framework inherit from a singular type of System.Data.Objects.DataClasses.EntityObject.  I’ve covered before how you can create your own custom validators with the Validation Application Block.  If we are able to create a custom database validator, catch the EntityObject and then investigate the object to discern its members from the entity framework we will be able to validate it against its database types.

I think it’s easier to explain by example, so here is my DoValidate method of my custom validator.

protected override void DoValidate(object objectToValidate, object currentTarget, string key, 
    ValidationResults validationResults)
{
    // Get the type of the object.
    string typeName = objectToValidate.GetType().Name;
 
    // Get the parameters
    PropertyInfo[] propertyInfos = objectToValidate.GetType().GetProperties();
 
    foreach (PropertyInfo propertyInfo in propertyInfos)
    {
        // Ignore entity state and entity key, they're variables of the entity framework.
        if ((!propertyInfo.Name.Equals("EntityState") && !propertyInfo.Name.Equals("EntityKey")))
        {
            if (propertyInfo.PropertyType.Equals(typeof(string)))
            {
                ValidateString(objectToValidate, typeName, propertyInfo.Name, 
                    (string)propertyInfo.GetValue(objectToValidate, null), validationResults);
            }
        }
    }
 
 
    rfSysObjectFieldDetail field = _FieldDetailRepository.GetField("MockEntityObject", "ID");
}

.NET Reflection is used (System.Reflection) to look into the properties of the object I’m validating.  We ignore EntityState and EntityKey as they’re base types and do not reference the database.  If you’re pulled your Entity Model straight from the database then the rest of the types will directly reference the database fields with the class name referencing the table.  The method above only validates strings so far.

The method ValidateString just looks into the database for the field definition and verifies that the string is within the correct length parameters.

private void ValidateString(object objectToValidate, string tableName, string fieldName, 
    string fieldValue, ValidationResults validationResults)
{
    rfSysObjectFieldDetail field = _FieldDetailRepository.GetField(tableName, fieldName);
 
    int fieldLength = fieldValue.Length;
 
    // Check the field length.
    if (fieldValue.Length > field.MaximumLength)
    {
        // TODO These must be loaded from the messages object
        ValidationResult result = new ValidationResult(
            "String length too long, maximum length is " + field.MaximumLength,
            objectToValidate, "", "", this);
 
        validationResults.AddResult(result);
    }
 
    if (fieldValue.Length < field.MinimumLength)
    {
        // TODO This must be loaded from the messages objects
        ValidationResult result = new ValidationResult(
            "String length too short, minimum length is " + field.MinimumLength,
            objectToValidate, "", "", this);
 
        validationResults.AddResult(result);
    }
 
}

And that’s about it.  Hopefully it’s useful to someone other than just myself.