0

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?

2
  • 1
    Is this .NET Framework or .NET Core? In other words, is it using JSON.Net or System.Text.Json? Commented Apr 8, 2021 at 12:31
  • @DavidG .NET full framework Newtonsoft.json Commented Apr 8, 2021 at 14:46

2 Answers 2

1

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)
Sign up to request clarification or add additional context in comments.

Comments

0

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.

2 Comments

Writing two methods like those i wrote above i get this error '404 bad request "Message": "Multiple actions were found that match the request"'
try give the method different name, so the url route will be different

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.