I am having trouble achieving the following scenario.
We currently have a method which expects a list of 'context' key value pairs. The value however can be of any type.
the goal is to make this method available using WCF. So I created a
public List<Element> Transform(List<Element> elements)
{
... Transformation of elements takes place
}
[DataContract(Namespace = Constants.NAMESPACE)]
public struct Element
{
[DataMember(Order = 0, IsRequired = true)]
public string Key;
[DataMember(Order = 1, IsRequired = true)]
public object Value;
}
When I use a .Net test project everything works fine.
However, when I call this service using SOAP UI I get an error message:
The formatter threw an exception while trying to deserialize the
message: There was an error while trying to deserialize parameter
elements. The InnerException message was 'Element Value cannot have
child contents to be deserialized as an object. Please use XmlNode[]
to deserialize this pattern of XML.'.
I am having trouble figuring out what to do. any help appreciated.
the xml i use is this:
<ws:Transform>
<ws:elements>
<ws:Element>
<ws:Key>Key1</ws:Key>
<ws:Value>A</ws:Value>
</ws:Element>
<ws:Element>
<ws:Key>Key2</ws:Key>
<ws:Value>B</ws:Value>
</ws:Element>
<ws:ScriptName>SetVariable</ws:ScriptName>
</ws:elements>
</ws:Transform>
In this case, SoapUI uses .Net technology which does not understand target type for object.
sending object is not valid across all platforms. In fact you might get an error with a .Net client as well. Your best bet is create a generic xml representation of the Value and have all clients inflate the object from the xml
Related
I have the following classes...
public abstract class Fallible<T> {
}
public class Success<T> : Fallible<T> {
public Success(T value) {
Value = value;
}
public T Value { get; private set; }
}
The background to this can be found in a previous question of mine, but you don't need to read that post as the classes above are all that's needed to see the problem.
If I have a simplified WCF service call like this...
[OperationContract]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
...then when I try to call the service from the WPF app that consumes it (or the WCF test client), I get a CommunicationException exception...
There was an error while trying to serialize parameter :GetPatientResult. The
InnerException message was 'Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer 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 the serializer.'. Please
see InnerException for more details.
...with an inner SerializationException exception of...
Type 'PhysioDiary.Entities.FallibleClasses.Success`1[[PhysioDiary.Entities.Patient,
PhysioDiary.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]'
with data contract name > 'SuccessOfPatient0yGilFAm:http://schemas.datacontract.org/2004/07/PhysioDiary.Entities.FallibleClasses'
is not expected. Consider using a DataContractResolver if you are using
DataContractSerializer 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 the serializer.
I've tried adding [DataContract] to the class and [DataMember] to each property, as well as adding a [KnownType] attribute for all four classes involved, and adding a [ServiceKnownType] for each of them on the service contract, but nothing helps.
I've read countless answers to the same question, but have not found anything that works. My services return other custom classes, and they all get serialised without a problem.
Anyone able to explain what the problem is here? Please let me know if I've not supplied enough information.
Turns out all I needed to do was decorate the service method with [ServiceKnownType] attributes for the base type, and each derived type...
[OperationContract]
[ServiceKnownType(typeof(Fallible<Patient>)]
[ServiceKnownType(typeof(Success<Patient>)]
[ServiceKnownType(typeof(BadIdea<Patient>)]
[ServiceKnownType(typeof(Failure<Patient>)]
public Fallible<Patient> GetPatient(int id) {
return new Success<Patient>(new Patient {ID = 1,FirstName = "Jim",Surname = "Spriggs"});
}
Although it's a pain to have to add four attributes to every call, it works. I'd like to know if there is a way to combine them into one attribute, but at least I have a working service now.
Hope this helps someone.
In WCF i have a class which is acting as the return type for all my methods.
public class ResponseResult
{
public object data {get;set;}
public string Name {get;set;}
}
and in IService interface i have method declaration like:
ResponseResult GetValues(int id);
if run the test client GetValues is not available.beside the method name i am getting cross sign on hover it says "this method is not supported in WCF Test client because it uses mmService.Common.ResponseResult".
if i remove the property data then it get visible and i want that object property. please help me out.
Object data type will not work with service client.service client need the serialize data type like list , string , int etc.... it will not actually decide the actual return type of object data type.
I am trying a host a service where there is a method that returns the following type:
[DataContract]
[Obfuscation(ApplyToMembers = true, Exclude = true)]
[Serializable]
public class Output
{
[DataMember]
public DataSet dsOutput{get;set;}
}
The method signature is as follows:
[OperationContract]
[WebGet]
function Output matchData(DataSet pDSSide1,DataSet pDSSide2)
{
return new Output();
}
On browsing the service I encounter the following exception:
System.InvalidOperationException: An exception was thrown in a call to a WSDL export extension:System.ServiceModel.Description.DataContractSerializerOperationBehavior
contract: http://tempuri.org/:TesterTool ---->
System.Runtime.Serialization.InvalidDataContractException: Type 'System.Data.DataRow' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
`
Any suggestions.
It's not a good practice to send a DataTable over a service.
As stated by govindaraj here:
The best way is to use custom collection of custom object.
If you're using 2.0, then you can use generic collection instead of
custom collection to reduce code.
How?
Create a custom data object (containing only private fields and public properties for each field) that is similar to each row in the
datatable.
Create a layer that will do all database (in this case, dataset) access and translation to the custom object.
All client code will access that layer.
Is there any switch that instructs svcutil to generate DataContract properties with their names as defined in code? For example when I create a proxy which uses the following DataContract:
[DataContract(Namespace = "http://schemas.mynamespace.com/2012/08")]
public class MyDataContract
{
[DataMember(IsRequired = true, Order = 0)]
private int _id;
public int Id
{
get { return _id; }
set { _id = value; }
}
}
I get this DataContract on the proxy generated class:
public partial class MyDataContract : object
{
private int _idField;
[System.Runtime.Serialization.DataMemberAttribute(IsRequired=true)]
public int _id
{
get
{
return this._idField;
}
set
{
this._idField = value;
}
}
}
The order property of the DataMemberAttribute is always ommited as well for the first 3 properties and a MessageContract ommits an IDisposable implementation.
Well, I cannot comment on the omitted order, but I may be able to help on the rest:
One usually specifies the DataMember attribute on the property, not on the field. The data-contract itself does not distinguish between a property and a field, but it knows the name, type, if it is mandatory, etc. etc.
Added: What Chris said: With [DataMember(Name="whateveryouwant")] you'll be able to set a name different from the field/property name. I do not like such usage, though, but it is helpful when refactoring code, but still keeping the API compatible.
Only other DataContract (and some intrinsically supported) types are serialized to/from messages. IDisposable seems not to be one.
Serializing the inherited IDisposable of a MessageContract would not make any sense. A message-contract is the .NET representation of a SOAP message. It literally has nothing else to do but to provide a 1:1 mapping between what is in the SOAP message XML, and the accessible .NET types.
A message is part of a ServiceContract, in that it specifies which kind of message must be sent to a certain operation to be a valid invocation, and another (response-)message contract specifies how the data, that the operation returns, will be structured. Nothing else; it is a data-aggregate.
If you want to capture the result of a service-operation on the client, and for convenience automatically send a message back upon going out of scope (or for instance unregistering from a service), you will have to implement this on the client-side. Be aware, however, that the service must not require this to happen (due to lost connections, crashes, etc.).
Use the name property on DataMember attribute
Such as:
[DataMember(Name="myname")]
I am attempting to use WCF to execute IronPython remotely inside of C#. Everything in my system is functioning beautifully as long as it is local.
I have isolated the problem to passing certain objects to the client via WCF:
If you try to pass these to a WCF client from a WCF server, the communications channel crashes:
PythonDictionaries containing values that are Tuples or Lists
Tuples of any kind
...Strangely, dictionaries containing dictionaries are ok (as long as the nested dictionary doesn't meet these 2 conditions). Here is my example code:
try
{
PythonFlow localPython = new PythonFlow();
IPythonFlow remotePython = new IronTesterWcfClient("localhost", "8000");
string tuple = "(1,2,3)";
string list = "[1,2,3]";
string complexDict0 = "{'a':'b','c':{'d':'f'}}";
string complexDict1 = "{'a':'b','c':(1,2,3),'e':'e'}";
string complexDict2 = "{'a':'b','c':[1,2,3],'d':'e'}";
string complexDict3 = "{'a':'b','c':[1,2,3],'d':(1,2,3),'e':{'a':'b','c':[1,2,3],'d':(1,2,3)}}";
localPython.OpenFlow(args[2]);
//OK
IronPython.Runtime.List list1 = localPython.PythonListFromString(list);
//OK
IronPython.Runtime.PythonDictionary dict0 = localPython.PythonDictionaryFromString(complexDict0);
//OK
IronPython.Runtime.PythonDictionary dict1 = localPython.PythonDictionaryFromString(complexDict1);
//OK
IronPython.Runtime.PythonDictionary dict2 = localPython.PythonDictionaryFromString(complexDict2);
//OK
IronPython.Runtime.PythonDictionary dict3 = localPython.PythonDictionaryFromString(complexDict3);
//OK
IronPython.Runtime.PythonTuple tuple1 = localPython.PythonTupleFromString(tuple);
remotePython.OpenFlow(args[2]);
//OK
IronPython.Runtime.List list2 = remotePython.PythonListFromString(list);
//OK
IronPython.Runtime.PythonDictionary dict5 = remotePython.PythonDictionaryFromString(complexDict0);
//Fail!!!
IronPython.Runtime.PythonDictionary dict6 = remotePython.PythonDictionaryFromString(complexDict1);
//Fail!!!
IronPython.Runtime.PythonDictionary dict7 = remotePython.PythonDictionaryFromString(complexDict2);
//Fail!!!
IronPython.Runtime.PythonDictionary dict8 = remotePython.PythonDictionaryFromString(complexDict3);
//Fail!!!
IronPython.Runtime.PythonTuple tuple2 = remotePython.PythonTupleFromString(tuple);
}
catch (Exception ex)
{
//The communication object, System.ServiceModel.Channels.ServiceChannel, cannot be used for communication because it is in the Faulted state.
Console.WriteLine(ex.ToString());
}
I am using NetTcpBinding with SecurityMode.None on the WCF server side... I should also mention that the python call is ultimately accessing a simple object in python which returns the result of eval()
It's basically making it impossible to use Python with WCF. Any ideas?
More info... I was finally able to extract the exceptions inside WCF when this happens:
Outer Exception:
There was an error while trying to serialize parameter http://Intel.ServiceModel.Samples:TestResult.
The InnerException message was 'Type 'IronPython.Runtime.PythonTuple' with data contract name 'ArrayOfanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' 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.'. Please see InnerException for more details.
Inner Exception:
Type 'IronPython.Runtime.PythonTuple' with data contract name 'ArrayOfanyType:http://schemas.microsoft.com/2003/10/Serialization/Arrays' 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.
You're getting a SerializationException, indicating that .NET doesn't know how to deserialize some chunk of the data you're sending. In this case, it's choking on ArrayOfanyType, which is any kind on non-generic collection (an ArrayList or plain array, for instance).
I've reviewed the source for IronPython 2.7.1 (what version are you using?), looking at the implementation of List and PythonTuple. Both contain an Object array, pretty much identically declared; List has a few other random instance fields.
// IronPython.Runtime.List
internal volatile object[] _data;
private const int INITIAL_SIZE = 20;
internal int _size;
// IronPython.Runtime.PythonTuple
internal readonly object[] _data;
I don't know why the serializer isn't happy with the PythonTuple class, when it's fine with List. What this probably indicates, however, is that .NET's type resolver can't resolve some element of the serialized object.
There are two ways to resolve this, that I know of.
You can try to convince .NET to consider a given type during deserialization, using the KnownTypes attribute. From MSDN:
When data arrives at a receiving endpoint, the WCF runtime attempts to deserialize the data into an instance of a common language runtime (CLR) type. The type that is instantiated for deserialization is chosen by first inspecting the incoming message to determine the data contract to which the contents of the message conform. The deserialization engine then attempts to find a CLR type that implements a data contract compatible with the message contents. The set of candidate types that the deserialization engine allows for during this process is referred to as the deserializer's set of "known types."
You'd want to apply this attribute to the class being transferred over the wire, and this isn't convenient when you don't control the class, as is the case here. So this is probably a non-starter.
You can specify a custom DataContractResolver to resolve your problematic types:
A data contract resolver allows you to configure known types dynamically. Known types are required when serializing or deserializing a type not expected by a data contract.
You can do this without controlling the class to be serialized, but it takes a bit more work. This MSDN blog post has a great writeup.
In summary, you'd create a DataContractResolver and override its two methods, TryResolveType and ResolveName. The first is used during serialization, and the second during deserialization. From the MSDN sample, with my comments:
public class MyCustomerResolver : DataContractResolver
{
public override bool TryResolveType(Type dataContractType, Type declaredType, DataContractResolver knownTypeResolver, out XmlDictionaryString typeName, out XmlDictionaryString typeNamespace)
{
if (dataContractType == typeof(Customer)) // a type I recognize
{
XmlDictionary dictionary = new XmlDictionary();
typeName = dictionary.Add("SomeCustomer");
typeNamespace = dictionary.Add("www.FPSTroller.com");
return true;
}
else // I don't know what this is; defer to the inbuilt type resolver
{
return knownTypeResolver.TryResolveType(dataContractType, declaredType, null, out typeName, out typeNamespace);
}
}
public override Type ResolveName(string typeName, string typeNamespace, DataContractResolver knownTypeResolver)
{
// my type
if (typeName == "SomeCustomer" && typeNamespace == "http://www.FPSTroller.com")
{
return typeof(Customer);
}
else // I don't know what this is; defer to the inbuilt type resolver
{
return knownTypeResolver.ResolveName(typeName, typeNamespace, null);
}
}
}
The blog post I mentioned above has some sample resolvers that might give .NET a better shot and handling your classes without writing anything custom (look for the "Useful resolvers" heading).
You'd use DataContractSerializerOperationBehavior. To plug your resolver into WCF; see the sample in the MSDN documentation.
Finally, before going down this path, you might consider changing your WCF operations interface. Do you really need to pass these custom, non-generic types over the wire? What I've read implies that non-generic types run into this kind of issue often. Consider using a plain old System.Collections.Generic.Dictionary<K,V> and (if you're using .NET 4+) System.Tuple. Lock down your types; don't make the resolver guess.