October 2008 - Posts
As promised, this is the first of a series of posts that intend to cover the new capabilities implemented in the WCF REST Starter Kit to enhance the development of RESTful services using WCF. Specifically, this post is focus on how to enable caching on RESTFul services by using the REST Starter Kit . Undoubtedly, caching is one of the greatest benefits of the Web programming model and one of the main attractive of REST over alternatives such as SOAP/WS-*. Throughout the evolution of the web, the industry has developed very innovative techniques for optimizing content retrieval by the use of caching. These techniques have been reflected in technologies such as MemCache, Oracle Coherence and more recently Microsoft's Velocity that specialized in distributed caching. Additionally, web technologies like ASP.NET provides generic programming models that address some of the most common caching scenarios. All this infrastructure and technologies can be naturally leveraged by RESTful services without the need of creating new caching mechanisms. Precisely, the REST Starter Kit leverages ASP.NET extending WCF RESTful services with caching capabilities.
The fundamental steps to add caching to a WCF RESTful service consists on adding the WebCache attribute to the operation intended to cache. The following code illustrates this concept on a simple WCF RESTful service which WAS NOT implemented using the WCF REST Starter Kit .
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class SampleService : ISampleService
{
[WebGet(UriTemplate= "/results")]
[WebCache(CacheProfileName = "SampleProfile")]
public Atom10FeedFormatter GetData()
{
SyndicationFeed feed = new SyndicationFeed();
feed.LastUpdatedTime = DateTime.Now;
feed.Id = OperationContext.Current.Host.BaseAddresses[0].ToString()
+ "/" + Guid.NewGuid().ToString();
feed.Title = new TextSyndicationContent("Sample feed");
SyndicationItem item= new SyndicationItem();
item.Title = new TextSyndicationContent( "sample feed" );
item.Content= new TextSyndicationContent("Time: " +
DateTime.Now.ToString());
item.Id= OperationContext.Current.Host.BaseAddresses[0].ToString()
+ "/" + Guid.NewGuid().ToString();
item.LastUpdatedTime= DateTime.Now;
List<SyndicationItem> items= new List<SyndicationItem>();
items.Add(item);
feed.Items = items;
Atom10FeedFormatter formatter = new Atom10FeedFormatter(feed);
return formatter;
}
As you can see, our sample operation is decorated with a WebCache attribute that references a specific caching profile. The details of the caching profile can either be configured as parameters of the WebCache attribute or as a configuration file section as illustrated in the following code.
<system.web>
...
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<clear/>
<add name="SampleProfile" duration="30" enabled="true"
location="Any" />
</outputCacheProfiles>
</outputCacheSettings>
</caching>
...
</system.web>
<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
<services>
<service name="SampleService"
behaviorConfiguration="ServiceBehavior">
<!-- Service Endpoints -->
<endpoint address="" binding="webHttpBinding"
contract="ISampleService">
…
</endpoint>
</service>
</services>
<behaviors>
...
</behaviors>
</system.serviceModel>
The configuration detailed above instructs ASP.NET to cache the results of the operation for thirty seconds. We can corroborate this by querying the following URI multiple times and checking the date returned in the Atom entry.
Although some scenarios might require different caching techniques, this model extend all the benefits of the ASP.NET caching programming model into WCF RESTFul services which directly a large variety of the most common caching use cases in real world REST-based solutions.
How does this work?
From the WCF programming model standpoint, the WebCache attribute is implemented as a WCF operation behavior.
[AttributeUsage(AttributeTargets.Method)]
public sealed class WebCacheAttribute : Attribute, IOperationBehavior
{
…Implementation omitted…
public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
{
…Implementation omitted…
dispatchOperation.ParameterInspectors.Add(
new CachingParameterInspector(…));
}
}
When the host initializes the behavior adds an instance of the CachingParameterInspector class to the dispatcher parameter inspector's collection. Ultimately, is this parameter inspector which executes the caching algorithms by leveraging the ASP.NET infrastructure.
If you are interested on getting deep into the things you can achieve with the WCF REST Starter Kit make sure you check the Hands On Labs available here.
Today Microsoft announced the first CTP of the WCF REST Starter Kit and the REST developer center.
This technology package includes a set of guidances, project templates and
extensibility components that complement the existing features of WCF 3.5 in
terms of RESTful services. Essentially, this packages addresses important aspects of real world RESTful scenarions such as caching, exception handling or security. I have been playing with this technology for a few
weeks now and I am really excited about it. I will be blogging some of my
thoughts and examples in the upcoming days.
Check out his reasooning here
A few days ago I participated in an interesting design session about an web Services identity federation solution. A lot of the debate was centered on the use of attribute and pseudonyms services for loosely coupled the security policies or client and services. As my article about Web Services Federated Identity Patterns was published recently on MSDN, I thought I could extract the sections on which I explain those patterns and blog about it so that you don't have to read the entire paper ;)
The use of attribute services is one of the classic derivations of Web Services Federation topologies on which one of the Security Token Services (IP/STS) can't issue tokens with just the information provided by the consumer. In other words, a STS might require more information than the one provided by the client in order to issue the corresponding tokens.
Why in the world would somebody do that? Well, confidentiality and privacy are some of the main drivers for this model in the sense that based on privacy requirements, only a subset of the consumer claims are used as part of the identity information issued by the IP/STS. The remaining consumer claims may be accessible to security entities such as IP/STSs but it should not be propagated to the different consumer applications.
Solution
The attributes needed for Web Services identity federation can be exposed via an Attribute Claim Service which can be invoked from the IP/STS and services on a Trust Domain. Using this service, either the IP/STS or the service itself can request more information about the requestor in order to complete the proper tasks. The following figure illustrates that concept.

Figure: Federation using an attribute claim service
In this scenario the consumer requests a security token from IP/STS-A which issues a security token and the claim set required for Trust Domain A. Then it will present that security token and claim set to an entity in Trust Domain B, which is either the service or IP/STS-B, depending of the federation pattern we are using. In order to complete the federation process, IP/STS-B might need some extra claims that are not included as part of the claim set issued by IP/STS-A. In this case, IP/STS-B would obtain those claims querying the attribute claim service and presenting the security token issued by IP/STS-A and its own security identity. This access is possible because the Trust relationship that exists between IP/STS-A and IP/STS-B allows this last one to present a valid set of claims and security tokens to the attribute service. This last step is required because the attribute claim service is typically part of the trust relationship between the two Trust Domains.
Although optional, the use of attribute claim services is becoming very popular in Web Services federation scenarios. Based on its flexibility, this pattern can be applied in a number of different topologies and is occasionally combined with the pseudonym service pattern. For instance, in some scenarios the attribute claim service and the IP/STS could be the same physical Web Service and in other scenarios they can be implemented as two separated Web Services in order to maximize the flexibility of the solution.
Although adding the BAM WCF-WF interceptors via .config files works for most of the scenarios, there are some cases on which you need to add these interceptors programmatically. Dealing with multiple BAM databases, dynamically enabling and disabling tracking and dynamically adjusting the polling intervals are some of the most common reasons for not relying 100% on the app.config configuration.
The techniques for adding the WF interceptor programmatically are well documented and essentially are not different from adding any other tracking service. The case of the WCF interceptors is a little different and requires us to implement a small trick. This is mostly given to the fact that the BamEndpointBehavior (WCF Endpoint Behavior) class which abstracts the BAM interceptor functionality is not public and consequently it can’t be added to the service endpoint behaviors collection. The trick to access this endpoint behavior is to invoke the CreateBehavior method of the BAM behavior extension element. Given that this is a protected operation we need to create a small class that inherits from the BamBehaviorExtension and provides access to the IEndpointBehavior. The following code illustrates the details.
private static void StartHost()
{
using (ServiceHost host = new
ServiceHost(typeof(FinancialTransactionService)))
{
WCFBAMProgExtension bamExtension= new WCFBAMProgExtension();
bamExtension.PrimaryImportConnectionString = "Connection String…";
bamExtension.PollingIntervalSec= 1500;
foreach(ServiceEndpoint endpoint in host.Description.Endpoints)
endpoint.Behaviors.Add(bamExtension.CurrentBAMBehavior);
host.Open();
Console.ReadLine();
host.Close();
}
}
internal class WCFBAMProgExtension : BamBehaviorExtension
{
public IEndpointBehavior CurrentBAMBehavior
{
get { return (IEndpointBehavior)base.CreateBehavior(); }
}
}
Two interesting REST-related documents have kept my
attention this week.
Also, I am super glad to see more interesting
initiatives evolving around AtomPub. For instance, this
specification proposes a representation for AtomPub multipart messages.
This is particularly useful for encoding binary data (MTOM kind stuff) using
AtomPub.
More Posts