Partager via


Interception in the Stock Trader: The News Module

Retired Content

This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This page may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.

The latest Enterprise Library information can be found at the Enterprise Library site.

patterns & practices Developer Center

On this page:
Caching through Interception | Catching and Handling Exceptions from the Service Boundary

In this chapter, we'll discuss how we've implemented interception in the Stock Trader V2 reference implementation.

Caching through Interception

To improve the performance of the news module, the news articles have to be cached. The News Module demonstrates how you can implement caching to asynchronous services using interception. The following diagram shows how the interception works.

Follow link to expand image

The ArticleViewModel initiates an asynchronous download by calling the BeginGetNews method on the NewsServiceAgent. When the download completes, the NewsServiceAgent will execute a callback that triggers the OnArticlesLoaded method on the ArticleViewModel.

The AsyncMethodCachingCallHandler intercepts the call to the BeginGetNews method. This call handler does require a specific method signature to work. The first parameter needs to identify the values to be cached; for example, the stock symbol that the news articles belong to. The second parameter needs to implement IAsyncServiceRequest because this controls how the callback should be executed and provides the mechanism for intercepting the callback. The following code sample shows the signature for the BeginGetNews method. This method was made virtual, because the interception mechanism uses the VirtualMethodInterceptor.

public virtual void BeginGetNews(string tickerSymbol,
       AsyncServiceRequest<ServiceListResult<NewsArticle>> asyncRequest)

The AsyncMethodCachingCallHandler checks if the requested news articles are already stored in the cache. If they are present in the cache, the cached news articles are returned immediately, by executing the callback. If the values were not in the cache, then the AsyncMethodCachingCallHandler will register itself to intercept the callback when it is executed. Because this is a callback, this cannot be done using Unity interception, so the callback will get intercepted explicitly by the AsyncMethodCachingCallHandler. The following code shows how the AsyncMethodCachingCallHandler intercepts the request:

public IMethodReturn Invoke(IMethodInvocation input, 
    GetNextHandlerDelegate getNext)
{
    // The first parameter should identify the data in the cache
    // The second parameter should be an IAsyncServiceREquest
    IAsyncServiceRequest request = input.Arguments[1] as IAsyncServiceRequest;

    if (request == null)
    {
        throw new InvalidOperationException(
           "Second parameter is not assignable to IAsyncServiceRequest");
    }

    // See if the item was already cached. 
    var cachedValue = (objectCache.Get(BuildCacheKey(input)));
    if (cachedValue != null)
    {
        // Item was already cached. Raise the callback with the 
        // cached value and return immediately
        request.ReturnResult(cachedValue);
 
        // By returning here, we can prevent the intercepted object
        // from being called
        return input.CreateMethodReturn(null);
    }

    // The item was not already cached. We'll need to wait until the 
    // callback and then return
    request.OnCallback += (sender, args) => 
         objectCache.Set(BuildCacheKey(input), args.Result, policy);
 
    // continue with calling the original intercepted method
    return getNext()(input, getNext);
}

Once the news articles have been loaded by the News Service Agent and it executes the callback to notify the UI, this method also gets intercepted. The AsyncMethodCachingCallHandler will then add the loaded news articles to the cache.

The Stock Trader V2 automatically sets up all types for interception through policy injection using the VirtualMethodInterceptor. How this works is described in more detail in the section called Enabling Policy Injection for all Registered Types. The NewsModule, which is also responsible for registering the NewsServiceAgent to the container, also creates a policy that sets up the AsyncMethodCachingCallHandler. The following code shows how this works:

unityContainer.Configure<Interception>()
    .AddPolicy("Cache")
    .AddMatchingRule<TypeMatchingRule>(new InjectionConstructor(
         new InjectionParameter(typeof(NewsServiceAgent))))
    .AddCallHandler<AsyncMethodCachingCallHandler>(
        new InjectionConstructor(new ResolvedParameter(typeof(ObjectCache)),
                                 new InjectionParameter(cacheItemPolicy)));

Catching and Handling Exceptions from the Service Boundary

The Stock Trader V2 relies heavily on web services for its information. While these web services are built in different technologies, such as regular Windows® Communication Foundation (WCF) Services, WCF RIA Services, and WCF Data Services, there are some common requirements with regards to exception handling:

  • If a technical exception has occurred while accessing a service, we need to create a log entry for this exception so that the problem can be analyzed by the support organization.
  • If the exception is a functional exception, for example a validation exception, then the validation results must be extracted from the exception and returned to the user interface.

In the news module, exception handling for service requests is implemented using interception. With synchronous exception handling, this would be really easy to implement, because Enterprise Library ships with the ExceptionCallHandler, which is a policy injection call handler that you can use to catch and handle any exceptions that occur within an intercepted member (and that are surfaced by the method).

With asynchronous methods, this technique cannot be easily applied. As described in the chapter on exception handling, if you wish to pass an exception back up to the user interface, you will need to do it explicitly.

The following code shows the OnNewsLoaded method from the NewsServiceAgent class that's called when the news is loaded. If the loadOperation has an error, it will be returned to the user interface by calling the ReturnError method from the AsyncRequest class. The AsyncExceptionHandlingCallHandler class will intercept the exception and use the Enterprise Library Exception Handling Application Block to handle it. If the exception was not handled, then the MarkErrorAsHandled method will not be called. This will re-throw the exception, which will trigger the Application.Unhandled_Exception event.

private void OnNewsLoaded(LoadOperation<NewsItem> loadOperation)
{
    var asyncRequest = AsyncServiceRequest<ServiceListResult<NewsArticle>>.RestoreFromUserState(loadOperation.UserState);
    var firstEntity = loadOperation.Entities.FirstOrDefault();

    if (loadOperation.HasError)
    {
        // Return the exception to the user interface. Here, it will be handled
        // by the AsyncexceptionHandlingCallHandler class. 
        if (asyncRequest.ReturnError(loadOperation.Error).IsHandled)
        {
            loadOperation.MarkErrorAsHandled();
        }
        return;
    }

    if (firstEntity == null)
    {
        asyncRequest.ReturnEmpty();
        return;
    }
            
    List<NewsArticle> result = GetNewsArticles(loadOperation);

    asyncRequest.ReturnResult(new ServiceListResult<NewsArticle>(result));

}

Next Topic | Previous Topic | Home

Last built: July 8, 2011