2016-12-08 2 views
0

오래 전, 나는 모든 행동이 JSON 그들의 결과는 최상위 래퍼 객체에 투입 할 것이다 반환 내 애플 리케이션을위한 코딩 표준을 설정 : 잘 작동하고있다사용자 정의 JSON 직렬화

var result = { 
    success: false, 
    message: 'Something went wrong', 
    data: {} // or [] 
} 

좋은 코드 표준화 행복을 제공했습니다.

그러나 오늘날 서버 측 코드는 항상 반환되는 항목의 전체 직렬화를 수행한다고 가정합니다. 이제 "데이터"페이로드가 이미 잘 구성된 JSON 문자열 인이 사람들 중 한 명을 직렬화하려고합니다.

이 일하고 있었다 일반적인 패턴입니다 : 그것은 나누기

bool success = false; 
string message = "Something went wrong"; 
object jsonData = "[{\"id\":\"0\",\"value\":\"1234\"}]"; // Broken 

dynamic finalData = new { success = success, message = message, data = jsonData }; 

JsonResult output = new JsonResult 
{ 
    Data = finalData, 
    JsonRequestBehavior = JsonRequestBehavior.AllowGet, 
    MaxJsonLength = int.MaxValue 
}; 
return output; 

는 "데이터"요소가 적절한 JSON으로 브라우저에 도달 할 때 문자열로받은, 그리고 될 것입니다 객체 (위의 예에서는 배열)가 있어야합니다.

"원시로 직렬화"라고하는 특성으로 속성을 꾸밀 수있는 방법이 있습니까, 아니면이 작업을 수행하기 위해 사용자 지정 JSON serializer를 작성해야할까요?

+1

'json.parse'를 사용해야합니다. 전체 세부 정보보기 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse –

+1

글쎄, 기술적으로 당신은 자신의 계약과 표준을 위반하고 있습니다. 이전에는 * object *를 기대했지만, 이제는 문자열을 전달합니다. 그것은 나에게 나쁜 일을하는 것처럼 보이지만,이 문자열을 피할 방법이 없다면'data = JsonSerializer.Deserialize (jsonData)'를 쓸 수 있습니다. 그래도 나중에 직렬화되지 않도록 직렬화 할 것입니다. – Rob

+0

json.parse가 브라우저 끝입니다.서버 측에서 직렬화를 조작하려고합니다. 롭, 당신은 정확히 문제에 직면 해 있습니다 ... 나는 그것을 직렬화하고 싶지 않습니다. 단지 즉시 다시 직렬화하고 싶습니다. (그리고 실제로는 이미 완벽하게 좋은 JSON이었던 것을 감싸고 있습니다.) 나는 해결책을 모은 것 같아요, 내일 게시 할 것입니다. 둘 다 감사합니다! – Eric

답변

0

여기에 내가 함께 ....이와

// Wrap "String" in a container class 
public class JsonStringWrapper 
{ 
    // Hey Microsoft - This is where it would be nice if "String" wasn't marked "sealed" 
    public string theString { get; set; } 
    public JsonStringWrapper() { } 
    public JsonStringWrapper(string stringToWrap) { theString = stringToWrap; } 
} 

// Custom JsonConverter that will just dump the raw string into 
// the serialization process. Loosely based on: 
// http://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm 
public class JsonStringWrapperConverter : JsonConverter 
{ 
    private readonly Type _type = typeof(JsonStringWrapper); 

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 
    { 
     JToken t = JToken.FromObject(value); 

     if (t.Type != JTokenType.Object) 
     { 
      t.WriteTo(writer); 
     } 
     else 
     { 
      string rawValue = ((JsonStringWrapper)value).theString; 
      writer.WriteRawValue((rawValue == null) ? "null" : rawValue); 
     } 
    } 

    public override bool CanWrite 
    { 
     get { return true; } 
    } 

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 
    { 
     throw new NotImplementedException("Unnecessary because CanRead is false. The type will skip the converter."); 
    } 

    public override bool CanRead 
    { 
     get { return false; } 
    } 

    public override bool CanConvert(Type objectType) 
    { 
     return _type == objectType; 
    } 
} 

// Custom JsonResult that will use the converter above, largely based on: 
// http://stackoverflow.com/questions/17244774/proper-json-serialization-in-mvc-4 
public class PreSerializedJsonResult : JsonResult 
{ 
    private static readonly JsonSerializerSettings Settings = new JsonSerializerSettings 
    { 
     Converters = new List<JsonConverter> { new JsonStringWrapperConverter() } 
    }; 

    public override void ExecuteResult(ControllerContext context) 
    { 
     if (this.JsonRequestBehavior == JsonRequestBehavior.DenyGet && 
      string.Equals(context.HttpContext.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase)) 
     { 
      throw new InvalidOperationException("GET request not allowed"); 
     } 

     var response = context.HttpContext.Response; 

     response.ContentType = !string.IsNullOrEmpty(this.ContentType) ? this.ContentType : "application/json"; 

     if (this.ContentEncoding != null) 
     { 
      response.ContentEncoding = this.ContentEncoding; 
     } 

     if (this.Data == null) 
     { 
      return; 
     } 

     response.Write(JsonConvert.SerializeObject(this.Data, Settings)); 
    } 
} 

// My base controller method that overrides Json()... 
protected JsonResult Json(string message, object data) 
{ 
    PreSerializedJsonResult output = new PreSerializedJsonResult(); 

    object finalData = (data is string && (new char[] { '[', '{' }.Contains(((string)data).First()))) 
     ? new JsonStringWrapper(data as string) 
     : data; 

    output.Data = new 
    { 
     success = string.IsNullOrEmpty(message), 
     message = message, 
     data = finalData 
    }; 
    output.JsonRequestBehavior = JsonRequestBehavior.AllowGet; 
    output.MaxJsonLength = int.MaxValue; 
    return output; 
} 

// Aaaand finally, here's how it might get called from an Action method: 
... 
return Json("This was a failure", null); 
... 
return Json(null, yourJsonStringVariableHere); 

, I는 서버에있는 JSON 구문 분석을하고 있지 않다 결국거야. 내 문자열은 데이터베이스에서 나오고 MVC를 건드리지 않고 곧바로 클라이언트로 전달됩니다.

EDIT : 업데이트 된 버전은 이제 JsonStringWrapper 유형의 계층 구조에서 개별 속성을 갖는 객체 직렬화를 지원합니다. 이 시나리오는 내 시나리오에서 "하이브리드"모델을 지원하는 데 유용합니다. 객체 A에 미리 만들어진 JSON 문자열 중 하나 인 속성 B가 있으면 위의 코드에서 올바르게 처리 할 것입니다.

1

두 번 serialize하는 중입니다 (jsonData + output). 당신은 그것을 할 수 없으며 한번만 비 직렬화 할 것을 기대합니다 (출력).

동적 "데이터"개체를 실제 C# 개체로 설정하면 작동 할 수 있습니다. 또는 속성 이름을 "jsonData"로 바꿀 수 있습니다.

dynamic finalData = new { success = success, message = message, jsonData = jsonData }; 

... 그래서 실제로 수행중인 작업을 반영합니다.

+0

감사합니다, jvenema, 나는 응답을 주셔서 감사합니다. 내 문제는 이것이 실제로 C# 개체가 아닙니다. 실제로 SQL에서 JSON 문자열로 곧장옵니다. 나는 그것과 동등한 중간 계층의 어떤 유형조차 가지고 있지 않습니다. 나는 웹 서버를 통과 시키려하고있다. 그 말은 - 다른 스레드를 기반으로하는 사용자 지정 serializer를 사용하여 솔루션을 작성했다고 생각합니다. 그것이 효과가 있다면, 나는 내일 떠올랐다. – Eric

0

Newtonsoft의 JsonWriter 클래스를 사용하여 JSON 패키지를 직접 만들면됩니다. 그것은 다음과 같이 보일 것입니다 :

using(var textWriter = new StringWriter()) 
using(var jsonWriter = new JsonTextWriter(textWriter)) 
{ 
    jsonWriter.WriteStartObject(); 

    jsonWriter.WritePropertyName("success"); 
    jsonWriter.WriteValue(success); 

    jsonWriter.WritePropertyName("message"); 
    jsonWriter.WriteValue(message); 

    jsonWriter.WritePropertyName("data"); 
    jsonWriter.WriteRaw(jsonData); 

    jsonWriter.WriteEndObject(); 

    var result = new ContentResult(); 
    result.Content = textWriter.ToString(); 
    result.ContentType = "application/json"; 
    return result; 
} 
0

내가 방금 NewtonSoft처럼 JSON 시리얼 라이저를 사용하여 객체에 SQL 테이블에서 반환되는 문자열을 직렬화 할 필요가 있다고 생각합니다.

bool success = false; 
string message = "Something went wrong"; 
string rawData = "[{\"id\":\"0\",\"value\":\"1234\"}]"; // Broken 
object jsonData = JsonConvert.DeserializeObject<dynamic>(rawData); 

dynamic finalData = new { success = success, message = message, data = jsonData }; 

JsonResult output = new JsonResult 
{ 
    Data = finalData, 
    JsonRequestBehavior = JsonRequestBehavior.AllowGet, 
    MaxJsonLength = int.MaxValue 
}; 
return output; 
관련 문제