简体   繁体   中英

ASP.NET web api how to exclude property from DTO object based on put/get/post/delete

I'm working on a ASP.NET web api (first time!). For every database object I have created a DTO object to flatten the objects. I use automapper to map these objects. I would like to only use one DTO object for all request types (get/put/post/delete).

Simplified example:

public class ProductDB
{
    public int ProductId { get; set; }
    public string Name { get; set; }
}

public class ProductDTO
{
    [JsonIgnore] -- only in case of a put/post/delete request
    [XmlIgnore] -- only in case of a put/post/delete request
    public int ProductId { get; set; }
    public string Name { get; set; }
}

If I perform a HttpGet to get a list of products, I want to include the ProductId in the response. The response type will be IEnumerable ProductDTO including ProductIds.

If I perform a HttpPut, the request will be: https://base-url/products/id with the ProductDTO as body. However, in this case I do not want the ProductId included in the ProductDTO.

I know how to exclude a property, by decorating them with both [JsonIgnore] and [XmlIgnore] attributes. However, this will always exclude them. I would like to exclude them conditionally, based on the request being HttpGet/HttpPost/HttpPut/HttpDelete.

Is this possible? Or is there another way to exclude properties from DTO's based on request type?

If I perform a HttpPut, the request will be: https://base-url/products/id with the ProductDTO as body. However, in this case I do not want the ProductId included in the ProductDTO.

Technically it doesn't need to be, since we're just talking about requests and not responses . Depending on what the client sends. If the client sends this JSON:

{
    "Name" : "Some Value"
}

Then as far as the model binder is concerned, that's valid. It would create an instance of ProductDTO with that Name property set. In the server-side code you can then set the ProductId property based on the id in the route, perform the mapping, and you have your domain object.

The client doesn't need to know that they can set a ProductId property in the JSON. (And if they set one anyway, it's just going to be silently overwritten by the route value in your code and basically ignored. Of course, if they had set one when there was no such property on the DTO then it would also have simply been ignored.)

For outgoing DTOs, you want to fine-tune what the serializer includes and what it doesn't. But for incoming DTOs you have a lot more leeway because you're not actually advertising the shape of the DTO to the consuming system in any way.

The only time I've ever seen this be a problem is when using a tool to generate API documentation. Something like Swashbuckle , for example, will include that property in the API docs. Which isn't ideal. In cases like that, I find the shortest path is to create separate DTOs for the separate actions. This isn't uncommon, some MVC frameworks are even designed specifically to match one model to one request.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM