String.Empty Converted to Null When Passing JSON Object to MVC Controller

string.empty converted to null when passing JSON object to MVC Controller

This is a MVC feature which binds empty strings to nulls.

This logic is controlled with the ModelMetadata.ConvertEmptyStringToNull property which is used by the DefaultModelBinder.

You can set the ConvertEmptyStringToNull with the DisplayFormat attribute

public class OrderDetailsModel
{
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string Comment { get; set; }

//...
}

However if you don't want to annotate all the properties you can create a custom model binder where you set it to false:

public class EmptyStringModelBinder : DefaultModelBinder 
{
public override object BindModel(ControllerContext controllerContext,
ModelBindingContext bindingContext)
{
bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
Binders = new ModelBinderDictionary() { DefaultBinder = this };
return base.BindModel(controllerContext, bindingContext);
}
}

And you can use the ModelBinderAttribute in your action:

public ActionResult SaveOrderDetails([ModelBinder(typeof(EmptyStringModelBinder))] 
OrderDetailsModel orderDetailsModel)
{
}

Or you can set it as the Default ModelBinder globally in your Global.asax:

ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();

You can read more about this feature here.

ASP.NET Core MVC - empty string to null when sending JSON to server

After going through source code of ASP.NET Core MVC (v2.1) and source code of Newtonsoft.Json (v11.0.2), I came up with following solution.

First, create custom JsonConverter:

public class EmptyStringToNullJsonConverter : JsonConverter
{
public override bool CanRead => true;
public override bool CanWrite => false;

public override bool CanConvert(Type objectType)
{
return typeof(string) == objectType;
}

public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
string value = (string)reader.Value;
return string.IsNullOrWhiteSpace(value) ? null : value.Trim();
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
throw new NotImplementedException("Unnecessary because CanWrite is false. The type will skip the converter.");
}
}

Then, register custom converter globally:

services
.AddMvc(.....)
.AddJsonOptions(options => options.SerializerSettings.Converters.Add(new EmptyStringToNullJsonConverter()))

Or, use it on per-property bases via JsonConverterAttribute. For example:

public class Item
{
public int Value { get; set; }

[StringLength(50, MinimumLength = 3)]
[JsonConverter(typeof(EmptyStringToNullJsonConverter))]
public string Description { get; set; }
}

How to resolve null json string passed to mvc controller?

Your controller needs to be created to accept the actual object, and not the json string.

By this i mean

[HttpPost]
public ActionResult updateStatus(stirng jsonString)
{
//deserialise the json to a Status object here
}

Should be

[HttpPost]
public ActionResult updateStatus(Status vm)
{
//no need to deserialize - was already done by the model binder
}

In order for the model binder to bind your json to Status you would need to pass a json object that replicates your viewmodel.

{
ID:yourId,
Contact_Email:yourContactEmail,
RID:YourRID,
Name:yourName
}

In pseudo-code, you could:

var statusData = {
ID:tableData[0],
Contact_Email:tableData[1],
RID:tableData[2],
Name:tableData[3]
};

Then in your ajax call,

data: JSON.stringify(statusData),

Ajax passing empty value but Controller get null in ASP.NET MVC

I decided summary from @Rahul Sharma's and @rhytonix's answers along with giving you examples and more detailed explanations.

  1. Why is it that when in Ajax I am sending empty, I get null value in my controller?

This is simply because MVC 2.0 defaults to initializing strings to null. To be more precise, if an empty string means has no value, So .NET sets the default value of its. And the default string (belonging to reference type) is null.

More details in Model String Property Binding Breaking Change


  1. Is there a better way and more elegant to resolve my problem like below?

There are some ways to bind String property as string.Empty instead of null

1. From C# 6, You can use DefaultValueAttribute to have auto-property an initial value like below

public string LastName => string.Empty; 

Basically, This way is the same as the OP's solution mentioned in the post, Just more elegant.

2. Custom default implementation of IModelBinder by inheriting from DefaultModelBinder and changing the ConvertEmptyStringToNull value to false on the internal ModelMetaData object.

public sealed class EmptyStringModelBinder : DefaultModelBinder 
{
public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
bindingContext.ModelMetadata.ConvertEmptyStringToNull = false;
return base.BindModel(controllerContext, bindingContext);
}
}

Then in Application_Start() method of Global.asax.cs you need to do like below to complete

protected void Application_Start()
{
ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();
RegisterRoutes( RouteTable.Routes );
}

3. Use DisplayFormatAttribute.ConvertEmptyStringToNull Property like below

[DisplayFormat(ConvertEmptyStringToNull = false)]
public string LastName { get; set; }

Simply because in ModelMetadata

true if empty string values are automatically converted to null;
otherwise, false. The default is true

JSON object with non-null values converted to null in MVC Controller method

I figured this out. In my C# object that represents the fields you see in the picture, I converted all to properties. Or in other words, I added "{ get; set; }" to all the fields that did not have it. Now all the values bind correctly when sent to my MVC Controller method.

Why do I get null instead of empty string when receiving POST request in from Razor View?

You can use the DisplayFormat attribute on the property of your model class:

[DisplayFormat(ConvertEmptyStringToNull = false)]

ASP.NET mvc 4 controller parameter always null when sending json to controller, why?

Thank you guys for the directions and solutions. The solution is a combination of all of your suggestions, so I decided to round it up in one post.

Solution to the problem is as follows:

  1. contentType should be application/json (as Ant P suggested above)
  2. json data should be in form of JSONString3 = {"Name" : "monday" } (as Ant P suggested above)
  3. before sending to controller, json should be stringifyed as follows: JSONString3 = JSON.stringify(JSONString3) (as Quan suggested)

Client side javascript

function getChart() {
JSONString3 = { "Name" : "monday" };
jQuery.ajaxSettings.traditional = true;
$.ajax({
url: "@Url.Action("getChart","SBM")",
type: 'POST',
contentType: 'application/json',
dataType: 'html',
data: JSON.stringify(JSONString3),
success: function (data) {
var imagestring = btoa(data);
$('#ChartImage').attr('src', "data:image/png;base64," + imagestring + "?" + new Date().getTime());
}
})
jQuery.ajaxSettings.traditional = false;
}

MVC Controller

[Authorize]
[HttpPost]
public ActionResult getChart(YAxis HAxis)
{
YAxis XAxisvalue = HAxis;
Charts chart = new Charts();
MemoryStream ms = new MemoryStream();
chart.Chart.SaveImage(ms);
string image = Convert.ToBase64String(ms.GetBuffer());
return File(ms.GetBuffer(), "image/png", "Chart.png");
}

Model

public class YAxis
{
public string Name { get; set; }
}

Instead of this:

JSONString3 = { "Name" : "monday" };

we can do this:

var JSONString3 = {};
JSONString.Name = "monday";

But we still need to stringify object before posting to controller!!!

To pass multiple objects to controller, below is the example

Client side javascript

   function getChart() {

//first json object
//note: each object Property name must be the same as it is in the Models classes on server side
Category = {};
Category.Name = "Category1";
Category.Values = [];
Category.Values[0] = "CategoryValue1";
Category.Values[1] = "CategoryValue2";

//second json object
XAxis = {};
XAxis.Name = "XAxis1";
XAxis.Values = [];
XAxis.Values[0] = "XAxisValue1";
XAxis.Values[1] = "XAxisValue2";

//third json object
YAxis = {};
YAxis.Name = "YAxis1";

//convert all three objects to string
//note: each object name should be the same as the controller parameter is!!
var StringToPost = JSON.stringify({CategoryObject : Category, XAxisObject : XAxis, YAxisObject : YAxis});

$.ajax({
url: "@Url.Action("getChart","SBM")",
type: 'POST',
contentType: "application/json",
dataType: 'html',
data: StringToPost,
success: function (data) {
var imagestring = btoa(data);
$('#ChartImage').html(data);
}
})
}

MVC Controller

[HttpPost]
public ActionResult getChart(Category CategoryObject, XAxis XAxisObject, YAxis YAxisObject)
{
//do some stuff with objects here and return something to client
return PartialView("_Chart");
}

Category model

public class Category
{
public string Name { get; set; }
public List<string> Values { get; set; }
}

XAxis model

public class XAxis
{
public string Name { get; set; }
public List<string> Values { get; set; }
}

YAxis model

public class YAxis
{
public string Name { get; set; }
}

Hope it will help someone to clarify the whole picture!

json string on POST to MVC action method using AJAX is null

The easiest solution is to create a model representing the JSON data that your controller will receive. For example, create a class like so:

public class AccountCheckModel
{
public string email { get; set }
}

Then, use it as the parameter for your controller method:

public ActionResult ReturnCheckAccountDuplication([FromBody] AccountCheckModel data)

This is the preferred way to access the request body. To get the request body as a string, you have to jump through some serious hoops.



Related Topics



Leave a reply



Submit