• tomaskallsen

Using a custom model binder in ASP.NET Core to parse JSON in GET request

I needed to include the data from a Javascript object in the request to a ASP.NET Core MVC controller, but wanted to use GET as the method. This left me with sending the data on the querystring; however, ASP.NET Core (currently) only parses JSON data from the request body which is empty for a GET request, so I needed something to get the client side data into my server side model.

After searching the web and not finding what I needed, I whipped up a solution based on a custom ModelBinder, which does a naive check to see if the querystring value is JSON, and then uses JsonConvert to deserialize into the supplied model type.

First we need to implement the actual ModelBinder:

using System;
using System.Threading.Tasks;
using Microsoft.AspNet.Mvc.ModelBinding;

public class JsonQueryStringModelBinder : IModelBinder {

public Task<ModelBindingResult> BindModelAsync(ModelBindingContext bindingContext) {
	ValueProviderResult vpr = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
	var possibleJson = vpr.FirstValue as string;
	if(!string.IsNullOrEmpty(possibleJson)) {
		if((possibleJson.StartsWith("[{") && bindingContext.ModelType.IsArray) ||possibleJson.StartsWith("{")) {
		try {
		return ModelBindingResult.SuccessAsync(bindingContext.ModelName,Newtonsoft.Json.JsonConvert.DeserializeObject(possibleJson,bindingContext.ModelType));} 
		catch(Exception) {// Something wrong with the value, handle or ignore
				}
				}
				}
				return ModelBindingResult.NoResultAsync;}}
				

Then we need to register it with in the MVC ModelBinders collection, in the Startup.ConfigureServices method:

services.AddMvc().AddMvcOptions(options => {
// ... your configuration
int i = 0;
for(; i < options.ModelBinders.Count; i++) {
    if(options.ModelBinders[i].GetType() == typeof(GenericModelBinder))                                    {
    break;
    }
 }
 
 options.ModelBinders.Insert(i, new JsonQueryStringModelBinder());});

The reason for inserting the Json Querystring modelbinder before the generic model binder is that otherwise it will process any array properties before we have a chance to try to bind to them.

With the setup out of the way, we can just use any POCO in a request model, and deserialize JSON from the querystring into the object.

public class MyCustomRequestModel {

public MyCustomObject CustomData { get; set; }
public bool SomeBoolean { get; set; }

[HttpGet]public IActionResult TranslateSomethingToString(MyCustomRequestModel requestModel) {
	// Do something with the data
	return "the result";
	}
}

Just make sure that the structure of the JSON data on the query string matches the structure on the server side (toJSON() in the ES/JS class can be a big help).

/?customData=my-json-string&someBoolean=false

Rev2

1 visning0 kommentarer