Pergunta

Esta é uma questão muito complicada sobre como serializar dados através de uma chamada de serviço web, quando os dados são não-fortemente tipado. Vou tentar colocá-lo fora como melhor possível.

objeto de armazenamento da amostra:

[Serializable]
public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  public List<NameValuePairs> OtherInfo { get; set; }  
}
[Serializable]   
public class NameValuePairs {
  public string Name { get; set; }
  public string Value { get; set; }
}

Use Amostra:

[WebMethod]
    public List<StorageObject> GetStorageObjects() {
      List<StorageObject> o = new List<StorageObject>() {
        new StorageObject() { 
          Name = "Matthew",
          Birthday = "Jan 1st, 2008", 
          OtherInfo = new List<NameValuePairs>() {
            new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
            new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
          }
        },
        new StorageObject() { 
          Name = "Joe",
          Birthday = "Jan 10th, 2008",
          OtherInfo = new List<NameValuePairs>() { 
            new NameValuePairs() { Name = "Hobbies", Value = "Programming" },
            new NameValuePairs() { Name = "Website", Value = "Stackoverflow.com" }
          }
        }
      };

      return o;
    }

Valor de retorno do serviço da Web:

<StorageObject>
    <Name>Matthew</Name>
    <Birthday>Jan 1st, 2008</Birthday>
    <OtherInfo>
        <NameValuePairs>
            <Name>Hobbies</Name>
            <Value>Programming</Value>
        </NameValuePairs>
        <NameValuePairs>
            <Name>Website</Name>
            <Value>Stackoverflow.com</Value>
        </NameValuePairs>
    </OtherInfo>
</StorageObject>

O que eu quero:

<OtherInfo>
    <Hobbies>Programming</Hobbies>
    <Website>Stackoverflow.com</Website>
</OtherInfo>

The Reason & Other Stuff:

Em primeiro lugar, eu sinto muito pelo comprimento do post, mas eu queria dar código reprodutível bem.

Eu quero que neste formato, porque eu estou consumindo os serviços web de PHP. Eu quero ir facilmente:

// Este é IMPORTANTES

In PHP => "$Result["StorageObject"]["OtherInfo"]["Hobbies"]".  

Se está em outro formato, então não haveria nenhuma maneira para eu conseguir isso, em tudo. Além disso, em C # se eu estou consumindo o serviço, eu também gostaria de ser capaz de fazer o seguinte:

// Este é IMPORTANTES

In C# => var m = ServiceResult[0].OtherInfo["Hobbies"];

Infelizmente, eu não sou certo como fazer isso. Eu era capaz de fazê-lo desta forma, através da construção de um dicionário personalizado que implementou IXmlSerializer (ver StackOverflow: IXmlSerializer Dictionary ), no entanto, ele soprou o esquema WSDL para fora da água. Também é muito complicado, e produziu resultados horríveis no meu aplicativo WinFormsTester!

Existe alguma maneira de conseguir isso? Que tipo de objetos que eu preciso para criar? Existe alguma maneira de fazer isso / diferente, fazendo uma coleção / fortemente tipado? Obviamente, se eu fizer isso fortemente tipificada como esta:

public class OtherInfo {
  public string Hobbies { get; set; }
  public string FavoriteWebsite { get; set; }
}

Em seguida, ele iria funcionar perfeitamente, eu não tenho problemas WSDL, eu seria capaz de acessá-lo facilmente a partir de PHP e C # (.OtherInfo.Hobbies).

No entanto, gostaria de perder completamente o ponto de NVP de, no que eu teria que saber com antecedência o que a lista é, e seria imutável .. digamos, a partir de um banco de dados.

Obrigado a todos !! Espero que sejamos capazes de chegar a algum tipo de solução para isso. Estão aqui estão os requisitos de novo:

  1. esquema WSDL não deve quebrar
  2. pares de valor de nome (de NVP) deve ser serializado em formato atributo
  3. Deve ser fácil de acesso NVP de em PHP pelo nome [ "Hobbies"]
  4. Deve ser de fácil acesso em C # (e ser compatível com o seu gerador de Proxy)
  5. Seja facilmente serializable
  6. Não me obrigar a escrever fortemente os dados

Agora, eu sou / completamente / aberto a entrada em uma maneira melhor / diferente para fazer isso. Eu estou armazenando alguns relativamente informação "estática" (como Name), e um monte de pedaços de dados. Se há uma maneira melhor, eu adoraria ouvi-lo.

Foi útil?

Solução

Isto é como propriedades dinâmicas para um objeto. C # não é bem uma linguagem dinâmica ao contrário javascript ou talvez PHP pode analisar as propriedades do objeto na mosca. Os dois métodos seguintes são o que eu posso pensar. O segundo pode se encaixam em suas necessidades.

O BEIJO Way

The Keep It Simple maneira Stupid

public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  public List<string> OtherInfo { get; set; }  
}

Você pode ter valor pares nome que é separados por '|'

OtherInfo = {"Hobbies|Programming", "Website|Stackoverflow.com"}

formas serializado

<StorageObject>
    <Name>Matthew</Name>
    <Birthday>Jan 1st, 2008</Birthday>
    <OtherInfo>
        <string>Hobbies|Programming</string>
        <string>Website|Stackoverflow.com</string>
    </OtherInfo>
</StorageObject>

A forma dinâmica em C #

Faça o valor do nome par parte tornar-se um elemento XML de modo que você pode construí-lo dinamicamente.

public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  public XElement OtherInfo { get; set; } // XmlElement for dot net 2
}

Você pode facilmente construir objeto OtherInfo como elemento centric por exemplo.

XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..Hobbies xelement & text value..);
OtherInfo.Add( ..WebSite xelement & text value..);

O formulário serializado será

<OtherInfo>
    <Hobbies>Programming</Hobbies>
    <Website>Stackoverflow.com</Website>
</OtherInfo>

ou construí-lo como atributo centrada

XElement OtherInfo = new XElement("OtherInfo");
OtherInfo.Add( ..nvp xattribute Hobbies & value..);
OtherInfo.Add( ..nvp xattribute WebSite & value..);

<OtherInfo>
    <nvp n="Hobbies" v="Programming" />
    <nvp n="Website" v="Stackoverflow.com" />
</OtherInfo>

Para qualquer linguagem dinâmica, ele pode acessar às propriedades diretamente. Para o resto, eles podem acessar o valor de ler o XML. XML leitura é bem suportado pela maioria dos quadro.

Outras dicas

Este é o que eu tenha resolvido em.

Estrutura Classe:

public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }
  [XmlAnyElement("Info")]  // this prevents double-nodes in the XML
  public XElement OtherInfo { get; set; }
}

Uso:

StorageObject o = new StorageObject();
o.OtherInfo.Add(new XElement("Hobbies","Programming");
o.OtherInfo.Add(new XElement("Website","Stackoverflow.com");

Output:

<Info>
  <Hobbies>Programming</Hobbies>
  <Website>Stackoverflow.com</Website>
</Info>

Gostaria de agradecer a todos por sua ajuda, eu realmente aprecio a ajuda e idéias.

Como uma tomada completamente diferente sobre isso, por que não pensar em fazê-lo de forma completamente diferente. Ter um método de serviço web para retornar o objeto de armazenamento serializado, menos o OtherInfo e outro método para retornar a lista de propriedades (chaves) para OtherInfo, e um terceiro para retornar a lista de valores para qualquer tecla. Concedido, ele vai fazer viagens mais redondos para o serviço de web se você quiser todos os dados, mas a solução será muito mais simples e mais flexível.

[Serializable]
public class StorageObject {
  public string Name { get; set; }
  public string Birthday { get; set; }

  [Nonserializable]
  public Dictionary<string,List<string>> OtherInfo { get; set; }  
}

[WebMethod]
public List<StorageObject> GetStorageObjects() {
    // returns list of storage objects from persistent storage or cache
}

[WebMethod]
public List<string> GetStorageObjectAttributes( string name )
{
    // find storage object, sObj
    return sObj.Keys.ToList();
}

[WebMethod]
public List<string> GetStorageObjectAtributeValues( sting name, string attribute )
{
    // find storage object, sObj
    return sObj[attribute];
}

Tenha um olhar para o atributo System.Xml.Serialization.XmlSerializerAssemblyAttribute. Isso permite que você especifique um serializador personalizado classe de nível. Você vai ser capaz de cuspir tudo o XML você gosta.

Uma maneira rápida de chegar até a velocidade sobre estes é usar sgen.exe para gerar um e ter uma espiada nisso com refletor.

-Oisin

Eu não estou certo de que este iria resolver o seu problema (que seria em C #, mas talvez não em PHP), mas tente usar Dictionary<string,List<string>> OtherInfo vez de List<NameValuePairs>. Em seguida, "Hobbies" e "sites" seria suas chaves e os valores seria a lista de hobbies ou web sites. Não tenho certeza como seria serializar, no entanto.

Você seria capaz de referenciar as listas de passatempos como:

List<string> hobbies = storageObject.OtherInfo["Hobbies"];

[editar] aqui para uma XML genérico dicionário serializável. Esta classe derivada é o que você precisa para usar em vez de genérico Dictionary.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top