Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Web API IQueryable<T> challenge

I want to use the following pattern in my controllers:

api/{controller}/{id}/{collection}

Example: api/customers/123/addresses

But I want to return IQueryable Of T from the corresponding Get action. I want something like this (simplified):

public IQueryable<????> GetCollection(int id, string collection)  
{  
    switch(collection)  
    {  
        case "addresses":  
            return _addresses.AsQueryable();  
            break;  
        case "orders":  
            return _orders.AsQueryable();  
            break;  
        default:  
            throw new Exception(NotSupported);  
    }  
}   

Can this be done?
What would be the recommended approach?

like image 752
Jan Ove Halvorsen Avatar asked Jan 17 '23 23:01

Jan Ove Halvorsen


2 Answers

@SLacks is correct that you should return IQueryable<object> or IQueryable<someBaseType> if you can.

The error your getting is a function of the DataContract Serializer. So you have a few options.

  1. Switch to an alternate xml serlializer that supports what you want.
  2. Swtitch to a form of output that bypasses the serializer at issue (say JSON using JSON.net)
  3. Teach the data contract serializer how to serialize your object using the

For the "teach" option, you can teach in two ways.

(A) leverage the [KnownType(typeof(...))] attribute. Here's a post on the KnownType attribute. It's for WCF but should get you started.

(B) use a data contract resolver. This post should get you started.

like image 172
EBarr Avatar answered Jan 21 '23 16:01

EBarr


Expanding on what @Ebarr said, the easiest way to accomplish this is to update the various classes which you want to be able to return this way, and have them inherit from a common base class or interface.

Example:

[KnownType(typeof(Address))]
[KnownType(typeof(Order))]
public abstract class _BaseObject { }

public partial class Address : _BaseObject { }
public partial class Order : _BaseObject { }

Now you can have your controller method look like:

public IQueryable<_BaseObject> GetCollection(int id, string collection) {  
    switch(collection) {  
        case "addresses":  
            return _addresses.AsQueryable();
        case "orders":  
            return _orders.AsQueryable();
        default:  
            throw new NotSupportedException();  
    }  
}

Note that the [KnownType] attribute is in System.Runtime.Serialization. You should also be aware that this method will result in exactly what you would expect with regards to JSON serialization - but XML serialization will generally result in tags which show your objects as the base class (because that's what you returned) rather than the sub-classes.

like image 41
Troy Alford Avatar answered Jan 21 '23 17:01

Troy Alford