source

ASP의 이유Net MVC 모델 바인더가 빈 JSON 배열을 null로 바인딩합니까?

ittop 2023. 3. 28. 22:36
반응형

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 arrayMVC 컨트롤러에 접속합니다.

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

컨트롤러

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

임신했어요.mode.MyEmplsnull이 아닌 빈 c# 배열이어야 합니다.빈 어레이를 실현하기 위해 커스텀 모델 바인더가 필요합니까?

다른 답변 중 일부는 질문의 의미를 놓쳤다고 생각합니다.기본 MVC 모델바인더가 빈 Json 어레이를 빈 C# 어레이가 아닌 null로 바인드하는 이유는 무엇입니까?

왜 그랬는지는 말할 수 없지만 어디서 그런 일이 일어나는지 보여 줄 수는 있어MVC의 소스는, 다음의 CodePlex 로 입수할 수 있습니다.찾으시는 파일은 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;
}

모델의 생성자에 있는 어레이를 초기화하면 이 문제를 피할 수 있습니다.소스를 빠르게 읽어보면 빈 어레이를 반환할 수 없는 이유나 반환하지 않기로 결정한 이유를 설명할 수 없지만 흥미로운 읽을거리가 될 것입니다.

이것은 C#의 참조 타입의 디폴트값이기 때문에 null 값은 C#의 참조 유형에 대한 기본값입니다.빈 어레이를 가져오려면 컨스트럭터를 사용하여 모델 내의 어레이를 초기화해야 합니다.그러나 초기화할 때 어레이 크기를 정의해야 하므로 다음과 같은 다른 유형의 수집을 사용하는 것이 좋습니다.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*/];
    }
}

모델을 받는다면.MyEmpls를 null로 하면 서버 측에서 다음과 같은 예외 발생을 중지하는 조건을 만들 수 있습니다.

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

MyEmpls는 커스텀클래스 어레이로 []만 송신하고 있기 때문에 무효가 됩니다.

도움이 되시길 바랍니다.

다음과 같이 모델 바인더를 작성합니다.

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
}

값이 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;}
}
[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는 빈 어레이를 올바르게 역직렬화합니다.따라서 전달된 모델을 무시하고 입력 요청 스트림에서 재구성할 수 있습니다.아마 올바른 방법은 아닐 겁니다. 하지만 일단 수고를 덜면 됩니다.시스템을 참조해야 합니다.Web.Extensions.

C# 어레이 초기화의 기본 동작은 빈 어레이가 아니라 늘입니다.

따라서 빈 어레이를 전송한 경우 빈 어레이는 시작되지 않지만 기본 초기화는 null로 트리거됩니다.

다음 링크를 참조하십시오.http://www.dotnetperls.com/null-array

언급URL : https://stackoverflow.com/questions/23108272/why-does-the-asp-net-mvc-model-binder-bind-an-empty-json-array-to-null

반응형