WebGet/WebInvoke attributes and inheritance

Topics: Web Api
Dec 3, 2011 at 7:05 PM

Hi!

First: I LOVE WCF Web Api!!

I am trying to implement the following pattern:

I have an interface that is implemented by an abstract api base class.  This interface is decorated by [ServiceContract] and have a handful methods decorated by [WebGet...] and [WebInvoke...].

All my api classes inherit from this api base class.  By doing so they all get a basic set of set of webget/webinvoke decorated methods.

Now, if I try to extend my inherited api classes by more webget-/webinvoke-decorated methods they do not get "recognized" by the framework, while the inherited methods works perfectly.

All my api classes are correctly registered and also correctly handled by the IoC (Autofac).  The "local" methods works fine if I remove the inheritance.

Should this pattern work? Am I doing something wrong? 

Thanks for any guidance!

Coordinator
Dec 5, 2011 at 7:19 PM

Contract inheritance in WCF only really works with interfaces, and each interface in the hierarchy needs to be marked as a service contract. So, you can’t just derive from a base type and then add more operations on your derived service type.

You could create a hierarchy of interfaces and then implement the most derived one, but then WCF will think that your service implementation actually implements multiple service contracts and you will have to configure your endpoints manually instead of having WCF provide them for you automatically.

Daniel Roth

Dec 6, 2011 at 9:00 AM
Edited Dec 6, 2011 at 9:01 AM

Hi!

This is what I am trying to do:

    public interface IApiEntity
    {
        public int Id { getset; }
    }
 
    [ServiceContract]
    public interface IApiBase<T>
    {
        [WebGet(UriTemplate = "")]
        IQueryable<T> List(HttpRequestMessage request);
 
        [WebGet(UriTemplate = "{id}")]
        HttpResponseMessage<T> Get(int id, HttpRequestMessage request);
 
        [WebInvoke(UriTemplate = "{id}", Method = "DELETE")]
        HttpResponseMessage Delete(int id, HttpRequestMessage request);
 
        [WebInvoke(UriTemplate = "{id}", Method = "PUT")]
        HttpResponseMessage<T> Put(HttpRequestMessage<JsonObject> request, int id);
 
        [WebInvoke(UriTemplate = "", Method = "POST")]
        HttpResponseMessage<T> Post(HttpRequestMessage<JsonObject> request);
    }
 
    public abstract class ApiBase<T> : IApiBase<T> where T : IApiEntity, new()
    {
        public IQueryable<T> List(HttpRequestMessage request)
        {
            return...;
        }
 
        public HttpResponseMessage<T> Get(int id, HttpRequestMessage request)
        {
            return...;
        }
 
        public HttpResponseMessage Delete(int id, HttpRequestMessage request)
        {
            return...;
        }
 
 
        public HttpResponseMessage<T> Put(HttpRequestMessage<JsonObject> request, int id)
        {
            return...;
        }
 
        public HttpResponseMessage<T> Post(HttpRequestMessage<JsonObject> request)
        {
	   return...;	
        }
    }
 
    public class Customer : IApiEntity
    {
        public int Id { getset; }
    }
 
    public class Contact : IApiEntity
    {
        public int Id { getset; }
    }
 
    public class Customers : ApiBase<Customer>
    {
        [WebGet(UriTemplate = "{id}/contacts")]
        public HttpResponseMessage<IQueryable<Contact>> GetContacts(int id, HttpRequestMessage request)
        {
            return...;
        }
    }
If I point the test client at .../customers/test I have the four methods defined by IApiBase 
and implemented by ApiBase available and can test them, but the method decorated by the 
[WebGet(UriTemplate = "{id}/contacts")] attribute doesn't appear to exist.
Is there any easier way around this?  I was really hoping I could things like above...
Coordinator
Dec 6, 2011 at 8:19 PM

I believe that you really can only do service contract inheritance with interfaces, not with concrete types.

Daniel Roth