2010-01-15 16 views
6

Tengo un servicio WCF. Utiliza Linq-to-objects para seleccionar de un Diccionario. El tipo de objeto es simple:No se puede serializar el parámetro del tipo 'System.Linq.Enumerable ...' cuando se utiliza WCF, LINQ, JSON

public class User 
{ 
    public Guid Id; 
    public String Name; 
} 

hay una colección de almacenado en un Dictionary<Guid,User>.

Quiero tener un OperationContract método WCF como esto:

public IEnumerable<Guid> GetAllUsers() 
{ 
    var selection = from user in list.Values 
     select user.Id; 
    return selection; 
} 

Se compila bien, pero cuando lo ejecuto me sale:

El servidor encontró un error al procesar la solicitud. El mensaje de excepción es 'No se puede serializar el parámetro del tipo' System.Linq.Enumerable + WhereSelectEnumerableIterator 2[Cheeso.Samples.Webservices._2010.Jan.User,System.Guid]' (for operation 'GetAllUsers', contract 'IJsonService') because it is not the exact type 'System.Collections.Generic.IEnumerable 1 [System.Guid] 'en la firma del método y no está en la colección de tipos conocidos. Para serializar el parámetro, agregue el tipo a la colección de tipos conocidos para la operación usando ServiceKnownTypeAttribute. '. Vea los registros del servidor para más detalles.

¿Cómo puedo forzar la selección para que sea un IEnumerable<Guid>?


EDITAR
Si modifico el código para hacer esto, funciona bien - buena interoperabilidad.

public List<Guid> GetAllUsers() 
{ 
    var selection = from user in list.Values 
     select user.Id; 
    return new List<Guid>(selection); 
} 

¿Hay alguna manera de evitar la creación/instanciación del List<T>?

Respuesta

9

No, se debe devolver una clase concreta desde un servicio web. Haga el tipo de retorno List y termine con él.

1

Debe pasar colecciones interoperables ay desde sus métodos WCF.

WCF funciona mejor con tipos y matrices simples.

Pase una matriz de su cliente y luego conviértala en un IEnumerable en el servicio.

Cosas como IEnumerable no son interoperables, que es lo que WCF intenta ser.

Puede haber una forma de evitarlo con tipos conocidos, pero siempre me esfuerzo para que mis componentes sean lo más flexibles posible.

+0

Supongo que no estoy tratando de repartir un IEnumerable . Lo que realmente quiero entregar es una lista de Guids. pero no quería tener que hacer un casting innecesario para que eso ocurra. De hecho, puedo simplemente cambiar el tipo de devolución del método a una lista , y luego crear una nueva lista pasando la selección al constructor de listas; eso funciona bien y el cliente obtiene la lista como yo quiero. Suficientemente simple. Esperaba que la creación explícita de la Lista fuera innecesaria. – Cheeso

+0

IEnumerable <> es solo una interfaz y no es del todo correcto decir que no es interoperable, ya que depende del tipo inicializado que implementa IEnumerable <> que devuelve el método. He utilizado IEnumerable <> como devolución de operaciones de servicio sin ningún problema, pero la clave es que el valor de retorno de la operación debe inicializarse correctamente. – Kwal

+0

MattK - entonces, ¿cómo puedo usar linq-to-objects para realizar una consulta que da como resultado un IEnumerable que puedo devolver desde un método expuesto a WCF? – Cheeso

4

Debe usar el atributo ServiceKnownTypes.

using System; 
using System.Collections.Generic; 
using System.ServiceModel; 
using System.ServiceModel.Web; 

namespace Test.Service 
{ 
    [ServiceContract(Name = "Service", Namespace = "")] 
    public interface IService 
    { 
     [OperationContract] 
     [WebInvoke(
      Method = "GET", 
      BodyStyle = WebMessageBodyStyle.WrappedRequest, 
      RequestFormat = WebMessageFormat.Json, 
      ResponseFormat = WebMessageFormat.Json)] 
     [ServiceKnownType(typeof(List<EventData>))] 
     IEnumerable<EventData> Method(Guid userId); 
    } 
} 

Básicamente necesita saber el tipo concreto de lo que está devolviendo. Bastante simple.

+0

+1 Para una solución más elegante – Basic

Cuestiones relacionadas