Pages

Thursday, 20 December 2012

Hiding SharePoint 2010 Blog Comments

The OOTB Blog provides commenting feature. One of my client asked me to remove the commenting feature from Blog.

Below is snapshot of OOTB SharePoint 2010 Blog:



If you have similar requirement then this post will help you. To hide comments, you have do following:

1. You have to remove Comments Listing web-part (that is easy!!!)
2. You have to remove Comments Form web-part (that is easy!!!)
3. Hiding comments links (this is one of the requirement from my client) using jQuery/javascript OR blog.xsl

Before writing javascript, I did some research/investigation that how comments are rendered. I found an blog.xsl located at /_layouts/XSL/blog.xsl

I don't want to touch the OOTB blog.xsl as it would apply to every site collection. So I decided to write javascript function to hide comments.


















From above picture, you can see the div for comments link. I need to find that div and find the last SPAN which contains comments link.

I googled and found the javascript to get that elements by class. Once I got that div, I iterated and scan the word 'comments' and made that span hidden.

Below code will grab the div element for class 'ms-PostFooter'
function getElementsByClass(theClass) {
            var allPageTags = new Array();
            allPageTags = document.getElementsByTagName("*");

            var Elements = new Array();
            var n = 0;
            for (i = 0; i < allPageTags.length; i++) {
                if (allPageTags[i].className == theClass) {
                    Elements[n] = allPageTags[i];
                    n++;
                }
            }

            return Elements;
        }


If you pay attention to above html source code, you will find there are two divs for class = 'ms-PostFooter', so we need to skip the first one and work on second div.

function hideComments() {
 var desiredElements = getElementsByClass('ms-PostFooter');            
 if (desiredElements.length > 0) {  
  for (var i = 0; i < desiredElements.length; i++) {
   var desiredElement = desiredElements[i];   
   if (desiredElement.innerHTML.indexOf('Comment(s)', 0) >= 0) {    
    var spans = desiredElement.getElementsByTagName("SPAN");
    for (var j = 0; j < spans.length; j++) {
     if( (spans[j].innerHTML.indexOf('comment(s)', 0) >= 0) ||
       (spans[j].innerHTML.indexOf('Comment(s)', 0) >= 0) ) {
      spans[j].style.visibility = 'hidden';
     }
     
     if( spans[j].innerHTML.indexOf('Number of Comments', 0) >= 0 )  {
      spans[j].style.visibility = 'hidden';
     }
    }
   }
  }
 } 
}  


Now, you have got codes. Copy all javascript code to a file and place it to /_layouts/YourProjectName/Js/BlogCommentsHider.js Now add a content editor web-part on page and write below markup:

<script src="/_layouts/YourProjectName/Js/BlogCommentsHider.js" type="text/javascript"></script><script language="javascript">


_spBodyOnLoadFunctionNames.push("hideComments");</script>


That's it.

Monday, 10 December 2012

Approval worfklow showing "System Account" in "Modified By" field


As you may know there is known issue or product feature that when you use OOTB Approval workflow, it publishes the item but leaves Modified by as System Account (http://sharepoint.microsoft.com/blog/Pages/BlogPost.aspx?PageType=4&ListId=%7b72C1C85B-1D2D-4A4A-90DE-CA74A7808184%7d&pID=865 ).

I am writing this blog 1) to save time of my other developer fellows as I have spent lot of time to figure out the issue 2) to help myself for future reference and my other fellows who are still struggling to find out the solution.

You may find below solution when you google it:

1.       Adding another column to track Modified By and displaying in all views

2.       Adding hidden column and call UpdateOverwriteVersion to overwrite when SharePoint Approval workflow updates the item

3.       Update OOTB Approval workflow (tried as well but having workflow publishing issue through SPD)

I have tried option #1 and it works fine, but our client was not happy with that solution. Then we implemented option #2, during testing we observed that after calling UpdateOverwriteVersion it increments by 0.1 version. So this solution is not going to work L

I started analysing “Approval – SharePoint 2010” OOTB workflow and I found that the workflow updates the content approval status using workflow author and that is leaving the “Modified By” field with System Account. Please see below snapshot of OOTB Approval workflow:


[Figure 1]

After analysis, I created a workflow association with below configuration:

 
[Figure 2]




[Figure 3]

When creating association, I did not select options (i.e. Start this workflow to approve publishing a major version of an item” and “Enable Content Approval”) and tested manually and everything worked as expected (i.e. not getting System Account in Modified By field).

So, I wrote an event receiver to publish item through code when the outcome of workflow is approved otherwise rejected.

So I came up with solution #4 that is given below:

1.       Create workflow association as shown in Figure 1 and Figure 2.
2.     An Event Receiver that kicks off the workflow (as I had a requirment to kick approval  process ONLY for some documents). If you don't have this kind of requirement then you don't need this even receiver.
 
3.       Write an event receiver (SPWorkflowEventReceiver) for workflow completed and publish item (a sample of code is posted below as image L)
 
 
 
 
 
 
 
 
 
NOTE: The properties contains information about Workflow History item.

You can download source code from https://approvalworkflowfix.codeplex.com/
Hope this post will help you.




Tuesday, 27 November 2012

Restoring a site collection from a backup

Recently I was doing migration of a site collection after verification from the client. I used Backup-SPSite command to backup the site collection.

Then I tried to restore a site collection from a backup to http://www.mmasood.com/sites/trainingByMM and it was giving below error:




 
 
 
 
 
I tried to restore the site collection to another web-application and it was successful. So I started looking the differences of configuration of both web-applications and I found the one web-application for which PowerShell was complaining, has got multiple databases attached to it.
so what I did to restore the site collection is that I created another Content Database called “WSS_Content_NewSiteCollection” and attached to desired web-application as shown below:
 

 
 
 
 
 
 
 
then executed the following command

Restore-SPSite http://www.mmasood.com/sites/trainingByMM -Path C:\temp\exportedSite\SiteBackup.bak –DatabaseServer <DBServerName> -DatabaseName WSS_Content_NewSiteCollection –Force

And this time PowerShell did not complain it and created my site collection.

Tuesday, 2 October 2012

Adding metadata into Word document for printing purpose

In this post I am going to share a feature that how can we include metadata values into a document for printing purposes.

Suppose we have a content type called "Procedure Document" with following columns:

1. Document Category
2. Reviewer
3. Review Date

you can have multiple columns but above columns are just for testing purpose to show you the idea.

Once you have uploaded a document and supplied the metadata as shown below:





















Now edit the document and follow below steps to add metadata into that document:

1. Go to Insert tab
2. Click on "Quick Part" > Document Property
3. Choose fields that you want to include in the document














Hope this helps.





Sunday, 9 September 2012

Checking SMTP settings in SharePoint environment

There are couple of ways to confirm/verify your SMTP settings for your SharePoint environment.

1) Add a domain user to your SharePoint site, and it lets you select the option to send a welcome email. Select that option and write your test message to verify that SharePoint is sending email to your users.

2) Create an alert for some list items or document libraries and update item and check whether your user gets an email.

3) Write some code and use SPUtility.SendEmail(...); For instance EmailTest utility

Sometime I use option 1 or 2 based on the user configuration. Sometime we get the user (from the client) but that user does not have email account. For that reason I use 3 option so that I can specify my own email address to verify the settings.

I have written a Email Tester utility for this purpose. You can download it from Codeplex or Softpedia

Below is an snapshot of that application.













Thanks for visiting my blog.

Monday, 13 August 2012

Provisioning custom html/javascripts/css in Content Editor WebPart through code

If you want to provision custom html/javascripts/css in Content Editor webpart through Feature code here it is:

1. Get SPLimitedWebPartManager from SPWeb
2. Create instance of ContentEditorWebPart class
3. Set all properties to that instance
4. Load your contents using CDATA section of xml in XmlDocument
5. Assign XmlElement type to yourwebPartInstance.Content
6. Ask WebPartManager to add that instance to your webpart zone
7. Call SaveChanges of SPLimitedWebPartManger class.

Here is the code

SPLimitedWebPartManager wpManager = web.GetLimitedWebPartManager("YourPageUrl", System.Web.UI.WebControls.WebParts.PersonalizationScope.Shared);

//create new webpart object ContentEditorWebPart webPartInstance = new ContentEditorWebPart();

//set properties of new webpart object
webPartInstance.ZoneID = "YourWebPartZone";
webPartInstance.Title = "Some Title"; webPartInstance.ChromeState = System.Web.UI.WebControls.WebParts.PartChromeState.Normal; webPartInstance.ChromeType = System.Web.UI.WebControls.WebParts.PartChromeType.None;

//Load your contents using CDATA section of xml
XmlDocument doc = new XmlDocument(); doc.LoadXml(@" <![CDATA[ <input onlcick="javascript:sayHello();" type="button" value="Say Hello" /> ]]> ");

//Get the contents as XmlElement
XmlElement contentsElement = (XmlElement)doc.SelectSingleNode("//Contents");

webPartInstance.Content = contentsElement;

//add new webpart object to webparts collection
wpManager.AddWebPart(webPartInstance, "YourWebPartZone", 0); wpManager.SaveChanges(webPartInstance);

//update spWeb object
web.Update();


That's it. Enjoy

Friday, 10 August 2012

SharePoint and IoC container

I was given a task to write a timer job that needs to read data from SharePoint list. My colleague has written a timer job for that purpose but the code was reading data directly from the database. So when I tried to use but could not because it was tight couple.

So I decided to modify that code in a plug-able way so that I can choose various data sources to be used with the same timer job for different clients. I implemented OCP (Open Closed Principal).

I have used StructureMap as IoC container to inject my dependency to SharePoint timer job. Because it is easy to use and other reason was it allows us to configure dependencies in a separate configuration file so I don't need to touch OWSTIMER.config file.

I wrote an interface called IRepository, and configured my timer job to pick the implementation from IoC container.
The container was configured with the concrete implementation class. If I want my timer job to read data from csv file, I just need to change the settings/configuration in IoC config.

Below is my project structure:




You can see there is a project called "Masood.SharePoint.ProcessingTimerJob.Interfaces" and it has got IRepository interface.

And Masood.SharePoint.ProcessingTimerJob.Repositories has got actual implementation of IRepository class.

So I can distribute Masood.SharePoint.ProcessingTimerJob.wsp to anyone who wants to use it, they  just need to implement that interface and timer job is read to process from your data source. You can download full source code from Codeplex.

Below is structure map config file that is use to inject actual implementation



Some output




That's it.

Friday, 3 August 2012

Developing First App for SharePoint 2013

Today finally I got my vm configured for development of Apps for SharePoint. I had couple of issues while configuring the vm that I want to share with you.

The first challenge was setting up app domain and the other was installing tools for SharePoint apps.

Following are the steps I performed to get my vm configured for apps development:

1) Installed SharePoint 2013 Preview (i.e obvious)
2) Created a site at http://myserver using Developer Site Template template
3) Enable and Restart SharePoint Administration Timer service
4) If you are running it twice or you have already created 'SettingsServiceApp' and 'AppServiceApp' service app then you have to delete it before running this script.
5) Ran the script, I will share that script with you

To install developer tools, you need to install sharepointclientcomponents_x64.msi first and then OfficeToolsForVS2012RCPreview.3f.3f.3fnew.exe

Here is the script that I used in step 4:
start of script
#--------------------------------------------
write-host "starting admin and timer service"
net start spadminv4
net start sptimerv4
write-host "setting apps.mmasood.com app domain..."
Set-SPAppDomain "apps.mmasood.com"
write-host "Ensuring that the SPSubscriptionSettingsService and AppManagementServiceInstance services are running..."
Get-SPServiceInstance | where{$_.GetType().Name -eq "AppManagementServiceInstance" -or $_.GetType().Name -eq "SPSubscriptionSettingsServiceInstance"} | Start-SPServiceInstance
Get-SPServiceInstance | where{$_.GetType().Name -eq "AppManagementServiceInstance" -or $_.GetType().Name -eq "SPSubscriptionSettingsServiceInstance"}
write-host "Checking managed account..."
$account = Get-SPManagedAccount | where {$_.UserName -eq "myserver\Administrator"}
if($account -eq $null){
 write-host "Creating new managed account"
 $account = New-SPManagedAccount
 write-host "Managed account created."
}
else{
 write-host "Managed account already exists."
}

$appPoolSubSvc = Get-SPServiceApplicationPool | where {$_.Name -eq "SettingsServiceAppPool"}
if($appPoolSubSvc -eq $null){
 write-host "Creating SettingsServiceAppPool..."
 $appPoolSubSvc = New-SPServiceApplicationPool -Name SettingsServiceAppPool -Account $account
 write-host "Creating SettingsServiceAppPool...done"
}
else{
 write-host "SettingsServiceAppPool already exists."
}
$appPoolAppSvc = Get-SPServiceApplicationPool | where {$_.Name -eq "AppServiceAppPool" }
if($appPoolAppSvc -eq $null){
 write-host "Creating AppServiceAppPool..."
 $appPoolAppSvc = New-SPServiceApplicationPool -Name AppServiceAppPool -Account $account
 write-host "Creating AppServiceAppPool...done"
}
else{
 write-host "AppServiceAppPool already exists."
}
write-host "creating service apps 'SettingsServiceApp'..."
$appSubSvc = New-SPSubscriptionSettingsServiceApplication –ApplicationPool $appPoolSubSvc –Name SettingsServiceApp –DatabaseName SettingsServiceDB
$proxySubSvc = New-SPSubscriptionSettingsServiceApplicationProxy –ServiceApplication $appSubSvc
write-host "creating service apps 'SettingsServiceApp'...done"
write-host "creating service apps 'AppServiceApp'..."
$appAppSvc = New-SPAppManagementServiceApplication -ApplicationPool $appPoolAppSvc -Name AppServiceApp -DatabaseName AppServiceDB
$proxyAppSvc = New-SPAppManagementServiceApplicationProxy -ServiceApplication $appAppSvc
write-host "creating service apps 'AppServiceApp'...done"
write-host "creating service apps...done"
write-host "setting tenant..."
Set-SPAppSiteSubscriptionName -Name "app" -Confirm:$false
write-host "setting tenant...done"
#----------------------------------------------------------

After that I created a HelloworldApp (the default provided by VS) and successfully deployed.

Updated:
You may need to disable loopback check if you are using hosts file for DNS routing. Please follow steps from http://support.microsoft.com/kb/896861 to disable loopback check.
You can find more details at http://msdn.microsoft.com/en-us/library/fp179923(v=office.15).aspx

That's it.

Saturday, 21 July 2012

Installing SharePoint 2013 Preview

I have tried installing SharePoint 2013 Preview on VirtualBox and kept failing on Configuration wizard.

Run following through powershell
PS C:\Program Files\Common Files\microsoft shared\Web Server Extensions\15\BIN>
 .\PSCONFIG.EXE -cmd Configdb create SkipRegisterAsDistributedCacheHost

Once you have ran above command re-run Configuration wizard. You may get an exception in step 8 (i.e failed to create sample data...). Ignore this exception as Central Admin has been provisioned.
You can find detail post from here: http://tomblog.insomniacminds.com/2012/07/17/sharepoint-2013-standalone-installation-issue/

Thanks for reading my post.

Tuesday, 10 July 2012

Calculated columns in SharePoint

One of the cool field type is the Calculated field. That is used to do some custom calculation or performing some logic based on existing field.

I used calculated field in one of the project that was based on SharePoint workflow and had some logic to kick of workflow. It was late 2 years back and that time I was not blogging. Recently I created couple of Calculated columns so I decided to blog it so that I can and my SharePoint felows can get benefit now and in future as well.

Calculated field works like Excel cell. For instance we want to calculate the next schedule/review date based after 60 days of the date supplied.

The formula for above scenario is very simple:

Next review date: [Review Date] + 60

Similarly if you want to show "First Name" + "Last Name" as Name in the list, just use below simple formula:

Name: [First Name] + " " + [Last Name]

We can also use IF ELSE in the formula. For instance if you need to calculate schedule/review date based on type of document. If document type is Urgent, then review should happen in 10 days otherwise in 30 days.

Next review date: =IF([Document Type]="Urgent", [Review Date]+10, [Review Date]+30)
Where [Document Type] is choice field, and 'Next review date' is calculated field type.

Remember, the fiels must be closed with [ and ] brackets.

Whenever I need to use formula in Calculated field, I open my excel and create a formula and use it in SharePoint.

For further reference please visit http://office.microsoft.com/en-us/windows-sharepoint-services-help/examples-of-common-formulas-HA001160947.aspx

Saturday, 7 July 2012

Learning SharePoint from SharePoint

Last week I was so busy with my family so I could not get time to write anything. Luckily I have got some time this week.

To learn anything you would need some tools related to what you are going to learn, perhaps some books or some software etc.
For SharePoint we need following things:
1.       SharePoint environment offcourse
2.       A tool to decompile the SharePoint dll code (dotPeek or Reflector)
3.       Items you want to learn (For instances Site Template, Features, Layout Pages etc)

You can find everything related to SharePoint in 12/14 hive. Let’s get started!
Below is the snapshot of 14 hives (as I am using SharePoint 2010)


If you want to deploy your own custom WCF or ASMX web service, ISAP is the recommended place to use it. When you deploy in 14 hives it is recommended that you should use your own folder.

WebService / WCF Service Deployment Scenario
Let’s say I want to deploy a WCF that creates an Order and save it to SharePoint list/or database.

So folder structure would be:
14 hives \ ISAPI \ CompanyName \ ProjectName \ CreateOrder.svc

When you reference you would be referencing with http://SharePointSiteUrl/_vti_bin/CompanyName/ProjectName/CreateOrder.svc

Also you can get the url from IIS. Go to your IIS as shown below and select the CreateOrder.svc page and right click and click Browse option.




Application Pages deployment scenario


If you want to deploy your own custom application page, you should deploy all your custom application pages to 14 hives\TEMPLATE\LAYOUTS\CompanyName\ProjectName\YourCustomPage.aspx

SharePoint Resources (Images/CSS/JS) scenario

Images should go to:
14 hives\TEMPLATE\LAYOUTS\1033\Images\CompanyName\ProjectName\your images

CSS should go to:
14 hives\TEMPLATE\LAYOUTS\1033\STYLES\CompanyName\ProjectName\your css

Javascript files should go to:
14 hives\TEMPLATE\LAYOUTS\1033\ CompanyName\ProjectName\javascript files

Creating Site Template scenario

Browse 14 hives\TEMPLATE\Site Templates and pick the easiest one that is sts and inspect the folder structure and files. If you observe the structure then it will be easy for you to create a custom site template that you can deploy through SharePoint solutions.

All the configuration related to SharePoint template goes to 14 hives\TEMPLATE\1033\XML


Also have a look at xml files located above in the picture. It will tell how to create a configuration and Site Provisioning Provider.

Provisioning a web part to a page using XML declaration

If you open xml located at 14 hives\TEMPLATE\SiteTemplates\sts\xml  or ONET.xml of any SharePoint site template you can see the Module node. Below is a snapshot of Onet.xm file:


If you pay close attention to the red box you will notice that we are saying that we want that web-part (Members webpart) to be added to “Right” zone in that page with order “1”. It means this web-part will be displayed first.

The easiest way to get the xml for web part is to export the web-part from the page and open it to some notepad.

There are lot of things but what I wanted to share is that how you can explore SharePoint yourself.
Some of you guys must be thing where we have used dotPeek or Reflector. J You can use where you want to know how SharePoint is doing some of the stuff. So you can inspect Microsoft.SharePoint.dll or desired dll.

Happy talking about SharePoint !!!

Wednesday, 4 July 2012

Customising Search result page through Feature

To customize your search result page, you need to follow below steps; at the end you will end up a .wsp solution that will be used for deployment to deploy your customization to various environments.
I am assuming that you have search centre site. Browse your search result page and modify web parts and supply your changes. For instance in “Search Box” web part you can specify the search result page.
Similarly in “Search core result” webpart you can specify your xsl for the custom layout for the results and if you want additional columns you can specify there as well.




Specify the xsl location not xsl itself. We will be deploying that xsl in _layouts/Masood/demo/customsearchresults.xsl through SharePoint 2010 project as show below.
Once you have done your modifications, it’s time to export those modifications to xml as shown below image:
Perform expert to only modified web parts. For instance we modified “Search Box” and “Search Core Results” web part and save those files.
Now create a SharePoint 2010 project.
Browse 14\TEMPLATE\SiteTemplates\SRCHCEN\XML and open xml file in notepad

 

and search for “<File Url="results.aspx" Type="GhostableInLibrary">”
Copy the contents of above node and paste it your Elements file of “SearchPage” module as show below:

Now open SearchBox.webpart file and copy the xml in clipboard and replace with the contents in <AllUsersWebPart WebPartZoneID="TopZone" WebPartOrder="1"> <![CDATA[ …old contens should be replaced with new
]]> </AllUsersWebPart>


Similarly open SearchCoreResults.webpart file and copy the xml in clipboard and replace with the contents in <AllUsersWebPart WebPartZoneID="BottomZone" WebPartOrder="3"><![CDATA[ old contents should be replaced with new from webpart file

]]> </AllUsersWebPart>


NOTE: make sure you replace the correct xml.  
Compile your project, deploy the .wsp and activate the web-scope feature that will create customsearchresults.aspx search result page with your customization.
There is another way as well … that is totally using C# code in the feature. I will blog it later…stay tuned.
Happy coding!



Sunday, 1 July 2012

Debugging SharePoint code in Production


Recently I was asked to troubleshoot production code. Unfortunately we did not have pre-prod or staging environment.

In production, you have to be very careful. You can’t deploy anything without going through some checks (or build pipeline).
Then what I did was very simple thing. Imagine what would have I done!!!
I chose a SharePoint layout page that only displays links. Guess which page it was? Yes it was _layouts\settings.aspx page.
I copied _\layouts\settings.aspx to _layouts\Masood\settings.aspx and modified with my debugging code.
I wrote code in scriptlet.
<%
Response.Write(“Beginning of my debugging code...”);
YourDependencyClass obj = new YourDependencyClass();
obj.SomeMethod();
%>
The other thing I did was I wrote whole classes between< % and %> and fortunately I found the issue. Following is an example

< %
public class YourDependencyClass {
   public void SomeMethod(){
          //your logic…
   }
}%>
I hope that will work for you if you need to do troubleshoot in production environment.

Wednesday, 20 June 2012

Feature activation depending on some logic

Some time we need to get our feature de-activated mode if it fails on some logic. For instance you have written a feature that provisions some lookup list that depends on an existent list or some timer job. The name of the existent list or timer job is supplied through properties.

The easiest way to tell SharePoint not to activate this feature is to throw SPException with your message.
public override void FeatureActivated(SPFeatureReceiverProperties properties)
{
   string someListName = properties.Definition.Properties["ParentListName"].Value;
   if (string.IsNullOrEmpty(someListName))
     throw new SPException("Please supply value of 'ParentListName' property.");          
   SPSite site = (SPSite)properties.Feature.Parent;
   SPList someList = site.RootWeb.Lists[someListName];

   if (someList == null)
     throw new SPException(string.Format("List:'{0}' does not exist. Please create it first before activating this feature.", someListName));

   //do your stuff
}


That's it.

Monday, 18 June 2012

Starting workflow programmatically

If you have an instance of SPListItem, and know the workflow association name, you can start it. First you need to find workflow assocation instance and tell SPSite.SPWorkflowManager to start your workflow.

Lets say I have a helper method that takes SPListItem and workfow association name.

private SPWorkflowAssociation GetWorkflowAssociationByName(SPListItem item, string workflowAssociationName)
{
    return item.ContentType.WorkflowAssociations.GetAssociationByName(workflowAssociationName, new System.Globalization.CultureInfo("en-US"));

}


public void StartWorkflow(SPListItem item, string associationName)
{
  try
   {                

//get workflow association object
workflowAssociation = GetWorkflowAssociationByName(item, associationName);                

if (workflowAssociation == null)
  throw new Exception(string.Format  ("Workflow association '{0}' could not be found in the list '{1}'", workflowAssociationName, item.ParentList.Title));

//start your workflow...
item.Web.Site.WorkflowManager.StartWorkflow(item, workflowAssociation, workflowAssociation.AssociationData);
   }            

   catch (SPException spEx)
   { //log your exception }
}


//that kicks off a associated workflow.
StartWorkflow(anInstanceOfSPListItem, "Masood - Approval workflow")

Below is the picture where higlighted box is the association name.


 

That's it. Happy coding.

Tuesday, 24 April 2012

Email template manager for SharePoint and C# developer


Email Templates Utility Description
This framework or utility will help you to manage email templates and allows you to integrate with your project easily.

There are scenarios when you need to send emails with customised text or template based in SharePoint or Asp.net or any C# project. This tool will help you achieve this goal.

Source code:
http://emailtemplatemanager.codeplex.com/

How to use it
This is very easy to include to your project. Following are the steps:
1.       Clone this project/source code and include in your target project.
2.       Implement AbstractTemplateManager class according to your need. For test purpose I have created TestTemplateManager in the source code. I have also created a SharePointTemplateManager just to give you an idea how to do it for SharePoint.
a.       When you implement AbstractTemplateManager you need to implement following methods:
                                                               i.      GetTemplate(string templateId)
You need to implement this method to let the framework know about the template that will be going to use for applying values

                                                             ii.      BeforeApplyingTemplateOnSubject
There would be some situation where you need to apply some custom logic before going to the framework.
If you don’t want to perform any custom logic then leave the method implementation blank but DO NOT throw any exception.

                                                            iii.      AfterApplyingTemplateOnSubject
There would be some situation where you need to perform some custom logic after applying values from framework.

For sample purpose I have added an implementation in TestTemplateManager class.

                                                           iv.      BeforeApplyingTemplateOnBody
                                                             v.      AfterApplyingTemplateOnBody
3.       Implement IItem interface. This interface is nothing but contains field names and their values. If you are implementing for SharePoint, then field names become SharePoint column/field name and value you can get SPListItem[fieldname]
4.       There is an enum which defined what type of Manager we have got in the system. Currently I have added
public enum EnumTemplateType
{
         SharePoint,
         Xml,
        Test
 }

This type lets the framework know where all templates are managed.
SharePoint: It means all templates are managed in SharePoint list.
Xml: It means all templates are managed in Xml file.
Test: It is just for testing purpose.

5.       In the consumer project do the following:

Get instance of template manager using Factory method as shown in below.
Here is the code to run the test project:
static void Main(string[] args)
        {
            IItem orderItem = new Item();
            orderItem.FieldAndValues.Add("DELIVERY_DATE", new DateTime(2012, 1, 1).ToString());
            orderItem.FieldAndValues.Add("CUSTOMER", "Unique world");

            AbstractTemplateManager manager = TemplateManagerFactory.Create(EnumTemplateType.Test);
            Email email = manager.ApplyTemplate("order_template", orderItem);

            //just for testing purpose
            Console.WriteLine("Displaying template...");
            EmailTemplate template = manager.GetTemplate("order_template");
            Console.WriteLine("Template.Subject: {0}", template.Subject);
            Console.WriteLine("Template.Body: {0}", template.Body);
            Console.WriteLine("");

            Console.WriteLine("After applying template...");
            Console.WriteLine("Email.Subject: {0}", email.Subject);
            Console.WriteLine("Email.Body: {0}", email.Body);

            Console.ReadKey();
        }