Pages

Monday, August 17, 2009

ASP.NET MVC Overview (C#)

ASP.NET MVC Overview (C#)

The Model-View-Controller (MVC) architectural pattern separates an application into three main components: the model, the view, and the controller. The ASP.NET MVC framework provides an alternative to the ASP.NET Web Forms pattern for creating MVC-based Web applications. The ASP.NET MVC framework is a lightweight, highly testable presentation framework that (as with Web Forms-based applications) is integrated with existing ASP.NET features, such as master pages and membership-based authentication. The MVC framework is defined in the System.Web.Mvc namespace and is a fundamental, supported part of the System.Web namespace.

MVC is a standard design pattern that many developers are familiar with. Some types of Web applications will benefit from the MVC framework. Others will continue to use the traditional ASP.NET application pattern that is based on Web Forms and postbacks. Other types of Web applications will combine the two approaches; neither approach excludes the other.

The MVC framework includes the following components:

Figure 01: Invoking a controller action that expects a parameter value (Click to view full-size image)

  • Models. Model objects are the parts of the application that implement the logic for the application's data domain. Often, model objects retrieve and store model state in a database. For example, a Product object might retrieve information from a database, operate on it, and then write updated information back to a Products table in SQL Server.

In small applications, the model is often a conceptual separation instead of a physical one. For example, if the application only reads a data set and sends it to the view, the application does not have a physical model layer and associated classes. In that case, the data set takes on the role of a model object.

  • Views. Views are the components that display the application's user interface (UI). Typically, this UI is created from the model data. An example would be an edit view of a Products table that displays text boxes, drop-down lists, and check boxes based on the current state of a Products object.

  • Controllers. Controllers are the components that handle user interaction, work with the model, and ultimately select a view to render that displays UI. In an MVC application, the view only displays information; the controller handles and responds to user input and interaction. For example, the controller handles query-string values, and passes these values to the model, which in turn queries the database by using the values.


The MVC pattern helps you create applications that separate the different aspects of the application (input logic, business logic, and UI logic), while providing a loose coupling between these elements. The pattern specifies where each kind of logic should be located in the application. The UI logic belongs in the view. Input logic belongs in the controller. Business logic belongs in the model. This separation helps you manage complexity when you build an application, because it enables you to focus on one aspect of the implementation at a time. For example, you can focus on the view without depending on the business logic.

In addition to managing complexity, the MVC pattern makes it easier to test applications than it is to test a Web Forms-based ASP.NET Web application. For example, in a Web Forms-based ASP.NET Web application, a single class is used both to display output and to respond to user input. Writing automated tests for Web Forms-based ASP.NET applications can be complex, because to test an individual page, you must instantiate the page class, all its child controls, and additional dependent classes in the application. Because so many classes are instantiated to run the page, it can be hard to write tests that focus exclusively on individual parts of the application. Tests for Web Forms-based ASP.NET applications can therefore be more difficult to implement than tests in an MVC application. Moreover, tests in a Web Forms-based ASP.NET application require a Web server. The MVC framework decouples the components and makes heavy use of interfaces, which makes it possible to test individual components in isolation from the rest of the framework.

The loose coupling between the three main components of an MVC application also promotes parallel development. For instance, one developer can work on the view, a second developer can work on the controller logic, and a third developer can focus on the business logic in the model.

Deciding When to Create an MVC Application

You must consider carefully whether to implement a Web application by using either the ASP.NET MVC framework or the ASP.NET Web Forms model. The MVC framework does not replace the Web Forms model; you can use either framework for Web applications. (If you have existing Web Forms-based applications, these continue to work exactly as they always have.)

Before you decide to use the MVC framework or the Web Forms model for a specific Web site, weigh the advantages of each approach.

Advantages of an MVC-Based Web Application

The ASP.NET MVC framework offers the following advantages:

  • It makes it easier to manage complexity by dividing an application into the model, the view, and the controller.
  • It does not use view state or server-based forms. This makes the MVC framework ideal for developers who want full control over the behavior of an application.
  • It uses a Front Controller pattern that processes Web application requests through a single controller. This enables you to design an application that supports a rich routing infrastructure. For more information, see Front Controller on the MSDN Web site.
  • It provides better support for test-driven development (TDD).
  • It works well for Web applications that are supported by large teams of developers and Web designers who need a high degree of control over the application behavior.


Advantages of a Web Forms-Based Web Application

The Web Forms-based framework offers the following advantages:

  • It supports an event model that preserves state over HTTP, which benefits line-of-business Web application development. The Web Forms-based application provides dozens of events that are supported in hundreds of server controls.
  • It uses a Page Controller pattern that adds functionality to individual pages. For more information, see Page Controller on the MSDN Web site.
  • It uses view state or server-based forms, which can make managing state information easier.
  • It works well for small teams of Web developers and designers who want to take advantage of the large number of components available for rapid application development.
  • In general, it is less complex for application development, because the components (the Page class, controls, and so on) are tightly integrated and usually require less code than the MVC model.

Features of the ASP.NET MVC Framework

The ASP.NET MVC framework provides the following features:

  • Separation of application tasks (input logic, business logic, and UI logic), testability, and test-driven development (TDD) by default. All core contracts in the MVC framework are interface-based and can be tested by using mock objects, which are simulated objects that imitate the behavior of actual objects in the application. You can unit-test the application without having to run the controllers in an ASP.NET process, which makes unit testing fast and flexible. You can use any unit-testing framework that is compatible with the .NET Framework.
  • An extensible and pluggable framework. The components of the ASP.NET MVC framework are designed so that they can be easily replaced or customized. You can plug in your own view engine, URL routing policy, action-method parameter serialization, and other components. The ASP.NET MVC framework also supports the use of Dependency Injection (DI) and Inversion of Control (IOC) container models. DI allows you to inject objects into a class, instead of relying on the class to create the object itself. IOC specifies that if an object requires another object, the first objects should get the second object from an outside source such as a configuration file. This makes testing easier.
  • A powerful URL-mapping component that lets you build applications that have comprehensible and searchable URLs. URLs do not have to include file-name extensions, and are designed to support URL naming patterns that work well for search engine optimization (SEO) and representational state transfer (REST) addressing.
  • Support for using the markup in existing ASP.NET page (.aspx files), user control (.ascx files), and master page (.master files) markup files as view templates. You can use existing ASP.NET features with the ASP.NET MVC framework, such as nested master pages, in-line expressions (<%= %>), declarative server controls, templates, data-binding, localization, and so on.
  • Support for existing ASP.NET features. ASP.NET MVC lets you use features such as forms authentication and Windows authentication, URL authorization, membership and roles, output and data caching, session and profile state management, health monitoring, the configuration system, and the provider architecture.

Sunday, August 16, 2009

AutoResizing ComboBox Silverlight

AutoResizing ComboBox Silverlight

All Silverlight 2.0 enthusiasts have faced an annoying known issue with a databound ComboBox:

the dropdown popup resizes itself only the first time it is shown.

After its first initialization, no matter if you bind a new datasource with fewer or more elements, the dropdown persists its original height.

One workaround is the following:

  1. store the Properties from the original ComboBox
  2. delete the ComboBox removing it from its container
  3. create a new ComboBox and place it in the container
  4. recover the stores Properties
  5. bind the new DataSource to the newly created combobox

Well, many of us will agree this workaround is annoying as the original issue was...

Here is my try to create a new ComboBox inheriting the original one.

It overrides the OnItemsChanged method, trying to guess the height needed to render the Items within the dropdown popup.


using System.Windows.Controls;

namespace CodeGolem.Controls
{
public class ComboBox : System.Windows.Controls.ComboBox
{
private double _maxDropDownHeight = 0;

public new double MaxDropDownHeight
{
get { return _maxDropDownHeight; }
set { _maxDropDownHeight = value; }
}

protected override void OnItemsChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
base.OnItemsChanged(e);

ScrollViewer scrollViewer = (ScrollViewer)GetTemplateChild("ScrollViewer");
scrollViewer.ScrollToVerticalOffset(0);
scrollViewer.ScrollToHorizontalOffset(0);


Border popupBorder = (Border)GetTemplateChild("PopupBorder");
double height = (ActualHeight - 1) * Items.Count + 5;
popupBorder.Height = _maxDropDownHeight > 0 && height > _maxDropDownHeight ? _maxDropDownHeight : height;
}
}
}

I tried this only without templated Items.
The final height is calculated supposing that the items' height is equal to the ComboBox height minus one.
I add also five pixels for upper and lower margins.

The height-calculating formula may be improved or changed to reflect your own needs.

Anyway I think having a custom ComboBox control within our projects is less annoying than re-creating each combo everytime we update their datasource.

Hope this helps all you readers... while we all confidently wait for the final Silverlight 3.0 release!

Themes are a great feature in our beloved ASP.NET platform.

Themes are a great feature in our beloved ASP.NET platform.

They allow us to easily create skins for our controls and we can bind stylesheets to each theme.

But did you notice most of the times we use a main color in a theme's stylesheet, and two or three other related colors, and we continously repeat their #rrggbb code along the whole .css files?
Most of the times, different themes simply means different color.
And there we go customizing the stylesheet files to repleace that red with this blue, etc.

Here I'm going to explain a way to create a Theme-based styleheet parameterizer which will allow us to place variable placeholders in our .css files.
The variables' values can be assigned from a Theme-dependant .xml file, our we could customize this parameterizer to get the values from a database.

The StylesheetParameterizer will be implemented as an HttpHandler which will handle each request to .css files, parse them looking for the variable placeholders, and replace their value depending on the current theme.

Since an HttpHandler is not theme-aware, we will need an HttpModule as well. It will listen to each page request and store the page's Theme name in a Session variable that will later be accessed by the HttpHandler.

We will start from the HttpModule:


using System;
using System.Web;
using System.Web.UI;

public class StylesheetParameterizerModule : IHttpModule
{
#region IHttpModule Members

public void Dispose()
{
}

public void Init(HttpApplication context)
{
context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute);
}

void context_PostRequestHandlerExecute(object sender, EventArgs e)
{
if (HttpContext.Current.Handler is Page)
HttpContext.Current.Session["StylesheetParameterizerTheme"] = ((Page)HttpContext.Current.Handler).Theme;
}

#endregion
}

This is a simple IHttpModule implementation, handling the PostRequestHandlerExecute event.
After a request has been executed, this module verifies if the executed handler was a Page.
If so, it stores the Page's Theme property in a Session variable.

This module has to be registered in the web.config file in the section ( in IIS7).



Now let's give a look at the HttpHandler.


using System.IO;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.SessionState;

public class StylesheetParameterizerHandler : IHttpHandler, IReadOnlySessionState
{
DataTable _parameters;

#region IHttpHandler Members

public bool IsReusable
{
get { return false; }
}

public void ProcessRequest(HttpContext context)
{
string requestedStylesheetPath = context.Request.PhysicalPath;
string stylesheet = string.Empty;

using (StreamReader reader = new StreamReader(requestedStylesheetPath))
{
stylesheet = reader.ReadToEnd();
reader.Close();
}

string cacheKey = "ParameterizedStylesheet_" + context.Session["StylesheetParameterizerTheme"].ToString();
if (context.Cache[cacheKey] != null)
stylesheet = context.Cache[cacheKey].ToString();
else
{
_parameters = getParameters(context.Session["StylesheetParameterizerTheme"].ToString());

Regex regex = new Regex("\\$.+\\$", RegexOptions.IgnoreCase);
stylesheet = regex.Replace(stylesheet, matchEvaluator);

context.Cache.Add(
cacheKey,
stylesheet,
null,
System.Web.Caching.Cache.NoAbsoluteExpiration,
TimeSpan.FromMinutes(context.Session.Timeout),
System.Web.Caching.CacheItemPriority.Normal,
null);
}

context.Response.Write(stylesheet);
}

#endregion
}

One important thing to note: the class implements the IReadOnlySessionState marker-interface.
An HttpHandler is not allowed to access the SessionState by default.
Implementing this interface tells the framework that the HttpHandler needs to access the SessionState, in read only mode.

The ProcessRequest method is where the magic occurs.

The handler reads the physical file that was requested (the .css stylesheet file), and stores its full content in a local string variable.
The handler looks then for the variable plaholders through the \$.+\$ regular expressions.
This means our placeholders will have this format within a stylesheet:

body
{
color: $color$;
}

In this example $color$ will be a placeholder that will be substituted by the "color" variable value defined in the parameter xml file.

Each match will be handled by the matchEvaluator() method.

This is the matchEvaluator() body


private string matchEvaluator(Match match)
{
string name = match.Value.Substring(1, match.Value.Length - 2);
DataRow row = _parameters.Rows.Find(new object[] { name });

return row["value"].ToString();
}

Parameters are stored in a DataTable that will be populated by the getParameters() method.
The matchEvaluator looks for a row in the table whose "name" column value equals the name of the matched variable in the stylesheets.
It then returns the corresponding value as a substitution.

Finally, this is the getParameters() implementation.


private DataTable getParameters(string theme)
{
DataTable parameters;

string parametersXmlPath = string.Format("~/App_Themes/{0}/StylesheetParameters.xml", theme);

DataSet dataSet = new DataSet();
dataSet.ReadXml(HttpContext.Current.Server.MapPath(parametersXmlPath));
parameters = dataSet.Tables[0];
parameters.PrimaryKey = new DataColumn[] { parameters.Columns["name"] };

return parameters;
}

This method reads the StylesheetParameters.xml file within the current Theme's folder.
The xml file is parsed as a DataTable and will have the following format:


This implementation can be customized for retrieving the parameters from different other stores: database, remote webservices, web.config configuration file, etc.

A little note about Caching: the whole modified stylesheet is stored in the Application Cache so it can be shared by any Session in the same application.
The stylesheet is stored in Cache with a sliding expiration equal to the timeout period of a Session.
This will prevent too much overload since this handler will be invoked on each page request.

To get it working, we have to register the handler in the web.config configuration file


That's all.

Now we can put a StylesheetParameters.xml file in each Theme's folder, and have a single stylesheet with variable placeholders set as needed.

I hope you will find the StylesheetParameterizer helpful in your projects.

Feedback will be greatly appreciated.

Friday, August 14, 2009