ExpandoObject
런타임에 서버 측 동적 객체를 컴파일하는 동안 정말 마음에 들지만 JSON 직렬화 중에이 것을 평평하게 만드는 데 문제가 있습니다. 먼저 개체를 인스턴스화합니다.
dynamic expando = new ExpandoObject();
var d = expando as IDictionary<string, object>;
expando.Add("SomeProp", SomeValueOrClass);
여태까지는 그런대로 잘됐다. 내 MVC 컨트롤러에서 이것을 JsonResult로 보내려고하므로 이렇게합니다.
return new JsonResult(expando);
이렇게하면 브라우저에서 사용할 JSON을 아래와 같이 직렬화합니다.
[{"Key":"SomeProp", "Value": SomeValueOrClass}]
그러나 내가 정말로 원하는 것은 이것을 보는 것입니다.
{SomeProp: SomeValueOrClass}
내가 사용하는 경우 내가 이것을 달성 할 수 알고 dynamic
대신 ExpandoObject
– JsonResult
직렬화 할 수 있습니다 dynamic
(아무 키 또는 값 사업과) 하나의 객체에 속성과 값을, 하지만 난 사용을 필요로하는 이유는 ExpandoObject
내가 모두를 알 수 없기 때문에입니다 내가 아는 한 런타임까지 객체에 원하는 속성을 dynamic
사용하지 않고 는 동적으로 속성을 추가 할 수 없습니다 ExpandoObject
.
내 자바 스크립트에서 “키”, “가치”비즈니스를 살펴 봐야 할 수도 있지만 클라이언트에게 보내기 전에이를 파악하고 싶었습니다. 당신의 도움을 주셔서 감사합니다!
답변
또한 ExpandoObject에서만 작동하는 특수 JSONConverter를 만든 다음 JavaScriptSerializer의 인스턴스에 등록 할 수 있습니다. 이렇게하면 expando 배열, expando 객체 조합 및 …을 직렬화 할 수 있습니다. 올바르게 직렬화되지 않은 다른 종류의 객체 ( “원하는 방식”)를 찾은 다음 다른 변환기를 만들거나 다른 유형을 이 하나. 도움이 되었기를 바랍니다.
using System.Web.Script.Serialization;
public class ExpandoJSONConverter : JavaScriptConverter
{
public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
{
throw new NotImplementedException();
}
public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
{
var result = new Dictionary<string, object>();
var dictionary = obj as IDictionary<string, object>;
foreach (var item in dictionary)
result.Add(item.Key, item.Value);
return result;
}
public override IEnumerable<Type> SupportedTypes
{
get
{
return new ReadOnlyCollection<Type>(new Type[] { typeof(System.Dynamic.ExpandoObject) });
}
}
}
변환기 사용
var serializer = new JavaScriptSerializer();
serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoJSONConverter()});
var json = serializer.Serialize(obj);
답변
JSON.NET을 사용하면 SerializeObject를 호출하여 expando 개체를 “평탄화”할 수 있습니다.
dynamic expando = new ExpandoObject();
expando.name = "John Smith";
expando.age = 30;
var json = JsonConvert.SerializeObject(expando);
다음을 출력합니다.
{"name":"John Smith","age":30}
ASP.NET MVC 컨트롤러의 컨텍스트에서 결과는 Content-method를 사용하여 반환 될 수 있습니다.
public class JsonController : Controller
{
public ActionResult Data()
{
dynamic expando = new ExpandoObject();
expando.name = "John Smith";
expando.age = 30;
var json = JsonConvert.SerializeObject(expando);
return Content(json, "application/json");
}
}
답변
설명하는 동작을 달성하기 위해 내가 한 작업은 다음과 같습니다.
dynamic expando = new ExpandoObject();
expando.Blah = 42;
expando.Foo = "test";
...
var d = expando as IDictionary<string, object>;
d.Add("SomeProp", SomeValueOrClass);
// After you've added the properties you would like.
d = d.ToDictionary(x => x.Key, x => x.Value);
return new JsonResult(d);
비용은 직렬화하기 전에 데이터의 복사본을 만드는 것입니다.
답변
ExpandoObject를 JSON 문자열로 변환하는 확장 메서드를 작성하여이 문제를 해결했습니다.
public static string Flatten(this ExpandoObject expando)
{
StringBuilder sb = new StringBuilder();
List<string> contents = new List<string>();
var d = expando as IDictionary<string, object>;
sb.Append("{");
foreach (KeyValuePair<string, object> kvp in d) {
contents.Add(String.Format("{0}: {1}", kvp.Key,
JsonConvert.SerializeObject(kvp.Value)));
}
sb.Append(String.Join(",", contents.ToArray()));
sb.Append("}");
return sb.ToString();
}
이것은 우수한 Newtonsoft를 사용합니다 라이브러리를 .
JsonResult는 다음과 같습니다.
return JsonResult(expando.Flatten());
그리고 이것은 브라우저에 반환됩니다.
"{SomeProp: SomeValueOrClass}"
그리고 다음을 수행하여 자바 스크립트에서 사용할 수 있습니다 ( 여기 참조 ).
var obj = JSON.parse(myJsonString);
이게 도움이 되길 바란다!
답변
JsonFx를 사용하여 동일한 문제를 해결할 수있었습니다 .
dynamic person = new System.Dynamic.ExpandoObject();
person.FirstName = "John";
person.LastName = "Doe";
person.Address = "1234 Home St";
person.City = "Home Town";
person.State = "CA";
person.Zip = "12345";
var writer = new JsonFx.Json.JsonWriter();
return writer.Write(person);
산출:
{ “FirstName”: “John”, “LastName”: “Doe”, “Address”: “1234 Home St”, “City”: “Home Town”, “State”: “CA”, “Zip”: “12345 “}
답변
평탄화 프로세스를 한 단계 더 진행하고 목록 객체를 확인하여 넌센스 키 값을 제거했습니다. 🙂
public string Flatten(ExpandoObject expando)
{
StringBuilder sb = new StringBuilder();
List<string> contents = new List<string>();
var d = expando as IDictionary<string, object>;
sb.Append("{ ");
foreach (KeyValuePair<string, object> kvp in d)
{
if (kvp.Value is ExpandoObject)
{
ExpandoObject expandoValue = (ExpandoObject)kvp.Value;
StringBuilder expandoBuilder = new StringBuilder();
expandoBuilder.Append(String.Format("\"{0}\":[", kvp.Key));
String flat = Flatten(expandoValue);
expandoBuilder.Append(flat);
string expandoResult = expandoBuilder.ToString();
// expandoResult = expandoResult.Remove(expandoResult.Length - 1);
expandoResult += "]";
contents.Add(expandoResult);
}
else if (kvp.Value is List<Object>)
{
List<Object> valueList = (List<Object>)kvp.Value;
StringBuilder listBuilder = new StringBuilder();
listBuilder.Append(String.Format("\"{0}\":[", kvp.Key));
foreach (Object item in valueList)
{
if (item is ExpandoObject)
{
String flat = Flatten(item as ExpandoObject);
listBuilder.Append(flat + ",");
}
}
string listResult = listBuilder.ToString();
listResult = listResult.Remove(listResult.Length - 1);
listResult += "]";
contents.Add(listResult);
}
else
{
contents.Add(String.Format("\"{0}\": {1}", kvp.Key,
JsonSerializer.Serialize(kvp.Value)));
}
//contents.Add("type: " + valueType);
}
sb.Append(String.Join(",", contents.ToArray()));
sb.Append("}");
return sb.ToString();
}
답변
이것은 유용하지 않을 수 있지만 비슷한 요구 사항이 있었지만 SerializableDynamicObject를 사용했습니다.
사전의 이름을 “Fields”로 변경 한 다음 Json.Net으로 직렬화하여 다음과 같은 json을 생성합니다.
{ “Fields”: { “Property1”: “Value1”, “Property2”: “Value2″등. 여기서 Property1 및 Property2는 동적으로 추가 된 속성 (예 : 사전 키))
나머지를 캡슐화하는 추가 “Fields”속성을 제거 할 수 있다면 완벽 할 것입니다.하지만 그 한계를 극복했습니다.
요청시이 질문 에서 답변이 이동되었습니다.