programing

ASP에 JSON 데이터를 게시하는 중입니다.넷 MVC

newnotes 2023. 3. 21. 22:33
반응형

ASP에 JSON 데이터를 게시하는 중입니다.넷 MVC

JSON을 사용하여 웹 페이지에 줄 항목 목록을 가져오려고 합니다. 웹 페이지는 도착한 것과 동일한 JSON 구조를 사용하여 Ajax 요청에 의해 조작되어 서버로 반송됩니다(필드 값이 변경된 것은 제외).

서버로부터의 데이터 수신은 간단합니다.조작도 간단합니다.다만, JSON 데이터를 서버에 되돌려 보존합니다.자살 시간!누가 좀 도와주세요!

자바스크립트

var lineitems;

// get data from server
$.ajax({
    url: '/Controller/GetData/',
    success: function(data){
        lineitems = data;
    }
});

// post data to server
$.ajax({
    url: '/Controller/SaveData/',
    data: { incoming: lineitems }
});

C# - 오브젝트

public class LineItem{
    public string reference;
    public int quantity;
    public decimal amount;
}

C# - 컨트롤러

public JsonResult GetData()
{
    IEnumerable<LineItem> lineItems = ... ; // a whole bunch of line items
    return Json(lineItems);
}

public JsonResult SaveData(IEnumerable<LineItem> incoming){
    foreach(LineItem item in incoming){
        // save some stuff
    }
    return Json(new { success = true, message = "Some message" });
}

데이터는 시리얼화된 포스트 데이터로 서버에 도착합니다.는 바인딩을 합니다.IEnumerable<LineItem> incoming 의외로 인 '이러한'을 수 있습니다.IEnumerable has of of LineItems가 안 요. - 데이터가 안 들어가요. - 데이터가 안 들어가요.

솔루션

사용하면서요.djch BeRecursive아래에서는 크게 두 가지 방법으로 문제를 해결했습니다.

서버측

합니다.System.Runtime.Serialization ★★★★★★★★★★★★★★★★★」using System.Runtime.Serialization.Json

private T Deserialise<T>(string json)
{
    using (var ms = new MemoryStream(Encoding.Unicode.GetBytes(json)))
    {
        var serialiser = new DataContractJsonSerializer(typeof(T));
        return (T)serialiser.ReadObject(ms);
    }
}

public void Action(int id, string items){
    IEnumerable<LineItem> lineitems = Deserialise<IEnumerable<LineItem>>(items);
    // do whatever needs to be done - create, update, delete etc.
}

클라이언트 측

json.org의 stringify 메서드를 사용합니다.이 stringify는 의존관계 https://github.com/douglascrockford/JSON-js/blob/master/json2.js에서 이용 가능합니다(최소화 시 2.5kb).

$.ajax({
    type: 'POST',
    url: '/Controller/Action',
    data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});

모델 바인딩 JSON 데이터에 대한 Phil Hack의 게시물을 보십시오.문제는 기본 모델 바인더가 JSON을 제대로 일련화하지 않는다는 것입니다.Value Provider가 필요하거나 커스텀 모델 바인더를 작성할 수 있습니다.

using System.IO;
using System.Web.Script.Serialization;

public class JsonModelBinder : DefaultModelBinder {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
            if(!IsJSONRequest(controllerContext)) {
                return base.BindModel(controllerContext, bindingContext);
            }

            // Get the JSON data that's been posted
            var request = controllerContext.HttpContext.Request;
            //in some setups there is something that already reads the input stream if content type = 'application/json', so seek to the begining
            request.InputStream.Seek(0, SeekOrigin.Begin);
            var jsonStringData = new StreamReader(request.InputStream).ReadToEnd();

            // Use the built-in serializer to do the work for us
            return new JavaScriptSerializer()
                .Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);

            // -- REQUIRES .NET4
            // If you want to use the .NET4 version of this, change the target framework and uncomment the line below
            // and comment out the above return statement
            //return new JavaScriptSerializer().Deserialize(jsonStringData, bindingContext.ModelMetadata.ModelType);
        }

        private static bool IsJSONRequest(ControllerContext controllerContext) {
            var contentType = controllerContext.HttpContext.Request.ContentType;
            return contentType.Contains("application/json");
        }
    }

public static class JavaScriptSerializerExt {
        public static object Deserialize(this JavaScriptSerializer serializer, string input, Type objType) {
            var deserializerMethod = serializer.GetType().GetMethod("Deserialize", BindingFlags.NonPublic | BindingFlags.Static);

            // internal static method to do the work for us
            //Deserialize(this, input, null, this.RecursionLimit);

            return deserializerMethod.Invoke(serializer,
                new object[] { serializer, input, objType, serializer.RecursionLimit });
        }
    }

MVC에 Global.asax 파일에서 사용하도록 지시합니다.

ModelBinders.Binders.DefaultBinder = new JsonModelBinder();

또한 이 코드는 컨텐츠 유형 = 'application/json'을 사용하므로 jquery에서 다음과 같이 설정하십시오.

$.ajax({
    dataType: "json",
    contentType: "application/json",            
    type: 'POST',
    url: '/Controller/Action',
    data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});

가장 간단한 방법

당신의 문제를 직접적으로 다루고 있는 이 블로그 글을 읽어보시길 권합니다.

커스텀 모델 바인더를 사용하는 것은 필 해크가 지적한 바와 같이 현명하지 않습니다(그의 블로그 투고는 위쪽 블로그 투고에도 링크되어 있습니다).

기본적으로 다음 세 가지 옵션이 있습니다.

  1. 를 쓰다JsonValueProviderFactory 측 합니다.json2.jsJSON에 관한 정보입니다.

  2. 를 쓰다JQueryValueProviderFactoryjQuery JSON에서 오브젝트 .$.ajax or or or openicle.

  3. 블로그 투고에 기재되어 있는 매우 심플하고 빠른 jQuery 플러그인을 사용하여 JSON 오브젝트(바인드되는 어레이도)를 준비합니다.IList<T>서버측에서 올바르게 해석되는 날짜를 지정합니다.DateTimeAsp.net MVC에 접속해 주세요.

이 세 가지 중 마지막 것은 가장 단순하고 Asp.net MVC 내부 작업을 방해하지 않으므로 버그 표면을 낮출 수 있습니다.블로그 투고에 기재되어 있는 이 기술을 사용하면 강력한 유형의 액션 파라미터를 올바르게 바인드하여 검증할 수 있습니다.그래서 기본적으로는 윈윈 상황입니다.

MVC3에서 이걸 추가했어요.

하지만 더 좋은 점은 MVC 소스 코드가 열려 있기 때문에 Value Provider를 직접 가져와 자신의 코드로 사용할 수 있다는 것입니다(MVC3에 아직 접속하지 않은 경우).

결국 이런 일이 생기게 될 거야

ValueProviderFactories.Factories.Add(new JsonValueProviderFactory())

나는 이 문제를 잔상의 조언에 따라 해결했다.

web.config에서 maxJsonLength의 길이를 무제한으로 설정할 수 있습니까?

컨트롤러의 액션에 큰 json을 게시해야 할 때 유명한 "Error during deserialization using the JSON JavaScript Serializer"가 표시됩니다.문자열 길이가 maxJsonLength 속성에 설정된 값을 초과합니다.\r\n 파라미터 이름: 입력값 공급자"입니다.

새로운 ValueProviderFactory LargeJsonValueProviderFactory를 만들고 MaxJsonLength = Int32를 설정했습니다.GetDeserializedObject 메서드의 MaxValue

public sealed class LargeJsonValueProviderFactory : ValueProviderFactory
{
    private static void AddToBackingStore(LargeJsonValueProviderFactory.EntryLimitedDictionary backingStore, string prefix, object value)
    {
        IDictionary<string, object> dictionary = value as IDictionary<string, object>;
        if (dictionary != null)
        {
            foreach (KeyValuePair<string, object> keyValuePair in (IEnumerable<KeyValuePair<string, object>>) dictionary)
                LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakePropertyKey(prefix, keyValuePair.Key), keyValuePair.Value);
        }
        else
        {
            IList list = value as IList;
            if (list != null)
            {
                for (int index = 0; index < list.Count; ++index)
                    LargeJsonValueProviderFactory.AddToBackingStore(backingStore, LargeJsonValueProviderFactory.MakeArrayKey(prefix, index), list[index]);
            }
            else
                backingStore.Add(prefix, value);
        }
    }

    private static object GetDeserializedObject(ControllerContext controllerContext)
    {
        if (!controllerContext.HttpContext.Request.ContentType.StartsWith("application/json", StringComparison.OrdinalIgnoreCase))
            return (object) null;
        string end = new StreamReader(controllerContext.HttpContext.Request.InputStream).ReadToEnd();
        if (string.IsNullOrEmpty(end))
            return (object) null;

        var serializer = new JavaScriptSerializer {MaxJsonLength = Int32.MaxValue};

        return serializer.DeserializeObject(end);
    }

    /// <summary>Returns a JSON value-provider object for the specified controller context.</summary>
    /// <returns>A JSON value-provider object for the specified controller context.</returns>
    /// <param name="controllerContext">The controller context.</param>
    public override IValueProvider GetValueProvider(ControllerContext controllerContext)
    {
        if (controllerContext == null)
            throw new ArgumentNullException("controllerContext");
        object deserializedObject = LargeJsonValueProviderFactory.GetDeserializedObject(controllerContext);
        if (deserializedObject == null)
            return (IValueProvider) null;
        Dictionary<string, object> dictionary = new Dictionary<string, object>((IEqualityComparer<string>) StringComparer.OrdinalIgnoreCase);
        LargeJsonValueProviderFactory.AddToBackingStore(new LargeJsonValueProviderFactory.EntryLimitedDictionary((IDictionary<string, object>) dictionary), string.Empty, deserializedObject);
        return (IValueProvider) new DictionaryValueProvider<object>((IDictionary<string, object>) dictionary, CultureInfo.CurrentCulture);
    }

    private static string MakeArrayKey(string prefix, int index)
    {
        return prefix + "[" + index.ToString((IFormatProvider) CultureInfo.InvariantCulture) + "]";
    }

    private static string MakePropertyKey(string prefix, string propertyName)
    {
        if (!string.IsNullOrEmpty(prefix))
            return prefix + "." + propertyName;
        return propertyName;
    }

    private class EntryLimitedDictionary
    {
        private static int _maximumDepth = LargeJsonValueProviderFactory.EntryLimitedDictionary.GetMaximumDepth();
        private readonly IDictionary<string, object> _innerDictionary;
        private int _itemCount;

        public EntryLimitedDictionary(IDictionary<string, object> innerDictionary)
        {
            this._innerDictionary = innerDictionary;
        }

        public void Add(string key, object value)
        {
            if (++this._itemCount > LargeJsonValueProviderFactory.EntryLimitedDictionary._maximumDepth)
                throw new InvalidOperationException("JsonValueProviderFactory_RequestTooLarge");
            this._innerDictionary.Add(key, value);
        }

        private static int GetMaximumDepth()
        {
            NameValueCollection appSettings = ConfigurationManager.AppSettings;
            if (appSettings != null)
            {
                string[] values = appSettings.GetValues("aspnet:MaxJsonDeserializerMembers");
                int result;
                if (values != null && values.Length > 0 && int.TryParse(values[0], out result))
                    return result;
            }
            return 1000;
        }
    }
}

그런 다음 Global.asax.cs의 Application_Start 메서드에서 ValueProviderFactory를 새 것으로 바꿉니다.

protected void Application_Start()
    {
        ...

        //Add LargeJsonValueProviderFactory
        ValueProviderFactory jsonFactory = null;
        foreach (var factory in ValueProviderFactories.Factories)
        {
            if (factory.GetType().FullName == "System.Web.Mvc.JsonValueProviderFactory")
            {
                jsonFactory = factory;
                break;
            }
        }

        if (jsonFactory != null)
        {
            ValueProviderFactories.Factories.Remove(jsonFactory);
        }

        var largeJsonValueProviderFactory = new LargeJsonValueProviderFactory();
        ValueProviderFactories.Factories.Add(largeJsonValueProviderFactory);
    }

이러한 방법을 시도해 볼 수 있습니다. 1. JSON 개체를 문자열화한 후 Ajax를 통해 서버 작업을 호출합니다.2. 동작에서 문자열을 역직렬화한 후 데이터를 사전으로 사용합니다.

아래 Javascript 샘플(JSON 객체 전송)

$.ajax(
   {
       type: 'POST',
       url: 'TheAction',
       data: { 'data': JSON.stringify(theJSONObject) 
   }
})

아래의 액션(C#) 샘플

[HttpPost]
public JsonResult TheAction(string data) {

       string _jsonObject = data.Replace(@"\", string.Empty);
       var serializer = new System.Web.Script.Serialization.JavaScriptSerializer();           
        Dictionary<string, string> jsonObject = serializer.Deserialize<Dictionary<string, string>>(_jsonObject);


        return Json(new object{status = true});

    }

수동 역직렬화를 사용하여 해결했습니다.암호로 설명하겠습니다.

public ActionResult MyMethod([System.Web.Http.FromBody] MyModel model)
{
 if (module.Fields == null && !string.IsNullOrEmpty(Request.Form["fields"]))
 {
   model.Fields = JsonConvert.DeserializeObject<MyFieldModel[]>(Request.Form["fields"]);
 }
 //... more code
}

문자열로 입력되는 JSON 데이터가 있는 경우(예: '[{"id":1,"name"):"Charles", {"id":8", "name":John", {"id":13", "name":"Sally"})

그런 다음 JSON.net을 사용하고 Linq to JSON을 사용하여 값을 가져옵니다.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{

    if (Request["items"] != null)
    {
        var items = Request["items"].ToString(); // Get the JSON string
        JArray o = JArray.Parse(items); // It is an array so parse into a JArray
        var a = o.SelectToken("[0].name").ToString(); // Get the name value of the 1st object in the array
        // a == "Charles"
    }
}
}

BeRecursive의 답변은 Json으로 표준화할 수 있도록 제가 사용한 답변입니다.Net(MVC5 및 WebApi5가 있습니다) WebApi5는 이미 Json을 사용하고 있습니다.Net) 단, 문제가 발견되었습니다.POST 하는 루트에 파라미터가 있는 경우 MVC는 모델바인더를 호출하여 URI 값을 취득하려고 합니다.이 코드는 투고된 JSON을 이러한 값에 바인드하려고 합니다.

예:

[HttpPost]
[Route("Customer/{customerId:int}/Vehicle/{vehicleId:int}/Policy/Create"]
public async Task<JsonNetResult> Create(int customerId, int vehicleId, PolicyRequest policyRequest)

BindModel이 함수는 JSON을 결합하려고 할 때 3회 호출되며, 첫 번째 함수는 폭격됩니다.customerId다음 오류와 함께:Error reading integer. Unexpected token: StartObject. Path '', line 1, position 1.

이 코드 블록을 위에 추가했습니다.BindModel:

if (bindingContext.ValueProvider.GetValue(bindingContext.ModelName) != null) {
    return base.BindModel(controllerContext, bindingContext);
}

Value Provider는 다행히 이 메서드에 도달했을 때 루트 값이 계산됩니다.

여기 있는 모든 사람들이 "먼 길을 갔다!"는 걸 봤어.사용하고 있는 한MVC가장 쉬운 방법을 사용하는 것을 강력히 추천합니다.Newtonsoft.JSON또, 라이브러리를 사용하지 않는 경우는, 다음의 회답 링크를 확인해 주세요.저는 이 문제를 스스로 해결하기 위해 충분한 연구 시간을 들였습니다.그리고 이것이 제가 찾은 해결책입니다.

먼저 뉴턴소프트를 구현합니다.Json:

using Newtonsoft.Json;

Ajax 요청 준비:

$.ajax({
    dataType: "json",
    contentType: "application/json",            
    type: 'POST',
    url: '/Controller/Action',
    data: { 'items': JSON.stringify(lineItems), 'id': documentId }
});

그런 다음 결과 클래스로 이동합니다.

public ActionResult SaveData(string incoming, int documentId){
    // DeSerialize into your Model as your Model Array
    LineItem[] jsr = JsonConvert.DeserializeObject<LineItem[]>(Temp);
    foreach(LineItem item in jsr){
        // save some stuff
    }
    return Json(new { success = true, message = "Some message" });
}

저기 비법 보이지?사용하는 대신JsonResult나는 레귤러를 사용했다.ActionResultjson 문자열을 포함하는 문자열로 지정합니다.그리고 나서 내 것으로 탈직렬화 되었다.Model제가 가지고 있는 어떤 액션에도 사용할 수 있도록 하겠습니다.

이 방법의 플러스 측면은 다음과 같습니다.

  1. 행동들 사이를 쉽게 넘길 수 있고,
  2. 코드의 사용법이 점점 더 명확해지고 있습니다.
  3. 모델을 변경할 필요가 없습니다.
  4. 심플한 실장JSON.stringify(Model)
  5. 문자열만 전달 중

이 방법의 단점은 다음과 같습니다.

  1. 문자열만 전달 중
  2. 탈직렬화 과정

또, 다음의 질문과 답변을 확인해 주세요.

https://stackoverflow.com/a/45682516/861019

다른 방법:

https://stackoverflow.com/a/31656160/861019

및 다른 방법:

https://stackoverflow.com/a/50787450/861019

언급URL : https://stackoverflow.com/questions/4164114/posting-json-data-to-asp-net-mvc

반응형