Tuesday, 24 December 2013

WPF DataGrid - Custom template for generic columns

Recently I had to bind a WPF DataGrid to a System.Data.DataSet. This is quite straightforward and there are many tutorials on how to achieve this.

By default all table columns are auto-generated using 4 predefined templates (Text, Hyperlink, CheckBox, and ComboBox) that support read-only and edit modes. If you wish to customize the way some columns are rendered you can also define a custom template and assign it to some columns by hooking into the AutoGeneratingColumns event of the DataGrid as described here.

Problem with generic columns

As you can see creating custom templates for columns is pretty straightforward as long as column names are fixed. If your WPF app uses a table that doesn't change dynamically you are all good. The problem starts when you use your datagrid to display tables, whose columns` names change e.g. tables loaded from a file at runtime. This is because you can't use the column name in your custom template.

Solution 1 - Create template programmatically

In this solution you build your custom template in code and assign it to the chosen column at runtime, in the AutoGeneratingColoumn event handler.
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    // First get the corresponding DataColumn
    var colName = e.PropertyName;
    var table this.DataContext as DataTable;
    var tableColumn = table.Columns[colName];

    // choose columns to customize e.g. by type
    if (YOUR CONDITION E.G. COLUMN TYPE)
    {
       var templateColumn = new DataGridTemplateColumn();
       templateColumn.Header = colName;
       templateColumn.CellTemplate = this.BuildCustomCellTemplate(colName);
       templateColumn.SortMemberPath = colName;
       e.Column = templateColumn;
    }
}

// builds custom template
private DataTemplate BuildCustomCellTemplate(string columnName)
{
    var template = new DataTemplate();

    var button = new FrameworkElementFactory(typeof (Button));
    template.VisualTree = button;

    var binding = new Binding();
    binding.Path = new PropertyPath(columnName);
     
    button.SetValue(ContentProperty, binding);

    return template;
}
The code above would create the following template for selected columns:

    
Obviously this is just an example - in real life you would need more than just a button that does nothing. In your code you can define full templates, use binding converters, assign commands etc. However, the code gets pretty complex. Therefore this solution is suitable for simple templates.

Solution 2 - Create template skeleton

Alternatively, you can create the template skeleton in XAML and replace all bindings in your event handler:


    
And the event handler:
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    (...)

    if (YOUR CONDITION E.G. COLUMN TYPE)
    {
       // Create wrapping template in code and populate all bindings accordingly 
       string xaml = @"";
       var template = (DataTemplate)XamlReader.Load(string.Format(xaml, "{Binding " + colName + "}", "{StaticResource customCellTemplate}"));
       templateColumn.CellTemplate = template;
       
       (...)
    }
}
The advantage of this approach is that you can create more complex templates in XAML and in your event handler code only populate all required bindings. The limitation of this method is that the custom template needs to be defined at the application level. I found this solution here.

Monday, 2 December 2013

Claims based authorization in MVC4

Recently I worked on a sample MVC4 application that was using Claims based authentication. I used the Identity and Access Visual Studio extension to help me configuring Windows Identity Foundation (WIF) in my app. In short, the tool updates your web.config by adding sections system.identityModel and system.identityModel.services to enable WIF. In result, my application is redirecting all unauthenticated users to my Identity Provider, which then generates a security token that is returned back to my app.

Once I had the authentication part done I started working on the authorization. I wanted it to be role-based i.e. very similar to what you use by default in the default MVC model:

[Authorize(Roles = "Administrator")]
public class AdminController : Controller
{
    // Controller code here
}
In theory, if your Identity Provider issues a token containing the Identity Role claim (http://schemas.microsoft.com/ws/2008/06/identity/claims/role) with the value of user's current role the above default authorization code should work. And it actually does! This is because some basic claims from the token are automatically used to populate the user's identity object, including roles. So when your app's authorization code checks user's role it will use values provided in the token (if any were provided).

Membership database issue

The above solution worked fine for me at the beginning. What I was not aware of is the fact that, by default, the Authorize attribute also connects to you Membership database, regardless the token content. By default as membership database MVC uses the local ASPNETDB.mdf file. I realized that when I moved the application to a different server, without moving the mdf file. Suddenly I started getting the following SQL exception when calling the Authorize attribute:
A network-related or instance-specific error occurred while establishing a connection to SQL Server. The server was not found or was not accessible. Verify that the instance name is correct and that SQL Server is configured to allow remote connections. (provider: SQL Network Interfaces, error: 26 - Error Locating Server/Instance Specified)
I guess there is an easy way to configure ASP not to connect to the database if roles are provided in the token. However, I decide to take a different approach to have more control over the code.

Custom authorization attribute

I decided to write a custom Authorization attribute, that would search for user's role directly in claims provided in the token:
public class ClaimsAuthorizeAttribute : AuthorizeAttribute
{
    private string claimType;
    private string claimValue;

    public ClaimsAuthorizeAttribute(string type, string value)
    {
        this.claimType = type;
        this.claimValue = value;
    }
  
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var identity = (ClaimsIdentity)Thread.CurrentPrincipal.Identity;
        var claim = identity.Claims.FirstOrDefault(c => c.Type == claimType && c.Value == claimValue);
             
        if (claim != null)
        {
            base.OnAuthorization(filterContext);
        }
        else
        {
             base.HandleUnauthorizedRequest(filterContext);
        }
    }
} 
This approach is more flexible as it allows me to use different types of claims for authorization in future, not only role. The usage of the attribute is still very simple:
[ClaimsAuthorize(ClaimTypes.Role, "Administrator")]
public class AdminController : Controller
{
    // Controller code here
}

Additional notes

When using claims based authorization it is often advised to use the existing ClaimsPrincipalPermission attribute together with the configured ClaimsAuthorizationManager. In my case this seemed like an overkill, especially that I wanted to keep the code similar to the default authorization model.