The Claims, Azure and SharePoint Integration Toolkit Part 3
This is part 3 of a 5 part series on the CASI (Claims, Azure and SharePoint Integration) Kit.
· Part 1: an introductory overview of the entire framework and solution and described what the series is going to try and cover.
· Part 2: the guidance part of the CASI Kit. It starts with making WCF the front end for all your data – could be datasets, Xml, custom classes, or just straight up Html. In phase 1 we take your standard WCF service and make it claims aware – that’s what allows us to take the user token from SharePoint and send it across application or data center boundaries to our custom WCF applications. In phase 2 I’ll go through the list of all the things you need to do take this typical WCF application from on premises to hosted up in Windows Azure. Once that is complete you’ll have the backend in place to support a multi-application, multi-datacenter with integrated authentication.
· Part 3: describes the custom toolkit assembly that provides the glue to connect your claims-aware WCF application in the cloud and your SharePoint farm. I’ll go through how you use the assembly, talk about the pretty easy custom control you need to create (about 5 lines of code) and how you can host it in a page in the _layouts directory as a means to retrieve and render data in web part. The full source code for the sample custom control and _layouts page will also be posted.
· Part 5: a brief walk-through of a couple of sample applications that demonstrate some other scenarios for using the custom control you build that’s described in part 3 in a couple of other common scenarios. One will be using the control to retrieve some kind of user or configuration data and storing it in the ASP.NET cache, then using it in a custom web part. The other scenario will be using the custom control to retrieve data from Azure and use it a custom task; in this case, a custom SharePoint timer job. The full source code for these sample applications will also be posted.
In this posting I’ll discuss one of the big deliverables of this framework, which is a custom control base class that you use to make your connection from SharePoint to your WCF application hosted in Windows Azure. These are the items we’ll cover:
· The base class – what is it, how do you use it in your project
· A Layouts page – how to add your new control to a page in the _layouts directory
· Important properties – a discussion of some of the important properties to know about in the base class
The CASI Kit Base Class
One of the main deliverables of the CASI Kit is the base class for a custom control that connects to your WCF application and submits requests with the current user’s logon token. The base class itself is a standard ASP.NET server control, and the implementation of this development pattern requires you to build a new ASP.NET server control that inherits from this base class. For reasons that are beyond the scope of this posting, your control will really need to do two things:
1. Create a service reference to your WCF application hosted in Windows Azure.
2. Override the ExecuteRequest method on the base class. This is actually fairly simple because all you need to do is write about five lines of code where you create and configure the proxy that is going to connect to your WCF application, and then call the base class’ ExecuteRequest method.
To get started on this you can create a new project in Visual Studio and choose the Windows Class Library type project. After getting your namespace and class name changed to whatever you want it to be, you will add a reference to the CASI Kit base class, which is in the AzureConnect.dll assembly. You will also need to add references to the following assemblies: Microsoft.SharePoint, System.ServiceModel, System.Runtime.Serialization and System.Web.
In your base class, add a using statement for Microsoft.SharePoint, then change your class so it inherits from AzureConnect.WcfConfig. WcfConfig is the base class that contains all of the code and logic to connect to the WCF application, incorporate all of the properties to add flexibility to the implementation and eliminate the need for all of the typical web.config changes that are normally necessary to connect to a WCF service endpoint. This is important to understand – you would typically need to add nearly a 100 lines of web.config changes for every WCF application to which you connect, to every web.config file on every server for every web application that used it. The WcfConfig base class wraps that all up in the control itself so you can just inherit from the control and it does the rest for you. All of those properties that would be changed in the web.config file though can also be changed in the WcfConfig control, because it exposes properties for all of them. I’ll discuss this further in the section on important properties.
Because you'll need to register this control in the Global Assembly Cache, you need to add a key that will be used to sign the assembly and give it a strong name. As with any Visual Studio project, you can do so in the project Properties, by clicking on the Signing tab.
Now it’s time to add a new Service Reference to your WCF application hosted in Windows Azure. There is nothing specific to the CASI Kit that needs to be done here – just right-click on References in your project and select Add Service Reference. Plug in the Url to your Azure WCF application with the “?WSDL” at the end so it retrieves the WSDL for your service implementation. Then change the name to whatever you want, add the reference and this part is complete.
At this point you have an empty class and a service reference to your WCF application. Now comes the code writing part, which is fortunately pretty small. You need to override the ExecuteRequest method, create and configure the service class proxy, then call the base class’ ExecuteRequest method. To simplify, here is the complete code for the sample control I’m attaching to this post; I’ve highlighted in yellow the parts that you need to change to match your service reference:
//requires References to:
public class WcfDataControl : AzureConnect.WcfConfig
//this method must be overridden so the proxy can be
//configured and created correctly
public override bool ExecuteRequest()
//create the proxy instance with bindings and endpoint the base class
//configuration control has created for this
CustomersWCF.CustomersClient cust =
//configure the channel so we can call it with
//create a channel to the WCF endpoint using the
//token and claims of the current user
CustomersWCF.ICustomers claimsWCF =
//set the client property for the base class
this.WcfClientProxy = claimsWCF;
catch (Exception ex)
//now that the configuration is complete, call the method
So there you have it – basically five lines of code, and you really can just copy and paste directly the code in the override for ExcecuteRequest shown here into your own override. After doing so you just need to replace the parts highlighted in yellow with the appropriate class and interfaces your WCF application exposes. In the highlighted code above:
· CustomersWCF.CustomersClient: “CustomersWCF” is the name I used when I created my service reference, and CustomersClient is the name of the class I’ve exposed through my WCF application. The class name in my WCF is actually just “Customers” and the VS.NET add service reference tools adds the “Client” part at the end.
· CustomersWCF.ICustomers: The “CustomersWCF” is the same as described above. “ICustomers” is the interface that I created in my WCF application, that my WCF “Customers” class actually implements.
That’s it – that’s all the code you need to write to provide that connection back to your WCF application hosted in Windows Azure. Hopefully you’ll agree that’s pretty painless. As a little background, the code you wrote is what allows the call to the WCF application to pass along the SharePoint user’s token. This is explained in a little more detail in this other posting I did: http://blogs.technet.com/b/speschka/archive/2010/09/08/calling-a-claims-aware-wcf-service-from-a-sharepoint-2010-claims-site.aspx.
Now that the code is complete, you need to make sure you register both the base class and your new custom control in the Global Assembly Cache on each server where it will be used. This can obviously be done pretty easily with a SharePoint solution. With the control complete and registered it’s time to take a look at how you use it to retrieve and render data. In the CASI Kit I tried to address three core scenarios for using Azure data:
1. Rendering content in a SharePoint page, using a web part
2. Retrieving configuration data for use by one to many controls and storing it in ASP.NET cache
3. Retrieving data and using it in task type executables, such as a SharePoint timer job
The first scenario is likely to be the most pervasive, so that’s the one we’ll tackle first. The easiest thing to do once this methodology was mapped out would have been to just create a custom web part that made all of these calls during a Load event or something like that, retrieve the data and render it out on the page. This however, I think would be a HUGE mistake. By wrapping that code up in the web part itself, so it executes server-side during the processing of a page request, could severely bog down the overall throughput of the farm. I had serious concerns about having one to many web parts on a page that were making one to many latent calls across applications and data centers to retrieve data, and could very easily envision a scenario where broad use could literally bring an entire farm down to its knees. However, there is this requirement that some code has to run on the server, because it is needed to configure the channel to the WCF application to send the user token along with the request. My solution for came to consist of two parts:
1. A custom page hosted in the _layouts folder. It will contain the custom control that we just wrote above and will actually render the data that’s returned from the WCF call.
The Layouts Page
The layouts page that will host your custom control is actually very easy to write. I did the whole thing in notepad in about five minutes. Hopefully it will be even quicker for you because I’m just going to copy and paste my layouts page here and show you what you need to replace in your page.
<%@ Page Language="C#" AutoEventWireup="true" Inherits="Microsoft.SharePoint.WebControls.LayoutsPageBase,Microsoft.SharePoint, Version=18.104.22.168, Culture=neutral, PublicKeyToken=71e9bce111e9429c" MasterPageFile="~/_layouts/simple.master" %>
<%@ Assembly Name="Microsoft.SharePoint.ApplicationPages, Version=22.214.171.124, Culture=neutral, PublicKeyToken=71e9bce111e9429c"%>
<%@ Import Namespace="Microsoft.SharePoint.ApplicationPages" %>
<%@ Register Tagprefix="SharePoint" Namespace="Microsoft.SharePoint.WebControls" Assembly="Microsoft.SharePoint, Version=126.96.36.199, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Register Tagprefix="Utilities" Namespace="Microsoft.SharePoint.Utilities" Assembly="Microsoft.SharePoint, Version=188.8.131.52, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Import Namespace="Microsoft.SharePoint" %>
<%@ Assembly Name="Microsoft.Web.CommandUI, Version=184.108.40.206, Culture=neutral, PublicKeyToken=71e9bce111e9429c" %>
<%@ Assembly Name="AzureConnect, Version=220.127.116.11, Culture=neutral, PublicKeyToken=c0b51bd3d3b33212"%>
<%@ Register Tagprefix="AzWcf" Namespace="AzureWcfPage" Assembly="AzureWcfPage, Version=18.104.22.168, Culture=neutral, PublicKeyToken=f0ed63b2f4046026" %>
<asp:Content ID="Content1" ContentPlaceHolderId="PlaceHolderPageTitle" runat="server">
<SharePoint:EncodedLiteral ID="wcfConnectPageTitle" runat="server" text="Azure Wcf Connect Page" EncodeMethod='HtmlEncode'/>
<asp:Content ID="Content2" ContentPlaceHolderId="PlaceHolderPageTitleInTitleArea" runat="server">
<SharePoint:EncodedLiteral ID="wcfConnectPage" runat="server" text="Azure Wcf Connect Page" EncodeMethod='HtmlEncode'/>
<asp:Content ID="Content3" ContentPlaceHolderId="PlaceHolderSiteName" runat="server"/>
<asp:Content ID="Content4" ContentPlaceHolderId="PlaceHolderMain" runat="server">
<AzWcf:WcfDataControl runat="server" id="wcf" WcfUrl="https://azurewcf.vbtoys.com/Customers.svc" OutputType="Page" MethodName="GetAllCustomersHtml" />
Again, the implementation of the page itself is really pretty easy. All that absolutely has to be changed is the strong name of the assembly for your custom control. For illustration purposes, I’ve also highlighted a couple of the properties in the control tag itself. Note that the "WcfDataControl" part that is highlighted is the name of your class that you created. These properties are specific to my WCF service, and can be change and in some cases removed entirely in your implementation. The properties will be discussed in more detail below. Once the layouts page is created it needs to be distributed to the _layouts directory on every web front end server in your SharePoint farm. At that point it can be called from any site in any claims-aware web application in your SharePoint farm. Obviously, you should not expect it to work in a classic authentication site, such as Central Admin. Once the page has been deployed then it can be used by the CASI Kit web part, which will be described in part 4 of this series.
The WcfConfig contains two big categories of properties – those for configuring the channel and connection to the WCF application, and those that configure the use of the control itself.
As described earlier, all of the configuration information for the WCF application that is normally contained in the web.config file has been encapsulated into the WcfConfig control. However, virtually all of those properties are exposed so that they can be modified depending on the needs of your implementation. Two important exceptions are the message security version, which is always MessageSecurityVersion.WSSecurity11WSTrust13WSSecureConversation13WSSecurityPolicy12BasicSecurityProfile10, and the transport, which is always HTTPS, not HTTP. Otherwise the control has a number of properties that may be useful to know a little better in your implementation (although in the common case you don’t need to change them).
First, there are five read only properties to expose the top-level configuration objects used in the configuration. By read-only, I mean the objects themselves are read-only, but you can set their individual properties if working with the control programmatically. Those four properties are:
The other properties can all be configured in the control tag that is added to the layouts aspx page. For these properties I used a naming convention that I was hoping would make sense for compound property values. For example, the SecurityBinding property has a property called LocalClient, which has a bool property called CacheCookies. To make this as easy to understand and use as possible, I just made one property called SecurityBindingLocalClientCacheCookies. You will see several properties like that, and this is also a clue for how to find the right property if you are looking at the .NET Framework SDK and wondering how you can modify some of those property values in the base class implementation. Here is the complete list of properties:
Again, these were all created so that they could be modified directly in the control tag in the layouts aspx page. For example, here’s how you would set the FedBindingUseDefaultWebProxy property:
<AzWcf:WcfDataControl runat="server" id="wcf" WcfUrl="https://azurewcf.vbtoys.com/Customers.svc" OutputType="Page" MethodName="GetAllCustomersHtml" FedBindingUseDefaultWebProxy="true" />
The other properties on the control are designed to control how it’s used. While there is a somewhat lengthy list of properties, note that they are mainly for flexibility of use – in the simple case you will only need to set one or two properties, or alternatively just set them in the web part that will be described in part four of this series. Here’s a list of each property and a short description of each.
string WcfUrl – this is the Url to the WCF service endpoint, i.e. https://azurewcf.vbtoys.com/Customers.svc.
string MethodName – this is the name of the method that should be invoked when the page is requested. You can set this to what method will be invoked by default. In addition, you can also set the AllowQueryStringOverride property to false, which will restrict the page to ONLY using the MethodName you define in the control tag. This property can be set via query string using the CASI Kit web part.
string MethodParams – this is a semi-colon delimited list of parameter values that should be passed to the method call. They need to be in the same order as they appear in the method signature. As explained in part 2 of this blog series, parameter values really only support simple data types, such as string, bool, int and datetime. If you wish to pass more complex objects as method parameters then you need to make the parameter a string, and deserialize your object to Xml before calling the method, and then in your WCF application you can serialize the string back into an object instance. If passing that as a query string parameter though you will be limited by the maximum query string length that your browser and IIS supports. This property can be set via query string using the CASI Kit web part.
object WcfClientProxy – the WcfClientProxy is what’s used to actually make the call to the WCF Application. It needs to be configured to support passing the user token along with the call, so that’s why the last of configuration code you write in your custom control in the ExecuteRequest override is to set this proxy object equal to the service application proxy you created and configured to use the current client credentials.
string QueryResultsString – this property contains a string representation of the results returned from the method call. If your WCF method returns a simple data type like bool, int, string or datetime, then the value of this property will be the return value ToString(). If your WCF method returns a custom class that’s okay too – when the base class gets the return value it will deserialize it to a string so you have an Xml representation of the data.
object QueryResultsObject – this property contains an object representation of the results returned from the method call. It is useful when you are using the control programmatically. For example, if you are using the control to retrieve data to store in ASP.NET cache, or to use in a SharePoint timer job, the QueryResultsObject property has exactly what the WCF method call returned. If it’s a custom class, then you can just cast the results of this property to the appropriate class type to use it.
DataOutputType OutputType – the OutputType property is an enum that can be one of four values: Page, ServerCache, Both or None. If you are using the control in the layouts page and you are going to render the results with the web part, then the OutputType should be Page or Both. If you want to retrieve the data and have it stored in ASP.NET cache then you should use ServerCache or Both. NOTE: When storing results in cache, ONLY the QueryResultsObject is stored. Obviously, Both will both render the data and store it in ASP.NET cache. If you are just using the control programmatically in something like a SharePoint timer job then you can set this property to None, because you will just read the QueryResultsString or QueryResultsObject after calling the ExecuteRequest method. This property can be set via query string using the CASI Kit web part.
string ServerCacheName – if you chose an OutputType of ServerCache or Both, then you need to set the ServerCacheName property to a non-empty string value or an exception will be thrown. This is the key that will be used to store the results in ASP.NET cache. For example, if you set the ServerCacheName property to be “MyFooProperty”, then after calling the ExecuteRequest method you can retrieve the object that was returned from the WCF application by referring to HttpContext.Current.Cache["MyFooProperty"]. This property can be set via query string using the CASI Kit web part.
int ServerCacheTime – this is the time, in minutes, that an item added to the ASP.NET cache should be kept. If you set the OutputType property to either ServerCache or Both then you must also set this property to a non-zero value or an exception will be thrown. This property can be set via query string using the CASI Kit web part.
bool DecodeResults – this property is provided in case your WCF application returns results that are HtmlEncoded. If you set this property to true then HtmlDecoding will be applied to the results. In most cases this is not necessary. This property can be set via query string using the CASI Kit web part.
string SharePointClaimsSiteUrl – this property is primarily provided for scenarios where you are creating the control programmatically outside of an Http request, such as in a SharePoint timer job. By default, when a request is made via the web part, the base class will use the Url of the current site to connect to the SharePoint STS endpoint to provide the user token to the WCF call. However, if you have created the control programmatically and don’t have an Http context, you can set this property to the Url of a claims-secured SharePoint site and that site will be used to access the SharePoint STS. So, for example, you should never need to set this property in the control tag on the layouts page because you will always have an Http context when invoking that page.
bool AllowQueryStringOverride – this property allows administrators to effectively lock down a control tag in the layouts page. If AllowQueryStringOverride is set to false then any query string override values that are passed in from the CASI Kit web part will be ignored.
string AccessDeniedMessage – this is the Access Denied error message that should be displayed in the CASI Kit web part if access is denied to the user for a particular method. For example, as explained in part 2 of this series, since we are passing the user’s token along to the WCF call, we can decorate any of the methods with a PrincipalPermission demand, like “this user must be part of the Sales Managers” group. If a user does not meet a PrincipalPermission demand then the WCF call will fail with an access denied error. In that case, the web part will display whatever the AccessDeniedMessage is. Note that you can use rich formatting in this message, to do things like set the font bold or red using HTML tags (i.e. <font color='red'>You have no access; contact your admin</font>). This property can be set via query string using the CASI Kit web part.
string TimeoutMessage – this is the message that will be displayed in the CASI Kit web part if there is a timeout error trying to execute the WCF method call. It also supports rich formatting such as setting the font bold, red, etc. This property can be set via query string using the CASI Kit web part.
The following set of properties were added to help you do debugging from the web part itself:
bool ReturnDiagnosticsInformation – this property controls whether diagnostic information will be sent back to caller. Since it could contain information that might be considered sensitive – such as the name of the server on which the request executed – you can set this to false to prevent the information from flowing back to the web part.
string ExecutionServerName – this is the name of the server on which the request was executed. If you have issues with the request then you can use this information to know on which server you may want to examine the ULS logs.
string ExecutionErrorMessage – this contains any error messages that occurred during the execution of the WCF method call.
string TraceInfoMessage – this includes tracing information about the request that was made. For example, it includes the method name, method parameters, the WCF Url that was used, etc.
Troubleshooting can sometimes be difficult to do in widely distributed system like this. Here are some tips to help you get started:
- Navigate to the custom _layouts page directly. It's often easier to see what data is being returned, or what error messages you are encountering if you just navigate to the custom page.
- Enable the Show Debugging Information property on the CASI Kit web part. It will tell you what all the parameter values were that it used in making the request, how long the request took, any error messages, etc.
- If you see an error message like "secure fault", make sure you have added the correct thumbprint for the SharePoint STS token signing certificate to the web.config for your WCF application, and also that you have added the SSL certificate and any root certificates above it to the trusted root authorities in SharePoint.
Okay, this was one LONG post, but it will probably be the longest of the series because it’s where the most significant glue of the CASI Kit is. In the next posting I’ll describe the web part that’s included with the CASI Kit to render the data from your WCF application, using the custom control and layouts page you developed in this step.
Also, attached to this post you will find a zip file that contains the sample Visual Studio 2010 project that I created that includes the CASI Kit base class assembly, my custom control that inherits from the CASI Kit base class, as well as my custom layouts page.
UPDATE 2/4/2011: I added a solution called AzureConnectRegister.wsp to the zip file attached to this post. I highly recommend you use it to distribute the CASI Kit base class because it has a feature receiver that registers a custom ULS logging area. Without it, the logging used in the base class will not be able to execute successfully, so you will lose all logging. I also included the source code for the feature so you can see what code it is using to register the custom ULS logging area.
UPDATE 2/24/2011: I added all of the additional debugging properties described above.
UPDATE 3/6/2011: There was a problem with the connection to the WCF not being properly closed. This could result in periodic timeout issues when the CASI Kit web part requested data from the WCF. That problem has been fixed. Also, the default SendTimeout and ReceiveTimeout properties are now set to 30 seconds, so if there were any issues they will appear more quickly than previously.
UPDATE 6/25/2011: Fixed a problem with some method parameter types not being cast correctly; this would result in an error stating that the method could not be found. The standard types described above are supported for method parameters: string, int, long, bool, and DateTime. Custom types should be deserialized to a string and rehydrated server-side.
UPDATE 7/12/2011: No code updates here, but just a gentle reminder. If you add the web part to a page and check the Show Debug Info checkbox, and then it fails to retrieve the data and says that it failed to establish a trust, there are two possible causes. One, you didn't properly configure the trust in the web.config file for the WCF application. I describe how to do this in part 2 of this series at http://blogs.technet.com/b/speschka/archive/2010/11/06/the-claims-azure-and-sharepoint-integration-toolkit-part-2.aspx. Two, you didn't add the SSL certificate or one of it's parent certificates to the list of trusted root authorities in your SharePoint farm. I describe how to do this at http://blogs.technet.com/b/speschka/archive/2010/02/13/root-of-certificate-chain-not-trusted-error-with-claims-authentication.aspx.