Is Class Per Uri/Method Possible

Topics: Web Api
May 25, 2011 at 9:46 PM

I'm just getting started with the new Web APIs and I like what I see, but I'm still pretty ignorant of how the API works and can be extended to fit my architectural aesthetic. Most of the samples seem to favor having a class per base uri. So "/contacts" and the ContactsResource. I would rather have a class per Uri/Method combination. So something like this:

GET "/contacts" ->

public class GetContacts {  

   public HttpResponseMessage RespondTo(HttpRequestMessage request) { ... }

}

POST "/contacts/{contactId}/avatar ->

public class PostContactAvatar {  

   public HttpResponseMessage RespondTo(HttpRequestMessage request) { ... }

}

Is there a way to achieve this type of "command" architecture?

May 26, 2011 at 12:59 AM
Edited May 26, 2011 at 1:01 AM

Fancy seeing you here, EisenbergEffect. :)

I have not tried this, but I'm pretty sure you can do this. In your Global.asax.cs file, you'd register the routes like this:

        private void RegisterRoutes()
        {
            RouteTable.Routes.MapServiceRoute<GetContacts>("contacts");
            RouteTable.Routes.MapServiceRoute<PostContactAvatar>("contacts/"); //note the terminating slash
        }

Then your class definitions would need to look like so:

    public class GetContacts
    {
        [WebGet(UriTemplate = "")]
        public HttpResponseMessage RespondTo() {...}
    }

    public class PostContactAvatar 
    {
        [WebInvoke(UriTemplate = "{id}/avatar", Method = "POST")]
        public HttpResponseMessage RespondTo(string id) {...}
    }

I think this will work only because WCF Web API is very particular about the slashes in the URIs. I once spent hours figuring out why my web service wasn't working, and it was all due to an extraneous slash that I added to the URI in the call from JavaScript.

In the example above, a call to /contacts is very different from a call to /contacts/. So WCF Web API will properly distinguish between the two and route the call to the correct class. However, in your case you'll run into a problem if you need to add another class that you would want to route to using a similar UriTemplate (e.g. "{id}/someothermethod").

 

May 26, 2011 at 1:35 AM

Thanks. I think I'm going to run into a lot of scenarios where the interesting part is after the id parameter and I'd like each of those to have their own class. I can work around this by having the standard resource class and delegate to other classes underneath, but I'd rather have the WCF infrastructure pipe the request directly to the handler I actually want. That also makes IoC much easier since all the request don't necessarily have the same dependencies.

Coordinator
May 26, 2011 at 2:28 AM

Did somebody say Caliburn? :-)

When you say the interesting part is after the id parameter what do you mean? You can have a uri template that grab other information, can you give me a concrete uir example? The example cv55555 showed does let you have services as separate classes. It is missing the [ServiceContract] atribute however.

Aside from that, I get exactly whta you are asking about. We have a thing that's coming in the future we refer to as "the Resource Model". You are describing some of it's salient aspects, I think in resources not classs with operations. I get to model my uri namespaces however I want to and map them to my handlers. The resource model is still in the earl phass,

For now, as you mentioned there are several possible approaches.  

  • Using a facade which then delegates to your actual resource classes is one way to go. If you do that model one way to make it easier is to use partial classes.
  • An alternative which WILL let you use separate classes it to use the UrlRewriter module in IIS where you specify routing rules which take the uri you want and translate it to another uri like "ContactAvatar/{id}".

Cheers

Glenn

 

May 26, 2011 at 3:18 AM

LOL. I'm excited about the notion of a resource model. Here's a few concrete examples:

POST /designs/{designNumber}/duplicate

GET /designs/{designNumber}/history?offset=30&limit=10

POST /designs/{designNumber}/convert

I'd like to have a separate class for handling each one of these. For the time being, I'll probably go the delegation route. But, it sounds like the resource model idea will do it for the future. Is that available anywhere in the prototype code? Can you say if it will be coming in the next drop or if it's farther out?

Coordinator
May 26, 2011 at 3:51 AM

Understood. This would have been easier today hard our routing allowed you to use params in the route. We intend to fix this at some point, but those are red-bits (part of .net 4.0) so it will take a bit.

Resource model....I am working on it. There's some early prototype old code but it's very rough. I'll let you know when the new thing is ready for looking at ;-)

Coordinator
May 26, 2011 at 4:07 AM

I can't say if it will be in the next drop.