Showing posts with label XML. Show all posts
Showing posts with label XML. Show all posts

Monday, June 6, 2011

Messin’ with the WCF Web API, part II – Content Negotiation & Formatters

In the last post, I briefly introduced the WCF Web API and walked through the creation of the first service that I constructed as I was experimenting with the framework. WCF Web API has a couple more tricks that it does. In this post I’d like to look at Formatters and their part in Content Negotiation.

Content Negotiation

In section 6.3.2.7 of his dissertation, Architectural Styles and the Design of Network-based Software Architectures, Roy Fielding describes Content Negotiation:

All resources map a request (consisting of method, identifier, request-header fields, and
sometimes a representation) to a response (consisting of a status code, response-header
fields, and sometimes a representation). When an HTTP request maps to multiple
representations on the server, the server may engage in content negotiation with the client in order to determine which one best meets the client’s needs. This is really more of a “content selection” process than negotiation.

So what does this mean? Let’s take a look at this in action. I’ll use the service that I built in the last post.

Using Fiddler I captured the request to retrieve the Xbox game with the ID of 12. That request looks like:

GET http://localhost:1064/MessinWebApi/games/12 HTTP/1.1
Accept: application/xml
Accept-Language: en-US
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: localhost:1064

And the response:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 405
Content-Type: application/xml; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcTWlrZVxEb2N1bWVudHNcVmlzdWFsIFN0dWRpbyAyMDEwXFByb2plY3RzXE1lc3NpbldlYkFwaVxNZXNzaW5XZWJBcGlPbmVcTWVzc2luV2ViQXBpT25lXGdhbWVzXDEy?=
X-Powered-By: ASP.NET
Date: Mon, 06 Jun 2011 00:51:12 GMT

<?xml version="1.0" encoding="utf-8"?><Game><Id>12</Id><Description>James Cameron's Dark Angel</Description><Developer>Radical Entertainment</Developer><Genre><Id>53</Id><Name>Action</Name></Genre><Name>James Cameron's Dark Angel</Name><Price>49.990000</Price><Publisher>Radical Entertainment</Publisher><Rating><Id>4</Id><Name>T (Teen)</Name></Rating><ReleaseDate>2002-09-01T00:00:00</ReleaseDate></Game>

And again:

GET http://localhost:1064/MessinWebApi/games/12 HTTP/1.1
Accept: application/json
Accept-Language: en-US
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: localhost:1064

And the response:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 293
Content-Type: application/json; charset=utf-8
Server: Microsoft-IIS/7.5
X-AspNet-Version: 4.0.30319
X-SourceFiles: =?UTF-8?B?QzpcVXNlcnNcTWlrZVxEb2N1bWVudHNcVmlzdWFsIFN0dWRpbyAyMDEwXFByb2plY3RzXE1lc3NpbldlYkFwaVxNZXNzaW5XZWJBcGlPbmVcTWVzc2luV2ViQXBpT25lXGdhbWVzXDEy?=
X-Powered-By: ASP.NET
Date: Mon, 06 Jun 2011 00:53:54 GMT

{"Description":"James Cameron's Dark Angel","Developer":"Radical Entertainment","Genre":{"Id":53,"Name":"Action"},"Id":12,"Name":"James Cameron's Dark Angel","Price":49.990000,"Publisher":"Radical Entertainment","Rating":{"Id":4,"Name":"T (Teen)"},"ReleaseDate":"\/Date(1030852800000-0400)\/"}

Now I didn’t make any changes to the service between those two requests. I only changed the Accept header in the request. For the first request I used a value of application/xml and application/json was used in the second. This is Content Negotiation. The client (Fiddler in this case) is using the Accept header to indicate the response formats that it can handle.

Note: To be fair, Content Negotiation can also be used to specify other preferences like encodings and language.

The client is free to indicate more than one format, or Media Type, as the value for the Accept header. The convention is that the values are specified in order of preference. The service is then free to use any of the specified formats that it can reproduce.

The role of rendering a response into the requested media type falls to the Formatters. These are components of the pipeline that I mentioned in the first post. The reason that I’m bringing this up at this point in time, seemingly out of order, is to introduce the base functionality that you get for free: the ability to product XML and JSON straight out of the box.

Custom Formatters

Xml and JSON are covered. You’ll need a custom formatter for anything else and luckily Microsoft has made it super easy to create them. The complexity required is dependent on the representation of the response that you’re trying to create. To demonstrate this, I’m going to create a custom formatter that returns the cover image for each game. When Shawn Wildermuth put together the Xbox games sample database, he included the cover image, as a jpg, in the Games table. My custom formatter is going to take the image and stream it back to the caller.

Note: I wish I could claim this as an original idea but it’s not. The sample application that ships with the WCF Web API has similar functionality. I’m just translating the functionality as appropriate for this data set.

To start I need to have Entity Framework return the Image column when a game is retrieved. To accomplish this I just have to add a property to the Game class with the same name as the field in the table:

    public class Game
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public string Developer { get; set; }
        public Genre Genre { get; set; }
        public string Name { get; set; }
        public decimal? Price { get; set; }
        public string Publisher { get; set; }
        public Rating Rating { get; set; }
        public DateTime? ReleaseDate { get; set; }
        public byte[] Image { get; set; }
    }



Next I create a new folder in the solution called Formatters and add the following new class, ImageFormatter:


    public class ImageFormatter : MediaTypeFormatter
    {
        public ImageFormatter()
        {
            this.SupportedMediaTypes.Add(new MediaTypeHeaderValue("image/jpeg"));
        }
 
        protected override bool OnCanReadType(Type type)
        {
            return false;
        }
 
        protected override bool OnCanWriteType(Type type)
        {
            return typeof (Game) == type;
        }
 
        public override object OnReadFromStream(Type type, Stream stream, HttpContentHeaders contentHeaders)
        {
            throw new NotImplementedException();
        }
 
        public override void OnWriteToStream(Type type, object value, Stream stream, HttpContentHeaders contentHeaders, TransportContext context)
        {
            var game = value as Game;
 
            // it would probably be better to write some null image - {shurg}
            if (null == game) return;
            if (null == game.Image) return;
            if (0 == game.Image.Length) return;
 
            stream.Write(game.Image, 0, game.Image.Length);
 
            contentHeaders.ContentType = new MediaTypeHeaderValue("image/jpeg");
        }
    }



I believe the code is pretty simple to follow. I just want to point out a couple of things. In the ctor, I’m adding the image/jpeg media type to the collection of media types supported by this formatter. I’ve also provided an override for the OnCanWriteType() method. With those two pieces in place, I’m instructing the WCF Web API pipeline that this formatter can create an image/jpeg representation of instances of Game.


The last piece is to adjust the configuration so that WCF Web API will include the formatter in the pipeline. This is done when the routes are registered in Global.asax:


        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
            var config = HttpHostConfiguration.Create()
                .AddFormatters(new ImageFormatter());
 
            routes.MapServiceRoute<GamesResource>("games", config);
 
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
        }



To retrieve the cover image, I make a request for a specific game, just as in the previous two examples, but use the value "image/jpeg” for the Accept header:


GET http://localhost:1064/MessinWebApi/games/12 HTTP/1.1
Accept: image/jpeg
Accept-Language: en-US
User-Agent: Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
Accept-Encoding: gzip, deflate
Connection: Keep-Alive
Host: localhost:1064


Fiddler is kind enough to render the image for me:


image



Note: the art of the cover image is probably copy written by someone. All rights belong to them.


Formatters are a key component of the pipeline. A formatter will be responsible for creating a representation of a resource and the WCF Web API will handle engaging the correct formatter based on the Accept header in the request.

Sunday, June 5, 2011

Messin’ with the WCF Web API

Back in April, Microsoft released the fourth preview of WCF Web API on CodePlex. The intent of the WCF Web API is to make it easier to expose application data and services over HTTP. I’ve seen a lot of people throw in the REST descriptor but I’m not ready to go there yet.

I’ve spent the last couple of weeks playing with the WCF Web API and I’ve decided to put what I’ve learned out there for others. I’m imagining a series of posts but we’ll have to see where my schedule allows me to go.

In this first post, I want to basically put down the steps that I used to get started; consider this a step above the traditional Hello World program.

It’s all about the data

To get started, I first needed something to serve up. There is always the typical Northwind or AdventureWorks database that everyone is probably already familiar with. Instead, I went for something different. Shawn Wildermuth has been kind enough to to make available a database of XBox games. I’m running SQL Server 2008 so I grabbed the appropriate zip file and attached the database that is contained within it.

Next I need a host. A WCF service can be hosted within a number of application. I going to use an ASP.NET MVC 3 Application.

As long as I’m playing with new tech, I’m going to use the Code First features of Entity Framework 4. If you’re following along at home and Entity Framework isn’t already installed, you can get it via NuGet. The package name is EntityFramework.

The next thing is to create some classes that EF will use to expose the data in the Xbox games database. I’ll create three: Game, Genre and Rating and put them in the Models folder. This seemed like a good enough place to store them for now. I can always move them later.

    public class Game
    {
        public int Id { get; set; }
        public string Description { get; set; }
        public string Developer { get; set; }
        public Genre Genre { get; set; }
        public string Name { get; set; }
        public decimal? Price { get; set; }
        public string Publisher { get; set; }
        public Rating Rating { get; set; }
        public DateTime? ReleaseDate { get; set; }
    }



    public class Genre
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }



    public class Rating
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }



The data is accessed through an instance of DbContext. Mine looks like this:


    public class XBoxGames : DbContext
    {
        public DbSet<Game> Games { get; set; }
        public DbSet<Genre> Genres { get; set; }
        public DbSet<Rating> Ratings { get; set; }
 
        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
 
            modelBuilder.Entity<Genre>().ToTable("Genres", "SimpleGames");
            modelBuilder.Entity<Genre>().HasKey(g => g.Id);
            modelBuilder.Entity<Genre>().Property(g => g.Id).HasColumnName("GenreID");
 
            modelBuilder.Entity<Rating>().ToTable("Ratings", "SimpleGames");
            modelBuilder.Entity<Rating>().HasKey(g => g.Id);
            modelBuilder.Entity<Rating>().Property(r => r.Id).HasColumnName("RatingID");
 
            modelBuilder.Entity<Game>().ToTable("Games", "SimpleGames");
            modelBuilder.Entity<Game>().HasKey(g => g.Id);
            modelBuilder.Entity<Game>().Property(g => g.Id).HasColumnName("GameID");
 
            modelBuilder.Entity<Game>()
                .HasOptional(g => g.Genre)
                .WithMany()
                .Map(m => m.MapKey("Genre"));
 
            modelBuilder.Entity<Game>()
                .HasOptional(g => g.Rating)
                .WithMany()
                .Map(m=>m.MapKey("Rating"));
        }
    }



The three properties Games, Genres and Ratings are used to access and manipulate the data using Linq. The OnModelCreating() override is the key to the Code First implementation. This method contains the mapping of the tables to the classes and defines the relationships between the tables, in terms of the classes.


The last item is to tell Entity Framework where to find the database. I’ve added the following connection string to the web.config file:


  <connectionStrings>
    <add name="XBoxGames"
         connectionString="data source=.\SQLEXPRESS; Integrated Security=SSPI; database=XBoxGames"
          providerName="System.Data.SqlClient"/>
  </connectionStrings>



 


Resources


The next step is to expose the game data over HTTP. If you were wondering when I’d get to WCF Web API, well, that’s now.


Like EntityFramework, WCF Web API can be added to the project using NuGet. The package to install is WebApi.All


image


The nice thing about using NuGet to add libraries to your solution is that it will automatically pickup any dependencies that are required. I needed four.


I’ve decided to create a resource called GamesResource and expose it over HTTP.


    [ServiceContract]
    public class GamesResource
    {
        [WebGet(UriTemplate = "")]
        public List<Game> GetGames()
        {
 
            using (var gamesRepository = new XBoxGames())
            {
                return gamesRepository
                    .Games
                    .AsNoTracking()
                    .OrderBy(g => g.Id)
                    .Include("Genre")
                    .Include("Rating")
                    .ToList();
            }
        }
    }



Accessing this resource will return a list of all the games, sorted by the game ID.



Note: Returning the entire table via HTTP is probably a very unlikely scenario, if for no other reason than you are stressing your network and server resources. The most common mitigation is to provide either filtering or paging capabilities. I plan to add paging in a future post.


The last thing that I have to do is add some configuration that exposes the new GamesResource. Within Global.asax.cs, I’ve changed the RegisterRoutes() method to:


        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
            routes.MapServiceRoute<GamesResource>("games");
 
            routes.MapRoute(
                "Default", // Route name
                "{controller}/{action}/{id}", // URL with parameters
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
            );
        }



The call to MapServiceRoute() exposes the GamesResource as an Uri whose path starts with “games”. For example, the Uri http://localhost/games would be directed to our GetGames() method within GamesResource.


Starting the site with F5 and navigating to the games resource (for me is: http://localhost:1064/MessinWebApi/games) displays the list of games, encoded using Xml!


image


Returning a single game


I now want to allow the consumer of my service to fetch a single game using an Uri similar to http://localhost/games/12. This is easy and built into the WCF Web API via the UriTemplate parameter of the WebGet Attribute. This will look familiar if you’ve worked with ASP.Net MVC routing.


I’m going to add a new method to GamesResource called GetSingleGame():


        [WebGet(UriTemplate = "{id}")]
        public Game GetSingleGame(string id)
        {
            using (var gamesRepository = new XBoxGames())
            {
                int idToFind = int.Parse(id);
 
                return gamesRepository
                    .Games
                    .AsNoTracking()
                    .Include("Genre")
                    .Include("Rating")
                    .Where(g => g.Id == idToFind)
                    .FirstOrDefault();
 
            }
        }

 

 

GetSingleGame() is very similar to GetGames() with the exception that I have defined a token called {id} within the UriTemplate property of the WebGet attribute and I’ve added a parameter to GetSingleGame() to receive the value. The WCF Web API infrastructure will handle parsing the incoming request to get the ID and making the appropriate call to GetSingleGame().


When put into motion, a request for the game with an ID of 12 (http://localhost:1064/MessinWebApi/games/12) results in the following Xml:


image


This is just the “tip of the iceberg” for WCF Web Api. There is a very extensible pipeline built into the framework. I plan to explore some of these features in future posts.

Sunday, August 29, 2010

Register Spring.Net objects with code

Anyone that has worked with Spring.Net is probably familiar with configuring the IOC container using an XML document. A typical example would be:

   2:  
   3: <objects xmlns="http://www.springframework.net" 
   4:          xmlns:v='http://www.springframework.net/validation' 
   5:          xmlns:aop="http://www.springframework.net/aop" 
   6:          xmlns:db="http://www.springframework.net/db" 
   8:  
   1: <?xml version="1.0" encoding="utf-8"?>
   9:   <object id="ConsoleWriter" type="SimpleCalculatorWithComplexTree.Writers.ConsoleWriter" singleton="false" >
  10:     <constructor-arg name="formatter" ref="HexFormatter" />
  11:   </object>
  12:  
  13:   <object id="Calculator" type="SimpleCalculatorWithComplexTree.Calculator" singleton="false">
  14:     <constructor-arg name="writer" ref="ConsoleWriter" />
  15:   </object>
  16:  
  17:   <object id="HexFormatter" type="SimpleCalculatorWithComplexTree.Formatters.HexFormatter" singleton="false" >
  18:     
  19:   </object>
  20:   
  21: </objects>

The last couple of years has seen an anti-XML movement begin to form. In the world of IOC containers, this has materialized as a movement away from XML configuration and more towards using code constructs and “convention over configuration.” I’m not against XML. After all, almost everything has a place.


I recently did a presentation on Spring.Net for a .NET user group. I wanted to introduce the IOC container without overwhelming people with XML. A quick search found an article about XMLless configuration of the container. This approach felt like it would be a distraction from my goal of getting to the container.


Luckily I stumbled into at article from early 2008 that discussed the configuration api. From this I was able to create this method that extends the GenericApplicationContext and allows for easy registration of a type in the container:



   1: Imports System.Runtime.CompilerServices
   2: Imports Spring.Context.Support
   3: Imports Spring.Objects.Factory.Support
   4:  
   5: Public Module SpringExtension
   6:  
   7:     <Extension()>
   8:     Public Sub RegisterType(Of T)(ByVal ctx As GenericApplicationContext, ByVal builderConfig As Action(Of ObjectDefinitionBuilder))
   9:         Dim objectDefinitionFactory As IObjectDefinitionFactory = New DefaultObjectDefinitionFactory()
  10:  
  11:         Dim builder As ObjectDefinitionBuilder = ObjectDefinitionBuilder.RootObjectDefinition(objectDefinitionFactory, GetType(T))
  12:         builderConfig.Invoke(builder)
  13:  
  14:         ctx.RegisterObjectDefinition(builder.ObjectDefinition.ObjectType.Name, builder.ObjectDefinition)
  15:  
  16:     End Sub
  17:  
  18: End Module

Here’s a quick example of its use:



   1: Dim ctx = New GenericApplicationContext()
   2:  
   3: ctx.RegisterType(Of Calculator)(Sub(b As ObjectDefinitionBuilder) b _
   4:                               .SetAutowireMode(Spring.Objects.Factory.Config.AutoWiringMode.AutoDetect) _
   5:                               .SetSingleton(False))
   6:  
   7: ctx.RegisterType(Of HexFormatter)(Sub(b As ObjectDefinitionBuilder) b _
   8:                       .SetAutowireMode(Spring.Objects.Factory.Config.AutoWiringMode.AutoDetect) _
   9:                       .SetSingleton(False))
  10:  
  11: ctx.RegisterType(Of ConsoleWriter)(Sub(b As ObjectDefinitionBuilder) b _
  12:                       .SetAutowireMode(Spring.Objects.Factory.Config.AutoWiringMode.AutoDetect) _
  13:                       .SetSingleton(False))

Wednesday, November 11, 2009

SQL Server XML - Replacing the value of an attribute with a column from the same row

This will hopefully save someone the 45 minutes that it took me to figure it out. I wanted to replace the value of an attribute within an XML column with the value of a column on the same row.

UPDATE myTable
SET xmlColumn.modify('replace value of (/x/y/@a)[1] with sql:column("columnName")')
WHERE ...


When I tried wrapping the call to sql:column with braces (ex. {sql:column("columnName")}, I received error 2224 - An expression was expected.

When I tried enclosing the whole thing in double-quotes (ex. "sql:column("columnName")", I received error 2370 - No more tokens expected at the end of the XQuery expression. Found 'columnName'