web 2.0

Getting Assembly Information Using Reflection

I recently took over a WPF application that needed a little bit of refactoring. One of the places that had a lot of repeated code was the about screen. By using reflection a bunch of properties were being created to display things like the assembly title, version, description and etcetera. The original code looked like this:

public string AssemblyDescription
{
    get
    {
        object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyDescriptionAttribute), false);
        if (attributes.Length == 0)
        {
            return "";
        }
        return ((AssemblyDescriptionAttribute)attributes[0]).Description;
    }
}

public string AssemblyProduct
{
    get
    {
        object[] attributes = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyProductAttribute), false);
        if (attributes.Length == 0)
        {
            return "";
        }
        return ((AssemblyProductAttribute)attributes[0]).Product;
    }
}

You may have noticed that this code does not follow the DRY principle. In case you arent familiar with the term, DRY stands for Don't repeat yourself. In otherwords, if you repeat the same code multiple times then you should try to refactor it into a more generic method.

After analyzing the code you may notice that both of the property getters do the same thing. First, it gets a handle to the current assembly. Next, the GetCustomAttributes method is called to get an object array which contains all the attribute values for a given type. Finally, a little bit of conditional logic is used to emit a value. Using the power of generics and some reflection we can easily build an extension method that will eliminate the redundant code.

Warning: If you are not familiar with generics, reflection and lambda statements then the following code may cause your brain to explode

public static TAttribute[] GetAttributes<TAttribute>(this Assembly assembly) where TAttribute : Attribute {
    return assembly.GetCustomAttributes(typeof(TAttribute), false) as TAttribute[];
}

public static object GetFirstAttributeValue<TAttribute>(
    this Assembly assembly,
    Expression<Func<TAttribute, object>> propertyLambda) where TAttribute : Attribute {
    Type type = typeof(TAttribute);

    var attributeValues = assembly.GetAttributes<TAttribute>();
    if (attributeValues.Length == 0)
        throw new ArgumentException("No values found");

    var member = propertyLambda.Body as MemberExpression;
    if (member == null)
        throw new ArgumentException(string.Format("Expression '{0}' refers to a method, not a property.", propertyLambda));

    var propInfo = member.Member as PropertyInfo;
    if (propInfo == null)
        throw new ArgumentException(string.Format("Expression '{0}' refers to a field, not a property.", propertyLambda));

    if (type != propInfo.ReflectedType && !type.IsSubclassOf(propInfo.ReflectedType))
        throw new ArgumentException(string.Format("Expresion '{0}' refers to a property that is not from type {1}.", propertyLambda, type));

    var firstValue = attributeValues[0];
    return propInfo.GetValue(firstValue, null);
}

The code above basically takes the lambda statement, makes sure its a property expression and then uses reflection to get the value of the object. By the way, I do not take credit for writing the reflection code, most of it was borrowed from this stackoverflow post. In any case, with the help of the extension method above we can now simplify our code as:

private Assembly Assembly { get; set; }

public AboutViewModel()
{
    Assembly = Assembly.GetExecutingAssembly();
}

public string AssemblyDescription {
    get {
        return Assembly.GetFirstAttributeValue<AssemblyDescriptionAttribute>(x => x.Description).ToString();
    }
}

public string AssemblyProduct {
    get {
        return Assembly.GetFirstAttributeValue<AssemblyProductAttribute>(x => x.Product).ToString();
    }
}

As you can see, the code is much cleaner. Also take notice that I cached the call to Assembly.GetExecutingAssembly() in a private variable. This helps with performance and also cleans up the code a little.

Happy Coding!

Tags: , ,

MVVM | dotNet | WPF

Using Ninject with MVVM Light

I recently changed jobs and as a result I find myself trying to draw parallels between the ASP.NET MVC development I used to do and the WPF MVVM projects that I am working on now. After spending a couple of weeks reading about WPF and learning the fundamentals I finally sat down to write my first WPF application. I chose MVVM Light as my framework because I felt it had a short learning curve and it was fairly lightweight when compared to some of the other frameworks that are out there.

As a MVC developer, one of my favorite NuGet packages has always been Ninject. Adding Ninject to an MVC application is extremely simple because there is a MVC specific implementation called Ninject.MVC which takes care of all the bootstrapping for you. Once you add the package to your MVC project you simply setup your bindings and your up and running. However, I found myself a little bit confused when I added Ninject to my MVVM Light application. I wasn’t sure how to bootstrap Ninject into the application and since there is no WPF specific version of Ninject I knew I had to do the work myself. However, after a little bit of research I came up with the following solution.

Step 1. Create your Ninject Modules

The NinjectModule class is the easiest way to get your bindings registered. You may have noticed that I have two different modules defined. A “Design Time” module and a “Run Time” module. The DesignTimeContext is a mock database. This allows me to avoid the need to access a real database for design time binding and I also use it for unit testing purposes.

public class DesignTimeModule : NinjectModule {
    public override void Load() {
        Bind<IUnitOfWork>().To<DesignTimeContext>();
    }
}

public class RunTimeModule : NinjectModule {
    public override void Load()
    {
        Bind<IUnitOfWork>().To<MyContext>();
    }
}

Step 2. Wire up the ViewModelLocator

The ViewModelLocator that comes with MVVM Light has a property called IsInDesignModeStatic which you can use to check if you are in design mode or not. We can use this property to figure out if we should utilize the DesignTimeModule or the RunTimeModule that we created in the previous step.

public ViewModelLocator()
{
    if (ViewModelBase.IsInDesignModeStatic)
        _kernel = new StandardKernel(new DesignTimeModule());
    else
        _kernel = new StandardKernel(new RunTimeModule());

    About = _kernel.Get<AboutViewModel>();
    Main = _kernel.Get<MainViewModel>();
}

In my project, I have a ViewModel called ProjectListViewModel and the constructor takes an IUnitOfWork as it’s only parameter:

public ProjectListViewModel( IUnitOfWork unitOfWork )

In order to use this new ViewModel I need to add a property to my ViewModelLocator. As you can see below, I use the Ninject kernel to instantiate a new instance of the ProjectListViewModel. Ninject will also take care of creating a concrete IUnitOfWork implementation and inject it into the constructor based on the bindings we established earlier.

public ProjectListViewModel ProjectList {
    get { return _kernel.Get<ProjectListViewModel>(); }
}

 

Finally, in the ProjectList View I use the global instance of the ViewModelLocator to assign the ViewModel to the DataContext property.

<Window x:Class="MyProject.View.ProjectList"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        Title="Projects" 
        Height="450" 
        Width="650"
        DataContext="{Binding ProjectList, Source={StaticResource Locator}}">

 

I must admit that having a mock database for design time is great because you can pre-populate your repositories with different kinds of data and get immediate feedback on how it works with your UI design. It also gives you the ability to see your databindings at work from within Visual Studio or Blend.

Tags: , , , ,

WPF | MVVM

Adding Export Capabilities to the Razor WebGrid

When MVC first came out I really missed having a native grid control. Now a few years later, we have grid support again! In case, you didn’t know the Razor WebGrid was included in the System.Web.Helpers assembly which shipped with ASP.NET MVC 3. Over the years, I have sampled a variety of grid controls such as jqGrid, the Infragistics grid control and the MvcContrib grid. Each grid control has its benefits and disadvantages but I think the new WebGrid offers a clean API which makes development tasks simple. Here is a screenshot of what the grid looks like:

Default webGrid

To display a grid on a razor view page, you basically create a new grid object, assign some properties and then call the GetHtml helper method. Here is an example:

@{
    var grid = new WebGrid(canPage: true, canSort: true, rowsPerPage: Model.PagingInfo.PageSize, ajaxUpdateContainerId: "grid");
    grid.Bind(Model.Data, rowCount: Model.PagingInfo.TotalItems, autoSortAndPage: false);       
}

@grid.GetHtml(
    columns: new List<WebGridColumn>() {            
        grid.Column(columnName: "Id", header: "#" ),
        grid.Column(columnName: "Date", header: "Date"),
        grid.Column(columnName: "UniqueId", header: "Unique Id" ),
        grid.Column(columnName: "Text", header: "Random Text" )
    }) 

Of course, displaying a simple table on a web page is never enough for my demanding clients. I needed to add some additional functionality to my grid, In particular I needed to add some exporting options to my grid. To get started I built out an export to CSV feature. By Utilizing the adapter pattern (a fancy way of saying I wrapped the method call) I was easily able to add in my custom html above the grid which has an export link. Here is my GetHtmlEx method: 

public static IHtmlString GetHtmlEx( 
    this WebGrid grid, 
    < a long list of parameters >
    string recordsText = RecordsText, 
    string pageText = PageText,
    string exportText = ExportText)
{
    var sb = new StringBuilder();
    sb.Append(grid.GetExportHtml());
    sb.Append(grid.GetHtml(tableStyle, headerStyle, footerStyle, rowStyle, alternatingRowStyle, selectedRowStyle,
                        caption, displayHeader, fillEmptyRows, emptyRowCellValue, columns, exclusions, mode, 
                        firstText, previousText, nextText, lastText, numericLinksCount, htmlAttributes));
    sb.Append(grid.GetTotalsHtml());
    return MvcHtmlString.Create(sb.ToString());
}        

Nothing too complicated here, just concatenating some HTML together and returning it as one big MvcHtmlString. The GetExportHtml method prints out the links for exporting to CSV. Since my method wraps the native GetHtml method, I just need to modify the view page and add an ‘Ex’ to the end of the @grid.GetHtml method.

@grid.GetHtmlEx(..) 

With the help of my wrapper above, my grid now has some new schizzle:

image

The code that actually exports the data to a CSV file is tucked away in my view model. However, In order to make my design modular and reusable, I created a base class called WebGridViewModel:

public abstract class WebGridViewModel<T>
{
    private IQueryable<T> _superset;        

    protected WebGridViewModel(WebGridSettings settings)
    {
        Settings = settings;                        
    }            
    
    public WebGridSettings Settings { get; set; }        

    public IPagination PagingInfo { 
        get { return Data as IPagination; } 
    }        

    protected abstract IQueryable<T> GetSuperSet();

    protected virtual IEnumerable<object> GetExportData()
    {
        return GetSuperSet() as IEnumerable<object>;
    }

    public ActionResult View( Controller controller, string viewName = "" )
    {
        var shouldExport = !String.IsNullOrWhiteSpace(Settings.ExportTo);            
        if( shouldExport ) return GetExportViewResult();

        controller.ViewData.Model = this;
        var viewResult = new ViewResult() {ViewData = controller.ViewData };

        if (!String.IsNullOrWhiteSpace(viewName))
            viewResult.ViewName = viewName;

        return viewResult;
    }

    private ActionResult GetExportViewResult()
    {
        var name = typeof(T).Name;
        return new CsvActionResult(name + ".csv", GetExportData().ToList());        
    }

    public IEnumerable<T> Data
    {
        get
        {
            if (_superset == null)
                _superset = GetSuperSet();
            
            var sortColumn = String.IsNullOrWhiteSpace(Settings.Sort) ? Settings.DefaultSort : Settings.Sort;
            var sort = String.Format("{0}{1}", sortColumn, String.IsNullOrWhiteSpace(Settings.SortDir) ? "" : " " + Settings.SortDir);
            var ordered = _superset.OrderBy(sort);                
            return ordered.AsPagination(Settings.Page ?? 1, Settings.PageSize);
        }
    }
}

So In order to build the model for my view, the only thing I have to do is inherit from WebGridViewModel and override the GetSuperSet method. I can optionally return a custom result set for the export by overriding the GetExportData method:

public class MyGridViewModel : WebGridViewModel<FakeData>
{
    public MyGridViewModel( WebGridSettings gridSettings )
        : base( gridSettings )
    {
        gridSettings.DefaultSort = "Id";            
    }

    protected override IQueryable<FakeData> GetSuperSet()
    {
        return FakeData.Records;
    }
}

In real life, the GetSuperSet method would hit a database and return some records. However, in order to keep things simple I am using some static data. The Index action of my Home controller takes care of creating the view model and passes it along to the View. Before I added the export feature, my controller action looked like this:

public ActionResult Index( WebGridSettings gridSettings )
{
    var model = new MyGridViewModel(gridSettings);
    return View(model);
}

However, now that my grid supports exporting, I need to support two different action results. A standard ViewResult for displaying the grid on the view page and a custom ActionResult which takes care of building the CSV file and returning it to the client via the response stream. If you look at the implementation details of the WebGridViewModel you may have noticed a method called “View” which basically detects whether or not an export was requested and conditionally returns a regular ViewResult or a CsvActionResult. So the only thing I need to change in the Index method is the return statement:

public ActionResult Index( WebGridSettings gridSettings )
{
    var model = new MyGridViewModel(gridSettings);
    return model.View(this);
}

So now when the Home/Index action is called a standard view is returned. However, when you click on the export hyperlink link an additional query string parameters is added to the url named ExportTo with a value of CSV (Home/Index?ExportTo=CSV). The WebGridViewModel inspects the ExportTo parameter and will automatically determine if a CSV file should be returned. 

Download The Sample Code (468.61 kb)

Tags:

ASPNet | MVC | Tech

Building MVC Select Lists The Easy Way

It is common to have a view model that contains a list of select list items ( IEnumerable ). However, I get a little annoyed when I see a select list item getting initialized like this:

Widgets = db.Widgets.FindAll().Select(x => new SelectListItem() { Text = x.Name, Value = x.Value });

Although this is legal syntax its just a little bit too ugly for my liking. In an effort to make life simpler I came up with the following helper class:

public static class SelectListFactory
{
    public static IEnumerable<SelectListItem> BuildList<T>(IEnumerable<T> items, Func<T, SelectListItem> func)
    {
        return items.Select(func);
    }        

    public static IEnumerable<SelectListItem> BuildList<T>(
        IEnumerable<T> items,
        Func<T, string> text,
        Func<T, string> value = null,
        Func<T, Boolean> selected = null)
    {
        return items.Select(x => new SelectListItem{
            Text = text.Invoke(x),
            Value = value == null ? text.Invoke(x) : value.Invoke(x),
            Selected = selected == null ? false : selected.Invoke(x)
        });            
    }        
}    

With the help of our new SelectListFactory we can now re-write that first block of code as:

Widgets = SelectListFactory.BuildList( db.Widgets.FindAll(), x => x.Name, x => x.Value );

Hmm, not to shabby. However, I think an extension method could make it even cleaner...

public static class SelectListExtensions
{
    public static IEnumerable<SelectListItem> BuildList<T>(
            this IEnumerable<T> items,
            Func<T, string> text,
            Func<T, string> value = null,
            Func<T, Boolean> selected = null
        )
    {
        return SelectListFactory.BuildList(items, text, value, selected);
    }
}

So now lets rewrite the method using our new extension method...

Widgets =  db.Widgets.BuildList( x => x.Name, x => x.Value );

Now that is considerably better than what we started with! Happy Coding!

Tags: ,

ASPNet | MVC | Tech

MVC–Showing a setup screen on the first run

Recently, I participated in a project where I helped to build a website in Orchard. One of the things that I admire (and there are many) about Orchard is the setup screen that appears the first time you run the site. It’s a nice touch and really makes the site easy to configure. No need to tweak a web.config, create a database or read a 20 page setup guide on how to get started. You just fill out the form and the site is ready…

Of course, I wanted to build something similar for my open source project WeBlog. First, I tried to reverse engineer the orchard code. However, orchard uses a lot of dynamic types and things are heavily abstracted so it was hard to re-use their code for my purposes. Next, I tried to Google for a solution but the only thing I could find was this stack overflow post.

My first thought was to create a base controller class and override the OnActionExecuting method. In that method I could force a redirect if the site was not configured yet. However, I abandoned this strategy because at this point in the process the wrong controller has already been created (the one assigned to the default route) and I basically have to cancel the previous request and redirect. Therefore, I decided to use a custom controller factory instead. This way I can intercept which controller and action should be fired if the site has not been configured yet much earlier in the process. Here is what I came up with:

public class WeBlogControllerFactory : DefaultControllerFactory
{
    public override IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
    {
        if (!SiteManager.Any())
        {
            requestContext.RouteData.Values["action"] = "Index";
            requestContext.RouteData.Values["controller"] = "Setup";
            return base.CreateController(requestContext, "Setup");
        }

        return base.CreateController(requestContext, controllerName);
    }
}

Finally, you will need to register your custom controller factory, just add this line to the application_start method in the global.asax:

ControllerBuilder.Current.SetControllerFactory(new WeBlogControllerFactory());

So now when my application runs the first time I get the setup screen. Sweet!

weblog_setup_screen

The code can be viewed here. Please leave a comment if you have an alternative solution.