ninja star Using Ninject with MVVM Light

by Michael Ceranski, posted on November 06 2011

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: , , , ,

ninja star Adding Export Capabilities to the Razor WebGrid

by Michael Ceranski, posted on September 03 2011

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:

ninja star Building MVC Select Lists The Easy Way

by Michael Ceranski, posted on July 18 2011

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: ,

ninja star MVC–Showing a setup screen on the first run

by Michael Ceranski, posted on July 09 2011

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.

ninja star Dapper.Net - A Micro ORM that puts you back in control

by Michael Ceranski, posted on May 12 2011

Its fun to reminisce about how database access has evolved over the years. In the early days I used to write parameterized SQL statements directly in my code. Eventually that evolved into using stored procedures. Mainly because by using a stored procedure I could change the way data was gathered without recompiling my source code. Eventually, I abandoned stored procedures altogether when LINQ to SQL was released. Finally, if we fast forward to the current day, my preferred method of accessing data is with EF code first. EF Code first is great because I can spend even less time managing my database and more time solving business problems. With the level of abstraction getting higher and higher it makes you wonder if perhaps the next generation of developers will not even write T-SQL anymore. They will probably laugh at us old timers when we talk about stored procs and T-SQL. 

human-evolution

Wait! Back up a minute! Just because we have abstracted ourselves from the database doesn’t mean that we have evolved into something superior. In my past life as a DBA, I spent many of long afternoons diagnosing performance issues. Most of the issues were due to auto-generated SQL statements from an ORM. Sometimes you could put a band-aid on the problem by adding a few indexes or modifying the source code to force different SQL to be produced. However, I was always frustrated by the fact that I had to trade abstraction for performance. Wouldn’t it be nice to have both….

Well you can. Sam Saffron, one of the geniuses at Stack Overflow, came up with a micro ORM called dapper dot net. Dapper dot net is a single file that you can drop into your project that will extend your IDbConnection interface. As I have said so many times before, let’s have the code do the talking.

Executing a query and mapping the results to a strongly typed list

public class Dog
{
    public int? Age { get; set; }
    public Guid Id { get; set; }
    public string Name { get; set; }
    public float? Weight { get; set; }

    public int IgnoredProperty { get { return 1; } }
}            
            
var guid = Guid.NewGuid();
var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid });
            
dog.Count()
    .IsEqualTo(1);

dog.First().Age
    .IsNull();

dog.First().Id
    .IsEqualTo(guid);

Notice that strange stuff in the middle. Yeah, that’s called a SQL Statement. Anyways, my point is that we get full control over our SQL statement and in addition we also get a strongly typed result set. Pretty sweet huh?

Multi-Mapping

var sql = 
@"select * from #Posts p 
left join #Users u on u.Id = p.OwnerId 
Order by p.Id";
 
var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; });
var post = data.First();
 
post.Content.IsEqualTo("Sams Post1");
post.Id.IsEqualTo(1);
post.Owner.Name.IsEqualTo("Sam");
post.Owner.Id.IsEqualTo(99);

This is an example of mapping a single row to multiple objects. In EF or Linq to SQL you would accomodate this functionality by leveraging a foreign key relationship. Once again, we have full control of the SQL and strongly typed results.

Multiple Results

var sql = 
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id";
 
using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
   var customer = multi.Read<Customer>().Single();
   var orders = multi.Read<Order>().ToList();
   var returns = multi.Read<Return>().ToList();
   ...
} 

Multiple resultsets, a single trip to the server and full control of the SQL. Need I say more?

So Should You Abandon Your Current ORM?

In my opinion, a developer should never settle on a single tool. Being abstracted from the nitty gritty details of writing SQL allows a developer to be more productive. In addition, if you are building small to medium size applications you can afford a small performance penalty because you are probably not dealing with tons of data. Unfortunately, you can't always predict the future of your application. You may start out with 10 users and end up with 10 thousand users. So perhaps the strategy is to develop most of your application using an ORM like EF Magic unicorn and then use Dapper for the parts of your application that need to be performant. This way you get the best of both worlds!

Tags:

About the author

MikeMichael Ceranski is a developer specializing in the .NET stack. I have spent time as a DBA, Web Developer and even a network engineer. Up til now most of my career has revolved around the .NET stack but I have recently taken an interest in microcontrollers which has forced me to get acquainted with lower level languages such as C, and C++.

View my resume

Sponsors