SharePoint 2010: Programatically Retrieve Credentials from the Secure Store Service

SharePoint 2010′s Secure Store Service provides a way to map credentials and delegate access to remote resources. You may already be familiar with the MOSS 2007 Single Sign-on Shared Service, which was the former equivalent. The Secure Store Service integrates seemlessly with Business Connectivity Services (BCS), but it also features an API that can be taken advantage of within custom development projects. This makes the service an attractive option for storing sensitive configuration data such as connection strings, Web service credentials, etc.

The Secure Store Service allows us to create Target Applications which house sets of credentials. The two main types are Individual and Group applications, Individual meaning credentials are mapped to individual users, and Group meaning all users share the same set of credentials.

While the raw API isn't very intuitive, its design was likely intentional (additional security by obfuscation). With a little marshalling help from our interop library friends, we are able to retrieve credentials (provided the appropriate permissions to the target application).

To begin, we need to reference a couple of assemblies.

Microsoft.BusinessData.dll

C:\Program Files\Common Files\Microsoft Shared\Web Server Extensions\14\ISAPI\Microsoft.BusinessData.dll

Microsoft.Office.SecureStoreService.dll

C:\Windows\assembly\GAC_MSIL\Microsoft.Office.SecureStoreService\14.0.0.0__71e9bce111e9429c\Microsoft.Office.SecureStoreService.dll

And now for the reason you came to this post … the code

using System.Collections.Generic; using System.Linq; using System.Runtime.InteropServices; using System.Security; using Microsoft.BusinessData.Infrastructure.SecureStore; using Microsoft.Office.SecureStoreService.Server; using Microsoft.SharePoint;   namespace Trentacular.SharePoint.Util {     public static class SecureStoreUtils     {         public static Dictionary<string, string> GetCredentials(string applicationID)         {             var serviceContext = SPServiceContext.Current;             var secureStoreProvider = new SecureStoreProvider { Context = serviceContext };             var credentialMap = new Dictionary<string, string>();               using (var credentials = secureStoreProvider.GetCredentials(applicationID))             {                 var fields = secureStoreProvider.GetTargetApplicationFields(applicationID);                 for (var i = 0; i < fields.Count; i++)                 {                     var field = fields[i];                     var credential = credentials[i];                     var decryptedCredential = ToClrString(credential.Credential);                       credentialMap.Add(field.Name, decryptedCredential);                 }             }               return credentialMap;         }           public static string ToClrString(this SecureString secureString)         {             var ptr = Marshal.SecureStringToBSTR(secureString);               try             {                 return Marshal.PtrToStringBSTR(ptr);             }             finally             {                 Marshal.FreeBSTR(ptr);             }         }     } }




FluentSP – The Fluent SharePoint API

Download FluentSP 1.0 from Codeplex.com

Once you are doing a lot of SharePoint programming you know you often have to write lengthy pieces of code to implement simple tasks like querying SharePoint lists. Nowadays you can read a lot of fluent APIs or fluent interface. For instance, jQuery, a JavaScript library that had successfully introduced a fluent API to handle the hierarchical structure of the HTML documents.

Today, I want to introduce a small library I have developed, FluentSP, a modern fluent interface around the classic SharePoint 2010 API. By using FluentSP instead of the classic SharePoint API, you will be able to chain methods and act on sets of items of the underlying SharePoint objects.

What is a fluent API?
Checkout this CodeProject article A Look at Fluent APIs and the Wikipedia article Fluent interface.

To start into the fluent API you call the Use() method on SPSite, SPWeb, SPWebCollection or SPListCollection. The Use() method is implemented as an extension method that will return the entry facade object (see facade table below). Another entry point to the fluent API is the static class SP with its static methods CurrentSite, CurrentWeb, CurrentLists or RootWebLists.

1 SPContext.Current.Site.Use()... // => Returns the SPSiteFacade as entry point
2
3 // OR:
4 SP.CurrentSite()... // => Returns the SPSiteFacade as entry point

Using the entry facade instance you can start chaining the available facade methods as follows:

1 SP.CurrentSite().Web("Home").List("Tasks").Items().ForEach(i => // Do something with the item i of type SPListItem...);
2
3 // OR:
4 SP.CurrentSite()
5 .Web("Home")
6 .List("Tasks")
7 .Items()
8 .ForEach(i => // Do something with...);

Each facade object is actually wrapping an underlying data item, for instance the SPSiteFacade class is the fluent wrapper of the SPSite class. Depending on what kind of facade methods you are calling the method is returning either the current facade instance (e.g., ForEach() or Where()) or the method is returning a new child facade object (e.g. Items()). During the process of chaining methods in such a way you will build up a tree or hierarchy of facade instances. In order to step back to the parent or previous facade instance you need to call the End() method:

1 site.Use()
2 .RootWeb()
3 .Site()
4 .End() // Returns SPWebFacade as parent facade
5 .Site()
6 .End() // Returns SPWebFacade as parent facade
7 .End(); // Returns SPSiteFacade as parent facade

FluentSP is currently missing a number of possible useful methods, but you can easily extend the FluentSP API with custom facade classes and extension methods, see below and source code for implementation examples.

Samples

1 SPSite site = SPContext.Current.Site;
2
3 // ----------------------------
4
5 // Outputs titles of all lists of the root web where the list title starts with T
6 site.Use().RootWeb().Lists().Where(l => l.Title.StartsWith("T")).ForEach(l => Console.WriteLine(l.Title));
7
8 // Outputs titles of all lists of the root web where the list title ends with a ts (using RegEx)
9 site.Use().RootWeb().Lists("ts$").ForEach(l => Console.WriteLine(l.Title)).Count(out c);
10
11 // Outputs titles of all lists of the root web in ascending order where the starts with T
12 site.Use().RootWeb().Lists().Where(l => l.Title.StartsWith("T")).OrderBy(l => l.Title).ForEach(l => Console.WriteLine(l.Title));
13
14 // Outputs titles of all lists of the root web in descending order where the starts with T
15 site.Use()
16 .RootWeb()
17 .Lists()
18 .Where(l => l.Title.StartsWith("T"))
19 .OrderByDescending(l => l.Title)
20 .ForEach(l => Console.WriteLine(l.Title));
21
22 // ----------------------------
23
24 // Delete all items in the Members list, then add 7 new members and then select and output
25 // the titles of a few of the newly created items
26 site.Use()
27 .RootWeb()
28 .List("Members")
29 .Do(w => Console.WriteLine("Deleting all members..."))
30 .Items()
31 .Delete()
32 .End()
33 .Do(w => Console.WriteLine("Adding all members..."))
34 .AddItems(7, (i, c) => i["Title"] = "Member " + c)
35 .Items()
36 .Skip(2)
37 .TakeUntil(i => ((string)i["Title"]).EndsWith("6"))
38 .ForEach(i => Console.WriteLine(i["Title"]));
39
40 // ----------------------------
41
42 // Search for lists that are created by specific a user and depending on the results
43 // displays different messages by calling the IfAny or IfEmpty methods
44 site.Use()
45 .RootWeb()
46 .Lists()
47 .ThatAreCreatedBy("Unknown User")
48 .IfAny(f => f.ForEach(l => Console.WriteLine(l.Title)))
49 .IfAny(l => l.Title.StartsWith("M"), f => Console.WriteLine("Lists found that starts with M*"))
50 .IfEmpty(f => Console.WriteLine("No lists found for user"))
51 .End()
52 .Do(w => Console.WriteLine("---"))
53 .Lists()
54 .ThatAreCreatedBy("System Account")
55 .IfAny(f => f.ForEach(l => Console.WriteLine(l.Title)));
56
57 // ----------------------------
58
59 var items = new List<SPListItem>();
60
61 // Query with Skip and TakeUnitl methods
62 site.Use().RootWeb().List("Members").Items().Skip(2).TakeUntil(i => i.Title.EndsWith("5")).ForEach(i => { items.Add(i); Console.WriteLine(i.Title); });
63
64 // Query with Skip and TakeWhile methods
65 site.Use()
66 .RootWeb()
67 .List("Members")
68 .Items()
69 .Skip(2)
70 .TakeWhile(i => i.Title.StartsWith("Member"))
71 .ForEach(i => { items.Add(i); Console.WriteLine(i.Title); })
72 .End()
73 .Items()
74 .Where(i => i.Title == "XYZ")
75 .ForEach(i => { items.Add(i); Console.WriteLine(i.Title); });
76
77 // ----------------------------
78
79 // Adds new items using the Do method with the passed facade object
80 site.Use()
81 .RootWeb()
82 .AllowUnsafeUpdates()
83 .List("Members")
84 .Do((f, l) => {
85 for(int c = 1; c <= 5; c++)
86 f.AddItem(i => i["Title"] = "Standard Member #" + c);
87 })
88 .AddItem(i => i["Title"] = "Premium Member")
89 .Items()
90 .OrderBy(i => i.Title)
91 .ForEach(i => Console.WriteLine(i["Title"]));

Extensibility Samples

1 // This sample is using the ThatAreCreatedBy extension method defined in Extensions.cs to show how to extend the fluent API
2 site.Use()
3 .RootWeb()
4 .Lists()
5 .ThatAreCreatedBy("System Account", "jbaurle")
6 .Count(c => Console.WriteLine("Lists found: {0}", c))
7 .ForEach(l => Console.WriteLine(l.Title));
8
9 // This sample uses the new SPWebApplicationFacade extenion defined in SPwebApplicationFacade.cs to show how to extend the fluent API
10 site.WebApplication.Use()
11 .Sites()
12 .ForEach(i => Console.WriteLine(i.Url));
13
14 // This sample uses an alternative implementation for SPSiteFacade defined in SPSiteFacadeAlternate.cs to show how to extend the fluent API
15 site.WebApplication.Use().WithFirstSite().DoSomething();
16 site.Use<SPSiteFacadeAlternate<BaseFacade>>().DoSomething();

The custom method ThatAreCreatedBy which is used in the first query of the extensibility samples is implemented as follows:

1 static class Extensions
2 {
3 public static SPListCollectionFacade<TParentFacade> ThatAreCreatedBy<TParentFacade>(this SPListCollectionFacade<TParentFacade> facade, params string[] names)
4 where TParentFacade : BaseFacade
5 {
6 // NOTE: This sample uses the GetCollection method of the given facade instance to retrieve the current
7 // collection and adds the its query (see LINQ Deferred Execution). The Set method updates the
8 // underlying collection. The GetCurrentFacade method will then return the current facade to allow
9 // method chaining.
10
11 if(names.Length > 0)
12 facade.Set(facade.GetCollection().Where(i => names.Contains(i.Author.Name)));
13
14 return facade.GetCurrentFacade();
15 }
16 }

For more samples and details check out the source code you can download from Codeplex.

Built-In Facades and Methods

See Codeplex



Export SharePoint Task List Data To PDF Using A Templating System

A couple of times I had the situation where I needed to export SharePoint list data into a PDF file in a customized way. I wanted to use some kind of template technology to translate SharePoint list data into a PDF file. I was working with a text templating system called DotLiquid before (see also my post Implement A Generic Template Engine For SharePoint 2010 Using DotLiquid).

It's a really simple and easy to use template engine for .NET. Another dependency is the PDF library ABCpdf8. You can download a trail version here. This library is very powerful in creating PDF files, especially in adding HTML content to a PDF document.

At the end of this post you can download a SharePoint 2010 sample solution that shows you how to create a new button called "Export to PDF" for each task list, see screenshot below:

This post is actually not describing all the implementation details. I currently have not the time to do this, but I still want to share this solution with you.

The SharePoint 2010 solution adds a new custom action called PDFCreationAction. This action will add a new ribbon button called "Export to PDF" next to the "Export to Excel" button. The button will be displayed for task lists only.

The command action will link to an ASPX-file called CreatePDF.aspx that is doing the actual work. The SharePoint list ID and will be passed as parameter. The Page_Load method of the web form is executing the template against the list data and then the HTML representation will get added to a PDF document using the ABCpdf8 library.

That's all!

Download Source





Implement A Generic Template Engine For SharePoint 2010 Using DotLiquid

During the process of creating a complex SharePoint application you often need to send mails and create text files based on SharePoint data elements like SPListItem or SPWeb. Mail templates for instance mostly contain specific list item data. It would be helpful sometimes if the text generation itself is template-driven.

This article shows how to implement a generic template manager based on the free DotLiquid templating system with SharePoint specific extensions. This allows you for example to iterate through all SharePoint lists available within a SiteCollection and render only details for lists which contain Task in their title:

1 <p>All task lists for the current web '{{SP.Web.Title}}' and site '{{SP.Site.Url}}'
2 <ul>
3 {% for list in SP.Lists %}
4 {% if list.Title contains 'Task' %}
5 <li><i>{{list.Title}}</i> with ID '{{Slist.ID|upcase}}' (<i>(Created:
6 {{list.Created|sp_format_date}})</i></li>
7 {% endif %}
8 {% endfor %}
9 </ul>
10 </p>
11 <p>All lists for current web '{{SP.Site.RootWeb.Title}}' created by the 'splists' tag
12 <ul>{% splists '<li>{0}</li>' %}</ul>
13 </p>

The screenshot below shows the result of the rendered template sample:

TemplateEngine

Of course the technique implemented in this article can also be used in conjunction with other technologies or applications, it's not only SharePoint related.

DotLiquid Template Engine

The DotLiquid template engine is a C# port of the Ruby's Liquid templating system and is available for .NET 3.5 and above. DotLiquid is open source and can be downloaded at dotliquidmarkup.org. The software is also available as NuGet package for Visual Studio.

The templating system includes features like variable, text replacement, conditional evaluation and loop statements that are similar to common programming languages. The language elements consists of tags and filter constructs.

The engine can also be easily extended by implementing and adding custom filters and/or tags. This article actually shows how to extend the DotLiquid and implement SharePoint specific parts.

The following sample shows a Liquid template file:

1 <p>{{ user.name | upcase }} has to do:</p>
2
3 <ul>
4 {% for item in user.tasks -%}
5 <li>{{ item.name }}</li>
6 {% endfor -%}
7 </ul>

Output markup is surrounded by curly brackets {{…}} and tag markup by {%…%}. Output markup can take filter definitions like upcase. Filters are simple static methods, where the first parameter is always the output of the left side of the filter and the return value of the filter will be the new left value when the next filter is run. When there are no more filters, the template will receive the resulting string.

There are a big number of standard filters available to use, but later on we will implement a custom filter method for SharePoint. The result of the above rendered template looks like:

1 <p>TIM JONES has to do:</p>
2
3 <ul>
4 <li>Documentation</li>
5 <li>Code comments</li>
6 </ul>

To pass variables and render the template you first need to parse the template and the then just call the Render method with the variable values:

1 string templateCode = @"<ul>
2 {% for item in user.tasks -%}
3 <li>{{ item.name }}</li>
4 {% endfor -%}
5 </ul>";
6
7 Template template = Template.Parse(templateCode);
8
9 string result = template.Render(Hash.FromAnonymousObject(new {
10 user = new User
11 {
12 Name = "Tim Jones",
13 Tasks = new List<Task> {
14 new Task { Name = "Documentation" },
15 new Task { Name = "Code comments" }
16 }
17 }}));
18
19 public class User : Drop
20 {
21 public string Name { get; set; }
22 public List<Task> Tasks { get; set; }
23 }
24
25 public class Task : Drop
26 {
27 public string Name { get; set; }
28 }

The User and Task classes inherit from the Drop class. This is an important class in DotLiquid. The next sections explains the class in more detail. It is out of scope of this article to discuss all the features for DotLiquid in detail. For more information please see the homepage of DotLiquid (dotliquidmarkup.org) or the website of the original creator of the Liquid template language at liquidmarkup.org. You will find there a lot of manuals and sample code.

Template Manager

The TemplateManager class is a wrapper over the DotLiquid template engine and provides SharePoint support. The class allows to cache parsed templates, to register tags and filters and render them using a top-level custom Drop class named SharePointDrop:

1 internal class TemplateManager
2 {
3 public Dictionary<string, Template> Templates { get; protected set; }
4
5 public TemplateManager()
6 {
7 Templates = new Dictionary<string, Template>();
8 }
9
10 public void AddTemplate(string name, string template)
11 {
12 if(string.IsNullOrEmpty(name))
13 throw new ArgumentNullException("name");
14 if(string.IsNullOrEmpty(template))
15 throw new ArgumentNullException("template");
16
17 if(Templates.ContainsKey(name))
18 Templates[name] = Template.Parse(template);
19 else
20 Templates.Add(name, Template.Parse(template));
21 }
22
23 public void RegisterTag<T>(string tagName) where T : Tag, new()
24 {
25 Template.RegisterTag<T>(tagName);
26 }
27
28 public void RegisterFilter(Type type)
29 {
30 Template.RegisterFilter(type);
31 }
32
33 public string Render(string nameOrTemplate, IDictionary<string, object> values)
34 {
35 Template template;
36
37 if(Templates.ContainsKey(nameOrTemplate))
38 template = Templates[nameOrTemplate];
39 else
40 template = Template.Parse(nameOrTemplate);
41
42 SharePointDrop sp = new SharePointDrop();
43
44 if(values != null)
45 {
46 foreach(KeyValuePair<string, object> kvp in values)
47 sp.AddValue(kvp.Key, kvp.Value);
48 }
49
50 return template.Render(new RenderParameters { LocalVariables =
51 Hash.FromAnonymousObject(new { SP = sp }), RethrowErrors = true });
52 }
53 }

The Render method is using the SharePointDrop class to support objects like SPListItem or SPListCollection. The Drop class as key concept of DotLiquid must be explained in detail. The DotLiquid template engine is focusing on making templates safe. A Drop is a class which allows you to export DOM like objects. DotLiquid, by default, only accepts a limited number of types as parameters to the Render method. These data types include the .NET primitive types (integer, float, string, etc.), and some collection types including IDictionary, IList and IIndexable (a custom DotLiquid interface).

If DotLiquid would support arbitrary types, then it could result in properties or methods being unintentionally exposed to template authors. To prevent this, DotLiquid templating system uses Drop classes that use an opt-in approach to exposing object data.

The code following shows the SharePointDrop implementation:

1 internal class SharePointDrop : Drop
2 {
3 Dictionary<string, object> _values;
4
5 public SharePointDrop()
6 {
7 _values = new Dictionary<string, object>();
8
9 if(SPContext.Current != null)
10 _values.Add("Site", SPContext.Current.Site);
11 if(SPContext.Current != null)
12 _values.Add("Web", SPContext.Current.Web);
13 if(SPContext.Current != null)
14 _values.Add("User", SPContext.Current.Web.CurrentUser);
15
16 _values.Add("Date", DateTime.Now);
17 _values.Add("DateISO8601",
18 SPUtility.CreateISO8601DateTimeFromSystemDateTime(DateTime.Now));
19
20 // TODO: Add more default values
21 }
22
23 public void AddValue(string name, object value)
24 {
25 if(string.IsNullOrEmpty(name))
26 throw new ArgumentNullException("name");
27
28 if(_values.ContainsKey(name))
29 _values[name] = value;
30 else
31 _values.Add(name, value);
32 }
33
34 public override object BeforeMethod(string method)
35 {
36 if(!string.IsNullOrEmpty(method) && _values.ContainsKey(method))
37 return DropHelper.MayConvertToDrop(_values[method]);
38
39 return null;
40 }
41 }

The SharePointDrop class main objective is to solve the problem of casting unsupported data types like SPListItem or SPListItemCollection and other SharePoint related types. Therefore the class is overriding the BeforeMethod method of the Drop class to analyse the requested variable value. If the variable is available in the value context the method will try to cast the data type to a known Drop type by calling the MayConvertToDrop method of the DropHelper class:

1 public static object MayConvertToDrop(object value)
2 {
3 if(value != null)
4 {
5 // TODO: Add your own drop implementations here
6
7 if(value is SPList)
8 return new SPPropertyDrop(value);
9 if(value is SPListCollection)
10 return ConvertDropableList<SPPropertyDrop, SPList>(value as ICollection);
11 if(value is SPListItem)
12 return new SPListItemDrop(value as SPListItem);
13 if(value is SPListItemCollection)
14 return ConvertDropableList<SPListItemDrop, SPListItem>(value as ICollection);
15 if(value is SPWeb)
16 return new SPPropertyDrop(value);
17 if(value is SPSite)
18 return new SPPropertyDrop(value);
19 if(value is SPUser)
20 return new SPPropertyDrop(value);
21 if(value is Uri)
22 return ((Uri)value).ToString();
23 if(value is Guid)
24 return ((Guid)value).ToString("B");
25 }
26
27 return value;
28 }

The SPListItemDrop class for instance is returning the value of the requested field:

1 internal class SPListItemDrop : SPDropBase
2 {
3 public SPListItem ListItem { get { return DropableObject as SPListItem; } }
4
5 public SPListItemDrop()
6 {
7 }
8
9 public SPListItemDrop(SPListItem listItem)
10 {
11 DropableObject = listItem;
12 }
13
14 public override object BeforeMethod(string method)
15 {
16 if(!string.IsNullOrEmpty(method))
17 {
18 StringBuilder sb = new StringBuilder();
19 string name = method + "\n";
20
21 for(int i = 0; i < name.Length; i++)
22 {
23 if(name[i] == '\n')
24 continue;
25 if(name[i] == '_')
26 {
27 if(name[i + 1] != '_')
28 sb.Append(' ');
29 else
30 {
31 i++;
32 sb.Append('_');
33 }
34 }
35 else
36 sb.Append(name[i]);
37 }
38
39 name = sb.ToString();
40
41 if(ListItem.Fields.ContainsField(name))
42 return DropHelper.MayConvertToDrop(ListItem[name]);
43 }
44
45 return null;
46 }
47 }

The method parameter (field name of the SPListItem) of the BeforeMethod method can contain underscores which are replaced by spaces. So, field names with spaces like Start Date of the Task item must be defined in the template as {{task.Start_Date}}.

The SPPropertyDrop class, also part of the solution of this article, is a generic Drop implementation which exposes all properties of an object and may cast them if needed into an Drop objects again. For implementation details see the source code.

Filters and Tags

The solution is also providing a custom filter and tag implementation. The filter called sp_format_date (see template above) is implemented by the method SPFormatDate and is calling the FormatDate method of the class SPUtility form the SharePoint API:

1 internal static class SPFilters
2 {
3 public static object SPFormatDate(object input)
4 {
5 DateTime dt = DateTime.MinValue;
6
7 if(input is string)
8 {
9 try
10 {
11 dt = SPUtility.ParseDate(SPContext.Current.Web, input as string,
12 SPDateFormat.DateOnly, false);
13 }
14 catch { }
15 }
16 else if(input is DateTime)
17 dt = (DateTime)input;
18
19 if(dt != DateTime.MinValue && dt != DateTime.MaxValue && SPContext.Current != null)
20 return SPUtility.FormatDate(SPContext.Current.Web, (DateTime)input,
21 SPDateFormat.DateOnly);
22
23 return input;
24 }
25 }

The custom tag named splists is returning a formatted list of all SPList object names of the current web (see template above):

1 internal class SPListsTag : Tag
2 {
3 string _format;
4
5 public override void Initialize(string tagName, string markup, List<string> tokens)
6 {
7 base.Initialize(tagName, markup, tokens);
8
9 if(string.IsNullOrEmpty(markup))
10 _format = "{0}";
11 else
12 _format = markup.Trim().Trim("\"".ToCharArray()).Trim("'".ToCharArray());
13 }
14
15 public override void Render(Context context, StreamWriter result)
16 {
17 base.Render(context, result);
18
19 if(SPContext.Current != null && !string.IsNullOrEmpty(_format))
20 {
21 foreach(SPList list in SPContext.Current.Web.Lists)
22 result.Write(string.Format(_format, list.Title));
23 }
24 }
25 }

Download Source Code | Download Article (PDF)