Passing an instance of anonymous type over WCF
Asked Answered
F

6

22

I have a WCF service method that expects an object and then retrieves its properties using reflection.

On the client side I create an anonymous type object

var obj = new {FirstName="John", LastName="Doe"}

and pass it to the method. I'm getting an exception:

Type '<>f__AnonymousType0`2[System.String,System.String]' cannot be serialized. 
Consider marking it with the DataContractAttribute attribute, and marking all 
of its members you want serialized with the DataMemberAttribute attribute.  
See the Microsoft .NET Framework documentation for other supported types.

I can't mark the type or its members with serialization attributes because there is really no type nor properties declared explicitly. Is there a way to overcome that problem?

Frijol answered 21/2, 2010 at 19:35 Comment(0)
P
19

Don't do this.

It's an attempt to be clever. Don't. Just declare the datatype you need, and use it. If you need a more loosely-defined datatype, just use a key-value mapping of some sort.

It will take you 5 minutes to write something that can handle this for good. Using any technique like this will cost you hours of debugging at some future point down the road.

Prowler answered 28/2, 2010 at 5:6 Comment(3)
Yup, I ended up passing a dictionary of keys-objectsFrijol
I had the same issue and passed half a day before I figured out it was a bad idea. Not my finest hour. I just wanted to support kyoryu with the anecdote of what he prophesied.Asymptotic
But what if you have no choice, because you are mimicking an existing contract. It can be done because I am looking at an existing contract that does it.Beccafico
G
20

The answers suggesting that you can't use an anonymous type over WCF are wrong.

If you are using the default DataContractSerializer to serialize your types on the channel, then yes, the answers are correct. This is because the DataContractSerializer supports the following scenarios:

  1. Types serialized using the Serializable attribute
  2. Types serialized using XML Serialization
  3. Types serialized using the DataContract attribute
  4. Plain-Old-C#-Object (POCO) Serialization

Respectively, they fail with anonymous types because of the following:

  1. You can't apply attributes to anonymous types.
  2. XML Serialization requires a default parameterless constructor, which anonymous types do not have.
  3. Same as 1.
  4. Same as 2.

However, you are not forced to use the DataContractSerializer to serialize your messages in WCF. You can create a custom message formatter which you can use to perform the serialization yourself.

You have a problem if the types you are sending out as the results of requests are anonymous types. When you get the results back, it's going to have a definite name within a namespace (not in a .NET sense, but in a SOA sense) and you are going to have to handle the mapping of that concrete type back to the anonymous type. However, because you don't have access to the actual anonymous type or ways of constructing it in code (at least in a dynamic way), you have no choice but to pass it along as an object if it's passed back to you, which makes it kind of worthless, since everyone will have to use bad practices such as dynamic (not a bad practice in itself, but to get around these limitations in this case, yes), or cast-by-example.

So in the end I will say that while it certainly is possible to serialize anonymous types and send them over the wire, the work invovled is usually not worth it.

Gateshead answered 21/2, 2010 at 20:27 Comment(2)
+1 for technically correct answer. -1 for mentioning a technique that's pure evil. I'm worried somebody will read this and ignore the "bad practices" warning - forget refactoring, you'd need an exorcist.Azikiwe
Mentioning ANY technique should be considered sharing of knowledge and not be scorned. Besides, even exorcists need to know about demons.Healion
P
19

Don't do this.

It's an attempt to be clever. Don't. Just declare the datatype you need, and use it. If you need a more loosely-defined datatype, just use a key-value mapping of some sort.

It will take you 5 minutes to write something that can handle this for good. Using any technique like this will cost you hours of debugging at some future point down the road.

Prowler answered 28/2, 2010 at 5:6 Comment(3)
Yup, I ended up passing a dictionary of keys-objectsFrijol
I had the same issue and passed half a day before I figured out it was a bad idea. Not my finest hour. I just wanted to support kyoryu with the anecdote of what he prophesied.Asymptotic
But what if you have no choice, because you are mimicking an existing contract. It can be done because I am looking at an existing contract that does it.Beccafico
R
4

You could serialize the object into a JSON string and send it through WCF, like so:

//in WCF Server
dynamic mysentclass = new { FirstName = "John", LastName = "Doe" };
string jsonstring = JsonConvert.SerializeObject(mysentclass, Newtonsoft.Json.Formatting.Indented);
//send the string through WCF

//in WCF client
dynamic myreceivedclass = JsonConvert.DeserializeObject<dynamic>(jsonstring);
MessageBox.Show(myreceivedclass.FirstName.ToString() + " " + myreceivedclass.LastName.ToString());

The example uses Json.Net, which can be obtained here:

http://www.nuget.org/packages/Newtonsoft.Json/

You could also use System.Web.Script.Serialization.JavaScriptSerializer (in System.Web.Extensions.dll), which is not as powerful as Json.Net, but would suffice for simple objects.

Redo answered 18/10, 2013 at 13:2 Comment(0)
P
2

No, there is not. While there are tricks and techniques to return objects of an anonymous type from a method, you cannot send them over WCF.

WCF needs to know all of its concrete types that will be sent across, since you're not really just calling a .NET method. Instead, the message call gets converted into a serialized message, and therefore, any "thing" being passed over a WCF call must be serializable - no exceptions.

Parole answered 21/2, 2010 at 19:38 Comment(0)
T
1

You've already got the answer. It can't be done.

In fact, you can't pass an instance of an anonymous type from one method to another within your program. You certainly can't pass them between programs.

Tomfoolery answered 21/2, 2010 at 19:37 Comment(7)
actually, you can - you could define a return type of "object" and then just return your instance of anonymous type. It's an anonymous type, but it still ultimately descends from "object". Not recommended, nor intended - but it is possible - at least within .NETParole
@marc_s: This would compile but be pretty much useless, since no metadata will be generated for a return type of System.Object.Azikiwe
@Aaronaught: I never said it was useful in any way, shape or form - just possible :-) I'd never do it myself, but it is technically possibleParole
@John Saunders: You most definitely can use an anonymous type in a strongly-typed manner outside the method you create it in. The mechanism is called "call-by-example" and uses type inference and the fact that anonymous types declared with the same layout names and types as members will actually be the same type (as guaranteed by the C# specification): https://mcmap.net/q/587762/-anonymous-types/… - Of course, it is a horrible practice (as per my linked answer), but whether or not it is possible, the answer is most definitely yes.Gateshead
@casperOne: I hold you responsible for placing this horrible idea into my head.Tomfoolery
@John Saunders: No problem, because I've thoroughly removed any responsibility in the link provided and pretty much say you should do anything but that. =)Gateshead
@casperOne: ok, but you could keep this evil to yourself in the future. I know that I will never divulge this secret.Tomfoolery
M
0

As said before, the objects must be deserializable and so you will have to define the structure beforehand. However, you can use inheritance to defining them, and hence lower the pain. WCF provides the KnownType attribute to allow a Service Operation to receive an object of the base class and deserialize it into an object of a derived class. So you will still only have one (or a few) Service Operations that can handle all your scenarios.

Misprision answered 28/2, 2010 at 5:3 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.