source

asp.net MVC에서 JsonResult를 통해 반환된 ExpandoObject를 평탄하게 하려면 어떻게 해야 합니까?

gigabyte 2023. 2. 10. 22:01
반응형

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}

가 이걸 쓸 수 걸 .dynamicExpandoObjectJsonResult는, 을 할 수 .dynamic속성 및 값을 단일 개체(키 또는 값 비즈니스 없음)로 변환합니다. 그러나 이 기능을 사용해야 하는 이유는 런타임까지 개체에서 원하는 속성을 모두 없기 때문입니다.또한 제가 아는 한 속성을 동적으로 추가할 수 없기 때문입니다.dynamic를 하지 않고ExpandoObject.

javascript에서 "Key"와 "Value"의 비즈니스를 검토해야 할 것 같습니다만, 고객에게 보내기 전에 이것을 확인하고 싶다고 생각하고 있었습니다.도와주셔서 감사합니다!

JSON 사용.NET Serialize Object를 호출하여 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");
    }
}

또한 ExpandoObject에만 사용할 수 있는 특별한 JSONConverter를 만든 후 JavaScriptSerializer 인스턴스에 등록할 수도 있습니다.이렇게 하면 expando 어레이, expando 객체 조합 등을 시리얼화할 수 있습니다.올바르게 시리얼화되지 않는 다른 종류의 오브젝트가 발견될 때까지("way you wanthed") 다른 Converter를 만들거나 이 Converter에 다른 유형을 추가합니다.이게 도움이 됐으면 좋겠다.

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);

당신이 설명한 행동을 달성하기 위해 제가 한 일은 다음과 같습니다.

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();
}

이것은 훌륭한 뉴턴소프트 라이브러리를 사용합니다.

Json Result는 다음과 같습니다.

return JsonResult(expando.Flatten());

그리고 브라우저로 돌아갑니다.

"{SomeProp: SomeValueOrClass}"

javascript에서는 다음과 같이 사용할 수 있습니다(여기 참조).

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();
    }

JsonResultJavaScriptSerializer(Dictionary<string, object>당신이 원하듯이.

이부 there of of of of of 가 되어 있다Dictionary<string, object>IDictionary<string, object>.

ExpandoObject를 실장하다IDictionary<string, object> 알 수 있을 것

단일 수준 Expando Object

dynamic expando = new ExpandoObject();

expando.hello = "hi";
expando.goodbye = "cya";

var dictionary = new Dictionary<string, object>(expando);

return this.Json(dictionary); // or new JsonResult { Data = dictionary };

모든 삽입 유형을 사용하여 코드 한 줄:)

중첩된 Expando Objects

네스트하고 있는 ExpandoObject 모든 으로 ㄴ, ㄴ, ㄴ, 으로 변환해야 합니다.Dictionary<string, object>s:

public static Dictionary<string, object> RecursivelyDictionary(
    IDictionary<string, object> dictionary)
{
    var concrete = new Dictionary<string, object>();

    foreach (var element in dictionary)
    {
        var cast = element.Value as IDictionary<string, object>;
        var value = cast == null ? element.Value : RecursivelyDictionary(cast);
        concrete.Add(element.Key, value);
    }

    return concrete;
}

당신의 마지막 코드가

dynamic expando = new ExpandoObject();
expando.hello = "hi";
expando.goodbye = "cya";
expando.world = new ExpandoObject();
expando.world.hello = "hello world";

var dictionary = RecursivelyDictionary(expando);

return this.Json(dictionary);

이것은 당신에게 유용하지 않을 수도 있지만, 저는 비슷한 요건이 있었지만 SerializableDynamicObject를 사용했습니다.

사전의 이름을 "필드"로 바꾸면 Json과 연재됩니다.넷은 다음과 같은 json을 생성합니다.

{"필드":{"Property1":"Value1", "Property2":"Value2" 등. 여기서 Property1과 Property2는 동적으로 추가된 속성입니다.사전 키

나머지 부분을 캡슐화하는 추가 "Fields" 속성을 제거할 수 있다면 더할 나위 없이 좋을 것입니다만, 저는 그 한계를 극복해 왔습니다.

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

늦은 답변이지만, 저도 같은 문제가 있었고, 이 질문이 문제를 해결하는 데 도움이 되었습니다.요약하자면, 다른 사람의 구현이 빨라지길 바라면서 결과를 게시해야겠다고 생각했습니다.

첫 번째 ExpandoJsonResult. 작업 중에 인스턴스를 반환할 수 있습니다.또는 컨트롤러에서 Json 메서드를 재정의하고 반환할 수 있습니다.

public class ExpandoJsonResult : JsonResult
{
    public override void ExecuteResult(ControllerContext context)
    {
        HttpResponseBase response = context.HttpContext.Response;
        response.ContentType = !string.IsNullOrEmpty(ContentType) ? ContentType : "application/json";
        response.ContentEncoding = ContentEncoding ?? response.ContentEncoding;

        if (Data != null)
        {
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            serializer.RegisterConverters(new JavaScriptConverter[] { new ExpandoConverter() });
            response.Write(serializer.Serialize(Data));
        }
    }
}

다음으로 컨버터(시리얼라이제이션과 디시리얼라이제이션 양쪽을 서포트).디시리얼라이즈의 예에 대해서는, 이하를 참조해 주세요.

public class ExpandoConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    { return DictionaryToExpando(dictionary); }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    { return ((ExpandoObject)obj).ToDictionary(x => x.Key, x => x.Value); }

    public override IEnumerable<Type> SupportedTypes
    { get { return new ReadOnlyCollection<Type>(new Type[] { typeof(System.Dynamic.ExpandoObject) }); } }

    private ExpandoObject DictionaryToExpando(IDictionary<string, object> source)
    {
        var expandoObject = new ExpandoObject();
        var expandoDictionary = (IDictionary<string, object>)expandoObject;
        foreach (var kvp in source)
        {
            if (kvp.Value is IDictionary<string, object>) expandoDictionary.Add(kvp.Key, DictionaryToExpando((IDictionary<string, object>)kvp.Value));
            else if (kvp.Value is ICollection)
            {
                var valueList = new List<object>();
                foreach (var value in (ICollection)kvp.Value)
                {
                    if (value is IDictionary<string, object>) valueList.Add(DictionaryToExpando((IDictionary<string, object>)value));
                    else valueList.Add(value);
                }
                expandoDictionary.Add(kvp.Key, valueList);
            }
            else expandoDictionary.Add(kvp.Key, kvp.Value);
        }
        return expandoObject;
    }
}

ExpandoJsonResult 클래스에서 직렬화에 사용하는 방법을 확인할 수 있습니다.시리얼화를 해제하려면 시리얼라이저를 작성하고 컨버터를 같은 방법으로 등록합니다만,

dynamic _data = serializer.Deserialize<ExpandoObject>("Your JSON string");

저를 도와주신 모든 참가자들에게 진심으로 감사드립니다.

ASP의 WebApi에서 동적 ExpandoObject를 반환하는 사용.Net 4, 기본 JSON 포메터는 ExpandoObjects를 단순한 JSON 개체로 평탄하게 만듭니다.

시리얼라이저는 Expando를 사전에 캐스팅한 후 시리얼화하는 것 같습니다(즉, 키/밸류 비즈니스).사전으로 역직렬화 한 후 Expando로 다시 돌려보셨나요?

나도 똑같은 문제가 있었는데 이상한 걸 알아냈어.이 경우:

dynamic x = new ExpandoObject();
x.Prop1 = "xxx";
x.Prop2 = "yyy";
return Json
(
    new
    {
        x.Prop1,
        x.Prop2
    }
);

동작합니다만, 내 메서드가 HttpPost 속성을 사용하는 경우에만 동작합니다.HttpGet을 사용하면 오류가 발생합니다.그래서 제 답변은 Http Post에서만 작동합니다.제 경우 Ajax Call이므로 HttpGet by HttpPPost를 변경할 수 있습니다.

언급URL : https://stackoverflow.com/questions/5156664/how-to-flatten-an-expandoobject-returned-via-jsonresult-in-asp-net-mvc

반응형