WebAPI: Deserialize URI parameter to poco action p

2019-08-23 03:29发布

Given a route definition like this:

        routes.MapHttpRoute(
            name: "Categories",
            routeTemplate: "{controller}/Categories/{entity}/{property}",
            defaults: new { action = "Categories", entity = RouteParameter.Optional, property = "Name" }
        );

And a controller actions declared like this:

public IEnumerable<Category> Categories(string property);
public IEnumerable<Category> Categories(string entity, string property);

The intent is that the controller represent a specific entity, and it can aggregate other entities. The returned Categories contains a groupby and count of property. So if the controller is UserController and the user Entity has a Name property, you could call User/Categories/Name and get a result showing distinct names and how many have each name.

If however a User also have an Address entity, and it has a ZipCode I could call User/Categories/Address/ZipCode and expect a result showing how many Users live at what ZipCodes.

The problem here is that the string entity parameter is of type string rather than type Type, so I have to dirty up my action with code to convert this to a Type instance representing the Entity, and throwing if it is an incorrect string.

What I would like is to instead declare my second action like this:

public IEnumerable<Category> Categories(Type entity, string property);

But then I need to deserialize the string with a custom deserializer. I allready have custom deserializers aka MediaTypeFormatters for things comming from the content body. My problem here is that in this case the source is a URI parameter rather than the content body.

Which leads to my questions:

  1. Will a MediaTypeFormatter also work for URI parameters?
  2. If not, what construct must I implement and hook up how to achieve what I want?

1条回答
劳资没心,怎么记你
2楼-- · 2019-08-23 04:04

Couple of things:

  1. User/Categories/Name will not map "Name" to {property}, it will match "Name" to {entity}. Routes match "greedily" left-to-right.

  2. Instead of a string for entity, you could use an enum

    public enum EntityType
    {
        Address,
        Department
    }
    
    public class UserController : ApiController
    {
        public IEnumerable<Category> Categories(EntityType entity, string property)
        {
        }
    }
    

    You'll still need code to do something with the entity type, but that seems safer than letting the client send you random CLR type names? And then the model binding will validate the {entity} segment in the URI. So if a client requests User/Categories/FavoriteBeer, they will get 400, Bad Request.

  3. Media-type formatters are specifically for serializing/deserializing the message body. (Formatters map to media types, and media types describe the entity body.)

    A media-type formatter does have access to the request URI, through the FormatterContext object, but it won't help for this scenario, because a GET request with no message body will not invoke a formatter.

查看更多
登录 后发表回答