views:

397

answers:

2

possible duplicate:
Cannot serialize parameter of type ‘System.Linq.Enumerable… ’ when using WCF, LINQ, JSON


Hi,

If my method signiature looks like this, it works fine.

[WebGet]
MyClass[] WebMethod()

If the signiature looks like this

[WebGet]
IEnumerable<T> WebMethod()

I get the following error: Cannot serialize parameter of type 'X.Y.Z.T+<WebMethod>d__2c' (for operation 'WebMethod', contract 'IService') because it is not the exact type 'System.Collections.Generic.IEnumerable`1[X.Y.Z.T]' in the method signature and is not in the known types collection. In order to serialize the parameter, add the type to the known types collection for the operation using ServiceKnownTypeAttribute.

I have tried adding. ServiceKnownType(typeof(IEnumerable))

Same error.

Is this a bug in 2010 beta 2, or is this likely to be correct going forward?

Thanks

+2  A: 

The iterator types generated by the C# compiler are not serializable and never will be.

If you read this page, you'll see that it wouldn't make sense to serialize the iterator.

You need to return an array.

EDIT: The simplest way to do that is to move your iterator to a seperate method, and change WebMethod to

[WebGet]
MyClass[] WebMethod() { return OtherMethod().ToArray(); }
SLaks
If needed, you can definitely work with `IEnumerable<T>` inside the method...and then use the `IEnumerable<T>.ToArray()` method to return the collection as an Array.
Justin Niessner
Or you can return a List<T>
Cheeso
Yes, but why bother?
SLaks
it depends on how the value is being constructed. Internally a List<T> is an IEnumerable<T>; it's possible the return value is already a List<T>, internally, in which case there is no bother at all.
Cheeso
@Cheeso: No, it isn't. He's writing an iterator. (See the error message - `X.Y.Z.T+<WebMethod>d__2c` is a generated iterator type)
SLaks
Thanks guys, I was under the impression that using IEnumerator was 'best practice' I does work for normal data contract serialisation. It only fails for 'WebGet'.I see your point though, and using MyClass[] is definitely not life or death.Thanks!
Jim
A: 

I've run into the same issue, and in my case it's simply not possible to change my entire object graph from iterator-based IEnumerable to concrete types. I simply cannot afford the memory to convert over to concrete types like List or Array. Additionally, what about the case where I return an IEnumerable of some object that has an IEnumerable property. It is unacceptable that I have to recurse my entire object graph converting all IEnumerables.

I don't see any good reason why the DataContractSerializer can't iterate any IEnumerable type and render its elements to XML in the same manner as any other collection type, even if the IEnumerable doesn't have a concrete backing type.

This is a bug which should be fixed.

Jim
The way that WCF works by default is to use buffered messaging, meaning that the entire serialized object graph of your return value gets built in memory before any of it is sent back to client. Due to this, even if you could return an IEnumerable it wouldn't help with the memory consumption. You can however enable streamed transfers which will cause the message to be sent as it is serialized. Unfortunately, you must use Stream, IXmlSerializable, or Message as your return type to utilize streaming; IEnumerable is still not allowed. See http://msdn.microsoft.com/en-us/library/ms789010.aspx
luksan