send custom type to wcf service - c#

i need to pass an unknown type from my client to a wcf service ,
the type is unknown to the service .
for instance i have a class Customer which i create an instance of serialize and send to the service , the problem arises when i need to deserialize i have to provide the type in order to cast the desrialized object to .
Type can't be serialized , when attempted i get the following error :
{"Type 'System.RuntimeType' with data contract name
'RuntimeType:http://schemas.datacontract.org/2004/07/System' is not expected. Consider
using a DataContractResolver or add any types not known statically to the list of
known types - for example, by using the KnownTypeAttribute attribute or by adding
them to the list of known types passed to DataContractSerializer."}
i need to find a work around for this issue , any ideas ?
just to summarize :
i'm looking for a workaround for sending an unknown Type to a WCF service .

If the other end doesn't know anything about it (comments), then you can't possibly deserialize. You couldn't do that even with Type-based serializers (BinaryFormatter/NetDataContractSerializer).
If you are sending completely foreign data, then you are basically limited to things like XML or JSON, and even then the meaning is slightly ambiguous (is <id>123<id> a string? int? float? long?).
WCF is not well suited to your scenario (nor most other contract-based stacks; most systems expect to be able to understand incoming data).

Related

How can I write a controller method in MVC 5 when the incoming notifications have different JSON structures?

I'm attempting to write a webhook receiving service in MVC 5 to receive notifications from the GoToConnect webapi.
The webhook notifications that will be coming from their server have a standard wrapping structure.
{
"source": "messaging",
"type": "message",
"content": {object}
}
However, the content value can be one of multiple types of notifications that all have different structures which can be identified by the value that comes in the "type" field. My issue is finding a way of doing the model binding when the incoming json structure can be completely different.
If I can get access to the raw json file, I can use a switch statement to manually deserialize the incoming content based on the type value but I've had difficulty finding an easy way to do that. Is there already a way to control the model binding so that I can choose the object that gets created and then lump them together using inheritance or is there an easy way to get the raw json as a parameter to a controller method?
So, with some more research I found an answer to my problem.
First, I created classes for each of the notification content types with an empty marker interface and also a wrapping class containing the Type and an property with that Interface type.
Then, I built a custom model binder by extending the DefaultModelBinder class. In the BindModel method, I used the Type value of the incoming notification to instantiate the specific Notification Content object that I wanted. I stored that object in the Interface type property and then returned it.
Afterwards, I could access that data by casting the Interface Type property to the specific type I wanted in the controller method.

Deserializing JSON object to runtime type in WinRT (C#)

I have a small WinRT client app to my online service (Azure Web Service). The server sends a JSON encoded object with (with potential additional metadata) to the client and the client's responsibility would be to deserialize this data properly into classes and forward it to appropriate handlers.
Currently, the objects received can be deserialized with a simple
TodoItem todo = JsonConvert.DeserializeObject<TodoItem>(message.Content);
However, there can be multiple types of items received. So what I am currently thinking is this:
I include the type info in the header serverside, such as "Content-Object: TodoItem"
I define attributes to TodoItem on the client side (see below)
Upon receiving a message from the server, I find the class using the attribute I defined.
I call the deserialization method with the resolved type
(Example of the attribute mentioned in 2.)
[BackendObjectType="TodoItem"]
public class TodoItem
My problem with this approach however is the Type to Generics in the deserialization as I can't call:
Type t = ResolveType(message);
JsonConvert.DeserializeObject<t>(message.Content);
I tried finding some solutions to this and getting method info for the DeserializeObject and calling it using reflection seemed to be the way to go. However, GetMethod() does not exist in WinRT and I was not able to find an alternative I could use to retrieve the generic version of the DeserializeObject (as fetching by the name gives me the non-generic overload). I don't mind using reflection and GetMethod as I can cache (?) the methods and call them every time a message is received without having to resolve it every time.
So how do I achieve the latter part and/or is there another way to approach this?
Alright, I feel like this was not really a problem at all to begin with as I discovered the DeserializeObject(string, Type, JsonSerializerSettings) overload for the method. It works splendidly. However, I would still like to hear some feedback on the approach. Do you think using attributes as a way to resolve the type names is reasonable or are there better ways? I don't want to use the class names directly though, because I don't want to risk any sort of man-in-the-middle things be able to initialize whatever.
Just a few minutes ago we have posted the alternative way to do what you want. Please look here, if you will have any questions feel free to ask:
Prblem in Deserialization of JSON
Try this
http://json2csharp.com/
Put your Json string here it will generate a class
then
public static T DeserializeFromJson<T>(string json)
{
T deserializedProduct = JsonConvert.DeserializeObject<T>(json);
return deserializedProduct;
}
var container = DeserializeFromJson<ClassName>(JsonString);

Deserialize to type whose namespace has changed

Using .NET 4/C#...
I need to deserialize old config files that contain the serialized representation of a type named, say, ns1.X . The serialization has been done using BinaryFormatter.
The problem is, after a round of refactoring, the type X has been moved to a different namespace, say ns2.X .
I have tried creating a new empty ns1.X type that derives from ns2.X, and while this circumvents the 'Can't find type ns1.X' error, the properties in the deserialized object are all null. Also, no ctors get called in the process.
Any suggestions?
You're going to need to use an ISerializationSurregate to make this happen. It's not too difficult and Jeff Richter explains it really well. I recommend his book CLR Via c# 3.

WCF service throw Exception for some types

I created a WCF service.in my data contract I have two attributes lets say:
[DataMember]
Private User objUser;
and
[DataMember]
Private tempClass ObjTemp;
I have get and set property for both the attributes. In my implementation class, I have an object of datacontract class... lets say. objData.
When I assign
objData.ObjTemp=(function which return objTemp);
the service work fine. But, when I assign.
objData.objUser=(function which return objUser)
it throws following error:
The underlying connection was closed: The connection was closed
unexpectedly.
When I comment
objData.objUser=(function which return objUser)
it works fine again.
When I inspect the code inside my User class, I found one property creating problem. When I change the property that property it works fine too; but i do not know why that property is creating problem.
The property is like this:
public IPAddress IP { get; set; }
Now this IPAdress class contains a constructor, and get and set for ip variable. In the get, it simply returns ip variable.
in set it checks some condition and then assign value to ip variable. If condition fails, it throws an exception. Can anybody explain what the problem could be?
I just checked another thing.
If i remove [DataMember] attribute from private User objUser; it works fine; but if i put [DataMember] back it generates the same error.
any suggestions?
You will most likely find that objUser is not serializable. For more info read this: MSDN: Using Data Contracts
To quote a short snippet of that:
All .NET Framework primitive types, such as integers and strings, as well as certain types treated as primitives, such as DateTime and XmlElement, can be serialized with no other preparation and are considered as having default data contracts.... New complex types that you create must have a data contract defined for them to be serializable.
You could also consider using the Service Trace Viewer tool from Microsoft to help track down the exact problem you are having.
Edit:
if it is the System.Net.IPAddress object you are talking about, then it is marked as [Serializable], but it doesn't have a default parameterless constructor, which is one of the requirements necessary when using the DataContractSerializer (which is what is used to serialize your data objects over the WCF boundary). You may also want to ensure that if any of your custom objects used in your WCF calls contain any further custom objects (in properties, like your IPAddress) then they are decorated with the KnownType attribute.
So, as a solution you can either write your own IPAddress class that plays nice with the DataContractSerializer, or switch to using the XmlSerializer in your WCF calls.

Parsing a dynamic enumeration

We are using a Microsoft ERP which dynamically exposes web services. The services generated by the service is out of our control. We have no say so in how the objects, including the type definitions, are created and exposed. When a new method is added or removed from the web service, all of the type enumerations are renumbered and everything that uses the web service, after updating to the new definitions, is hosed up. So essentially,
enumeration Type1
Item1
Item2
Item3
... could become
enumeration Type6
Item1
Item2
Item3
...with the enumeration type name changing, but members of the type remaining static. The service outputs a service which looks exactly like the end result of using the XSD.exe to generate objects. So anytime someone exposes a new method on the service (via the ERP GUI), the objects are rebuilt, types are assigned to the service definitions in alphabetical order, reexposed, leaving the entire code base shot.
I attempted to use reflection to determine the type and then parse out the static member into the new business object, but it doesn't work because I can't type cast the enumeration without knowing the actual name of the type. The following won't work.
System.Type t = service.BusinessObjectEnumeration.GetType();
service.SomeField = Enum.Parse(t,"Item1");
...as the compiler throws an error because I'm not explicitly casting the enumeration.
Any ideas how I can overcome this issue while dynamically casting the type to the correct enumeration?
Again, I cannot modify the actual objects exposed by the service, only the code subscribing to the service.
Re the example code:
System.Type t = service.BusinessObjectEnumeration.GetType();
service.SomeField = Enum.Parse(t,"Item1");
Maybe the way to do this is via reflection:
var prop = service.GetType().GetProperty("SomeField");
prop.SetValue(service, Enum.Parse(prop.PropertyType, "Item1"), null);
I had a similar issue with Nav web services. The solution I used to to create a new web reference for each service you expose through Nav rather than just a single one for all services. This prevents the name collisions you are experiencing without using reflection or hacks.
Why should you need to parse things?
If I understand Enums correctly, they pass on the value (and not the Enum itself).
EDIT: What I mean is, enum is not same as a class. For a class, one expects an instance to be passed/received. For an enum, it is one or combination of its members, which is passed in form of an int value.
EDIT2: Are you trying to use the enum as some kind of struct here?
EDIT3: You will have to see what type is the enum in debug mode, to figure out how to reflect on it.
object enumValueReturned = service.BusinessObjectEnumeration;
Put the enumValueReturned in watch window & play with it using reflection (GetMembers) to see, how would you reach Item1.

Categories