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 }
});
가장 간단한 방법
당신의 문제를 직접적으로 다루고 있는 이 블로그 글을 읽어보시길 권합니다.
커스텀 모델 바인더를 사용하는 것은 필 해크가 지적한 바와 같이 현명하지 않습니다(그의 블로그 투고는 위쪽 블로그 투고에도 링크되어 있습니다).
기본적으로 다음 세 가지 옵션이 있습니다.
를 쓰다
JsonValueProviderFactory측 합니다.json2.jsJSON에 관한 정보입니다.를 쓰다
JQueryValueProviderFactoryjQuery JSON에서 오브젝트 .$.ajaxor or or openicle.블로그 투고에 기재되어 있는 매우 심플하고 빠른 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제가 가지고 있는 어떤 액션에도 사용할 수 있도록 하겠습니다.
이 방법의 플러스 측면은 다음과 같습니다.
- 행동들 사이를 쉽게 넘길 수 있고,
- 코드의 사용법이 점점 더 명확해지고 있습니다.
- 모델을 변경할 필요가 없습니다.
- 심플한 실장
JSON.stringify(Model) - 문자열만 전달 중
이 방법의 단점은 다음과 같습니다.
- 문자열만 전달 중
- 탈직렬화 과정
또, 다음의 질문과 답변을 확인해 주세요.
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
'programing' 카테고리의 다른 글
| ReactJS 구성 요소가 상태 변수를 사용하여 텍스트 영역을 렌더링하지 않음 (0) | 2023.03.21 |
|---|---|
| 리액트 라우터에서 DefaultRoute를 다른 루트로 설정하는 방법 (0) | 2023.03.21 |
| 스프링 부트에서의 Log4j.properties (0) | 2023.03.21 |
| Angular를 얻으려면JS를 A 태그의 제목 속성에 바인딩하시겠습니까? (0) | 2023.03.21 |
| 디렉티브의 링크 함수에서의 동작을 테스트하는 방법 (0) | 2023.03.21 |