Monday, August 27, 2012

SharePoint 2010 Development in Visual Studio 2012

There is plenty to get excited about for SharePoint 2010 developers with Visual Studio 2012. A new content type designer, a more intuitive template structure and Javascript intellisense are a few of the things that will make most of our lives a little easier. Below, I outline a few of the new features for SharePoint 2010 developers in Visual Studio 2012.

Content Type Designer
Content types are a critical component of SharePoint development. Unfortunately, they have a legacy of a rather unusual inheritance structure. Inheritance is done through the content type id. This is a nuisance for SharePoint developers that have to remember content type ids or constantly look them up. Now there is a Content Type item template and designer that provides a nice little drop down for setting up inheritance:



Once you have selected what content type you would like to inherit from, you are presented with a nice little designer. While I am not a huge fan of many of the Visual Studio designers, I do like this one because it simplifies the rather mundane task of adding columns to your content type.


Note that this designer builds out a declarative content type. Also note that if you add a new site column using the new site column item template, the site column is immediately available for selection in the content type designer.

I did notice some quirky behavior. For example, when I double click on the elements.xml file for the content type in order to view the raw xml, I am presented with a dialog box that tells me the file is already open (even though it is not) and asks me if I want to close it. If I click yes, the raw xml is opened and the designer closes. That is what I wanted, but the dialog was a little confusing.

Streamlined Templates
Many of the SharePoint 2010 project templates were moved to item templates. This more closely aligns the templates with how SharePoint developers setup their projects and solutions. In Visual Studio 2010 most of us got in the habit of creating a blank SharePoint project and building from there. In Visual Studio, you will select the "SharePoint 2010 Project" template instead, which really isn't much different, but a lot of the noise has been reduced.

There are now just a few SharePoint 2010 project templates. Below are the templates available in Visual Studio 2012 out of the box.



Most of the templates are now at the item level. Below are the SharePoint 2010 item templates available in Visual Studio 2012 out of the box.



Note that the item level templates now specify whether they are available as Sandbox solutions ("Farm Solution only").

You can find all of the documentation on the SharePoint 2010 templates available in Visual Studio 2012 here: http://msdn.microsoft.com/en-us/library/ee231554.aspx

Javascript Intellisense
If you work with Javascript on a regular basis, you probably have a tool that provides Javascript intellisense (I personally love ReSharper by JetBrains). But if Visual Studio 2012 can provide it as part of the built in functionality...even better.

 

What Else
There is a new, lightweight find bar (I was always moving my find window around in Visual Studio 2010 because it was so big and clunky).


Project managers will love the much improved Agile and Scrum templates for Team Foundation Server 2012. And, of course, Visual Studio 2012 integrates perfectly with them. You can update work items, track bugs, manage builds, and even set alerts all from the comfortable confines of Visual Studio 2012.

Visual Studio 2012 officially launches on September 12 but is available now (http://www.microsoft.com/visualstudio/11/en-us). If you haven't already tried it, you should. I think you will like it.

Tuesday, August 7, 2012

Creating a Custom E-mail Notification Solution for SharePoint 2010

In this post I outline a possible solution for a custom e-mail notification system built on SharePoint Server 2010.

Requirements

  • The notification system must allow for fully branded and customized e-mails.
  • Administrators and Designers must be allowed to easily modify branding elements and content within each e-mail notification.
  • Each e-mail notification must allow for personalized dynamic content (for example, recipient name, address, etc...).
  • Some e-mail notifications will be time delayed or scheduled.
Our task is to create a scalable n-tier code solution that will allow other developers to easily generate custom e-mails using predefined templates.

High Level Process Flow

The high level process flow will look something like this:


Some type of web based activity on SharePoint 2010 will trigger the need for a notification. We don't really care what the activity is for our task. We just need to provide other developers some way of plugging into the e-mail notification framework that we are building. Once an activity is triggered, we need to know two things (these are our inputs):
  1. Which e-mail template to use
  2. The values of any personalized properties for the notification (for example, the e-mail address to which the e-mail will be sent).

Data Layer

You could probably set this up a hundred different ways. For my purposes and for this example, I created two tables and a SharePoint document library.

SharePoint Document Library

The SharePoint document library stores an html file for each e-mail template. The example file I will use is a temporary password e-mail. The file, called TemporaryPasswordEmailTemplate.html looks like something this:

[ a bunch of branding stuff]
Your temporary password is: #!#TEMPORARYPASSWORD#!#
[further instructions, disclaimers, and more branding]

#!#TEMPORARYPASSWORD#!# is the replacement key. The code will look for and replace that key with the actual temporary password at the time the e-mail is generated.

Also in the SharePoint document library is a column for the template name. In this example, the template name is TempPassword. The template name in the document library tells the code which replacement keys to look for.

EmailTemplateConfiguration Table

The EmailTemplateConfigurationTable has two relevant columns:
  • TemplateId: the template id
  • Key: the name of a replacement key contained in the template
In this example we have one entry (but there could be as many as needed):
  • TemplateId: 2
  • Key: TemporaryPassword

Email Table

This table stores all outgoing e-mails. A timer job picks up any unsent e-mail and sends it. It has columns for To, From, Subject, Body, ScheduledSendTime, ActualSendTime, etc...

Base Layer

The base layer contains an enum for EmailTemplateType and an abstract class that the business layer will inherit. The abstract class does the heavy lifting.

EmailTemplateType Enum

First, I create an enum for the e-mail template types. Right now, we just have two (an undefined default type and an e-mail type for sending out a temporary password).

    public enum EmailTemplateType : int
    {
        Undefined = 0,
        TempPassword = 1
    }

CustomEmailMessage Abstract Class

Next I create an abstract class that will do most of the work of constructing the e-mails. The idea is that a new class will be created for each e-mail type (the implementation classes). Each new class will inherit the core functionality from the abstract class. The implementations will set the template type in the constructor. Properties on each of the implementations will set the values of dynamic content (if any). The implementations will then call the SendMail method (added later in this post) to do the work of constructing the e-mail and sending it out.

    public abstract class CustomEmailMessage : MailMessage
    {
         //Placeholder
    }

Note that the CustomEmailMessage abstract class inherits from System.Net.Mail.MailMessage. We will use the functionality in that class to set the To, From, Subject, and Body properties rather than create them ourselves.
Next I add the appropriate properties to the abstract class:
   
    public abstract class CustomEmailMessage : MailMessage
    {     
        private EmailTemplateType _type = EmailTemplateType.Undefined;
        private StringDictionary _replacementTags = new StringDictionary();
        private DateTime _sendDateTime = DateTime.Now;
        
        public EmailTemplateType TemplateType
        {
            get { return _type; }
            set { _type = value; }
        }
    }

The _type will be used to determine the e-mail template that we are going to use. The constructor of the implementation class will set the TemplateType property. Notice that it is of type EmailTemplateType (the enum created above).

The _replacementTags StringDictionary will be used to place personalized content in the e-mail templates. Each e-mail template with personalized content will contain placeholder keys. The placeholder keys will correspond to properties in the implementation class. At run time, the implementation class will set those properties and, when the SendEmail method is called, the base class will match up the properties with the appropriate keys in the template.

The _sendDateTime will be used to queue up e-mails that need to be scheduled for a certain time in the future.

Next I stub out the methods:
   
    public abstract class CustomEmailMessage : MailMessage
    {     
        private EmailTemplateType _type = EmailTemplateType.Undefined;
        private StringDictionary _replacementTags = new StringDictionary();
        private DateTime _sendDateTime = DateTime.Now;
        
        public EmailTemplateType TemplateType
        {
            get { return _type; }
            set { _type = value; }
        }
        
        public virtual void GetReplacementKeys()
        {
            //Placeholder
        }

        public virtual void GetReplacementValues(object sender)
        {
            //Placeholder
        }

        public virtual void GetTemplateHtml()
        {
            //Placeholder
        }

        public virtual void ReplaceTags()
        {
            //Placeholder
        }

        public virtual void WriteEmailToDB()
        {
            //Placeholder
        }

        public virtual void SendEmail()
        {
            //Placeholder
        }
    }

GetReplacementKeys
GetReplacementKeys does just as the name suggests. It populates _replacementTags with the appropriate keys. It's a StringDictionary so it is stored in key/value pairs. At this point we are just populating the keys. I won't include the code here, because I have a data layer with another level of abstraction that doesn't suit this walk through. The simplest way to do this, though is to create a SharePoint list with a column for TemplateType (_type) and a column for Key. Use the _type to pull the appropriate keys and add them to the StringDictionary _replacementTags.

GetReplacementValues
This method is a little trickier. We are going to use reflection to get the values of the implementing method's properties and match them up with the keys in _replacementTags. The code looks like this:
    public virtual void GetReplacementValues (object sender)
    {
        PropertyInfo[] propertyInfos = this.GetType().GetProperties();
        foreach (PropertyInfo propertyInfo in propertyInfos)
        {
             object _internal = propertyInfo.GetValue(sender, null);
             if (_internal != null)
             {
                  if(_internal.GetType() == typeof(string))
                  {
                       _replacementTags[Globals.Delimiter + 
                           propertyInfo.Name.ToLowerInvariant() +
                           Globals.Delimiter] =
                           (string)_internal;
                  }
             }
        }           
    }

The caller of this method is actually the SendEmail method (which we will get to shortly). It passes in "this" as the sender object used in the GetReplacementValues method above.

Next, I get all the properties of the implementation object and put them into a PropertyInfo array. I enumerate through the array and extract the values from the sender object. As long as the values are not null and are of type string, I add them to the _replacementTags StringDictionary using the property name (plus a delimiter) as the key.

So this is important...in this setup, the property names on the implementation object must match the keys stored for the EmailTemplateType and they must match the replacement values in the html markup.

Note Globals.Delimiter. I have a class in my code for global variables. I have to use some kind of delimiter in the html markup to denote a replacement key. In this example, our delimiter is "#!#". The markup includes the delimiter but the stored keys don't. I add it here.

GetTemplateHtml
This method is pretty simple...go get the template html file and put it in the Body property (the Body property is part of the inherited MailMessage class. I store the template html files in a document library with a custom column to denote which EmailTemplateType the file corresponds to. Sparing you all the code to get the appropriate document library item, here is the most important line:
    Body = web.GetFileAsString(items[0].File.ToString());
ReplaceTags
Once I have all the appropriate template in the Body property and I have the key/value pairs in the _replacementTags StringDictionary, it's time to actually replace the tags:

    public virtual void ReplaceTags()
    {
        foreach (string key in _replacementTags.Keys)
        {
             Body = Body.Replace(key.ToUpperInvariant(), _replacementTags[key]);
        }
    }

WriteEmailToDB
Now I write the e-mail to a SQL database and a timer job picks it up and sends it.
    public virtual void WriteEmailToDB()
    {
        emailHelper.WriteToDB(To.ToString(), From.ToString(), Subject, Body,
            _sendDateTime);
    }

Note that I use a helper class. I don't include the code that actually writes the data to the table in this post.

SendEmail
Finally, the SendEmail method pulls it all together:

    public virtual void SendEmail(DateTime sendDateTime)
    {
        _sendDateTime = sendDateTime;

        GetReplacementKeys();
        GetReplacementValues(this);
        GetTemplateHtml()l
        ReplaceTags();
        WriteEmailToDB();
    }

Business Layer

Every time I create a new e-mail type, I will add an entry to the EmailTemplateType enum, create appropriate rows on the EmailTemplateConfiguration table, add the template html to the SharePoint document library, and create a class in the business layer that inherits from the CustomEmailMessage abstract class. For this example, I create a Temporary Password e-mail. My business layer implementation looks like this:
    public class TempPasswordEmail : CustomEmailMessage
    {
        public string TemporaryPassword { get; set; }
        
        public TempPassword()
        {
             TemplateType = EmailTemplateType.TempPassword;
             base.Subject = "Your Temporary Password";
             base.From = new MailAddress("SharePointDoug@doughemminger.com");
        }
    }

In this example, I know that the From and the Subject are going to be the same for every instance of the TempPassword class. So, I set them in the constructor.

UI Layer

When the user clicks a button to request a temporary password, the process triggers a notification to the user. Assuming the temporary password is appropriately generated and stored in the variable "x" and the user's email address is stored in the variable "userEmail" we would trigger a notification like this:

    TempPasswordEmail tempPasswordEmail = new TempPasswordEmail();
    tempPasswordEmail.To = userEmail;
    tempPasswordEmail.TemporaryPassword = x;
    tempPasswordEmail.SendEmail(DateTime.Now);

Wrap-Up

There are a few disadvantages and things to note about this approach:
  • A new e-mail type (for example, if we were to add an e-mail type for workflow notifications), requires a code change. An enum value has to be added at Base layer and implementations have to be added at the business layer and possibly at the UI layer.
  • I intentionally left out all of the try/catches and RunWithElevatedPrivileges. Add where appropriate if you use this code.
  • The properties in the business layer implementations must match the Keys stored in the data layer. In this example TemporaryPassword matches exactly at the business layer and the data layer
  • The replacement keys in the html markup must be all uppercase. In this example, #!#TEMPORARYPASSWORD#!# is all uppercase.
There are many advantages to this approach:
  • New e-mail types are added relatively easily (even though they require a code change). And once a new e-mail type is created, it can be easily implemented wherever you need it.
  • Storing the e-mail templates as html in a document library allows designers to mock-up and make changes to the templates as needed. In my real-world implementation we use header and footer html files to store CSS, logo, and disclaimer information for all e-mails.
  • It is fairly straightforward to implement dynamic content by using replacement keys in the html markup and the e-mail implementations.
  • Any of the methods in the abstract class can be overridden. If for, example, there were a use case to bypass the timer job and send the e-mail immediately, you could override the SendMail method, call all of the appropriate methods that are already there except the WriteEmailToDB method.