October 2010 - Posts

One of the common problems that you might find when using the generated DataServiceContext for consuming an existing WCF data service is that you have magic strings everywhere for handling links (expanding, adding, deleting, etc). The problem with all those magic strings is that they make your code to compile correctly, but you might run into some error at runtime because you used a link that does not exist or it was just renamed.

To give an example, this is how you expand the items associated to an order using the traditional way with magic strings.

context.Orders.Expand(“Items”)

If that property is later renamed to “OrderItems” on the service side, and the proxy is updated, that code will still compile but you will receive an error at runtime.

Fortunately, you can get rid of those “magic” strings and making the compiler your friend by leveraging Expression trees. The expression trees will make your code easier to maintain, and what’s more important, the compiler will verify the expressions correctness at compilation time.

Continuing what Stuart Leeks did for link expansions with expressions, I added a few more methods for managing links. 

namespace System.Data.Services.Client
{
    public static class DataServiceExtensions
    {
        public static void SetLink<TSource, TPropType>(this DataServiceContext context, TSource source, 
            Expression<Func<TSource, TPropType>> propertySelector, object target)
        {
            string expandString = BuildString(propertySelector);
            context.SetLink(source, expandString, target);
        }
 
        public static void AddLink<TSource, TPropType>(this DataServiceContext context, 
            TSource source, Expression<Func<TSource, TPropType>> propertySelector, object target)
        {
            string expandString = BuildString(propertySelector);
            context.AddLink(source, expandString, target);
        }
 
        public static void DeleteLink<TSource, TPropType>(this DataServiceContext context, 
            TSource source, Expression<Func<TSource, TPropType>> propertySelector, object target)
        {
            string expandString = BuildString(propertySelector);
            context.DeleteLink(source, expandString, target);
        }
 
        public static void LoadProperty<TSource, TPropType>(this DataServiceContext context, 
            TSource source, Expression<Func<TSource, TPropType>> propertySelector)
        {
            string expandString = BuildString(propertySelector);
            context.LoadProperty(source, expandString);
        }
 
        public static DataServiceQuery<TSource> Expand<TSource, TPropType>(this DataServiceQuery<TSource> source, 
            Expression<Func<TSource, TPropType>> propertySelector)
        {
            string expandString = BuildString(propertySelector);
            return source.Expand(expandString);
        }
 
        private static string BuildString(Expression propertySelector)
        {
            switch (propertySelector.NodeType)
            {
                case ExpressionType.Lambda:
                    LambdaExpression lambdaExpression = (LambdaExpression)propertySelector;
                    return BuildString(lambdaExpression.Body);
 
                case ExpressionType.Quote:
                    UnaryExpression unaryExpression = (UnaryExpression)propertySelector;
                    return BuildString(unaryExpression.Operand);
 
                case ExpressionType.MemberAccess:
                    MemberInfo propertyInfo = ((MemberExpression)propertySelector).Member;
                    return propertyInfo.Name;
 
                case ExpressionType.Call:
                    MethodCallExpression methodCallExpression = (MethodCallExpression)propertySelector;
                    if (IsSubExpand(methodCallExpression.Method)) // check that it's a SubExpand call
                    {
                        // argument 0 is the expression to which the SubExpand is applied (this could be member access or another SubExpand)
                        // argument 1 is the expression to apply to get the expanded property
                        // Pass both to BuildString to get the full expression
                        return BuildString(methodCallExpression.Arguments[0]) + "/" +
                               BuildString(methodCallExpression.Arguments[1]);
                    }
                    // else drop out and throw
                    break;
            }
            throw new InvalidOperationException("Expression must be a member expression or an SubExpand call: " + propertySelector.ToString());
 
        }
 
        private static readonly MethodInfo[] SubExpandMethods;
        static DataServiceExtensions()
        {
            Type type = typeof(DataServiceExtensions);
            SubExpandMethods = type.GetMethods().Where(mi => mi.Name == "SubExpand").ToArray();
        }
        private static bool IsSubExpand(MethodInfo methodInfo)
        {
            if (methodInfo.IsGenericMethod)
            {
                if (!methodInfo.IsGenericMethodDefinition)
                {
                    methodInfo = methodInfo.GetGenericMethodDefinition();
                }
            }
            return SubExpandMethods.Contains(methodInfo);
        }
 
        public static TPropType SubExpand<TSource, TPropType>(this Collection<TSource> source, Expression<Func<TSource, TPropType>> propertySelector)
            where TSource : class
            where TPropType : class
        {
            throw new InvalidOperationException("This method is only intended for use with DataServiceQueryExtensions.Expand"); 
        }
 
        public static TPropType SubExpand<TSource, TPropType>(this TSource source, Expression<Func<TSource, TPropType>> propertySelector)
            where TSource : class
            where TPropType : class
        {
            throw new InvalidOperationException("This method is only intended for use with DataServiceQueryExtensions.Expand"); 
        }
    }
}

With all these extensions in place you can do the following things,

1. Expanding a collection

context.Orders.Expand(o => o.Items)

2. Expanding a collection and subcollection

context.Orders.Expand(o => o.Items.SubExpand(i => i.Product))

3. Adding a link

context.AddLink(order, o => o.Items, item)

4. Removing a link

context.DeleteLink(order, o => o.Items, item)

5. Loading an association

context.LoadProperty(order, o => o.Items)

Posted by cibrax | 2 comment(s)

A UI driven service is usually a service implementation that only makes sense in the context of the UI for solving an specific use case, and not something that you might want to share or expose to third parties. Typical examples of UI driven services are AJAX endpoints, which you build for supporting partial updates in a page. The implementation of this kind of services can take the form of a simple http endpoints, which could adhere to the REST principles or not, or SOAP web services.   

As the AJAX endpoints are consumed by the web browser on behalf of the user, you will typically want to propagate the web browser security context to this service, and not a new one, so the web pages and the services both run under the same user identity.

If the web pages and the services are both running in the same hosting stack like ASP.NET, this does not represent a problem at all, as they both share the security context of the host. For example, if you implement the services as ASMX web services, or Http Handlers, or MVC controller actions, they will all share the ASP.NET security context with the pages.

WCF runs by default in its own hosting space, which is not dependant of ASP.NET, so here is where the problem begins. Message security is obviously discarded for this scenario, as a client script does not know how to handle cryptographic material for doing all the message signing and encryption. In addition, it would add some unnecessary complexity to the solution, which is not need for the scenarios that an AJAX endpoint tries to achieve. Therefore, transport security is the right choice for WCF Ajax endpoints if you want to encrypt the traffic with SSL, and none if the information does not need to be encrypted because it is not sensitive. In both cases, the right choice for a binding is “basicHttpBinding” for SOAP services and “webHttpBinding” for any other Http endpoint that does not use soap envelopes.

For example, the following binding configures a SOAP service with “basicHttpBinding” and no security.

<basicHttpBinding>
        <binding name="AjaxEndpoints">
          <security mode="None"></security>
        </binding>
</basicHttpBinding>

In addition, as you want to propagate the user identity from ASP.NET to the WCF services. You need to enable the ASP.NET compatibility mode in the service, so ASP.NET and the WCF Ajax services both share the same user identity, no matter which security mechanism was configured in ASP.NET (forms, claims, or any http authentication mechanism).

For enabling the ASP.NET compatibility mode, you have to add the following configuration to the serviceModel section,

<system.serviceModel>
<serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>


And decorate your service with the AspNetCompatibilityRequirements attribute,

[AspNetCompatibilityRequirements(RequirementsMode=AspNetCompatibilityRequirementsMode.Allowed)]
public class Service1 : IService1
Posted by cibrax | 2 comment(s)
Filed under: , ,

I am happy to announce today the support in Visual Studio 2008 for adding new service references from the SO-Aware service repository. We have created a simple plugin that you can register in Visual Studio to support this new functionality.

The functionality provided by this plugin is equivalent to what you already have for Visual Studio 2010. A new option is added to the project context menu “Add Service Reference From SO-Aware”, which is almost similar to the classic “Add Service Reference” option with the difference that you can look for existing services in the repository and the generated proxy derives from ConfigurableClientBase<T> rather than ClientBase<T>

AddServiceReference

Once you clicked in that option, a new screen will appear to select one of the existing services in the repository.

Repository

The generated proxy will have methods to consume the service operation as any regular service proxy, but also two methods that are specific to WCF for optionally configuring a client behavior (SetClientBehavior) or a binding (SetDefaultBinding) from the repository. These are optional as otherwise, the behaviors and bindings configured for the service in the repository will be used.

CustomersClient client = new CustomersClient();
client.SetClientBehavior("BehaviorName");
client.SetDefaultBinding("BindingName");

Those methods receive an string with the name of the behavior or binding you want to resolve from the repository, so there is no need to have the “serviceModel” configuration section anymore :).

This new plugin is available as part of the SO-Aware SDK that you can get from here.

Posted by cibrax
Filed under: , ,

Disclaimer: This post only contains personal opinions about this subject

In the way I see it, REST mainly comes in for two scenarios, when you need to expose some AJAX endpoints for your web application or when you need to expose an API to external applications through well defined services.  

For AJAX endpoints, the scenario is clear, you want to expose some data for being consumed by different web pages with client scripts. At this point, what you expose is either HTML, text, plain XML, or JSON, which is the most common, compact and efficient format for dealing with data in javascript. Different client libraries like JQuery or MooTools already come with built-in support for JSON. This data is not intended for being consumed by other clients rather than the pages running in the same web domain. In fact, some companies add custom logic in these endpoints for responding only to requests originated in the same domain.

For RESTful services, the scenario is completely different, you want to expose data or business logic to many different client applications through a well know API. Good examples of REST services are twitter, the Windows Azure storage services or the Amazon S3 services to name a few.

Smart client applications implemented with Silverlight, Flex or Adobe Air also represent client applications that can be included in this category with some restrictions, as they can not make cross domain call to http services by default unless you override the cross-domain policies.   

A common misconception is to think that REST services only mean CRUD for data, which is one of the most common scenarios, but business workflows can also be exposed through this kind of service as it is shown in this article “How to get a cup of coffe”

When it comes to the .NET world, you have three options for implementing REST services (I am not considering third party framework or OS projects in this post),

  1. ASP.NET MVC
  2. WCF REST
  3. WCF Data Services (OData)

ASP.NET MVC

This framework represents the implementation of the popular model-view-controller (MVC) pattern for building web applications in the .NET space. The reason for moving traditional web application development toward this pattern is to produce more testable components by having a clean separation of concerns. The three components in this architecture are the model, which only represents data that is shared between the view and the controller, the view, which knows how to render output results for different web agents (i.e. a web browser), and finally the controller, which coordinates the execution of an use case and the place where all the main logic associated to the application lives on. Testing ASP.NET Forms applications was pretty hard, as the implementation of a page usually mixed business logic with rendering details, the view and the controller were tied together, and therefore you did not have a way to focus testing efforts on the business logic only. You could prepare your asp.net forms application to use MVC or MVP (Model-View-Presenter) patterns to have all that logic separated, but the framework itself did not enforce that.

On the other hand, in ASP.NET MVC, the framework itself drives the design of the web application to follow an MVC pattern. Although it is not common, developers can still make terrible mistakes by putting business logic in the views, but in general, the main logic for the application will be in the controllers, and those are the ones you will want to test.

In addition, controllers are TDD friendly, and the ASP.NET MVC team has made a great work by making sure that all the ASP.NET intrinsic objects like the Http Context, Sessions, Request or Response can be mocked in an unit test.

While this framework represents a great addition for building web applications on top of ASP.NET, the API or some components in the framework (like view engines) not necessarily make a lot of sense when building stand alone services. I am not saying that you could not build REST services with ASP.NET MVC, but you will have to leverage some of the framework extensibility points to support some of the scenarios you might want to use with this kind of services.

Content negotiation is a good example of an scenario not supported by default in the framework, but something you can implement on your own using some of the available extensions. For example, if you do not want to tie your controller method implementation to an specific content type, you should return an specific ActionResult implementation that would know how to handle and serialize the response in all the supported content types. Same thing for request messages, you might need to implement model binders for mapping different content types to the objects actually expected by the controller.

The public API for the controller also exposes methods that are more oriented to build web applications rather than services. For instance, you have methods for rendering javascript content, or for storing temporary data for the views.

If you are already developing a website with ASP.NET MVC, and you need to expose some AJAX endpoints (which actually represents UI driven services) for being consumed in the views, probably the best thing you can do is to implement them with MVC too as operations in the controller. It does not make sense at this point to bring WCF to implement those, as it would only complicate the overall architecture of the application. WCF would only make sense if you need to implement some business driven services that need to be consumed by your MVC application and some other possible clients applications as well.

This framework also introduced a new routing mechanism for mapping URLs to controller actions in ASP.NET, making possible to have friendly and nice URLS for exposing the different resources in the API.

As this framework is layered on top of ASP.NET, one thing you might find complicated to implement is security. Security in ASP.NET is commonly tied to a web application, so it is hard to support schemes where you need different authentication mechanisms for your services. For example, if you have basic authentication enabled for the web application hosting the services, it would be complicated to support other authentication mechanism like OAuth. You can  develop custom modules for handling these scenarios, but that is something else you need to implement.   

WCF REST

The WCF Web Http programming model was first introduced as part of the .NET framework 3.5 SP1 for building non-SOAP http services that might follow or not the different REST architectural constraint. This new model brought to the scene some new capabilities for WCF by adding new attributes in the service model ([WebGet] and [WebInvoke]) for routing messages to service operations through URIs and Http methods, behaviors for doing same basic content negotiation and exception handling, a new WebOperationContext static object for getting access and controlling different http header and messages, and finally a new binding WebHttpBinding for handling some underline details related to the http protocol.

The WCF team later released an REST starter kit in codeplex with new features on top of this web programming model to help developers to produce more RESTful services. This starter kit also included a combination of examples and Visual Studio templates for showing how some of the REST constraints could be implemented in WCF, and also a couple of interesting features to support help pages, output caching, intercepting request messages and a very useful Http client library for consuming existing services (HttpClient)

Many of those features were finally included in the latest WCF release, 4.0, and also the ability of routing messages to the services with friendly URLs using the same ASP.NET routing mechanism that ASP.NET MVC uses.

As services are first citizens in WCF, you have exclusive control over security, message size quotas and throttling for every individual services and not for all services running in a host as it would happen with ASP.NET.  In addition, WCF provides its own hosting infrastructure, which is not dependant of ASP.NET so it is possible to self hosting services in any regular .NET application like a windows service for example.

In the case of hosting services in ASP.NET with IIS, previous versions of WCF (3.0 and 3.5) relied on a file with “svc” extension to activate the service host when a new message arrived. WCF 4.0 now supports file-less activation for services hosted in ASP.NET, which relies on a configuration setting, and also a mechanism based on Http routing equivalent to what ASP.NET MVC provides, making possible to support friendly URLs. However, there is an slight difference in the way this last one works compared to ASP.NET MVC. In ASP.NET MVC, a route specifies the controller and also the operation or method that should handle a message. In WCF, the route is associated to a factory that knows how to create new instances of the service host associated to the service, and URI templates attached to [WebGet] and [WebInkoke] attributes in the operations take care of the final routing. This approach works much better in the way I see it, as you can create an URI schema more oriented to resources, and route messages based on Http Verbs as well without needing to redefine additional routes. 

The support for doing TDD at this point is somehow limited fore the fact that services rely on the static context class for getting and setting http headers, making very difficult to initialize that one in a test or mock it for setting some expectations.

The content negotiation story was improved in WCF 4.0, but it still needs some twists to make it complete as you might need to extend the default WebContentTypeMapper class for supporting custom media types other than the standard “application/xml” for xml and “application/json” for JSON.

The WCF team is seriously considering to improve these last two aspects and adding some other capabilities to the stack for a next version.

WCF Data Services

WCF Data Services, formerly called ADO.NET Data Services, was introduced in the .NET stack as way of making any IQueryable data source public to the world through a REST API. Although a WCF Data Service sits on top of the WCF Web programming model, and therefore is a regular WCF service, I wanted to make a distinction here for the fact that this kind of service exposes metadata for the consumers, and also adds some restrictions for the URIs and the types that can be exposed in the service. All these features and restrictions have been documented and published as a separate specification known as OData. 

The framework includes a set of providers or extensibility points that you can customize to make your model writable, extend the available metadata, intercepting messages or supporting different paging and querying schemas. 

A WCF Data Service basically uses URI segments as mechanism for expressing queries that can be translated to an underline linq provider, making possible to execute the queries on the data source itself, and not something that happens in memory. The result of executing those queries is what finally got returned as response from the service. Therefore, WCF Data services use URI segments to express many of supported linq operators, and the entities that need to be retrieved. This capability of course is what limit the URI space that you can use on your service, as any URI that does not follow the OData standard will result in an error.

Content negotiation is also limited to two media types, JSON and Xml Atom, and the content payload itself is restricted to specific types that you can find as part of the OData specification.

Besides of those two limitations, WCF Data Service is still extremely useful for exposing a complete data set with query capabilities through a REST interface with just a few lines of code. JSON and Atom are two very accepted formats nowadays, making this technology very appealing for exposing data that can easily be consumed by any existing client platform, and even web browsers.

Also, for Web applications with ajax and smart client applications, you do not need to reinvent the wheel and create a complete set of services for just exposing data with a CRUD interface. You get your existing data model, configure some views or filters for the data you want to expose in the model in the data service itself, and that is all.          

Posted by cibrax | 6 comment(s)
Filed under: , , ,
More Posts