![]() |
Web Development »
ASP.NET »
General
Intermediate
PixelDragonsMVC.NET - An open source MVC frameworkBy BigAndyAn MVC framework with built-in NHibernate support that makes creating ASP.NET 2 applications easier by minimizing code and configuration |
C#, Windows, .NET, ASP.NET, Visual Studio, WebForms, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
![]()
PixelDragonsMVC.NET is an open source, easy-to-use MVC framework for use with ASP.NET 2.0. It has built-in support for NHibernate and Log4Net and was produced by Pixel Dragons Ltd. to make creating ASP.NET 2.0 applications as easy as possible for us and you. We've created a project on CodePlex.
From Wikipedia: "Model-view-controller (MVC) is an architectural pattern used in software engineering. In complex computer applications that present lots of data to the user, one often wishes to separate data (model) and user interface (view) concerns, so that changes to the user interface do not affect the data handling, and that the data can be reorganized without changing the user interface. The model-view-controller solves this problem by decoupling data access and business logic from data presentation and user interaction, by introducing an intermediate component: the controller." See Wikipedia for more information.
The ZIP file above includes a sample application and the full source code of the MVC framework (linked using project references). Follow these instructions:
We have also put our sample project online for you to see.
We've tried various MVC frameworks with our ASP.NET applications, but there were always a few things about them that we didn't like. So when the opportunity came up with a new project, we decided to create our own and make it available to everyone. In this article, we talk about NHibernate and assume that the reader has some knowledge of the framework. If you are new to NHibernate, check this out first.
We found that there were a lot of unnecessary XML configuration in existing MVC frameworks. We always tried to name our models, view and controllers in a similar way to aid maintenance and make our code understandable and consistent. So we thought it would be cool if the MVC could work out on its own what controller/action/view to use based on the requested URL.
We've seen controllers in some of the Java MVCs that support multiple "actions" inside a controller class. This means that the number of class files is reduced and easier to manage, especially for large projects. A controller can then contain all related methods for a particular entity or section of the application.
In one particular framework, data that is posted or on the querystring can be accessed in a controller by creating public properties for each one. So for each piece of data, we had to create a private field and a get/set public property. That's quite a bit of typing if there is a lot of data. We thought it would be better to allow data to be passed to an action method via its parameters. The data should be converted automatically to the correct type, including HttpPostedFile.
We've started using NHibernate in our projects and we love it. We wanted the MVC to take care of the session and transactions and provide a generic DAO class that we could use or derive from. We wanted to be able to specify a regular expression and if the action method name matches, the MVC should automatically start a transaction for you and commit/rollback as required at the end of the request.
With various frameworks, we've been doing various things with Ajax and we've found that a lot of the time we had separate UI code for the same thing depending on whether the server or client was doing the rendering. So we wanted to support a way to use the same UI code that could be used on the server-side or client-side. You can see this in the sample application when paging through contacts.
We also wanted the MVC to automatically create and give the controller access to a Log4Net logger, just to try and do as much of the work as possible. With all these things, it means that everything is available in the controller without any extra work. We can just focus on the application.
For a given request, here are the steps the MVC goes through to make it all work. Code showing what is happening at a given step is included where it is of interest:
For example, in the sample application, take a look at default.aspx. It is the start page for the project and redirects to home.ashx.
Take a look in the web.config file and you will see that PixelDragonsMVC.NET is setup to handle all requests for ASHX files using an HttpHandler. You can change this to any file extension. You just need to change web.config and configure IIS to use ASP.NET to process these files and un-tick the "Check that file exists" option. ASHX is set up like this by default.
<httpHandlers>
<remove verb="*" path="*.ashx"/>
<add verb="*" path="*.ashx"
type="PixelDragons.MVC.MVCHandler, PixelDragons.MVC" />
</httpHandlers>
You also need to add the config sections for PixelDragonsMVC.NET:
<section name="mvc"
type="PixelDragons.MVC.Configuration.MVCConfigurationHandler," +
" PixelDragons.MVC" />
<mvc mappingFile="mvc.config"
controllerPattern=
"PixelDragons.MVCSample.Controllers.[ControllerName]Controller"
viewWithActionPattern="UI/views/[ControllerName]/[ActionName].aspx"
viewWithNoActionPattern="UI/views/[ControllerName].aspx"
defaultController="PixelDragons.MVC.Controllers.Controller">
<entityAssemblies>
<add name="PixelDragons.MVCSample.Domain" />
</entityAssemblies>
<autoTransactions>
<add regex="^Save.*" type="NewTransaction" />
<add regex="^Delete.*" type="NewTransaction" />
</autoTransactions>
</mvc>
PixelDragonsMVC.NET creates a SessionManager and TransactionManager ready for use with the controllers. NHibernate is initialised and a session is created for this request. The web.config of the sample application shows how to setup NHibernate by adding the config sections. When the session starts, NHibernate will look for entities in the assemblies listed in the entityAssemblies list of the mvc section and load them up. More details about autoTransactions is below.
<section name="nhibernate"
type="System.Configuration.NameValueSectionHandler,
System, Version=1.0.3300.0,Culture=neutral,
PublicKeyToken=b77a5c561934e089"/>
<nhibernate>
<add key="hibernate.connection.provider"
value="NHibernate.Connection.DriverConnectionProvider"/>;
<add key="hibernate.dialect"
value="NHibernate.Dialect.MsSql2000Dialect"/>
<add key="hibernate.connection.driver_class"
value="NHibernate.Driver.SqlClientDriver"/>
<add key="hibernate.connection.connection_string"
value="server=[YOUR SERVER HERE];" +
"database=[YOUR DATABASE HERE];uid=[YOUR USER ID];" +
"pwd=[YOUR PASSWORD HERE];"/>
</nhibernate>
Next, PixelDragonsMVC.NET works out what the controller and action names are based on the requested file. It looks for the following patterns to match:
It creates a Command object that holds this information ready for use later.
PixelDragonsMVC.NET can automatically start an NHibernate transaction based on the action name found in step 4. You can set this up in the web.config (see the autoTransactions section) by specifying a regular expression to match with. You can use the TransactionManager in your controllers to start a transaction manually, but you will be responsible for rolling it back if you need to. Currently, the only type supported is NewTransaction.
<autoTransactions>
<add regex="^Save.*" type="NewTransaction" />
<add regex="^Delete.*" type="NewTransaction" />
</autoTransactions>
Now that PixelDragonsMVC.NET has the controller name, it tries to create a controller object. First it looks at the controllerPattern setting in the web.config and replaces [ControllerName] with the controller name found in step 4. If there is no class by that name, PixelDragonsMVC.NET looks in the mapping file (mvc.config) for a controller mapping.
<controller name="different"
class="MVCSample.Controllers.Different.AnotherController" />
If there is no mapping for the controller, then PixelDragonsMVC.NET creates the default controller as specified in web.config (defaultController). Note: Controllers need to implement IController, there is a base Controller class provided that you can derive from (see sample) to make creating controllers as easy as possible. When a controller is instantiated, it is given access to various important objects including HttpContext, Server, Request, Response, SessionManager, TransactionManager and PersistenceManager. The PersistenceManager makes it easy to create a DAO for any entity type that exists in assemblies listed in the entityAssemblies section of the web.config. The generic DAO can be derived from to create your own DAO.
GenericDao<Contact> contactDao = this.PersistenceManager.CreateDao<Contact>();
List<Contact> contacts = contactDao.ListAll();
Next PixelDragonsMVC.NET calls the BeforeAction() method inside the controller. Here you can throw an ActionException to skip the rest of the action calls and override the view to show. This is good if you want to perform some checks before continuing, as in the sample application. Then PixelDragonsMVC.NET calls the method in the controller with the matching action name detected in step 4 (the action). If there is no action name in step 4, then DefaultAction() is called. For example, if the requested file is users-list.ashx, the method List inside the controller UsersController is called.
If the action method inside the controller class has parameters, PixelDragonsMVC.NET uses reflection to get a list of these and then searches the request for data that has been posted (or on the querystring) by matching the names. It then converts the data to the correct type before passing it into the action method. For example, if the requested file was users-save.ashx, the method Save(string name, string userId, string password) inside the controller UsersController is called. PixelDragonsMVC.NET would look in the request for data named name, userId and password, and convert it to the correct type as required. Then it would pass it in when calling the action method.
If the parameter can't be found in the request, the default value for the parameter is used, i.e. object = null, int = 0, etc. The action can then set the model and view to display. Here is an example action that takes data from the request and sets the view and model. Here is what the Save action might look like:
public void Save(string name, string userId, string password)
{
GenericDao<User> userDao = this.PersistenceManager.CreateDao<User>();
User user = userDao.Create();
user.Name = name;
user.UserId = userId;
user.Password = password;
user = userDao.Store(user);
Session["LoggedInUserUid"] = user.UserUid;
this.ViewName = "saveSuccess";
this.Model = user;
}
Lastly, AfterAction() is called.
If the action sets a view name, PixelDragonsMVC.NET will look it up in the mapping file for that controller/action. From the mapping, the view can either be rendered directly or redirected to. For the above example, PixelDragonsMVC.NET will render UI/contacts/form.aspx.
<views>
<view id="contact-form" path="UI/contacts/form.aspx" />
</views>
<controller name="users">
<action name="save">
<view name="saveSuccess" type="render" ref="contact-form" />
</action>
</controller>
If no view is found matching the name set by the action, then PixelDragonsMVC.NET looks in the shared area. If no view is found in the shared area or the action doesn't set a view name, the default view is rendered. The default view is defined in web.config as viewWithActionPattern or viewWithNoActionPattern depending on if there is a specific action name or not. [ControllerName] and [ActionName] are replaced to create a path to an ASPX file. This is the view file to render and pass the model to.
If a transaction was created, it is either committed or rolled back depending on if an exception was thrown other than ActionException.
If the view is to be rendered, the ASPX file is executed on the server and returned to the browser. The model that is set by the controller/action is available to the view for rendering. This keeps the business logic separate from the UI. If the view is a redirect, the browser is redirected to the specified URL. An ASPX view might contain code like this:
<%
User user = (User)Context.Items["model"];
%>
...
<input type="text" name="name" id="name" value="<%=user.Name%>" />
The NHibernate session is closed.
This article is a quick overview of how the MVC works. We probably need to create some better documentation and code references, but it's something for you to have a go with at least. As we develop the project, we'll try and improve this. If you have any questions, comments or suggestions, please let us know. We are using this MVC framework in a new project and so will be improving it as and when we find the need. We'll write another article soon with a step-by-step guide of how to create an application that uses our MVC. You can see our other stuff here.
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 29 Jun 2007 Editor: Genevieve Sovereign |
Copyright 2007 by BigAndy Everything else Copyright © CodeProject, 1999-2009 Web18 | Advertise on the Code Project |