Tuesday, September 18, 2012

Migrating an existing Entity Framework code first MVC4 website to Windows Azure – Part 2

My last post involved creating a simple fully functioning MVC 4 application, talking to a SQL server 2012 backend DB. In this post, my aim is to demonstrate how you could easily migrate this application and host it entirely in the cloud, using Windows Azure. In order to proceed, it is vital that you sign up for the service and have got all the right tools required to allow deploying applications and services to the cloud. Fee free to browse to the following links and familiarize yourself with the content. Trust me, its all very cool!

Go ahead and sign up for an account (if you don't already have one) and install the azure development tools for visual studio 2012. Make sure that you also sign up for the Azure Websites preview as well.

Create an Azure Website & Database instance

I begin by signing into my windows azure management portal. My first step is to create a new Azure SQL database. The database needs to be hosted via Azure, hence it is required when creating a new DB to instruct Azure to create a new server or re-use an existing server that may have been created in the past. We will simply instruct it to create a new DB server. Follow the wizard through to provide a login which can be used to access the server and complete the DB creation process

image  image

Once this is created, we must configure the new DB server to accept requests from the client machine we are currently working on. To do this, navigate to the SQL Databases tab from the navigation menu, find out newly created ToDoListDB DB instance from the list. Under the server column, we find a link to the current server created and configured by windows Azure to host our DB instance (yes its in the portion that I have had to black out as the web no longer relies on an honour system for safety these days). Clicking on it takes us to the landing page for configuring the azure server instance. Once in there, click the option to Configure the server

image

On the configuration page, the site outlines what the current client IP address is (i.e. our dev machine used to create the website previously). Please note that for safety reasons, I have blocked out some values on the page. Copy this IP address and create a new rule Allow and paste the IP address in the textbox for the start & end IP address. This configures our Azure server to accept requests from our client machine

image

Once this is done, we can go back to the Azure DB instance. Selecting the the DB instance from the list takes us to a separate page which allows us to obtain a copy of the ADO.net connection string for this DB. Make sure you maintain this connection string as we will require this later on in the post. Ensure that you have provided the correct username and password details in the connection string (not included by default).

image

Next we go ahead and create a new Azure Web site instance. The wizard prompts us to pick a URL name. Note that url names are reserved and you have pick one that is not already in use. For this blog, I have used the name toDoListBlog, may sound a bit clunky but as long as it gets the job done. Another thing to note is that currently (at the time of writing this post), it seems that all azure websites have to be affiliated with a region in the US. I am not sure if this is only a azure website preview feature but I honestly do not have any more information at present. Bear in mind that this may affect stuff like regional settings, time zones, privacy agreements etc.

image image

At this point we are all setup to migrate and host our application in the cloud using windows azure. One final step before we move on is to get the publishing profile for this website so that we can instruct VS2012 where this needs to be uploaded. Navigate to the dashboard of our newly created site, click on the option to Download Publishing Profile and save this file somewhere on your machine

image

Altering the MyToDoApp VS2012 Solution

I can now fire up my solution created in my previous blog post. Since I have all the azure SDK & tools for VS2012 installed, I can go ahead and add a new Windows Azure cloud service project to my solution. Once you have instructed VS2012 to create the solution, a small wizard pops up prompting us to add new .Net roles to the cloud service solution. In our case, we do not need to add any new roles, so we can simply click Ok.

image   image     

Once your solution is setup, navigate to the newly created MyToDoApp.CloudSvc project and find the item marked Roles. Right click and from the options, choose Add Web Role Project from this Solution. Select the MVC4 project MyToDoApp from the wizard and click ok

image    image

This gets VS2012 to modify your current solution and adds a number of references to the project to allow it to be hosted inside the cloud. We can then add a reference to our previously created azure DB, ToDoListDB. Using the copied connection string, I can add an entry to my release configuration file (i.e. Web.Release.config) like so:

<?xml version="1.0"?>

<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">

  <connectionStrings>

<add name="ToDoListDb"
providerName="System.Data.SqlClient"
connectionString="Server=tcp:[Server Name].database.windows.net,1433;Database=ToDoListDb;User ID=[User Name]@[Server Name];Password=[Password];Trusted_Connection=False;Encrypt=True;Connection Timeout=30;"
xdt:Transform="SetAttributes"
xdt:Locator="Match(name)"/>

</connectionStrings>

<system.web>
<compilation xdt:Transform="RemoveAttributes(debug)" />
</system.web>
</configuration>



This ensures that during release deployment, our application will connect to and use the Azure SQL DB as its persistence store. The original connection string added in my previous post still resides in the parent Web.Config. This allows us to utilize the local SQL 2012 DB on our dev machines during debugging.



Publishing Application to Windows Azure


We are now finally ready to deploy our application to WIndows Azure. In the solution explorer, right click on the MyToDoApp project and select Publish. In the corresponding Publish Wizard interface, within the Profile section, find and import the azure *.publishsettings file previously saved. This should automatically populate the next section of the interface, Connection. Feel free to validate your connection with the cloud service. This ensures that your client machine’s IP is capable of deploying to Azure


image  image


Moving onto the next section, Settings, set the configuration as Release. In the sections labelled Databases, ensure that your connection string to the Azure DB is set. Ensure the following options shown below are also ticked. These will ensure that the code migrations are deployed and run on the target DB


image


And were done! Feel free to preview the deployment. Hit the publish button. The first upload usually takes a while, but any subsequent uploads are capable of merging changes with the existing files. No, I have still not worked out when I am going to mow my lawn.


image

Thursday, September 13, 2012

Migrating an existing Entity Framework code first MVC4 website to Windows Azure – Part 1

I have been playing with some awesome new toys from Microsoft this week, namely Entity Framework Code First and Windows Azure. As I was working through all the awesome project templates that create & add web roles etc., one thing that struck me as a common usage scenario for anybody that would like to migrate to the cloud, would basically involve migrating an existing site into Azure and hosting it from an Azure website. I thought I might try working out how to do this. Since this may turn into a mega post,I thought I might break it up into a couple of posts.

As part of this post I will first create a simple MVC 4 standalone website from scratch. To add a bit of extra jazz, I am going to build it using Entity Framework Code First, using a SQL 2012 backend. I will then migrate and host both the site and database in Azure.

To start off, let us describe a very simple idea for a website. Assume we wish to create a simple site that will allow us to create and maintain a TODO list of items, basically something we can use to create, timestamp and manage things to do throughout our day. I must stress, its going to be a very simple solution for demonstration purposes. To start off with, within VS2010, create a simple MVC 4 solution, labelled ‘MyToDoApp’, using the Basic project template.
image   image

Creating the Entity Model

Once the solution is created, note that the project template should have already enabled Entity Framework for the solution. Verify this via the package manager console via the following command
image
The next step, I am going to go ahead and create my entity model. To keep things simple, we only need 1 entity in our model, a Task entity to capture all the information we need. We create the entity class like so (note the namespace):
   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:   
   6:  namespace MyToDoApp.Models
   7:  {
   8:      public class Task
   9:      {
  10:          public int Id { get; set; }
  11:   
  12:          public string Description { get; set; }
  13:          
  14:          public DateTime? DueBy { get; set; }
  15:          
  16:          public bool Completed { get; set; }
  17:      }
  18:  }



I purposely chose the class name ‘ToDoTask’ over the simple and obvious ‘Task’ mainly to avoid any conflicts with the .NET TPL library. Also I have left made the DueBy property nullable as we may have a task that does not need to be completed by some time framed (like mowing the lawn). My next step is to create a an EF context. We can do this like so:


   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Data.Entity;
   4:  using System.Linq;
   5:  using System.Web;
   6:   
   7:  namespace MyToDoApp.Models
   8:  {
   9:      public class TaskListContext: DbContext
  10:      {
  11:          public DbSet<ToDoTask> Tasks { get; set; }
  12:      }
  13:  }





This is all the code we need to define out entity model (yes it is that awesome).

Using Entity Framework Code-First to push the entity schema to an external database


To mimic a real world scenario, I want Entity Framework to translate and host the entity model on my local SQL 2012 DB. I proceed by creating a simple database which we can label ‘ToDoListDb’. Once this is done, we need to instruct entity framework where it needs to point and create the DB schema to. Navigate to the Web.config in your solution, find the element labelled ‘connectionStrings’ & add a new connection entry, similarly labelled ‘ToDoListDb’, to our newly created DB as shown. You may comment out/delete the existing connection string entry labelled “DefaultConnection” (created by default by the project template)
<connectionStrings>
    <add name="ToDoListDb"
         providerName="System.Data.SqlClient"
         connectionString="Data Source=.;Initial Catalog=ToDoListDb;Integrated Security=True;Connect Timeout=15;Encrypt=False;TrustServerCertificate=False" />
    
  </connectionStrings>



We may now proceed to translate our entity model to the database. Navigate to the Nuget Package manager console and run the following commands (in the same sequence). First we will instruct EF to enable code first migrations in our project, telling it that we would like to use the DB in the connection string we added previously to the web.config (Note: make sure you specify this parameter using double quotes)

PM> Enable-Migrations -ConnectionStringName "ToDoListDb"



Next we instruct EF code first to add a base migration to our project to reflect the current state of the entity model, again passing in the connection string as a parameter

PM> Add-Migration Base -ConnectionStringName "ToDoListDb"



Finally we ask it to update the database

PM> Update-Database -ConnectionStringName "ToDoListDb"



If all goes as planned, we should see a schema applied to our database like so

image

Creating the MVC Web UX

Now that we have our entity model created and deployed to our SQL db, we now need  to instruct the TaskListContext initially created to connect to and utilize the ‘ToDoListDb’ created. We can do this via a constructor for the TaskListContext class, which can accept a connection string as a parameter and pass this onto its superclass DbContext like so:

   1:  namespace MyToDoApp.Models
   2:  {
   3:      public class TaskListContext: DbContext
   4:      {
   5:          public DbSet<ToDoTask> Tasks { get; set; }
   6:   
   7:          public TaskListContext(string connectionString)
   8:              :base(connectionString)
   9:          { }
  10:      }
  11:  }

  To simplify creating an instance of the TaskListContext class, we may use a Factory to create and serve new instances to any MVC controller that wishes to utilize it:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Configuration;
   6:   
   7:  namespace MyToDoApp.Models
   8:  {
   9:      public static class TaskListContextFactory
  10:      {
  11:          public static TaskListContext GetNewContext()
  12:          {
  13:              //get the connection string entry "ToDoListDb"
  14:              var connectionString = ConfigurationManager.ConnectionStrings["ToDoListDb"].ConnectionString;
  15:              return new TaskListContext(connectionString);
  16:          }
  17:      }
  18:  }

The TaskListContextFactory class simply uses the System.Configuration.ConfigurationManager class to retrieve the connection string from our web.config and pass that as an argument to our TaskListContext, ensuring any instance of the context is always communicating with the correct DB. Being a static class adds to the convenience of just being able to invoke any of its methods statically to get a new context. Our next step is to create an MVC controller & view to display all the tasks. The view will also allow the user to add a new task, edit & remove existing tasks. We start with specifying the controller TaskController like so:

   1:  using System;
   2:  using System.Collections.Generic;
   3:  using System.Linq;
   4:  using System.Web;
   5:  using System.Web.Mvc;
   6:  using MyToDoApp.Models;
   7:   
   8:  namespace MyToDoApp.Controllers
   9:  {
  10:      public class TaskController : Controller
  11:      {
  12:          TaskListContext taskContext;
  13:   
  14:          public TaskController()
  15:          {
  16:              taskContext = TaskListContextFactory.GetNewContext();
  17:          }
  18:   
  19:   
  20:          //display all tasks
  21:          public ActionResult Index()
  22:          {
  23:              return View(taskContext.Tasks);
  24:          }
  25:   
  26:      }
  27:  }

The Index mvc action method simply selects all the tasks and passes them as a parameter to the view. Next we create the strongly typed Index.cshtml MVC View to simply list all the tasks:
@model IEnumerable<MyToDoApp.Models.ToDoTask>

@{
    ViewBag.Title = "My Task List";
}

<h2>My Task List</h2>

<table>
    <thead>
        <tr>
            <th>Description</th>
            <th>DueBy</th>
            <th>Completed</th>
        </tr>
    </thead>
    <tbody>

        @foreach (var task in Model)
        {
            <tr>
                <td>@Html.DisplayFor(model => task.Description)</td>
                <td>@Html.DisplayFor(model => task.DueBy)</td>
                <td>@Html.DisplayFor(model => task.Completed)</td>
            </tr>    
        }

    </tbody>
</table>

Ensure you also have the following rout configured for the application in your RouteConfig.cs

   1:   public static void RegisterRoutes(RouteCollection routes)
   2:          {
   3:              routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
   4:   
   5:              routes.MapRoute(
   6:                  name: "Default",
   7:                  url: "{controller}/{action}/{id}",
   8:                  defaults: new { controller = "Task", action = "Index", id = UrlParameter.Optional }
   9:              );
  10:          }



If we create and run the application we now have the *currently empty’ list of tasks

image

Next we want to be able to allow adding a new ToDoTask. We start by providing an Action-link in our current MVC view like so:
@model IEnumerable<MyToDoApp.Models.ToDoTask>

@{
    ViewBag.Title = "My Task List";
}

<h2>My Task List</h2>

@Html.ActionLink("Add Task", "add")

<table>
    <thead>
        <tr>
            <th>Description</th>
            <th>DueBy</th>
            <th>Completed</th>
        </tr>
    </thead>
    <tbody>

        @foreach (var task in Model)
        {
            <tr>
                <td>@Html.DisplayFor(model => task.Description)</td>
                <td>@Html.DisplayFor(model => task.DueBy)</td>
                <td>@Html.DisplayFor(model => task.Completed)</td>
            </tr>    
        }

    </tbody>
</table>

This is followed by adding the Add action method to our TaskController class. Notice that I am explicitly stating the name of the MVC view to use, reason being I intend to reuse the same view for the edit template. Also, as per best practise in MVC, I pass a new ToDoTask instance to the view, defaulting the Completed flag to false:


   1:  public ActionResult Add()
   2:          {
   3:              return View("TaskEdit", new ToDoTask() { Completed=false});
   4:          }

The TaskEdit.cshtml view contains the following html
@model MyToDoApp.Models.ToDoTask

@{
    ViewBag.Title = "Edit Task";
}

<script type="text/javascript">
    //use JQuery to add a datepicker
    $(function () {
        $("#@ViewData.TemplateInfo.GetFullHtmlFieldName("DueBy")")
            .datepicker({ dateFormat: 'dd/mm/yy' });
    });
</script>

<h2>Edit Task</h2>
@using (Html.BeginForm())
{
    @Html.EditorForModel()
    <input type="submit" name="submit" value="Save" />
}

Debugging the site in its current state should render the following

image   image


This outlines a tiny issue, the Id member of a ToDoTask should not be editable as it is the primary and hence automatically incremented using an Identity in TSQL. We can fix this by editing the class ToDoTask to add a HiddenInput data annotation attribute to the Id member field like so (line 7-8):


   1:  using System.Web.Mvc;
   2:   
   3:  namespace MyToDoApp.Models
   4:  {
   5:      public class ToDoTask
   6:      {
   7:          [HiddenInput(DisplayValue=false)]
   8:          public int Id { get; set; }
   9:   
  10:          public string Description { get; set; }
  11:          
  12:          public DateTime? DueBy { get; set; }
  13:          
  14:          public bool Completed { get; set; }
  15:      }
  16:  }
This ensures that MVC’s scaffolding renders the field as a Hidden input when editing a ToDoTask model item

image

Finally, we handle the POST back when the user clicks save to persist the task. We add the following MVC action method to the TaskController.cs:

   1:  [HttpPost]
   2:          public ActionResult Add(ToDoTask task)
   3:          {
   4:              if(ModelState.IsValid 
   5:                  && task !=null)
   6:              {
   7:                  taskContext.Tasks.Add(task);
   8:                  taskContext.SaveChanges();
   9:                  return RedirectToAction("Index");
  10:              }
  11:              return View();
  12:          }
Once this is done, we can easily create new tasks for the list

image    image

The final step is to add some actions to allow editing and deleting values from the list. For the sake of brevity I will now simply list the additional actions I will add to support deleting and editing items in TaskController.cs:

   1:   public ActionResult Edit(int? Id)
   2:          {
   3:              if(Id == null)
   4:                  throw new ArgumentNullException("Id");
   5:   
   6:              if (taskContext.Tasks.Any(tsk => tsk.Id == Id))
   7:              {
   8:                  var task = taskContext.Tasks.FirstOrDefault(tsk => tsk.Id == Id);
   9:                  //we are reusing the TaskEdit.cshtml view that was added earlier
  10:                  return View("TaskEdit",task);
  11:              }
  12:   
  13:              return RedirectToAction("Index");
  14:          }
  15:   
  16:          [HttpPost]
  17:          public ActionResult Edit(ToDoTask task)
  18:          {
  19:              if (task != null)
  20:              {
  21:                  taskContext.Tasks.Attach(task);
  22:                  //signal that the entity has been modified
  23:                  taskContext.Entry(task).State = System.Data.EntityState.Modified;
  24:                  taskContext.SaveChanges();
  25:              }
  26:              return RedirectToAction("Index");
  27:          }
  28:   
  29:          public ActionResult Delete(int? Id)
  30:          {
  31:               if(Id == null)
  32:                  throw new ArgumentNullException("Id");
  33:   
  34:              if (taskContext.Tasks.Any(tsk => tsk.Id == Id))
  35:              {
  36:                  var task = taskContext.Tasks.FirstOrDefault(tsk => tsk.Id == Id);
  37:                  taskContext.Tasks.Remove(task);
  38:                  taskContext.SaveChanges();
  39:              }
  40:   
  41:              return RedirectToAction("Index");
  42:          }

And finally modify the Index.cshtml view to be able to invoke these extra actions:
@model IEnumerable<MyToDoApp.Models.ToDoTask>

@{
    ViewBag.Title = "My Task List";
}

<h2>My Task List</h2>

@Html.ActionLink("Add Task", "add")

<table>
    <thead>
        <tr>
            <th>Description</th>
            <th>DueBy</th>
            <th>Completed</th>
        </tr>
    </thead>
    <tbody>

        @foreach (var task in Model)
        {
            <tr>
                <td>@Html.DisplayFor(model => task.Description)</td>
                <td>@Html.DisplayFor(model => task.DueBy)</td>
                <td>@Html.DisplayFor(model => task.Completed)</td>
                <td>@Html.ActionLink("Edit", "edit", new { Id = task.Id})</td>
                <td>@Html.ActionLink("Delete", "delete", new { Id = task.Id})</td>
            </tr>    
        }

    </tbody>
</table>
This concludes our simple MVC4 application. We now have our application in place, communicating with a backend SQL 2012 database.

image  image

This mimics a common situation we may all face, whereby we have a standalone web application communicating with an existing backend SQL DB. At this point, there is no suggestion that any of this code should be hosted on Azure anywhere in the solution. In my next post, I will outline how easy it is to host and run this MVC application from Azure

Sunday, September 9, 2012

4 recommended tools for developing on SharePoint 2010 for newbies

I seem to have done a fair share of development work for SharePoint 2010. Prior to my current job, I had never used, touched or tried to understand the product. Then I moved onto my current job, a .Net engineering consultancy, which provides a number of services including “Business Collaboration software” (this is what SharePoint is designed to be). Pow! I was “thrown in the deep end”. I had to shift between producing awesome Silverlight 4 apps(all the rage at the time) to clicking on ribbons, creating lists, working with XML based definitions of various structures, all of which were linked & referenced using GUIDs. For any developer that has never worked with anything less awesome than proper code based frameworks (PHP developers exempt … my condolences), having to work with SharePoint for the first time can be likened to an experience comparable with cliff diving off Mt Everest on a scud missile, all on a cold, miserable, snowy day. Even though once you understand why, everything has its place in SharePoint but seriously, GUIDs! GUIDS! GUIDS!!
Some stuff that I have had to do with SharePoint includes:
  • Creating custom site templates
  • Creating custom connected SharePoint Webparts to serve context specific Silverlight content
  • Creating custom content types, List definitions
  • Synching issues from a SharePoint list to a TFS 2010 project
  • Accessing site collections through the SP Client/Server Object model
As such, during my time working on SharePoint, I have come across a couple of tools which I though I may share with anyone out there in the same situation. I cannot honestly say I would have made much progress without them (note: click on the links to download the tool)

SharePoint CAML query Builder – U2U

CAML (Collaborative Application Markup Language) is SharePoint's custom query language used to allow interrogating lists through its API, specifying views, site building etc. Unfortunately, it is not as clean as something like LINQ or T-SQL. Its all specified in nested XML (surprise!).Thankfully, U2U’s CAML query builder tool saves me from insanity. The app allows users to specify & execute their CAML queries expressively, via a reasonably intuitive UI which can then be translated into CAML, run against a list on a SP farm etc. Simply outline what it is you want to search for and copy the generated mark-up. An absolute recommendation for any SharePoint developers arsenal.

camltreeview          buildwhereclause2

SharePoint Manager

Available via Codeplex, this is a handy tool which acts as a SharePoint object model explorer. What this means is that it uses the SharePoint server object model (yes this means it has to be installed on the same machine hosting the SharePoint farm) allowing the user to interrogate all properties, view xml mark-up definitions, object hierarchy etc. of every server object including SPSites, SPWeb, SPList.While primarily aimed at helping SharePoint farm admins, its just works with any farm installed locally or on a dev server. Comes in real handy when having to create custom SharePoint content types and list definitions.
03170127_small

SharePoint ULS viewer

As with every web application, the SharePoint farm maintains a log for reporting errors etc. The logs themselves are quite verbose and navigating through them can be quite time consuming from a normal text editor, especially given the logs recycle at regular intervals. This tool constantly monitors those logs and allows users to view log entries in soft real time in a friendly interface that facilitates filtering, highlighting errors etc. There are a number of different versions of this tool available but I like this version the best. Useful to have in your corner during development.
2011-06-09_150048

SharePoint Designer

Published and maintained by Microsoft, SharePoint designer is aimed at allowing any user to connect with SharePoint and easily configure, design SharePoint components such as lists, custom content types, list views forms, workflows etc, all without having to physically browse the website. The list of things it is capable of are way too many to list on this blog, so feel free to hit the source link to find out more. One thing to remember, to allow SharePoint designer to install correctly, interact with any other office products, I recommend installing both products as either x86 or x64 bit.
So that completes my list of apps that make SharePoint development a little less painful. Hope this helps anybody out there starting out with SharePoint. May the Force be with you.

Wednesday, June 6, 2012

Editing complex entities within an MVC3 view

Recently I have been busy at work building this site to help us manage all our buildings access cards, helping assign/re-assign and generally keep track of who can access various levels of our building etc. We decided to go down the route of constructing the site using a combination of MVC3, Entity Framework, sql server 2008 and some other front end client side libraries such as bootstrap to help speed up the page design (we were told to build it quick with as less $$ as possible). Given that I myself have just recently started using the framework, I ran into a small issue to do with representing complex entities within our MVC views.
Our Db schema resembled something of the sort shown below (note: I have toned it down quite a bit to keep it simple):
Create Table Cards(
id int  Identity(1,1) Constraint pk_card_id primary key
, AssignedTo varchar(50));

create table Locations
(
id int Identity(1,1) Constraint pk_locations_id primary key
, Name varchar(20));

create table CardLocations
(
 CardId int not null Constraint fk_card_id Foreign key references Cards(id)
, LocationId int not null Constraint fk_location_id Foreign key references Locations(id)
, Constraint pk_CardLocations_id primary key(CardId, LocationId)
);
We have 2 primary entities, Cards which maintains a list of all access cards handed out to people and Locations which is a list of all locations in our building and other facilities. The CardLocations table maintains a mapping of all the Locations that a Card has access to (note: both columns of the table are part of a composite primary key). Let us assume that we have the following sample data inserted in the DB:

Cards
id          AssignedTo
----------- --------------------------------------------------
1           Employee A
2           Employee B
3           Employee C

Locations
id          Name
----------- --------------------
1           Level 1
2           Level 2
3           Level 3
4           Level 4
5           Level 5


CardLocations
CardId      LocationId
----------- -----------
1           1
1           2
2           3
2           4
3           5

Hence if we use EF to generate an Entity model for this DB schema we end up with the following:

image

Entity framework automatically detects the many-many association between a Card and a Location entity and does not see the need to create a separate entity for the CardLocations table instead maintaining this as an Entity Association. Let us assume that we wish to allow the user to edit an access card’s details such as who it is assigned to and what locations it has access to. The next listing shows the mock-up of a simple controller used to edit a Card:
   1:  public class CardsController : Controller
   2:      {
   3:   
   4:          CardsEntities model; //The Entity Model
   5:   
   6:          public CardsController()
   7:          {
   8:              model = new CardsEntities();
   9:          }
  10:   
  11:          public ViewResult Edit(int? id)
  12:          {
  13:              if (id == null)
  14:                  throw new ArgumentNullException("id");
  15:              var card = model.Cards.Single(c => c.id == id);
  16:              return View(card);
  17:          }
  18:      }
As seen, the Edit action method takes the id of the card that we wish to edit and using the reference to the entity model, retrieves the card and passes it to the strongly typed view Edit.cshtml (scripted below).
   1:  @model ComplexMvcEf.Library.Model.Card
   2:  @{
   3:      ViewBag.Title = "Edit";
   4:  }
   5:  @using (Html.BeginForm())
   6:  {
   7:      <h2>
   8:          Card</h2>
   9:   
  10:      @Html.HiddenFor(model => model.id)
  11:   
  12:      @Html.LabelFor(model => model.AssignedTo) @Html.EditorFor(model => model.AssignedTo)
  13:   
  14:   
  15:      <h2>
  16:          Locations</h2>
  17:      foreach (var location in Model.Locations)
  18:      {
  19:          @Html.EditorFor(model => location);
  20:      }
  21:   
  22:      <input type="submit" name="Submit" value="Edit" />
  23:  }

Now, does anyone see what is wrong here? The HTML helpers all do their jobs, we have created a strongly typed model (for the type of the Card entity object) where we simply create editors allowing the user to edit who the card is assigned to. However our problems start with being able to assign locations to this card. Navigating to this view renders the following:

image

Obviously binding to the list of locations only allows us bind to and edit the Location entity object, but it is only the 2 location entities that are associated with the card. What about adding a new location? Also in the true spirit of the view we really don't want to be able to edit a location and that functionality should be restricted to a different page. We would basically like some means of selecting from a list of locations, which ones we wish the card to have access to. I know a whole heap of you HTML cowboys out there are probably coming up with a zillion flash ideas constituting fancy JQuery dropdowns with a whole lot of Ajax magic to dynamically manage a cards location. Any other time, I would love to go down that path, however that would simply eat up project hours like popcorn. In retrospect, the number of locations in our building are always going to be few and finite, hence simply listing them on the page is not going to do anybody any harm. Our primary problem here is that we have tried to use what are primarily, our domain models (the Card and Location entities) as a view model, something which may not always work out, especially since without writing some unnecessary boilerplate code, there is no easy way we can represent that a location is selected/ not selected and not to mention any extra effort required to have the mvc model binders work correctly etc (remember that we are dealing with entity objects and model contexts). To rectify the issue, we introduce a couple of classes to use as our view-model

   1:  public class CardEditModel
   2:      {
   3:          //the card being edited
   4:          public Card Card { get; set; }
   5:   
   6:          //the list of locations to display on the view
   7:          public List<CardLocationModel> LocationsModel { get; set; }
   8:      }
   9:   
  10:      public class CardLocationModel 
  11:      {
  12:          //The location Id
  13:          public int Id { get; set; }
  14:          
  15:          //The location name
  16:          public string Name { get; set; }
  17:          
  18:          //Flag to indicate if card can access this location
  19:          public bool Selected { get; set; }
  20:      }

Notice that there are 2 classes created. A collection of CardLocationModel objects is maintained by the CardEditModel class. The use for this will become more apparent in the following sections. We can now integrate this within our Edit action method

   1:  public ViewResult Edit(int? id)
   2:          {
   3:              if (id == null)
   4:                  throw new ArgumentNullException("id");
   5:              //Create a new viewModel
   6:              var viewModel = new CardEditModel();
   7:              //read the card from the DB
   8:              var card = model.Cards.Single(c => c.id == id);
   9:              if (card != null)
  10:              {
  11:                  viewModel.Card = card;
  12:                  //set the locations
  13:                  viewModel.LocationsModel = model.Locations
  14:                      .AsEnumerable() 
  15:                      .Select(location => new CardLocationModel()
  16:                      {
  17:                          Id = location.id
  18:                          //Set flag if the access card has access to this location
  19:                          ,Selected = card.Locations.Any(loc => loc.id == location.id)
  20:                          ,Name = location.Name
  21:                      }).ToList();
  22:              }
  23:   
  24:              return View(viewModel);
  25:          }

The logic for the Edit action method in the shown above basically involves reading the card entity from the models context (line 8) and referencing it via our view model of type CardEditModel (line 11). Lines 13-21 basically involve selecting all the locations from the model’s context. We then use this list to generate a list of CardLocationModel objects which is then referenced by our view-model. Hence we now have a complete list of locations to display to the user. The Selected boolean flag of the CardLocationModel class allows us to represent if the access card being edited is allowed to access this location(line 19). Hence incorporating this into our Edit.cshtml view

   1:  @model ComplexMvcEf.Models.CardEditModel
   2:  @{
   3:      ViewBag.Title = "Edit";
   4:  }
   5:  @using (Html.BeginForm())
   6:  {
   7:      <h2>Card</h2>
   8:      @Html.HiddenFor(model => model.Card.id)
   9:      @Html.LabelFor(model => model.Card.AssignedTo) @Html.EditorFor(model => model.Card.AssignedTo)
  10:      
  11:      <h2>Locations</h2>
  12:      <p>
  13:      @for (int i = 0; i < Model.LocationsModel.Count; i++)
  14:              {
  15:               @Html.HiddenFor(model => model.LocationsModel[i].Id)
  16:               @Html.CheckBoxFor(model =>  model.LocationsModel[i].Selected) @(Model.LocationsModel[i].Name)
  17:              }
  18:      </p>
  19:      <input type="submit" name="Submit" value="Edit" />
  20:  }

Hence, our new view-model allows us to logically represent all the locations available to the user and easily change the mappings as part of the form

image

Additionally to handle the post-back we simply add another Edit action method to the CardController class like so

   1:         [HttpPost]
   2:          public ActionResult Edit(
   3:              int? id
   4:              , List<CardLocationModel> locationsModel)
   5:          {
   6:              //ensure that the entity object is attached to the model context
   7:              var card = model.Cards.Single(c => c.id == id);
   8:   
   9:              if (card != null
  10:                  //update the name if edited in the view
  11:                  && TryUpdateModel(card)
  12:                  )
  13:              {
  14:                  //remove all the cards locations that are no longer selected
  15:                  card.Locations
  16:                      .RemoveAll(l => !locationsModel.Any(crdLocationModel => crdLocationModel.Id == l.id && crdLocationModel.Selected));
  17:   
  18:                  card.Locations.AddAll(
  19:                      model.Locations
  20:                      .AsEnumerable()
  21:                      .Where(
  22:                      l => //ensure that the location is selected by user
  23:                          locationsModel.Any(crdModelLocation => crdModelLocation.Id == l.id && crdModelLocation.Selected)
  24:                          &&
  25:                          //ensure that the location is not already set
  26:                          !card.Locations.Contains(l)));
  27:   
  28:                  model.SaveChanges();
  29:              }
  30:              //simply redirecting to the same edit window
  31:              return RedirectToAction("edit");
  32:          }

Couple of things to note here. The action method is decorated with an mvc HttpPostAttribute filter (line 1), which ensures that this action only gets called on a post request. Also note that as part of our method parameter’s, we have a collection of CardLocationModel objects (line 4). This allows mvc’s model binders to search for and automatically populate the list from the form values. It may seem a little weird, but I purposely read out the card that we are interested in editing from the context first (line 7) followed by making a call to manually ask the controller to try and update the model’s values. This is done with the intent of ensuring that the Card entity object is always bound to the model’s context, and avoids any problems associated with attaching to the context. I am not suggesting that this is a recommended practise but I found that it saved me a lot of time.

Line’s 15-26 represent the code to synchronize the locations represented in our view-model with the actual Locations mapped to the card. The logic is quite simple. I simply remove any Location entity associated with the Card entity that does not have an equivalent CardLocationModel object in our locationsModel list (line 15-16) with its flag set to true (implying selected). I then go about adding mappings for all newly selected Locations to the Card (line 18-26). Note that I am using the following extension methods

   1:  public static class EntityCollectionExtensions
   2:      {
   3:          public static void RemoveAll<E>(this EntityCollection<E> collection
   4:              , Func<E, bool> itemSelector) where E : EntityObject
   5:          {
   6:              foreach (E item in collection.Where(entity => itemSelector(entity)).ToArray())
   7:                  collection.Remove(item);
   8:          }
   9:   
  10:          public static void AddAll<E>(this EntityCollection<E> collection
  11:              , IEnumerable<E> itemsToAdd) where E : EntityObject
  12:          {
  13:              foreach (var item in itemsToAdd)
  14:                  collection.Add(item);
  15:          }
  16:      }

We conclude by saving the changes made to the model context and because our application only has one view, we simply redirect back to the edit screen.

I hope this demonstrates the advantage behind using a view model inside all your MVC views. Binding directly to objects that represent your domain logic may not always be feasible and may limit the ability to logically represent a view to the user (for example, we were unable to provide a complete list of locations to the user). By creating a custom view model, we now have a clear control over how our domain objects can be represented to the user and also allows for the flexibility to represent the intent behind our view logically to the user.