Sunday, May 24, 2015

The Case for MVC (Part 2)

Summary

My last blog post summarized a series that I'm currently working on that explains why the MVC layout if superior to Classic ASP and ASP.Net web forms (aka C# dot net and VB dot net).  I also explained that I was going to go beyond the standard all-in-one MVC project and demonstrate a technique to break your project into two primary projects: The front-end MVC containing the view components and the back-end API containing the business model.


The Project

First I'm going to design and build a project for the business code.  Then I'm going to use MVC to connect the project to a website.  In a future post I will expand this setup to include a Web API between the web site and the business layer.

The business layer will be a database consisting of information about classrooms in a university building that can be scheduled.  This tiny example will have three time slots and a schedule table that will tell which time slots are reserved and which time slots are free.


The Database

 The ERD for the database looks like this:


As I mentioned, this is a tiny example.  I'm going to build this application without the required security.  The data and code for the API security filter will be demonstrated in a future post.

Included in the package will the sql files to generate the tables and the test data.


The MVC Project

Let's take a look at the basic MVC project.  When you first create a project, you can start a new project that is empty.  This is my preferred method since I don't like to cut out baggage that I don't need.  I can start with nothing and build it up.  When the blank project starts, you'll see that there are some files already created for you.  These files are needed in order to run the routing and filters.  There is also the standard web.config file, which is always present in .Net applications.  Technically, there are two web.config files, one at the application level and one inside the views.

Initially, you can ignore all of this and move on to where you will place your project files.  Here's a picture of an empty MVC project:







There is an App_Data folder, you can put your Entity Framework files in this folder, or a local database if you're using something like Microsoft Access.  I never use this folder and I'll get to the reason in a minute.  The next folder is the App_Start, which is pre-populated as I mentioned earlier.  The next folder will contain your controllers.  This is the part that connects your Business layer to your website.  The only actual code that we will put in here will be wire-up code to connect your business layer project code with the website.

Next on the list of folders is the Models folder.  This is usually where your business layer code goes, but I never use this folder either.  The last folder is the views.  The views contain all the html files (or in the case of MVC, they start out as cshtml files).

OK, now some explanation is required.  This project is a bare-bones website project.  Microsoft set it up so that a small website can be created and all the files can be contained inside this one project.  For our purposes, we'll be putting all the business layer code into a separate project and connect the two together.  This will give us a clean separation of concerns and provide a way to use unit testing on the business logic without worrying about faking or mocking the controllers.  So our data context and our "models" will be contained in a library project.


The Content Folder

One folder that was not created and we will need to create will be the "Content" folder.  This is used to hold the css, js and image files.  I usually name these folders "js", "css" and "img", but you can use any naming convention that suites your needs.  I also delete the folders I will not be using ("App_Data" and "Models").  So now I have something like this:






The ultimate goal is to be able to isolate any static files that you created.  This means that js, css and image files can be sent up to a CDN, like Amazon CloudFront or Fastly.  MVC also has the capability to designate which js and css files will be minified and/or bundled to reduce website load time.


The Business Layer Code

I'm going to skip all the details of creating the business layer and just post it on-line so you can download it and poke through the code.  There isn't much to it.  The main project is named UniveristyApp and it contains the Entity Framework code to read data from the database using 3 different criteria (see the ClassRoomReservation object for more details).  I specifically designed this object to use an API, but we'll just ignore that fact for now and just instantiate this object inside the controller and pass parameters to get the results we want.  At first, I'm just going to hard-code the parameters and then we'll later connect to a drop-down list box to allow the user to control what results they want to see.

The unit test project uses the NHibernate Mapping Generator that I developed in previous blog posts.  We can ignore the NHibernate ORM portion of this and use the mapping generator to generate test data.  This is contained in the DummyDataLayer folder.  This will need the SQL Local DB program in order to run (it's very small and easy to install).  You can get more information about this from my github account here: NHibernateMappingGenerator Wiki.


Create a Controller

Let's create one controller to connect a web page to the business layer.  Right-click on the Controllers folder and add Controller.  Select a blank MVC controller and name it RoomListController:



Now, you'll see code similar to this:

namespace MVCUniversityDemo.Controllers
{
    public class RoomListController : Controller
    {
        //
        // GET: /RoomList/


        public ActionResult Index()
        {
            return View();
        }
    }
}


Right-click on "View();" and add a view.  Just leave the name as the default index name.  If you hit F-5, you'll notice that the home page cannot be found.  We need to change the route to make sure that RoomList is the starting controller.  So open the RouteConfig.cs file inside the App_Start folder and change your code to look like this:

namespace MVCUniversityDemo
{
    public class RouteConfig
    {
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "RoomList", action = "Index", id = UrlParameter.Optional }
            );
        }
    }
}


As you can see the default startup page is controlled by the controller.  Instead of naming our starting controller "Home" we just change the name to whatever we want (in this example, RoomList).  Now you can hit F-5 and a blank web page will startup.


Connecting the Controller

OK, time to do something real.  Let's just connect our business logic to the web page and list some data out in raw format.  First, add a reference to the UniversityApp, then open the RoomListController.cs file and addd a using at the top for the UniversityApp name space.  Now we're going to use a built-in dynamic object called the ViewBag.  This object makes wire-ups a very easy task.  I normally just create my object and assign it to the view bag like this:

public ActionResult Index()
{
  var classRoomReservationList = new ClassRoomReservationList(new ClassAPIRoomRequest { AllAvailable = true });
  ViewBag.ClassRoomReservationList = classRoomReservationList;

  return View();
}


Now all the properties from this object are visible from the web page.  Change your Index.cshtml file to look like this:

<h2>Class Room List</h2>

@foreach (var item in ViewBag.ClassRoomReservationList.ReservedRoomList)
{
    <div>@item.Name @item.Reserved</div>
}


Now hit F-5 and you'll see something like this:


Yup, it's ugly.  Formatting of the output can be controlled by the html and an external css file.  I'm going to skip over that part here.


User Control of Displayed Values

Now it's time to refactor our code to make sure the drop-down list can filter which rooms we want to see.  So for your view, you'll need to change to this:

<h2>Class Room List</h2>

@using (Html.BeginForm("ChangeSelection", "RoomList", FormMethod.Post, new { role = "form" }))
{
    @Html.DropDownList("lstRoomSelector", (SelectList)ViewBag.RoomList, new { onchange = "this.form.submit();" })
}
<br />
@foreach (var item in ViewBag.ClassRoomReservationList.ReservedRoomList)
{
    <div>@item.Name @item.Reserved</div>
}


Remember, this is dumb and dirty.  In a real-world website you would probably use a framework and ajax to present your data.  In my next post, I'll show how that is done using AngularJS and ajax.  For this simple demo, I'm trying to keep the code as small as possible.

For your controller code:

private void PopulateViewBagData(string lstRoomSelector)
{
    ClassAPIRoomRequest classAPIRoomRequest = new ClassAPIRoomRequest();

    switch (lstRoomSelector)
    {
        case "Show Only Reserved Rooms":
            classAPIRoomRequest.AllReserved = true;
            break;
        case "Show Only Available Rooms":
            classAPIRoomRequest.AllAvailable = true;
            break;
    }

    var classRoomReservationList = new ClassRoomReservationList(classAPIRoomRequest);
    ViewBag.ClassRoomReservationList = classRoomReservationList;

    var listItems = new List<string> {
        "Show All Rooms",
        "Show Only Reserved Rooms",
        "Show Only Available Rooms"
    };

    ViewBag.RoomList = new SelectList(listItems);
}

    //
    // GET: /RoomList/

public ActionResult Index()
{
    PopulateViewBagData("");
    return View();
}

[HttpPost]
public ActionResult ChangeSelection(string lstRoomSelector)
{
    PopulateViewBagData(lstRoomSelector);
    return View("Index");
}


I moved the code that creates the business layer object to a separate method.  This is shared by both controllers.  The first controller is used on startup and the second controller is used during a post operation.  


Summary

I'm going to wrap up this portion of my case for MVC.  I would encourage you to download the simple app and poke around a bit to see how this fits together.  Next, I'm going to show how to set up an MVC application to use APIs to connect between the web site MVC project and the business layer code.  The purpose in going this far is to provide the ability to serve data from another server.  This is important for very large applications and also for web sites that will be connecting to data from many different sources possibly located at different data centers.  

One last piece I want to demonstrate is a security filter. If your website uses APIs, then there will need to be a way to do cross-site scripting and provide a token in the header to ensure that only authenticated users can access data.  I will create a demonstration application to show how this works.

I have yet to make my case that MVC is superior to the standard .Net webforms.  When I demonstrate the use of AngularJS, Ajax and a Web API, it'll become clear why I've jumped on the MVC bandwagon.


How to Get the Code

You can go to my GitHub account by clicking here and download the entire package, including the sql scripts you'll need in order to create the tables and populate the data.  To use the scripts, create a database in your MS SQL server named APIUniversity (see "CreateAPIUniversityData.sql" file in the root directory).  You'll need to go to the UniversityApp project and open up the ClassDatabase.cs file and change "{YOUR SQL NAME}" to match the name of your sql server.  You can add user id and password to the connection string if you need to.

 






Saturday, May 9, 2015

The Case for MVC (Part 1)

Summary

In this blog post I'm going to present a case for using the MVC framework. My case is not that MVC is better than MVVM or any other framework, but that it is better than no framework (such as Classic ASP or plain old VB.Net or C#.Net).  This will be a multi-part series that will explain why MVC should be used and give examples of how to achieve the end goal.


Legacy Code (In the Dot Net World)


I've created a few blog posts on the subject of legacy code.  I haven't spent nearly enough blog time explaining how to get from legacy code such as ASP into something more modern.  In addition, I need to explain the advantages of conversion.  Why?  Because we don't convert software just to use the latest and greatest, or that it's trendy (though, I'm sure there are a lot of young developers out there that have that very goal in mind).

Classic ASP is a very bad language.  Nobody can argue against that.  Classic ASP was released when object oriented languages were just getting off the ground and going mainstream.  My best guess is that Microsoft had to come up with some sort of scripting language to allow developers to create dynamic web sites and use Microsoft servers.  Technically, Classic ASP programs can be written in a very structured and organized fashion.  Unfortunately, it seems that programmers view Classic ASP as a license to commit every bad programming pattern on the planet.  If Classic ASP supported gotos and line numbers, I swear programmers would use them!

The next thing up from Classic ASP is VB.Net.  This language is also found everywhere.  I know that most of the VB.Net programmers are software developers who did not obtain a formal degree and/or they learned VB as their first language.  The problems with VB.Net are many.  First, it has legacy capabilities that allow the developer to write code that does not use namespaces (as one example).  Developers seem to ignore the object oriented aspect of the language and treat subroutines and functions as, well subroutines and functions of a linear language (by keeping the name "function" and "subroutine", the fact that VB was at one time not object oriented is obvious).  This language, like Classic ASP also seems to give license to a lot of bad programming habits.  Though I have seen some well written VB.Net code, it is rare.  Unit tests are also very rare in a VB.Net project (in fact, I've never seen a unit test in existing VB.Net code).

Next up is C# Dot Net.  This is where there is an aspx page and a code-behind page.  This is the same as VB.Net and a lot of ugly programming habits are used with this due to the fact that business layers, view layers, etc. were not in common use when this technique of writing a website came along.  Developers are becoming more aware that they need to use the code-behind for wire-up code only, but it's very typical to find a lot of business logic in the code-behind pages.  Restricting the code-behind as a wire-up to a separate project containing the business logic is a much improved practice.  Other issues come up when there is a lot of mingled C# code in the aspx page using the <% %> syntax.  This breaks the structure of the HTML in the page (and the javascript) and the C# code on this page is not compiled (causing errors only at run-time).

MVC is the latest and greatest thing that has been incorporated into Visual Studio.  The improvements from code-behind to MVC are immense.  First, the new razor syntax for the mingling of C# with HTML is structured the same as C# and HTML (in a hierarchy).  Second, there is a distinct division between Javascript, CSS, HTML, C# APIs and the business logic (called the model).  Also built into MVC is the ability to turn on minimization of both Javascript and CSS as well as bundling (where all the Javascript files and all CSS are merged into one file for more efficient download).  In order to maximize efficient use of minimization, the Javascript must be contained in JS files and not embedded in HTML or printed from C#.  MVC also supports the dynamic function known as the viewbag.  This makes wiring up the API to HTML easy.

The next step up from MVC is to use two MVC projects to divide the front-end and business sides using Web API.  This is just one step away from SOA and has some very distinct advantages.  First, all of the front-end code (HTML, CSS, Javascript) is in one project which can be modified by a designer to change the look, without touching a lot of C# code.  Second, there can be two or more front-ends that connect using the same APIs (such as a mobile site, or a web site with a different purpose, or to connect to another system).  Everything from the database to the API can be written in any language (PHP, Python on unix or C# in IIS for example) and the front-end can be just HTML with Javascript and CSS, or the front-end could use a framework such as AngularJS.  This type of design is very modular in the fact that APIs can be split across different servers to balance the load.  A website can be broken into distinct logical sections and written to operate on different web servers.


Next

Next up, I'm going to talk about MVC and how to setup a basic project.  If your looking for a good book to read, this is the best that I've found:





This book breaks the MVC subject into its components and teaches them in an order that makes it connect together in an easy fashion.  The first part of MVC covered is the Controller, then the View and finally the Model.  There is a chapter on the Routing section, which is very important to understand.  Other chapters go into unit testing details and other advanced subjects.


Saturday, May 2, 2015

XML Serializing Nullable Optional Attribute

Summary

The title of this blog post is a bit of a mouth-full.  I do a lot of xml serialization and de-serialization.  It's all part of the new paradigm of using APIs to communicate with other systems over the Internet.  One of the annoying "features" of the xml serializer is that it doesn't support nullable attributes.  It'll serialize nullable elements, but not attributes.  So I'm going to show how to serialize nullable attributes and make the attribute optional.


The Problem

Here's the example code of an XML serializer that will not work

public class House
{
    [XmlElement]
    public List<Room> rooms = new List<Room>();
}

public class Room
{
    [XmlAttribute(AttributeName = "name")]
    public string Name { get; set; }

    [XmlAttribute(AttributeName = "windows")]
    public int? NumberOfWindows { get; set; }       
}


In this instance I'm attempting to serialize a nullable integer named "NumberOfWindows".  My goal is to produce an XML file that looks something like this (I removed the schema info to make this easier to read):

<?xml version="1.0" encoding="utf-8"?>
  <rooms name="kitchen" windows="2" />
  <rooms name="bathroom" windows="0" />
  <rooms name="closet" />
</House>


Notice how the "closet" doesn't have any windows.  For a closet, we'll assume that a window does not apply.  So the windows property must be nullable and it must be optional.


How to Fix it
 
First, let's change the Room class so that it will serialize without getting an error.  The first thing to note is that we can turn the NumberOfWindows parameter into a string, and treat an empty string as the null value:

public class Room
{
    [XmlAttribute(AttributeName = "name")]
    public string Name { get; set; }

    [XmlIgnore]
    public int? NumberOfWindows { get; set; }

    [XmlAttribute(AttributeName = "windows")]
    public string WindowsSerializable 

    {
        get
        {
            if (NumberOfWindows != null)
            {
                return NumberOfWindows.ToString();
            }
            else
            {
                return "";
            }
        }
        set
        {
            if (WindowsSerializable != null)
            {
                NumberOfWindows = int.Parse(WindowsSerializable);
            }
        }
    }
}


So the NumberOfWindows variable is checked for null and if it is then return an empty string.  That will cause the closet to return: windows="", which is not quite what we want.  But at least it will execute and generate an xml output without causing an error.  Also, notice that I put an XmlIgnore on the variable that will be populated, but not used to generate the serialized output.

Now we need to make the NumberOfWindows attribute optional.  To make it optional we can add this to the end of the WindowsSerializable getter:

public bool ShouldSerializeWindowsSerializable()
{
    return NumberOfWindows.HasValue;
}


You can also do something like this:

public bool ShouldSerializeWindowsSerializable()
{
    return WindowsSerializable != "";
}


The "ShouldSerialize{varname}" method will output your results for the variable indicated if it returns true.  So you can put any fancy logic in this method that you want to show or hide the attribute of your choice.


Where to Get the Code

You can go to my github account and download the sample code by clicking here.