Pregunta

Googled y leer durante horas y no puedo encontrar a alguien que se ocupa de mi escenario específico ...

Quiero utilizar las interfaces en mis contratos de servicio WCF para vagamente par el servicio de las clases que se utilizan en cada extremo del cable. Esto nos permitirá tener un bajo nivel de ensamblado que contiene sólo los contratos de servicios y de datos (sólo interfaces) que podemos entregar a un consultor. En su extremo del cable que pueden crear instancias de sus clases de datos que implementan nuestra interfaz Contrato de datos, lo envía a través del cable a nosotros, y nuestro servicio WCF traducirán / cast / lo que sea que los datos de entrada en nuestro versión de una clase de datos que implementa la misma interfaz.

Este es un ejemplo. IDataContract contiene la información desnudo quiero transmitir a través del cable. Los criterios de valoración y otra configuración específica de WCF son todas las cosas por defecto (mis problemas pueden radicar en que, para que pueda incluir más de lo mismo si es allí donde las cosas que tengo que cambiar).

Editar : He incluido más del código y el nuevo nombre de un par de clases para ayudar a los menos confuso. Las adiciones nombre y espacio de nombres al DataContractAttributes, así como las dos secciones en los archivos de configuración de nuevas adiciones basadas en información de esta entrada de blog . Si me cambio a una clase base abstracta en lugar de una interfaz, funciona . Sin embargo, me gustaría conseguir este trabajo con una interfaz si es posible.

biblioteca compartida (mi código, compartida con los autores de los clientes):

public interface IDataContract
{
    string MyProperty { get; set; }
}
[ServiceContract]
public interface ITestService
{
    [OperationContract]
    IDataContract TestSharedInterface(IDataContract clientData);
}

El código de cliente (de los):

[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ClientDataClass : IDataContract
{
    [DataMember]
    public string MyProperty { get; set; }
}
private static void CallTestSharedInterface()
{
    EndpointAddress address = new EndpointAddress("http://localhost/ServiceContractsTest.WcfService/TestService.svc");
    ChannelFactory<ITestService> factory = new ChannelFactory<ITestService>("ITestService", address);
    ITestService proxy = factory.CreateChannel();
    ((IClientChannel)proxy).Open();

    IDataContract clientData = new ClientDataClass() { MyProperty = "client data" };
    IDataContract serverData = proxy.TestSharedInterface(clientData);
    MessageBox.Show(serverData.MyProperty);
}

config Cliente:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
                <knownType type="ServiceContractsTest.WcfClient.ClientDataClass, ServiceContractsTest.WcfClient"/>
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

código Server (mina):

public class TestService : ITestService
{
    public IDataContract TestSharedInterface(IDataContract clientData)
    {
        ServerDataClass convertedClientData = (ServerDataClass)clientData;
        IDataContract serverData = new ServerDataClass() { MyProperty = convertedClientData.MyProperty + " + server data added" };
        return serverData;
    }
}
[DataContract(Name = "IDataContract", Namespace = "http://services.sliderhouserules.com")]
public class ServerDataClass : IDataContract
{
    [DataMember]
    public string MyProperty { get; set; }
}

configuración del servidor:

<system.runtime.serialization>
    <dataContractSerializer>
        <declaredTypes>
            <add type="ServiceContractsTest.Contracts.DataContracts.IDataContract, ServiceContractsTest.Contracts">
                <knownType type="ServiceContractsTest.WcfService.ServerDataClass, ServiceContractsTest.WcfService"/>
            </add>
        </declaredTypes>
    </dataContractSerializer>
</system.runtime.serialization>

Estoy recibiendo un error de serialización en la llamada del cliente quejándose de tipos conocidos. ¿Soy sólo faltan algunos metadatos marcado en esa clase de cliente? Estoy en una pérdida en cuanto a dónde incluso conocer el problema incluso mentiras, como he intentado todas las búsquedas que se me ocurren y nadie parece haber tratado este escenario específico.

Básicamente, quiero ClientDataClass para serializar a <IDataContract><MyProperty>client data</MyProperty></IDataContract> y luego ser capaz de deserializar que en una instancia ServerDataClass. Esta parece que debería ser posible.

¿Fue útil?

Solución

Si sus contratos de datos son interfaces WCF no puede saber qué objeto para crear una instancia de una solicitud entrante. No hay necesidad de que la clase sea la misma que en el servicio, después de todo el Agregar referencia de servicio lee el WSDL y genera nuevas clases basadas en la información de tipo en el WSDL.

Otros consejos

Este blog me da la dirección correcta para encontrar la solución para mi problema. En realidad tengo exactamente el mismo escenario como sliderhouserules describe en su puesto.

Pero en mi escenario que no puede utilizar cualquier clase abstracta o base de heredar de. Por lo que utiliza una clase TypesHelper de leer la sección DataContractSerializer por mí y pasar los tipos de interés para el servicio WCF.

namespace ExampleNamespace
{
  public interface IJustAInstance { }

  [ServiceContract]
  [ServiceKnownType("GetKnownTypes", typeof(ExampleNamespace.TypesHelper))]
  public interface ICreateInstance
  {
    IJustAInstance CreateInstance();
  }

  public static class TypesHelper
  {
    public static IEnumerable<Type> GetKnownTypes(ICustomAttributeProvider provider)
    {
      DataContractSerializerSection section = (DataContractSerializerSection)
        ConfigurationManager.GetSection(
        "system.runtime.serialization/dataContractSerializer");
      if (dataContractSerializerSection != null)
      {
        foreach (DeclaredTypeElement item in dataContractSerializerSection.DeclaredTypes)
        {
          foreach (TypeElement innterItem in item.KnownTypes)
          {
            Type type = Type.GetType(innterItem.Type);
            if (typeof(IJustAInstance).IsAssignableFrom(type ))
              yield return type;
          }
        }
      }
    }
  }
}

Se puede crear un BaseContract que su ClientContract y ServerContract pueden proporcionar (como propiedad) y que se pueden utilizar en el respectivo constructor de la hora de crear nuevas instancias del ClientContract o ServerContract. Entonces sólo tiene que añadir el BaseContract a su librería compartida.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top