Ajax передает пустое значение, но контроллер получает нулевое значение в ASP. NET MVC - PullRequest
6 голосов
/ 08 февраля 2020

Я работаю с ASP.NET MVC и у меня проблема со значением, отправленным с Ajax на мой контроллер.

Допустим, у меня есть SampleViewModel, например так:

public class SampleViewModel
{
    private string _firstName = string.Empty;

    public SampleViewModel()
    {
        _firstName = string.Empty;
    }

    public string FirstName
    {
        get { return _firstName; }
        set { _firstName = value ?? string.Empty; }
    }

    public string LastName { get; set; }

    public string FullName { get; set; }
}

Контроллер

[HttpPost]
public JsonResult ActionSubmit(SampleViewModel model)
{               
    var result = "";

    if(model.FirstName == null)
          result += "\nFirstName is null";

    if(model.LastName == null)
          result += "\nLastName is null";

    return Json(result);
}

Ajax

$('.submit').click(function() {
        $.ajax({
            url: '@Url.RouteUrl(new{ action="ActionSubmit", controller="Home"})',
            data: JSON.stringify({ FirstName: '', LastName: '', FullName: 'Phong_Nguyen' }),
                  // Even though I use { FirstName: '', LastName: '', FullName: 'Phong_Nguyen' } without JSON.stringify
            type: 'POST',
            dataType: 'json',
            contentType: "application/json; charset=utf-8",
            success: function(resp) {
                   alert(resp);
            }});
         });

Как видите, я отправляю пустой значение, но на конце контроллера, я получаю нулевое значение (значение ответа всегда "LastName is null"): enter image description here

Вопрос

  1. Почему в Ajax я посылаю empty, я получаю null значение в моем контроллере?

  2. Есть ли лучший способ и более элегантно, чтобы решить мою проблему, как показано ниже?

public string FirstName
{
   get { return _firstName; }
   set { _firstName = value ?? string.Empty; }
}

Ответы [ 4 ]

5 голосов
/ 11 февраля 2020

Это конкретное изменение было задокументировано здесь , и это одно из критических изменений с MVC 1.0. Этот лог c привязки пустой строки к null s управляется свойством ModelMetadata.ConvertEmptyStringToNull, которое используется DefaultModelBinder.

Теперь, если вы не хотите аннотировать все свои свойства, вы можно создать пользовательский механизм связывания модели:

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);
    }
}

и установить его в Global.asax:

ModelBinders.Binders.DefaultBinder = new EmptyStringModelBinder();

Или в заданном вами c действии:

[HttpPost]
public JsonResult ActionSubmit([ModelBinder(typeof(EmptyStringModelBinder))SampleViewModel model)

Почему это было сделано?

Это было сделано потому, что значение string по умолчанию равно null, а string - reference type, а значение по умолчанию для всех ссылочных типов - null. Следовательно, это изменение структуры может быть разумным. Но с другой стороны, мы должны стараться вообще избегать нулевых значений, поэтому нам нужно написать пользовательское связующее для моделей, чтобы избежать таких случаев.

Возникает вопрос, почему значение по умолчанию для строки введите пустую строку вместо пустой строки? . Вы можете go, чтобы понять, почему это изменение было сделано.

Согласно @Anton: в c# 8.0 вы можете включить нулевые проверки, чтобы избежать NullReferenceException и установить значения по умолчанию для ссылочных типов. вместо null

4 голосов
/ 09 февраля 2020

Почему при Ajax отправке пустого значения в контроллере появляется нулевое значение?

string является ссылочным типом, а его значение по умолчанию равно null. ModelBinder устанавливает для свойств значение по умолчанию, если в запросе не указано значение.

Есть ли лучший и более элегантный способ решения моей проблемы, как показано ниже?

  1. Вы можете аннотировать свойство с помощью [DisplayFormat(ConvertEmptyStringToNull = false)], поэтому значение пустой строки сохраняется.

  2. Вы можете написать пользовательский ModelBinder, который устанавливает * От 1022 * до false, и применять его во всем мире.

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

//register it in Application_Start()
ModelBinders.Binders.Add(typeof(string), new NullStringModelBinder());
1 голос
/ 12 февраля 2020

Благодаря ответу @Rahul Sharma и @ rhytonix. Они оба хорошо выглядят. Я мог бы sh Я мог принять оба ваших ответа, но я не мог. Мне трудно решить, кто заслуживает получить всю награду, поэтому она должна быть разделена на две равные части.

Поэтому я решила подвести итоги вместе с примерами и более подробными объяснениями.

Почему ?

Это просто потому, что из MVC 2.0 по умолчанию инициализируются строки как ноль. Чтобы быть более точным, если empty означает, что строка не имеет значения, то. NET устанавливает ее значение по умолчанию. И строка по умолчанию (принадлежащая ссылочному типу): null.

Подробнее в Привязка свойства строки модели Разрывное изменение

Решение

Есть несколько способов связать свойство String как string.Empty вместо null

1. Начиная с C# 6, вы можете использовать DefaultValueAttribute , чтобы автоматически определять начальное значение, как показано ниже

public string LastName => string.Empty; 

По сути, этот способ аналогичен упомянутому решению OP. в посте, только более элегантно.

2. Пользовательская реализация по умолчанию IModelBinder путем наследования от DefaultModelBinder и изменения значения ConvertEmptyStringToNull на false для внутреннего объекта ModelMetaData.

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

Затем в Application_Start() метод Global.asax.cs вам нужно сделать, как показано ниже, чтобы завершить

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

3. Используйте DisplayFormatAttribute.ConvertEmptyStringToNull Свойство как показано ниже

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

Просто потому, что в ModelMetadata

true если пусто строковые значения автоматически конвертируются в null; в противном случае false. По умолчанию true

0 голосов
/ 11 февраля 2020

Когда вы объявляете строковую переменную в C#, ее значение равно null, пока не будет присвоено значение.

Когда данные отправляются посредством отправки формы, любые поля, в которые не была введена информация, отправляются как пустые строки. Лучший аналог без предоставленной информации - это null, поэтому он устанавливает эти значения на null (или, скорее, не устанавливает значение вообще).

MVC не может различить guish между пустой строкой, поскольку информация не была предоставлена, и пустой строкой, потому что это было значение, присвоенное в JavaScript перед передачей. Он просто знает, что одно из полей не имеет информации, поэтому это значение должно быть null.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...