Подтвердить что ты не робот

Почему механизм связывания модели ASP.Net MVC связывает пустой массив JSON со значением NULL?

Вот мой класс модели:

public class MyModel
{
    public Employees[] MyEmpls{get;set;}
    public int Id{get;set;}
    public OrgName{get;set;}
}

Передача объекта структуры JSON ниже с MyEmpls as empty array в контроллер MVC.

["Id":12, "MyEmpls":[], "OrgName":"Kekran Mcran"]

контроллер

[HttpPost]
public ActionResult SaveOrg(MyModel model)
{
  //model.MyEmpls is null here
}

Я ожидаю, что mode.MyEmpls будет пустым массивом С#, а не null. Нужно ли связывать пользовательские модели для получения пустого массива?

4b9b3361

Ответ 1

Я думаю, что некоторые из других ответов упустили смысл вопроса: почему привязка модели MVC по умолчанию связывает пустой массив Json с нулевым, а не пустым массивом С#?

Хорошо, я не могу сказать вам, почему они это сделали, но я могу показать вам, где это происходит. Источник для MVC можно найти на CodePlex здесь: http://aspnetwebstack.codeplex.com/SourceControl/latest. Файл, который вы ищете, ValueProviderResult.cs, где вы можете видеть:

    private static object UnwrapPossibleArrayType(CultureInfo culture, object value, Type destinationType)
    {
        if (value == null || destinationType.IsInstanceOfType(value))
        {
            return value;
        }

        // array conversion results in four cases, as below
        Array valueAsArray = value as Array;
        if (destinationType.IsArray)
        {
            Type destinationElementType = destinationType.GetElementType();
            if (valueAsArray != null)
            {
                // case 1: both destination + source type are arrays, so convert each element
                IList converted = Array.CreateInstance(destinationElementType, valueAsArray.Length);
                for (int i = 0; i < valueAsArray.Length; i++)
                {
                    converted[i] = ConvertSimpleType(culture, valueAsArray.GetValue(i), destinationElementType);
                }
                return converted;
            }
            else
            {
                // case 2: destination type is array but source is single element, so wrap element in array + convert
                object element = ConvertSimpleType(culture, value, destinationElementType);
                IList converted = Array.CreateInstance(destinationElementType, 1);
                converted[0] = element;
                return converted;
            }
        }
        else if (valueAsArray != null)
        {
            // case 3: destination type is single element but source is array, so extract first element + convert
            if (valueAsArray.Length > 0)
            {
                value = valueAsArray.GetValue(0);
                return ConvertSimpleType(culture, value, destinationType);
            }
            else
            {
                // case 3(a): source is empty array, so can't perform conversion
                return null;
            }
        }
        // case 4: both destination + source type are single elements, so convert
        return ConvertSimpleType(culture, value, destinationType);
    }
}

Интересной частью является "случай 3":

else
{
    // case 3(a): source is empty array, so can't perform conversion
    return null;
}

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

Ответ 2

Вы получаете нулевое значение, так как это значение по умолчанию для ссылочного типа в С#. Чтобы получить пустой массив, вам нужно будет инициализировать массив в вашей модели с помощью конструктора. Однако, поскольку вам нужно будет определить размер массива при его инициализации, возможно, лучше использовать другой тип коллекции, такой как List:

public class MyModel
{
    public List<Employees> MyEmpls{get;set;}
    public int Id{get;set;}
    public OrgName{get;set;}

    public MyModel() 
    {
         MyEmpls = new List<Employees>();
    }
}

Затем вы получите пустой список, когда пустой пул передается из json.

Если вам действительно нужно использовать массив, просто инициализируйте его размером:

public class MyModel
{
    public Employees[] MyEmpls{get;set;}
    public int Id{get;set;}
    public OrgName{get;set;}

    public MyModel() 
    {
         MyEmpls = new Employees[//enter size of array in here];
    }
}

Ответ 3

Если вы получаете model.MyEmpls как null, тогда вы можете создать условие на стороне сервера, чтобы остановить повышение исключений, например:

if(model.MyEmpls !=null){
...
}

И вы получаете его null, потому что MyEmpls - это массив пользовательского класса, и вы отправляете только [].

Надеюсь, это поможет вам.

Ответ 4

Попробуйте создать привязку к модели, как показано ниже

public class MyModelBinder : IModelBinder
{
    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        try
        {                
            var request = controllerContext.HttpContext.Request;

            return new MyModel
            {
                MyEmpls = request[] ?? new Employees[0],
                Id = request["Id"] ?? "",
                OrgName = request["OrgName"] ?? ""

            };
        }
        catch 
        {
            //do required exception handling
        }
    }
}

В регистре Application_Start привязка к модели

ModelBinders.Binders.Add(typeof(MyModel), new MyModelBinder())

И измените контроллер как

[HttpPost]
public ActionResult SaveOrg([ModelBinder(typeof(MyModelBinder))] MyModel model)
{
  //model.MyEmpls is null here
}

Ответ 5

[HttpPost]
public ActionResult SaveOrg(MyModel model)
{
    var serializer = new JavaScriptSerializer();
    var stream = System.Web.HttpContext.Current.Request.InputStream;
    var reader = new StreamReader(stream);
    stream.Position = 0;
    var json = reader.ReadToEnd();
    model= serializer.Deserialize<MyModel>(json);
    //model.MyEmpls is [] here
}

JavaScriptSerializer корректно десериализует пустые массивы. Таким образом, вы можете игнорировать переданную модель и перестроить ее из потока запросов ввода. Наверное, не правильный путь, но если вам нужно сделать это только после того, как это сэкономит какое-то усилие. Вам нужно будет ссылаться на System.Web.Extensions.

Ответ 6

Поведение по умолчанию для инициализации массива С# - это пустой пустой массив

Итак, если вы отправляете пустой массив, вы не будете запускать пустой массив, но вы инициируете инициализацию по умолчанию null

См. следующую ссылку http://www.dotnetperls.com/null-array

Ответ 7

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

public class MyModel
{
    private _myEmpls{get;set;}
    public Employees[] MyEmpls{
     get{return _myEmpls;}
     set{_myEmpls=(value==null?new List<Employees>():value);}
    }

    public int Id{get;set;}
    public OrgName{get;set;}
}