pinale
pinale

Reputation: 2214

multiple types webapi parameters binding

is it possible to have an api endpoint whose method's sign can accepts a parameter that can be a single object or a collection of objects?

i have a method like this:

[HttpPost, Route("DoSomething")]
public async Task<IHttpActionResult> DoSomething([FromBody] MyType xxx, CancellationToken cancel)

i need to modify this method to accept a collection of MyType class (an array, enumerable, list... doesn't matter)

[HttpPost, Route("DoSomething")]
public async Task<IHttpActionResult> DoSomething([FromBody] IEnumerable<MyType> xxx, CancellationToken cancel)

anyway for a little while the client that calls this endpoint will continue to send me a single object { } and not a collection of objects [{ },{ }]

is it possible to modify this endpoint to accept both types?

Upvotes: 0

Views: 205

Answers (2)

DavidG
DavidG

Reputation: 118957

You can do this with a custom JsonConverter. For example, this should work, or at least be enough for you to customise:

public class SingleOrListConverter<T> : JsonConverter
{
    public override bool CanConvert(Type objectType) => objectType == typeof(List<T>);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 
        JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);

        if (token.Type == JTokenType.Array)
        {
            return token.ToObject<List<T>>();
        }

        return new List<T>
        {
            token.ToObject<T>()
        };
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }
}

Now you add it to your configuration. In Global.asax.cs, add this line:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.Converters
    .Add(new SingleOrListConverter<string>());

Now just use a single endpoint:

public async Task<IHttpActionResult> DoSomething(
    [FromBody] IEnumerable<MyType> xxx, CancellationToken cancel)

Upvotes: 1

yu yang Jian
yu yang Jian

Reputation: 7171

I think 2 solutions:

  1. Accepet the data as string, and you can parse it yourself in any way, you can process the string, give it different rules to judge which type it should be convert, e.g. if contains [ then parse it as List, otherwise a single object.

  2. Write 2 methods one accept List another Single Obj, and write usage clearly in api documentation, then provide the document to the user.

Upvotes: 0

Related Questions