[c#] asp.net mvc에서 JsonResult를 통해 반환 된 ExpandoObject를 평면화하는 방법은 무엇입니까?

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대신 ExpandoObjectJsonResult직렬화 할 수 있습니다 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”속성을 제거 할 수 있다면 완벽 할 것입니다.하지만 그 한계를 극복했습니다.

요청시이 질문 에서 답변이 이동되었습니다.