S#arp Architecture

Edit

A Few S#arp Architecture Best Practices

All of the best practices described below should be seen as general rules of thumb which are certainly subject to excepted cases. But any exception to the rule should have a justifiable reason, accordingly.

Edit

Within the Web Layer

Edit

When using ASPX views

  • Within a data bound control, avoid using Eval(“PropertyName”). Instead, convert the data item to a domain object to leverage strongly typed accessors; e.g.:

    <%# ((Customer) Container.DataItem).ContactName %>


Edit

Configuring web.config

  • In production environments, include the following setting:
     <compilation debug=”false” /> 


  • Disable session state by default:
     <sessionState mode=”Off” /> 


  • Disable view state by default:
     <pages enableViewState=”false” /> 

    If you find that you absolutely have to have it on a particular page or control, enable it on the page or control only:
    For pages:
     <%@ Page EnableViewState=”True” %> 

    For controls:
     <asp:ControlType enableViewState=”true”> 

  • Declare custom server controls in web.config:
          <pages>
            <controls>
              <add tagPrefix=”MyPrefix”  
                   namespace=”MyNamespace” assembly=”MyAssembly” />
            </controls>
          </pages>
    

Edit

Managing Routes

Routes are a facet of control logic. Accordingly, I prefer to keep route management contained within a class within the controllers layer called RouteRegistrar.cs. This facilitates unit testing without requiring a reference to Global.asax.cs and introduction a great separation of concerns between view and control.

Edit

Securing Against Cross Site Scripting Attacks

ASP.NET MVC provides some basic capabilities for hindering Cross Site Scripting (XSS) attacks. The easiest to employ is the <%= Html.AntiForgeryToken() %> which may be placed within HTML forms and then validated in the controller with the [ValidateAntiForgeryToken] attribute. This technique is discussed further at http://weblogs.asp.net/shijuvarghese/archive/2008/12/18/secure-asp-net-mvc-applications.aspx.

Edit

Within the Controllers Layer

When passing data from a controller to a view, Data Transfer Objects (DTOs) should be used to encapsulate multiple data elements to be strongly type passed to a view. For example, assume you have a ProductsController with an action called List. The view data DTO, if it contains more than one type of object, would be called ListViewData and would have public properties to hold the data elements to be passed on to the view. (Suggested by http://weblogs.asp.net/scottgu/archive/2007/12/06/asp-net-mvc-framework-part-3-passing-viewdata-from-controllers-to-views.aspx.) For organization purposes, the view data DTOs should be placed within the controllers which they support. So the aforementioned example would be referenced via ProductsController.ListViewData.

For creating and editing an item, the "Create" action should be invoked to initialize a form. The form should then submit itself to the "Create" action via the POST method which will handle capturing the form data and saving the data item. See the EmployeesController for a full CRUD example.

Edit

Within the Tests Layer

  • Test classes should be organized under sub-folders, having one sub-folder for each layer being tested. For example, a folder would be added to ProjectName.Tests called ProjectName.Core. This folder would contain all the test fixtures for testing the Projectname.Core assembly.
  • The default namespace of this class library should be changed to “Tests” to avoid namespace ambiguity.
  • The CRUD scaffolding generates a mock repository for each controller. Often times, you’ll need to use similar mock repositories across different controllers and/or application service tests. In these situations, I’d typically recommend moving the duplicated mock repository code to a reusable CreateMockRepositoryFactory class to eliminate duplicated code within the unit testing layer.

Edit

Managing Solution Items

Whenever possible, assembly dependencies should never be placed into the GAC. Instead, application dependencies should be maintained in a folder called “Solution Items” which resides in the root of the source directory. This facilitates multiple applications on a single server using different versions of an assembly.

Edit

NHibernate

Edit

General Mapping File Tips

  • For organization purposes, only declare one class per mapping file.
  • For consistency and better organization, regardless of using HBMs or Fluent NHibernate, keep the mapping artifacts in MyProject.Data.
  • Don’t bother including database meta data (e.g., column length) in mapping files unless intending to auto generate the SQL using the hbm2dll tool.
  • Is using HBMs, set the assembly and namespace for the tag to decrease typing and ease future maintenance.

Edit

Associations

  • Set .Inverse(), or inverse=true if you’re using HBMs, on the parent in a bi-directional parent/child relationship to avoid foreign key constraint violations (NRD 6.8 Bidirectional Associations). But note that large bags mapped with this setting are inefficient and should be avoided (NRD 6.2 Mapping a Collection).
  • When mapping many-to-many relationships, use an <idbag> for much increased performance (NRD 6.7 Using an <idbag>).
  • Remember that there is a difference between <bag> and <list> (list having an index property) and should be used appropriately; either may be mapped to a generic IList<> (NRD 6.2 Mapping a Collection).

Edit

Mapping Strategies

  • While there are a few inheritance-mapping strategies to choose from, favor the table-per-class-hierarchy mapping strategy but consider your needs carefully, as well (NRD 5.1.13 subclass).
  • If you’re dealing with money, create a Money class and an associated ICompositeUserType for the monetary amount to bind to it. Storing money as a decimal in your domain layer is quite limiting.

Edit

Microformats

Per http://microformats.org/wiki/Main_Page, "microformats are small bits of HTML that represent things like people, events, tags, etc. in web pages. Microformats enable the publishing of higher fidelity information on the Web, providing the fastest and simplest way to support feeds and APIs for your website."

To be more concise, microformats are industry accepted standards for facilitating semantic XHTML. CSS should be used to alter look and layout of microformat output.

The following microformat standards should be followed when applicable:

ScrewTurn Wiki version 2.0.36. Some of the icons created by FamFamFam.