EditA 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.
EditWithin the Web Layer
EditWhen using ASPX views
EditConfiguring 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>
EditManaging 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.
EditSecuring 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.
EditWithin 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.
EditWithin 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.
EditManaging 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.
EditNHibernate
EditGeneral 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.
EditAssociations
- 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).
EditMapping 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.
EditMicroformats
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:
- hCard (http://microformats.org/wiki/hcard) for people, companies, organizations, and places.
- hCalendar (http://microformats.org/wiki/hcalendar) for calendaring and events.
- hReview (http://microformats.org/wiki/hreview) for reviews of products, services, business, events, etc.
- XFN (http://www.gmpg.org/xfn/) for organizational information, relationships, and social networks.
- XOXO (http://microformats.org/wiki/xoxo) for outlines.
- If another microformat is available for the information being displayed, use when appropriate.