14

I realize that the Web API is REST focused, but I would still like to configure a single controller method that can handle a Command/Response scenario. So far I haven't been successful... is there a way to have the following class structure recognized by a single API endpoint?

[Serializable]
public abstract class Command{
    public int CommandId{get; set;}
}
[Serializable]
public class RegisterNewPersonCommand:Command{
   public string Name{get; set;}
}
//etc... various Command subclasses. Similar thing for Responses.

//now have a single endpoint to Handle Commands
public class CommandsController : ApiController{
   public Response HandleCommand(Command command){
      //handle Command based on which subclass it is
      //return appropriate Response subclass
   }
}

Thus far it doesn't seem the serialization system can handle this scenario, but I hope someone out there has found a way to do it :)

2
  • Even if it works, how does this help re-use any code? Commented Nov 28, 2012 at 17:06
  • 1
    I want to reduce code in my Controller. Instead of a boilerplate method for each subclass of Command (HandleNewUserCommand(NewUserCommand){}, HandleUserPasswordChangeCommand(UserPasswordChangeCommand){}', etc), the single HandleCommand` method will be responsible for using reflection and IoC to pass the Command along to the appropriate domain logic. Commented Dec 3, 2012 at 23:46

1 Answer 1

15

In order for polymorphism to work in Web API, you will need to enable type name handling and the data has to contain the type information.

You'll need to turn on TypeNameHandling in WebApiConfig.cs if you're using JSON in your scenario:

config.Formatters.JsonFormatter.SerializerSettings.TypeNameHandling = 
    Newtonsoft.Json.TypeNameHandling.All;

Then, the content body that you are sending to your HandleCommand(...) action must contain the type information:

{"$type":"MvcApplication.Models.RegisterNewPersonCommand, MvcApplication", ... }

For XML, you'll need to use DataContract's KnownType...

By the way, is there any specific reason why you are using [Serializable] (since POCO types and [DataContract] types are also supported...)?

Sign up to request clarification or add additional context in comments.

4 Comments

This seems to be the right idea. Is there a way to configure the HttpClient to include the $type info? In my tests, var task= client.PostAsJsonAsync("api/commands/handlecommand", testCommand); does not include the $type information when it serializes to json.
This answered my question and helped me figure out how to specify formatting on the client end. For what it's worth, the simplest client code looks something like: private void SendCommand(Command command){var json = new JsonMediaTypeFormatter {SerializerSettings = {TypeNameHandling = TypeNameHandling.All}};var response = client.PostAsync("api/commands/handlecommand", command, json).Result;//handle response}
This helped me.. The only other thing I had to search all over the internet to find was that Interfaces are not serializable, something I've known forever, but due to all the magic of Json serialization in .Net I seemed to forget:) So NO ICollection, IEnumerable, instead use List<> etc... Now I have polymorphic serialization working :) And now I wonder if I should be flattening my DTO's :p
TypeNameHandling.Auto is nicer because it doesn't write the instance type name when it matches the type of the field/property, which is usually the case for most types.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.