Eu realmente gosto da ExpandoObject
compilação de um objeto dinâmico do lado do servidor em tempo de execução, mas estou tendo problemas para nivelar isso durante a serialização JSON. Primeiro, eu instancio o objeto:
dynamic expando = new ExpandoObject();
var d = expando as IDictionary<string, object>;
expando.Add("SomeProp", SomeValueOrClass);
Por enquanto, tudo bem. Em meu controlador MVC, quero enviar isso como um JsonResult, então faço o seguinte:
return new JsonResult(expando);
Isso serializa o JSON abaixo, para ser consumido pelo navegador:
[{"Key":"SomeProp", "Value": SomeValueOrClass}]
MAS, o que eu realmente gostaria é de ver isso:
{SomeProp: SomeValueOrClass}
Sei que posso conseguir isso se usar em dynamic
vez de ExpandoObject
- JsonResult
for capaz de serializar as dynamic
propriedades e valores em um único objeto (sem negócios de chave ou valor), mas o motivo pelo qual preciso usar ExpandoObject
é porque não conheço todos as propriedades que desejo no objeto até o tempo de execução e, até onde sei, não posso adicionar dinamicamente uma propriedade a a dynamic
sem usar um ExpandoObject
.
Posso ter que vasculhar o negócio "Chave", "Valor" em meu javascript, mas esperava descobrir isso antes de enviá-lo ao cliente. Obrigado pela ajuda!
fonte
Respostas:
Você também pode fazer um JSONConverter especial que funcione apenas para ExpandoObject e registrá-lo em uma instância de JavaScriptSerializer. Desta forma você poderia serializar arrays de expando, combinações de objetos expando e ... até encontrar outro tipo de objeto que não está sendo serializado corretamente ("do jeito que você quer"), então você faz outro Conversor, ou adiciona outro tipo a este. Espero que isto ajude.
Usando conversor
fonte
NotImplementedException
inserir algum código para adicionar algo comoserializer.Deserialize<ExpandoObject>(json);
, @theburningmonk oferece uma solução que funcionou para mim.Usando JSON.NET, você pode chamar SerializeObject para "nivelar" o objeto expando:
Irá produzir:
No contexto de um controlador ASP.NET MVC, o resultado pode ser retornado usando o método Content:
fonte
Aqui está o que fiz para atingir o comportamento que você está descrevendo:
O custo é que você está fazendo uma cópia dos dados antes de serializá-los.
fonte
ExpandoObject
oferece muito mais flexibilidade do que um simples Dicionário. Embora o exemplo acima não demonstre isso, você pode usar os recursos dinâmicos doExpandoObject
para adicionar as propriedades que deseja ter em seu JSON. UmDictioanry
objeto normal será convertido para JSON sem problemas, portanto, ao fazer a conversão, é uma maneira simples de colocar a dinâmica fácil de usarExpandoObject
em um formato que pode ser JSONified. Você está correto, porém, o exemplo acima seria um uso ridículo doExpandoObject
; um simplesDictionary
seria muito melhor.Resolvi isso escrevendo um método de extensão que converte o ExpandoObject em uma string JSON:
Ele usa a excelente biblioteca Newtonsoft .
JsonResult então se parece com isto:
E isso é retornado ao navegador:
E posso usá-lo em javascript fazendo isso (referenciado aqui ):
Eu espero que isso ajude!
fonte
Consegui resolver esse mesmo problema usando JsonFx .
resultado:
fonte
Eu levei o processo de nivelamento um passo adiante e verifiquei os objetos de lista, o que remove o absurdo do valor da chave. :)
fonte
Isso pode não ser útil para você, mas eu tinha um requisito semelhante, mas usei um SerializableDynamicObject
Mudei o nome do dicionário para "Campos" e então ele serializa com Json.Net para produzir json que se parece com:
{"Campos": {"Propriedade1": "Valor1", "Propriedade2": "Valor2" etc. onde Propriedade1 e Propriedade2 são propriedades adicionadas dinamicamente - isto é, chaves de dicionário
Seria perfeito se eu pudesse me livrar da propriedade extra "Fields" que encapsula o resto, mas eu contornei essa limitação.
Resposta movida desta pergunta a pedido
fonte
Esta é uma resposta tardia, mas eu tive o mesmo problema, e essa pergunta me ajudou a resolvê-los. Resumindo, achei que deveria postar meus resultados, na esperança de que isso acelere a implementação para outras pessoas.
Primeiro o ExpandoJsonResult, do qual você pode retornar uma instância em sua ação. Ou você pode substituir o método Json em seu controlador e retorná-lo lá.
Em seguida, o conversor (que suporta serialização e desserialização. Veja abaixo um exemplo de como desserializar).
Você pode ver na classe ExpandoJsonResult como usá-lo para serialização. Para desserializar, crie o serializador e registre o conversor da mesma forma, mas use
Um grande obrigado, a todos os participantes aqui que me ajudaram.
fonte
Usando o retorno de ExpandoObject dinâmico de WebApi no ASP.Net 4, o formatador JSON padrão parece achatar ExpandoObjects em um objeto JSON simples.
fonte
JsonResult
usaJavaScriptSerializer
que realmente desserializa (o concreto)Dictionary<string, object>
como você deseja.Há uma sobrecarga do
Dictionary<string, object>
construtor que levaIDictionary<string, object>
.ExpandoObject
implementosIDictionary<string, object>
(acho que você pode ver onde estou indo aqui ...)ExpandoObject de nível único
Uma linha de código, usando todos os tipos integrados :)
ExpandoObjects aninhados
Claro, se você estiver aninhando
ExpandoObject
s, será necessário convertê-los recursivamente emDictionary<string, object>
s:seu código final se tornando
fonte
Parece que o serializador está convertendo o Expando em um Dicionário e, em seguida, serializando-o (portanto, o negócio de Chave / Valor). Você já tentou desserializar como um dicionário e depois lançar isso de volta para um Expando?
fonte
Eu simplesmente tive o mesmo problema e descobri algo muito estranho. Se eu fizer:
Funciona, mas apenas se meu método usar o atributo HttpPost. Se eu usar o HttpGet, recebo um erro. Portanto, minha resposta funciona apenas no HttpPost. No meu caso, foi uma chamada Ajax para que eu pudesse alterar HttpGet por HttpPost.
fonte