Strategy without tactics is the slowest route to victory. Tactics without strategy is the noise before defeat.
Sun-Tzu

Happiness, that grand mistress of the ceremonies in the dance of life, impels us through all its mazes and meandering, but leads none of us by the same route
Charles Caleb Colton

Recently, I decided to use ASP.NET MVC2 to write a report router.  There are only three pages in the web application.  Information, Error and Report page that shows while the PDF report is being created.

I have Visual Studio 2008.  To download the templates, go to Microsoft download centerScott Gu’s blog is frequently a good place to start reading about MVC 2.

I started by reading the Nerd Dinner Tutorial.  I feel queasy about so many “magic strings” used in the whole MVC process.  For instance, if the route map says the controller name is Home, then the controller class name must be HomeController Per Microsoft documentation, All controller classes must be named by using the “Controller” suffix.  I do not like this style.  A class attribute should allow for different class names for the controllers.  I do not like Microsoft forcing my application file naming conventions.

Here is a screen shot of Visual Studio 2008 enforcing the Controller naming convention.

Some of the other “magic strings” can be changed but this is not apparent in the tutorial.  Also, I find the whole ASP.NET approach to MVC to still be thinking how to re-write Web Form apps into an MVC pattern.

Fortunately, the MVC 2 framework allows a strategy that may be more conducive for a blog or other web application that has a small number of different types of web pages.  Below, I will show some of the things I am learning as I build this report router.

My web application report structure is collection of folders with optional sub-folders.  In each folder, there can be any number of unique report definition files.  Also, each folder may contain a config file, which contains settings like Database and Report Access.  An optional config file in a sub-folder can add additional settings or override settings from the parent config file, much like a class hierarchy.

For example, the following shows a few folders.  Each of the Folder/Sub-Folders becomes part of the web application url, therefore, no spaces in the folder names or report names.

Accounting
  --PublicReports
      --Projects
      --HR
  --RestrictedReports
    --Payroll
    --Finances
        ReportBigMoney
        ReportSmallPay
GIS
  ReportAreaMap
IT
  --DataBase
      ReportAudit
  --Applications
  --HelpDesk
Operations
  --Fleet
  --Facilities

All the Microsoft examples I have seen, use a pattern of {controller}/{action}/{id} for the url.  The two “magic strings” are controller and action.  Other than that, you can use any any names you want.  The code below shows the default route for the MVC 2 template.  The routes are defined in the Global.asax.cs file.

routes.MapRoute(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);

// HomeController Index method
public ActionResult Index()
{
  ViewData["Message"] = "Welcome to ASP.NET MVC!";

  return View();
}

My router code has four url patterns defined.  All four patterns call the same HomeController and the same method, RunReport.  From the code above, the Index Method returns View() which calls the Views/Home/Index.aspx.  More automatic from Microsoft but it can be overridden.  This works because the Method Name is Index and it is running in the HomeController.  The method, RunReport, below explicitly specifies the Index.aspx file but it still coming from the Views/Home folder.

The url pattern is {folder}/<0,1,2,3 Sub-Folders>/{reportName}

string controllerName = "Home";
string actionName = "RunReport";

routes.MapRoute("Report Root", // Unique Route name
  "{folder}/{reportName}", // URL with parameters

  new { controller = controllerName, action = actionName,
  folder = UrlParameter.Optional, reportName = UrlParameter.Optional
  } // Parameter defaults
);

routes.MapRoute("Report SubFolder1", // Unique Route name
  "{folder}/{subFolder1}/{reportName}", // URL with parameters

  new { controller = controllerName, action = actionName,
  folder = UrlParameter.Optional, subFolder1 = UrlParameter.Optional,
  reportName = UrlParameter.Optional
  } // Parameter defaults
);

routes.MapRoute("Report SubFolder2", // Unique Route name
  "{folder}/{subFolder1}/{subFolder2}/{reportName}", // URL with parameters

  new { controller = controllerName, action = actionName,
  folder = UrlParameter.Optional, subFolder1 = UrlParameter.Optional,
  subFolder2 = UrlParameter.Optional, reportName = UrlParameter.Optional
  } // Parameter defaults
);

routes.MapRoute("Report SubFolder3", // Unique Route name
  "{folder}/{subFolder1}/{subFolder2}/{subFolder3}/{reportName}", // URL with parameters

  new { controller = controllerName, action = actionName,
  folder = UrlParameter.Optional, subFolder1 = UrlParameter.Optional,
  subFolder2 = UrlParameter.Optional, subFolder3 = UrlParameter.Optional,
  reportName = UrlParameter.Optional
  } // Parameter defaults
);

// HomeController RunReport Method
public ActionResult RunReport(string folder, string subFolder1, string subFolder2,
  string subFolder3, string reportName)
{
  ViewData["Message"] = "Welcome to Run Report!";

  return View("Index");
}

Tags: , , ,

Leave a Reply


*