Jul 9, 2011

Customizing rendering templates for Document Set

In my previous article I blogged about how to provision custom Document Set with custom Welcome Page.

There are cases in which we want to preserve out-of-the-box functionality for adding and editing Document Set, but to plug in the screens our custom UI controls and logic for persisting the users’ input.

The challenges are:

- Plug your own UI controls in the out-of-the-box Share Point page

- Catch the out-of-the-box save event and plug your own persistence logic there to handle the user’s input

The default form templates for Edit and Display are ListForm. You can see it from the Document Set Elements.xml definition.

RenderingTemplatesOOB

So, if we want to customize the Edit form, we have to either modify ListForm template (which will affect tons of other functionality and behavior, so please don’t do that) or create new rendering template which is copy of ListForm template, to modify it according our needs and to use it in the definition of the Document Set.

You can find the ListForm template in 14\TEMPLATE\CONTROLTEMPLATES\DefaultTemplates.ascx

DefaultTemplates

If you open the file and search for “ListForm”, you will see the definition of the rendering template used in Edit form for Document Sets.

RenderingTemplate

In the solution I created new user control under the CONTROLTEMPLATES mapped folder and named it KBDocSetEditTemplate.ascx. That is what I am going to use from now on for editing my custom Document Set.

SolutionRenderingTemplate

Below is its content, but in generally you can copy paste the register controls from DefaultTemplates.ascx (on the top of the file) and after that you should paste the OOB ListForm template definition. After that you can customize it according your needs. You can plug custom controls, user controls, etc. in the template’s definition.

<%@ Control Language="C#"   AutoEventWireup="false" %>
<%@Assembly Name="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@Register TagPrefix="SharePoint" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.WebControls"%>
<%@Register TagPrefix="ApplicationPages" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.ApplicationPages.WebControls"%>
<%@Register TagPrefix="SPHttpUtility" Assembly="Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c" namespace="Microsoft.SharePoint.Utilities"%>
<%@ Register TagPrefix="wssuc" TagName="ToolBar" src="~/_controltemplates/ToolBar.ascx" %>
<%@ Register TagPrefix="wssuc" TagName="ToolBarButton" src="~/_controltemplates/ToolBarButton.ascx" %>
<%@ Register TagPrefix="KB" TagName="Meeting" Src="~/_controltemplates/KB/MeetingDetails.ascx" %>
<%@ Register Tagprefix="KB" Namespace="KB.Core" Assembly="KB.Core, Version=1.0.0.0, Culture=neutral, PublicKeyToken=6f920b1b926475ec" %>
<SharePoint:RenderingTemplate id="KBDocumentSetEdit" runat="server">
  <Template>
    <span id='part1'>
      <SharePoint:InformationBar runat="server"/>
      <div id="listFormToolBarTop">
      <wssuc:ToolBar CssClass="ms-formtoolbar" RightButtonSeparator="&amp;#160;" runat="server">
          <Template_RightButtons>
            <SharePoint:NextPageButton ID="NextPageButton1" runat="server"/>
            <KB:DocSetEditFormSaveButton runat="server"/>
            <SharePoint:GoBackButton ID="GoBackButton1" runat="server"/>
          </Template_RightButtons>
      </wssuc:ToolBar>
      </div>
        <SharePoint:FormToolBar  runat="server"/>
      <SharePoint:ItemValidationFailedMessage  runat="server"/>
      <table class="ms-formtable" style="margin-top: 8px;" border="0" cellpadding="0" cellspacing="0" width="100%">
      <SharePoint:ChangeContentType runat="server"/>
      <SharePoint:FolderFormFields  runat="server"/>
      <SharePoint:ListFieldIterator runat="server"/>
      <SharePoint:ApprovalStatus runat="server"/>
      <SharePoint:FormComponent TemplateName="AttachmentRows" runat="server"/>
      </table>
      <table cellpadding="0" cellspacing="0" width="100%"><tr><td class="ms-formline"><img src="/_layouts/images/blank.gif" width='1' height='1' alt="" /></td></tr></table>
      <table cellpadding="0" cellspacing="0" width="100%" style="padding-top: 7px"><tr><td width="100%">
      <SharePoint:ItemHiddenVersion runat="server"/>
      <SharePoint:ParentInformationField runat="server"/>
            <div class="form-container">
                <KB:Meeting runat="server" />
            </div>
      <SharePoint:InitContentType runat="server"/>
      <wssuc:ToolBar CssClass="ms-formtoolbar" id="toolBarTbl" RightButtonSeparator="&amp;#160;" runat="server">
          <Template_Buttons>
            <SharePoint:CreatedModifiedInfo runat="server"/>
          </Template_Buttons>
          <Template_RightButtons>
            <KB:DocSetEditFormSaveButton runat="server"/>
            <SharePoint:GoBackButton runat="server"/>
          </Template_RightButtons>
      </wssuc:ToolBar>
      </td></tr></table>
    </span>
    <SharePoint:AttachmentUpload runat="server"/>
  </Template>
</SharePoint:RenderingTemplate>

In my custom template I plugged one user control - MeetingDetails.

  <div class="form-container">
    <KB:Meeting runat="server" />
  </div>

In my sample I want to fill data for “Outcome Due Date” and based on its value to fill “Meeting Reference Number” behind the scene. The idea here is to demonstrate how you can invoke javascript code on clicking the “Save” button in Document Set Edit form

I created user control MeetingDetails.ascx which contains one SharePoint Web Control for displaying the current value of “Outcome Due Date”. It is placed within KB folder in CONTROLTEMPLATES.

<SharePoint:FormField ID="fldOutcomeDueDate" runat="server" ControlMode="Edit" FieldName="OutcomeDueDate" />

Next I had to figure out is how to intercept the “Save” button event and to plug there my own logic (which in my case is javascript function for setting the value “Meeting Reference Number” and updating the custom Document Set data in order the users’ input to be saved).

From the ListForm template definition we can see that there is a control called SharePoint:SaveButton.

If we review its definition with ILSpy (or .Net Reflector), on its OnPreRender method we will see that the

ButtonControl property is responsible for instantiating the save button. Unfortunately it is internal, so we cannot access it through our code.

SaveButton

If we review the OnBubbleEvent we will see that there is event called: FormContext.OnSaveHandler.

To achieve what I need I had to define a button which inherits from SaveButton, accesses the instance (as in the screenshot above) and changing its OnClientClick property in its OnPreRender.

public class DocSetEditFormSaveButton : SaveButton
    {
        internal Button customButton
        {
            get
            {
                Button button = (Button)this.TemplateContainer.FindControl("diidIOSaveItem");
                return button;
            }
        }
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            //overrides the original Save button javascript and replaces with our method
            customButton.OnClientClick = "InitializeMeetingRefNumber()";
        }
    }

In the javascript function we must preserve what is organically called in SaveButton OnClientClick – the invocation of PreSaveItem() function.

The function code doesn’t really make sense, but in generally it takes the value of “Outcome Due Date” and copies it in a hidden field by appending “client side set” string to its value. In the code behind the “Meeting Reference Number” is populated based on the hidden input value.

JavaScript

The custom save button implementation is placed in KB.Core project in solution.

The last thing I had to do is to subscribe for SPContext.Current.FormContext.OnSaveHandler and to update “Meeting Reference Number” field of my custom Document Set.

userControlCodeBehind

In Elements.xml of our custom Document Set we must change the rendering template for Edit and to place our custom one.



changeRenderingTemplate

After deploy and creation of custom Document Set “Meeting Document Set”, View All Properties screen looks like this:


ViewProperties

On Edit Properties our custom templates kicks in and we can see our user control at the bottom of the page.

Edit Properties

After hitting the “Save” button, our custom save button logic is executed and “Meeting Reference Number” is updated based on the value of filled “Outcome Due Date”.

viewPropertiesAfter

You can attach the related code sample here.
Read full article!

Jul 8, 2011

Provision custom Document Sets with CAML

In this article I am going to review how to provision a custom Document Set with CAML. For the demo I will create a custom Document Set called “Meeting Document Set” with one associated custom content type “Meeting Document”. I will provision a custom document library list (named “Meeting Documents”) and our custom content types will be associated with the list, so after the deployment the user can start adding Document Sets and documents within the list. The article also explains how to provision custom Welcome Page for the Document Set and discusses how to customize this page. Below is a brief description how to implement and provision the solution step by step:

1. Activate feature Document Set is a site collection level feature that must be first activated.

  • Go to Site Settings > Site Collection Features page
  • Activate Document Sets feature

DocSetSiteCollectionFeature

2. Create the metadata

Metadata

For the sake of the code sample let’s assume that our custom Document Set will have next columns metadata:

· Meeting Notes – brief description of the meeting

· Conducted At Date – date on which the meeting has held

· Witness – User who is responsible for the goals of the meeting

· Position – his position

· Outcome due Date – end date for achieving goals raised during the meeting

· Internal meeting reference number – internal number. This won’t be visible and will be filled behind the scene (for dummy data for the sake of the demo). The population of this field will be discussed in a separate article for the Document Sets.

The other content type (“Meeting Document”) inherits from Document and which will be associated with the document set will have next metadata:

· Document Internal number – department internal number attached to each document attached to the meeting.

3. Create content types

Creating the “Meeting Document” is out of the scope of this article, so I will skip this.

Below is the CAML definition of “Meeting Document Set” content type:

<?xml version="1.0" encoding="utf-8"?>
<Elements xmlns="http://schemas.microsoft.com/sharepoint/">
  <ContentType ID="0x0120D5200064ab7524b97440fcba3080cd5edb05ac"
             Name="Meeting Document Set"
             Group="KB Content Types"
             Description="A custom document set."
             ProgId="SharePoint.DocumentSet" >
    <Folder TargetName="_cts/Meeting Document Set" />
    <FieldRefs>
      <FieldRef ID="{CBB92DA4-FD46-4C7D-AF6C-3128C2A5576E}" ShowInNewForm="TRUE" ShowInEditForm="TRUE"  Name="DocumentSetDescription" />
      <FieldRef ID="{a3a36b22-c551-462c-9ccb-205208770332}" Name="MeetingNotes" Required="TRUE" />
      <FieldRef ID="{4d55b920-f135-4a41-b7cb-4dd94151046d}" Name="ConductedAt"  Required="TRUE" />
      <FieldRef ID="{a646fbed-e3cd-4551-b510-cc92d9eb3c43}" Name="WitnessPosition" Required="TRUE" />
      <FieldRef ID="{165017b9-08c9-4e9e-8560-69488cf67abf}" Name="Witness" Required="TRUE" />
      <FieldRef ID="{36dfd900-a47a-11e0-8264-0800200c9a66}" Name="OutcomeDueDate" />
      <FieldRef ID="{2340e4d0-a55a-11e0-8264-0800200c9a66}" Name="MeetingInternalRefNumber" />
    </FieldRefs>
    <XmlDocuments>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/sharedfields">
        <sf:SharedFields xmlns:sf="http://schemas.microsoft.com/office/documentsets/sharedfields" LastModified="1/1/2010 08:00:00 AM">
        </sf:SharedFields>
      </XmlDocument>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes">
        <act:AllowedContentTypes xmlns:act="http://schemas.microsoft.com/office/documentsets/allowedcontenttypes" LastModified="1/1/2010 08:00:00 AM">
          <AllowedContentType id="0x01010051a7427b4c1d4fe3aa6a9c0055f60067" />
        </act:AllowedContentTypes>
      </XmlDocument>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/welcomepagefields">
        <wpFields:WelcomePageFields xmlns:wpFields="http://schemas.microsoft.com/office/documentsets/welcomepagefields" LastModified="1/1/2010 08:00:00 AM">
          <WelcomePageField id="CBB92DA4-FD46-4C7D-AF6C-3128C2A5576E" />
          <WelcomePageField id="4d55b920-f135-4a41-b7cb-4dd94151046d" />
          <WelcomePageField id="165017b9-08c9-4e9e-8560-69488cf67abf" />
          <WelcomePageField id="a646fbed-e3cd-4551-b510-cc92d9eb3c43" />
        </wpFields:WelcomePageFields>
      </XmlDocument>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/office/documentsets/defaultdocuments">
        <dd:DefaultDocuments xmlns:dd="http://schemas.microsoft.com/office/documentsets/defaultdocuments" AddSetName="TRUE" LastModified="1/1/2010 08:00:00 AM">
        </dd:DefaultDocuments>
      </XmlDocument>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
        <FormUrls xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms/url">
          <New>_layouts/NewDocSet.aspx</New>
        </FormUrls>
      </XmlDocument>
      <XmlDocument NamespaceURI="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
        <FormTemplates  xmlns="http://schemas.microsoft.com/sharepoint/v3/contenttype/forms">
          <Display>ListForm</Display>
          <Edit>KBDocumentSetEdit</Edit>
          <New>DocSetDisplayForm</New>
        </FormTemplates>
      </XmlDocument>
    </XmlDocuments>
  </ContentType>
</Elements>

As you see the outcome due date and internal reference number fields are not required.

On the Welcome Page we show the out-of-the-box Description field, conducted at, witness and witness position fields.
To get the out-of-the-box description field:
  • Go to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\FEATURES\DocumentSet

  • Open Elements.XML
Tip: Don’t put comments in your content type definitions. You most likely will face unexpected results, as missing the columns in the content type definition.

4. Create custom Welcome Page
  • Go to C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\TEMPLATE\FEATURES\DocumentSet

  • Create new module element in your solution and name it MeetingDocSetWelcomePage

  • Copy the DocSetHomePage.aspx from the content of the folder with path 1) and place in the newly created module
Modify the Element.xml in the module to look like this:

CustomWelcomePage


At this point your newly created Welcome Page will be completely empty, and you will see an empty page after creating new meeting document set.

Customization it is up to you and may include custom web parts, user controls, custom controls, etc.

WebPartZones

The out-of-the-box Welcome Page comes with 4 WebPartZones, but you can define as many as you need for your customization purposes.

5. Define web parts for your custom Welcome Page

In this code sample I will define the same content for my custom page as it is in the Document Set OOB.

Create new Document Set (based on OOB content type), select “Edit Page” and export next web parts:
  • Image

  • Document Set Properties

  • Document Set Contents
Below is screenshot of how to export the image web part.

exportImageCustomizingHomePage

Go to the Elements.xml in module MeetingDocSetWelcomePage, open the content of each exported *.dwp file and place them under AllowWebPart elements with appropriate WebPartZoneID within a CDATA.

pageWebParts

At this point you may build and deploy your solution.
If you want to test it:
  • Create new document library

  • Go to Library Settings

  • Go to Advanced settings and select “yes” for Allow management of content types.

  • Under the Content Types list click “Add from existing content types” link, find and add Meeting Document Set.

newDocumentSet

DocSetHome

6. Create List

Now we can create a custom document library, which has the Meeting Document Set associated and it is ready and operational.

The image below is a screen shot from the list definition Schema.xml. Outlined in red are the changes which allow management of list’s content types and associate the custom document set content type and the “Meeting Documents” content type.

In <Fields> sections we enumerate the existing column definitions.

Schema

Our final solution deploys the column definitions, our custom content types “Meeting Document Set” and “Meeting Document”, and custom document library called “Meeting Documents”.

Final

You can attach the related code sample here.

The code sample contains code related to my next article about the rendering templates of Document Set and their customization.
Read full article!

Jun 8, 2011

Architecting loosely coupled MVC.NET applications

Since I already blogged about MVC.NET and loosely coupled design with Spring.NET, I decided to review the same architecture approach within the context of MVC.NET 3.

For some background refer my previous articles on this subject:

http://kbochevski.blogspot.com/2009/11/mvc-custom-authorization.html

http://kbochevski.blogspot.com/2010/03/mvcnet-and-ioc-using-spring-net.html

http://kbochevski.blogspot.com/2010/06/unit-testing-mvcnet.html

In generally the goals stay the same:

· Loosely coupling the building components of the MVC.NET application

· Achieving better granularity at code level and unit testing the components

· Achieving custom authorization at role and user level, fine-grained control over action methods

· Reviewing how the .Net framework v4 and the new features which I missed in MVC.NET helped me out to resolve architecture, data validation and security problems like XSS attacks

· Presenting cool thin client built with jquery grid

Tightly coupled vs. loosely coupled in the world of MVC.NET and inversion of control

Since MVC.NET as a framework implies to separation of concerns by its nature, the more accurate and reasonable question is : what are the surrounding components that build one MVC.NET application?

Beside the framework in a real life application we also have to deal with many more components like database, GUI frameworks (jquery plugins, extjs, YUI, etc.), web services, reports, etc. So, if we review the most common scenario we will have next components which we should handle:

· MVC.NET framework OB (out-of-the-box)

· Database

· Business logic. Let’s mark this one as a separate component which may be referred and used in our MVC.NET application

· GUI

Considering what our components are, we usually have to build an application which is cost-effective, extensible, maintainable, and testable. All those factors are in their nature quite subjective, but let’s review how the loosely coupled approach helps us to resolve some problems and makes our life (as developers) easier.

Tightly and loosely coupled architectures, and the Inversion of Control are very abstract as terminology and explanations. I won’t copy paste their definitions here, but I will try to give my explanation in the terms of MVC.NET application.

The tightly coupled approach will be to put all of the listed above components in one solution, or to make project reference between the MVC.NET web project and the rest of the projects (no matter how many they are, how they are grouped and managed). Doing so, all of our components will know about the rest of components at compile time, and will depend on them to compile and function properly.

Life is easier, future is dark… In fast growing and evolving enterprise application, inevitably we will end up facing problems like refactoring, functionality changes, and quality demands. If we put the all of the components within the same project, or hard reference them we will potentially have next problems:

· Logic leaks: Nobody and nothing can stop a developer from instantiating the database context within action method in a controller, querying it and rendering the result. Yes, no doubt it will be most likely faster to achieve, but we should ask ourselves – What controllers, database entities and database tables have in common? And the reasonable answer is – they have nothing to do with each other. Another scenario is the supporting of application once it goes life (hopefully…at the end we all code for this). Well, if we build our application as tightly coupled, changing one component will imply to changing all components that refer it and use its functionality, rebuilding all the projects and wondering how to deliver a patch which may not be related to most of the assemblies that we rebuilt. The scenarios here might be complex and scary…

· Code duplication: Referring and instantiating components across our application will lead to code duplication. This makes the refactoring and unit-testing unbearable burden. Imagine what one change request may bring…chaos and much iteration to validate it. For sure that will be neither cost effective, nor maintainable. The bodies of our methods become more longer, more messy and more mixed with database stuff, business logic, action results, etc.

self-controlling

The loosely coupled approach in our case will be to isolate the instantiating of the components from their functionality. The instances of the components will be launched run time, but they will communicate to each other based on their contracts (functionality contracts from business perspective, interfaces from development perspective). In the same time since they depend on each other based on their features (contracts), we can always replace one component with another as long as it provides the same functionality which the consumer expects.

In our case we can always replace the database layer, the business logic implementation and even the database. All these components don’t know about the others at compile time, but know how to consume the exposed by them functionality.

IoC

· Pros: Obviously we are safe in the terms of logic leaks, which is a very strong advantage. The components are more independent, hence easier maintainable and testable. The overall solution is more scalable and extensible because of the granularity of its components. Imagine how easier would be to build a web service on the top of our existing functionality rather than developing its logic from scratch (with copy\paste in most of the cases). And what if we decide to change our presentation layer. Should we redevelop all business logic, all persistence logic from scratch? We can develop only the UI, but to keep what we have in terms of logic implementation.

· Cons: This approach has its own learning curve. New to these concepts developers may face some problems at the beginning. Also the performance is worse in most of the cases.

Inversion of control and dependency injection

DI




Spring.NET instantiates a component and injects it in another component (consumer) which uses its functionality. For example Spring.NET instantiates the UserService class, which provides functionality related to the user management and authentication, and injects it in Controller class, which on his behalf knows how to use it.

IOC_container

Don’t over-engineer your solution

Always consider as many as possible points of view when you design your application. At the end the ultimate goal of our work is to make the clients happy…and happiness has many aspects, most of them unfortunately not related to architecture, but to the functionality and the price. For smaller applications, which are unlikely to evolve, sophisticated approach like loosely-coupling the dependencies might be budget overkill.

Even though I prefer to design my applications as loosely-coupled even if I don’t use IoC frameworks. I just try to put the “right” design, which I can improve in the future. That would be my solid baseline.

Let’s dive into the technical aspects

We reviewed the pros and cons of the approaches, some valid cases which we better consider when designing our applications. Now let’s see how we implemented the loosely coupled approach with MVC.NET and Spring.NET as IoC framework.

solution

Our code sample contains 10 projects, which form the set of components which are decoupled.

· The “Business” folder contains the domain objects and the business functionality of our application.

· “DataAccess” folder the data access layer implementation which is based on the repository pattern.

· WebPlatformMVCNet is our startup MVC.NET application.

· WebPlatform.Data contains the database layer based on Entity model.

· Platform.Contracts contains all contracts (interface) definitions which are referred by the rest components and define the functionality which will be exposed through them. This project should not refer any of the solution projects, because you will easily end up with circular dependency.

· WebPlatform.Core contains common functionality implementation and provides single location of reused logic and behavior among the projects in the solution.

· WebPlatformTests contains the unit tests based on NUnit framework.

Let’s quickly review the database diagram from our code-sample, which you can download at the bottom of this article.

It is designed to be extensible and quite granular. The “Modules” table holds the names of all modules in our application. The “Function” table contains the names of the functions (actions) which exist in the application. “Users” and “Roles” tables are straight-forward and self-explanatory. “AccessToModuleFunctions” is the most important table since it describes the mapping of users’ rights to the corresponding functionality within a certain module. If the user don’t have specific access right, then his role (if assigned) is been checked. Hence, one user can obtain access to certain functionality either through his username assignment or through his role.

Database backup can be found in the source code.

DatabaseDiagram

Spring.NET with MVC.NET 3

In the previous versions of MVC.NET we could download the MVCContrib.Extras.release, get the MvcContrib.Spring.dll and type few lines of code to plug the IoC framework in the controllers factories.

private void ConfigureIoC()
{

WebApplicationContext webApplicationContext = ContextRegistry.GetContext() as WebApplicationContext;
DependencyResolver.InitializeWith(new SpringDependencyResolver(webApplicationContext.ObjectFactory));
ControllerBuilder.Current.SetControllerFactory(typeof(IoCControllerFactory));
}


Well, this one doesn’t work any longer.

MVC.NET 3 presented IDependencyResolver and DependencyResolver for allocating components that we want to get injected by the underlying dependency injection container.

So, to make things work for us we implemented our own dependency resolver.

 public class SpringDependencyResolver : IDependencyResolver
{
private Spring.Objects.Factory.Config.IConfigurableListableObjectFactory springFactory;

public SpringDependencyResolver(Spring.Objects.Factory.Config.IConfigurableListableObjectFactory factory)
{
this.springFactory = factory;
}

#region IDependencyResolver Members

public object GetService(Type serviceType)
{
var instances = this.springFactory.GetObjectsOfType(serviceType);
var enumerator = instances.GetEnumerator();

enumerator.MoveNext();
try
{
return enumerator.Value;
}
catch (Exception)
{
return null;
}
}

public IEnumerable&lt;object&gt; GetServices(Type serviceType)
{
return this.springFactory.GetObjectsOfType(serviceType).Cast&lt;object&gt;();
}

#endregion
}


Then, we need to register the resolvers in global.asax



protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();

GlobalFilters.Filters.Add(new CompressionFilterAttribute());

RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);

log4net.Config.XmlConfigurator.Configure();

IResource daoInput = new FileSystemResource(Server.MapPath("~/Config/DAO.xml"));
IObjectFactory daoFactory = new XmlObjectFactory(daoInput);

IResource servicesInput = new FileSystemResource(Server.MapPath("~/Config/Services.xml"));
IObjectFactory servicesFactory = new XmlObjectFactory(servicesInput, daoFactory);

IResource controllersInput = new FileSystemResource(Server.MapPath("~/Config/spring-config.xml"));

DependencyResolver.SetResolver(new WebPlatformMVCNet.Utils.SpringDependencyResolver(new XmlObjectFactory(controllersInput, servicesFactory)));

}


Now we are ready to inject dependencies, which we have defined in our xml config files
 public abstract class BaseController : Controller
{

public abstract IUserService UserService { get; set; }

private const string cookieName = "AccessibleMenus";

protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.IsCustomErrorEnabled)
{
//just sample logging
log4net.ILog log = log4net.LogManager.GetLogger(GetType());
log.Error(filterContext.Exception.Message, filterContext.Exception);
filterContext.ExceptionHandled = true;
ViewData["ErrorMessage"] = filterContext.Exception.Message;

string errorView = ((System.Web.Mvc.ViewResult)(filterContext.Result)).ViewName ?? "Error";
this.View(errorView).ExecuteResult(this.ControllerContext);
}
}
protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
base.Initialize(requestContext);
HttpCookie cookie = requestContext.HttpContext.Request.Cookies[cookieName];
if (cookie != null)
{
ViewData[cookieName] = Array.ConvertAll(cookie.Value.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries), m =&gt; Convert.ToByte(m)).ToList();
return;
}

AuthenticationWebPlatformPrincipal webPlatformPrincipal = requestContext.HttpContext.User as AuthenticationWebPlatformPrincipal;
if (webPlatformPrincipal == null)
return;

IList<byte> modules = this.GetAccessableModuleNames(webPlatformPrincipal.UserData.UserID);
ViewData[cookieName] = modules;

cookie = new HttpCookie(cookieName, string.Join(",", modules.ToArray()));
cookie.Expires = DateTime.Now.AddMinutes(20);
requestContext.HttpContext.Response.Cookies.Add(cookie);

}
}


Our abstract base controller class returns list of modules which the authenticated user has access to. It has injected “UserService” instance through which it requests the required functionality.

Regardless if the user sees the menus rendered in the output html, our custom authorize attribute prevents him from accessing functionality which he is not allowed to.
 public class ActionAuthorizeAttribute : AuthorizeAttribute
{
public Modules Module { get; set; }
public Functions Permission { get; set; }
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
AuthenticationWebPlatformPrincipal webPlatformPrincipal = filterContext.HttpContext.User as AuthenticationWebPlatformPrincipal;
if (webPlatformPrincipal == null)
{
CloseConnection(filterContext);
return;
}
List<byte> functionIds = new List<byte>();
foreach (Functions function in Enum.GetValues(typeof(Functions)))
{
if ((Permission &amp; function) == function)
functionIds.Add((byte)function);
}

BaseController controller = filterContext.Controller as BaseController;
if (controller == null || controller.UserService == null)
{
CloseConnection(filterContext);
return;
}
byte moduleId = (byte)Module;

if (!controller.UserService.IsUserAuthorized(webPlatformPrincipal.UserData.UserID, moduleId, functionIds))
CloseConnection(filterContext);
}
}


User “administrator” has no access to Product module, and even if he knows the url and tries to access it, he will get the next result:

noAccess

Technical challenges


From technical point of view the biggest challenge which we have to handle is how to keep the components independent. We have to make them “speak” a language which is not strictly bound to their definition (object instances), but to their functionality features.

Application layers and components communicate through interfaces or generic collections, which are defined in the Platform.Contracts project.
Contracts

The hardest task to achieve is to decouple the database from the business logic layer, because the database in our case is LINQ To Entities model, which every developer can regenerate at certain moment during the development life-cycle.

If we want our data access layer (built with Repository pattern) to expose the generic collections or interfaces which represent the entities from generated database model, we have to either create classes inheriting from the generated entity classes or to make the entities from Entity Framework to implement interfaces and to return these interfaces as return types. This approach will secure our loosely coupled design and will decouple the database from the rest of the application layers.

public interface IDBContext
{
IQueryable<IUser> Users { get; }
IQueryable<IAccessToModuleFunctions> AccessToModuleFunctions { get; }
IQueryable<IModulesFunction> ModulesFunctions { get; }
IQueryable<IModule> Modules { get; }
IQueryable<IFunction> Functions { get; }
IQueryable<IRole> Roles { get; }
IQueryable<IProduct> Products { get; }
IQueryable<IOrder> Orders { get; }
void AddToUsers(IUser user);
IUser CreateUser(Int32 id, String userName, String hash, String salt, String firstName, String lastName, String email);
void SaveChanges();
}


I defined contract called IDBContext, which will contain IQuerable<T> collections representing the Entity Framework entities. IDBContext will also contain all operations that we would like to perform against the database through the Entity Framework supported functionality.

Our entities from the Entity Framework on their behalf must also implement interfaces. The partial classes allow us to extend the behavior outside of the generated code.


 public partial class ModulesFunction : IModulesFunction
{
}
public partial class Module : IModule
{

}
public partial class Function : IFunction
{

}
public partial class Role : IRole
{

}
public partial class Product : IProduct
{

}

public partial class Order : IOrder
{

}



All of the interfaces must have exactly the same properties as their corresponding generated entities.

EntityInterface

If we define our Entity interfaces manually this becomes a boring and time consuming task. T4 templates could be decent choice to automate this in your projects.

You can see that generated entity’s class placed in the designer.cs has the same public properties as our interface IModule.

generatedEntitiy


Another partial class which implements our IDBContext extends the Entity Framework generated database model.

dbContextExtender

Covariance which is one of the new features in .NET 4.0 allows us to return entities as IQuarable<Interface>, which indeed is great improvement compared to the previous versions.

Covariance

In .NET 3.5 when we didn’t have covariance, we had to solve our problems with extension methods like this:
 public static class Extensions
{
/// <summary>
/// Casts all objects inside an IQueryable<T> to their corresponding interface type
/// </summary>
/// <typeparam name="TClass">Type of the class</typeparam>
/// <typeparam name="TInterface">Interface to which to cast to</typeparam>
/// <param name="source">Source collection</param>
/// <returns></returns>
public static IEnumerable<TInterface> AsInterfaceEnumerable<TClass, TInterface>(this IQueryable<TClass> source)
where TClass : class, TInterface, new()
where TInterface : IEntity
{
foreach (var item in source)
yield return (TInterface)item;
}
}


The rest of the job is handled by Spring.NET, which reads its configuration files and injects IDBContext in our repositories.

DAOxml

Refer my previous post about deeper explanations about Spring.NET with MVC.NET.

The last thing which I will mention is about controlling the scope of the objects which we inject.

If we inject DBContext at application scope we may end up with weird messages about failed DBContext operations. The scope of the injected objects must be either session or request. We have to refer Spring.Web assembly to secure this.

XmlObjectFactory is defined in Spring.Core, and the “session” and “request” scopes maintenance are defined in Spring.Web. So, regardless if we put scope “request”, when we use XmlObjectFactory it won’t work.

That is why we have to use webApplicationContext.ObjectFactory and to make the configurations in our web.config which are related to Spring.

Since Spring.NET relies on HttpModules for loading the resources, hence we can access WebApplicationContext in Init() event in global.asax. The code sample has the code commented out in Init().

Validation
Always validate your inputs on every possible place: client side, code behind (business logic), even at database level. This becomes more valid in the loosely coupled context, because every of our components might be plugged in another application which doesn’t do any validations.
For client side validation i recommend you to check the article of Nikolay, who has many more cool posts about the client side development.
Refer Nikolay’s article for demonstrating how to prevent a MVC.NET application from XSS attacks.

GUI layer or polishing our views

JQuery grid gives us extremely flexibility, because it is easily extensible and comes with sorting, paging and searching functionality out-of-the-box.

In our sample we used it to list the products defined in our database.

grid

The multi-criteria searching in this case is very flexible, because its rules are handled by expression trees.

Refer this link for deeper details http://www.codeproject.com/KB/aspnet/AspNetMVCandJqGrid.aspx.


The parameters which are specific to the jquery grid (page, sidx, sort, etc..) are passed through the layers by a single object instance. Doing so, we keep the parameters which are related to the presentation layer, but used even in our repositories (we need them for the paging, sorting and searching) wrapped within a single object.

Unit testing the components of loosely coupled MVC.NET application
The components that ideally we would like to have unit tested are:

· Repository logic – paging, filtering, sorting

· Business logic – the most important part of every application. Here are implemented all business rules and requirements.

· Controllers actions and their results –even JSON result can be unit tested

· Routing rules

MvcContrib.TestHelper.dll and Rhino.Mocks.dll come to help and to mock our external dependencies.

The code below displays how I mocked the database context generated from Entity framework. We have to override its IQuerable<T> properties, which we want to replace runtime with our custom (fake) object collections.

dbcontextunittest



unitTestingRepository


Refer the code sample for more details on the unit tests.

The related source code can be downloaded here.

Links and sources used:
http://www.springframework.net/
http://mvccontrib.codeplex.com/
http://www.trirand.com/blog/?page_id=6
http://trirand.com/blog/jqgrid/jqgrid.html
http://jqueryui.com/themeroller/
http://ayende.com/blog
http://www.nunit.org/?p=download
http://www.codeproject.com/KB/cs/stringenum.aspx
http://www.codeproject.com/KB/aspnet/AspNetMVCandJqGrid.aspx - many thanks to the guys for the deep and detailed explanations and for the code as well.


Read full article!