With this request (or plain Model)
public class SomeRequest : IRequest<List<string>> {
public string Id { get;set; }
[JsonIgnore] public string Name { get; set; }
When POST, JsonIgnore works and Name is hidden from swagger
public async Task<List<string>> Post(SomeRequest request)
When GET and FromQuery, it does not. All fields are shown.
public async Task<List<string>> Get([FromQuery] SomeRequest request)
I have been playing around with SchemaFilter, but wonder if this could become built-in default behavior for consistency purpose.
Thanks.
I added this, now JsonIgnore works on [FromQuery] model parameter. If someone spot any issue, let me know. Thanks
public class JsonIgnoreQueryOperationFilter : IOperationFilter
{
public void Apply(Operation operation, OperationFilterContext context)
{
context.ApiDescription.ParameterDescriptions
.Where(d => d.Source.Id == "Query").ToList()
.ForEach(param =>
{
var toIgnore =
((DefaultModelMetadata)param.ModelMetadata)
.Attributes.PropertyAttributes
?.Any(x => x is JsonIgnoreAttribute);
var toRemove = operation.Parameters
.SingleOrDefault(p => p.Name == param.Name);
if (toIgnore ?? false)
operation.Parameters.Remove(toRemove);
});
}
}
Is this behavior by design or is this a bug? We are having the same issue.
@ZeinSleiman I think GET using Model with JsonIgnore and FromQuery is not a standard approach in most Api. I did this because I also use MediatR, which makes everything a request, with a base request auto filed from authentication token via validation and authorization filter, etc.
The filter I posted seems working well. You can also do something crazier like
public class SomeRequest : IRequest<List<string>> {
[FromRoute] public string Id { get;set; }
[FromQuery] public bool Really {get; set;}
[JsonIgnore] public string Name { get; set; }
[HttpGet, Route("/SomeController/{Id}")]
public async Task<List<string>> Get(
[FromQuery] SomeRequest request)
This is to generate swagger definition, so I suppose there's no impact on actual calls.
@ThisNoName Thanks for the response. What do you mean Get using Model and FromQuery is not a standard? If you have filters, how do you pass them into your controller.
We do something like this
[HttpGet("/[controller]/{group}/{name}/Products")]
public ActionResult Get(string group, string name, [FromQuery]MoreFilters moreFilters)
We pass the group and name in the filter but we dont want the user to pass them in the query string. We can do two different classes but it seems an overkill for me. I will give your filter a try.
@ZeinSleiman If you really prefer using a single filter parameter on the method,
[HttpGet("/Product/{group}/{name}/Products")]
public string Get([FromQuery] ProductFilters productFilters) {
return "product";
}
public class ProductFilters {
[FromRoute]
public string group { get; set; }
[FromRoute]
public string name { get; set; }
public string filter1 { get; set; }
public string filter2 { get; set; }
}
Should get you
GET /Product/{group}/{name}/Products?filer1=some&filter2=thing
But normally, I try stick to all simple parameters on GET method, or prefer your existing split approach, rather than a single class. It looks cleaner and more direct. But that's just personal preference. At api level, they all end up the same.
The filter I posted is only needed if you try hiding fields with JsonIgore on model marked with FromQuery. I don't think that's a common scenario.
That [FromRoute] might be good for me. I didnt know about it. Thanks a lot.
[JsonIgnore] is specifically related to how an object should be serialized to/from JSON. In the case of a query string, there's no JSON serialization involved and so that attribute has no meaning when the containing object is used in that context.
If you want the property to be ignored in the query string context, i.e. when being bound to query parameters, decorate it with the [BindNever] attribute
Most helpful comment
[JsonIgnore]is specifically related to how an object should be serialized to/from JSON. In the case of a query string, there's no JSON serialization involved and so that attribute has no meaning when the containing object is used in that context.If you want the property to be ignored in the query string context, i.e. when being bound to query parameters, decorate it with the
[BindNever]attribute