ksoap2 and WCF complex types - wcf

I'm sending this request to my WCF webservice with a Android client using ksoap2:
<v:Envelope xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns:d="http://www.w3.org/2001/XMLSchema" xmlns:c="http://schemas.xmlsoap.org/soap/encoding/" xmlns:v="http://schemas.xmlsoap.org/soap/envelope/"><v:Header />
<v:Body>
<HelloComplex xmlns="http://tempuri.org/" id="o0" c:root="1">
<complex i:type="n0:SampleComplexType" xmlns:n0="http://tempuri.org/">
<Value i:type="d:string">Hello!</Value>
</complex>
</HelloComplex>
</v:Body>
</v:Envelope>
and receive back this:
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<s:Fault>
<faultcode xmlns:a="http://schemas.microsoft.com/net/2005/12/windowscommunicationfoundation/dispatcher">a:DeserializationFailed</faultcode>
<faultstring xml:lang="pt-BR">
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter http://tempuri.org/:complex. The InnerException message was 'Error in line 1 position 363. Element 'http://tempuri.org/:complex' contains data from a type that maps to the name 'http://tempuri.org/:SampleComplexType'. The deserializer has no knowledge of any type that maps to this name. Consider using a DataContractResolver or add the type corresponding to 'SampleComplexType' to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding it to the list of known types passed to DataContractSerializer.'. Please see InnerException for more details.
</faultstring>
</s:Fault>
</s:Body>
</s:Envelope>
But when my other application (AspNew MVC) call this :
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body>
<HelloComplex xmlns="http://tempuri.org/">
<complex xmlns:a="http://schemas.datacontract.org/2004/07/IssueCenter.Core" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Value>C#VALUE!</a:Value>
</complex>
</HelloComplex>
</s:Body>
</s:Envelope>
ant it works.
What can I do to fix my Android client requests?
Notes: I know about the namespace diference and I already try to make the same.

The service doesn't know how to deal with the "ComplexType" type attribute in the XML, so you basically need to tell the service-side serializer what it means. You can do it in a few ways: either you add a DataContractResolver that tells the serializer what this unknown type ID means, or you can add the type (if it exists on the service side) to the list of "known types", so that the service knows exactly what to do with it. I think you should use a DataContractResolver.
In the version 4.0 of the framework, WCF introduced the data contract resolver. Instead of defining the set of known types “statically” (e.g. by specifying the types directly in a KnownTypeAttribute like you did until .NET 4), the data contract resolver provides some hooks which allow you to specify, at the moment when the object is being serialized or deserialized, a mapping between the CLR type and the name / namespace in the XML which will be used to represent this “unknown” type. To do this, you just inherit from the DataContractResolver class and provide your mapping logic.
I think this is the better solution for you, because you likely don't want to create a dummy type on the server side just to deal with this problem, which is what you'd have to do if you were to use KnownTypeAttribute. Only thing to remember is that a resolver makes the serialization slower than using the “standard” known types feature (since known types are static, they can be cached and the calls don’t need to be made all the time), so be aware that when using the resolver, the additional functionality comes at a price in terms of execution time.

Related

For a BizTalk WCF-SQL adapter in Solicit-Response Send port. How to let adapter handle the response data like XmlPolling?

For a SP using For Xml returns a xml as response, If this sp was consumed by a WCF receive location, we can specify the Polling as XmlPolling to let adapter keep the responsed xml "as-is". But for a wcf-sql Solicit-Response Send port, It seems no same way to do it. Currently, the best result I can get is let adapter treat the xml response as a CDATA. Like below:
<usp_MySPResponse xmlns="http://schemas.microsoft.com/Sql/2008/05/TypedProcedures/dbo">
<StoredProcedureResultSet0>
<StoredProcedureResultSet0 xmlns="http://schemas.microsoft.com/Sql/2008/05/ProceduresResultSets/dbo/usp_MySP">
<UnNamedColumn0><![CDATA[ <!-- The XML content of sp returned goes here -->
....
Assuming the Stored Procedure uses the FOR XML clause, there are two binding properties you must set for the result to be recognized as Xml:
XmlStoredProcedureRootNodeName
XmlStoredProcedureRootNodeNamespace
It's these two properties that tell the Adapter it's a FOR XML Stored Procedure. These are essentially the same as the legacy SQL Adapter.
Details here: http://msdn.microsoft.com/en-us/library/dd787898.aspx
There is no way around this so your BizTalk Schema must match these values.
Reading the link https://learn.microsoft.com/en-us/biztalk/adapters-and-accelerators/adapter-sql/execute-stored-procedures-having-a-for-xml-clause-in-sql-server-using-biztalk carefully, it says that the request schema must be generated selecting from "Procedures", undeniably not "TypedProcedures". The request message will therefore be in the namespace http://schemas.microsoft.com/Sql/2008/05/Procedures/dbo which is not explicitly mentioned in
https://learn.microsoft.com/en-us/biztalk/adapters-and-accelerators/adapter-sql/message-schemas-for-procedures-and-functions but the action for a "for xml"-typed procedure is specified there. To summarize: A request message is thus:
<YOURSPNAME xmlns="http://schemas.microsoft.com/Sql/2008/05/Procedures/dbo" />
and the port configuration action header is
<BtsActionMapping xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Operation Name="YOURSPNAME" Action="XmlProcedure/dbo/YOURSPNAME" />
</BtsActionMapping>
Note the discrepancy between the request message's namespace and the operation action, only the action has "Xml" in it. And don't forget to specify the (FOR XML) binding parameters, as answered by Johns-305.

WCF Service ref string param that accepts XML?

I'm writing a WCF service that receives events. It's to an agreed standard so I've got to stick to the service definition, and I don't control the data the clients send. Again this is to an agreed standard although the data can vary.
Here's one of the methods on my service:
complexType ErrorEvent(int requestId, complexType returnValue, ref string errorInfo)
Clients send XML in the errorInfo string that my function will manipulate and return.
The data I get is like this (full SOAP request):
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ErrorEvent xmlns="http://blah">
<requestId>1</requestId>
<returnValue>
<returnCode>0</returnCode>
</returnValue>
<errorInfo>
<ErrorMessage>An error message</ErrorMessage>
<DefaultTask><!-- Complex data --></DefaultTask>
<Task><!-- Complex data --></Task>
<Task><!-- Complex data --></Task>
<Task><!-- Complex data --></Task>
<ExtraMessage>hello</ExtraMessage>
<ExtraMessage>world</ExtraMessage>
</errorInfo>
</ErrorEvent>
</s:Body>
</s:Envelope>
However, when I try and run this I get this error (edited):
The formatter threw an exception while trying to deserialize the message: There was an error while trying to deserialize parameter errorInfo. The InnerException message was 'There was an error deserializing the object of type System.String. End element 'errorInfo' from namespace '' expected. Found element 'ErrorMessage' from namespace ''.
So my question is, is there any way I achieve what I want to do without altering the signature of my method? For example adding attributes to my service etc? Or do I need to intercept the message?
Thanks for any pointers.
Does it have to be passed as a string? You know you can also receive XmlElement and XElements in WCF?
Are you generating the SOAP request yourself? Could you use a CDATA section, i.e.
<?xml version="1.0"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<ErrorEvent xmlns="http://blah">
<requestId>1</requestId>
<returnValue>
<returnCode>0</returnCode>
</returnValue>
<errorInfo>
<![CDATA[<ErrorMessage>An error message</ErrorMessage>
<DefaultTask><!-- Complex data --></DefaultTask>
<Task><!-- Complex data --></Task>
<Task><!-- Complex data --></Task>
<Task><!-- Complex data --></Task>
<ExtraMessage>hello</ExtraMessage>
<ExtraMessage>world</ExtraMessage>]]>
</errorInfo>
</ErrorEvent>
</s:Body>
</s:Envelope>
I didn't find a way to make this work and as #luksan says, it's a misuse by a client to send unescaped XML to a string parameter.
The workaround I adopted was to make a class that implements IClientMessageInspector, IDispatchMessageInspector and IEndpointBehavior to intercept, check and modify any messages that were incorrect.
If I could have changed the interface, another workaround would have been to accept XmlNode[] instead of string.

Error when accessing access the WSDL of my WCF services: "The ... operation references a message element … that has already been exported from the …"

I experience a weird behavior when accessing my web services into a web browser and it leads to an exception while generating.
Here is my scenario:
Access web page: http://localhost:10100/WCFService1.svc?wsdl
Access web page: http://localhost:10100/WCFService2.svc?wsdl
The problem is that the output of WCFService2.svc WSDL contains all the definition of WCFService1 merged with WCFService2.
Furthermore, when I access another WSDL which contains a method having the same name of previously generated WSDL, I get this exception (surely because my WSDL are being merged together).
I also notice the name of the contract is kind of weird having the ":" before the service name: http://MyCompany.ca/:IWCFService3
Someone have a clue what is going on with the "WSDL export extension"?
An ExceptionDetail, likely created by
IncludeExceptionDetailInFaults=true,
whose value is:
System.InvalidOperationException: An exception was thrown in a call to a
WSDL export extension:
System.ServiceModel.Description.DataContractSerializerOperationBehavior
contract: http://MyCompany.ca/:IWCFService3
----> System.InvalidOperationException: The
MyCompany.IWCFService3.Import
operation references a message element
[http://MyCompany.ca/:Import] that has
already been exported from the
MyCompany.IWCFService2.Import
operation. You can change the name of
one of the operations by changing the
method name or using the Name property
of OperationContractAttribute.
Alternatively, you can control the
element name in greater detail using
the MessageContract programming model.
at System.ServiceModel.Description.MessageContractExporter.AddElementToSchema(XmlSchemaElement
element, String elementNs,
XmlSchemaSet schemaSet)
at System.ServiceModel.Description.MessageContractExporter.ExportWrappedPart(Message
message, String elementName, String
elementNs, XmlSchemaSet schemaSet,
Boolean skipSchemaExport)
at System.ServiceModel.Description.DataContractSerializerMessageContractExporter.ExportBody(Int32
messageIndex, Object state)
at System.ServiceModel.Description.MessageContractExporter.ExportMessage(Int32
messageIndex, Object state)
at System.ServiceModel.Description.MessageContractExporter.ExportMessageContract()
at System.ServiceModel.Description.DataContractSerializerOperationBehavior.System.ServiceModel.Description.IWsdlExportExtension.ExportContract(WsdlExporter
exporter,
WsdlContractConversionContext
contractContext)
at System.ServiceModel.Description.WsdlExporter.CallExtension(WsdlContractConversionContext
contractContext, IWsdlExportExtension
extension)
I found my problem: We have a huge set of Web Services and we were having a single instance of System.ServiceModel.Description.ServiceMetadataBehavior that we were sharing among all the services. Making a new instance of ServiceMetadataBehavior for each service fixed the issue.

Unable to add body to RestSharp RestRequest using enums

I am using RestSharp in ASP .NET MVC 2 project. Trying to create RestRequest (using POST method) and add two enum values (my enum type -- OrderStatusFlags) to request body -- using build-in RestSharp XmlSerializer:
var request = new RestRequest("orders/{vendorID}/{number}", Method.POST);
request.AddBody(previousOrderStatus);
request.AddBody(newOrderStatus);
But after calling AddBody method in request parameters can see only empty but no value. And while calling MVC action method an error occurs:
The parameters dictionary contains a null entry for parameter 'previousStatus' of non-nullable type 'OrderStatusFlags' for method 'RestResponse PostOrderStatus(Int32, System.String, OrderStatusFlags, OrderStatusFlags)' in 'OrdersResourceEndpoint'. An optional parameter must be a reference type, a nullable type, or be declared as an optional parameter.
Parameter name: parameters
Enum look like this:
public enum OrderStatusFlags : long
{
Pending,
Confirmed,
...
}
Does anybody occurs a similiar situation?
A couple issues here. First, you can only call AddBody() once or the last call will take precedence. AddBody() is also only for sending XML as the request body. What is the required XML schema that you need to send to that URL? Can you post some sample XML that you're trying to generate?
I think more likely you actually want to use AddParameter() to add some POST parameters since that is far more common than XML request bodies.

WCF server method - returning DataSet kills output parameters

Looking for some collective wisdom. Here is the situation. This is using Visual Studio 2008.
We have a simple WCF contract exposing the following method:
DataSet ExecuteQuery (out string someStuff);
This method is implemented as:
public DataSet ExecuteQuery (out string someStuff)
{
someStuff = "abc";
return new DataSet(); // simplified
}
Client side proxy is generated by svcutil, and appears to be correct.
Problem:
someStuff is always null on the client side.
Observations:
Same problem appears on our build machine.
Returning a string instead of DataSet makes client proxy receive proper value of out parameter:
public string ExecuteQuery(out string someStuff) ...
Removing the client proxy completely and regenerating it doesn't help.
Client definitely receives both DataSet and the "out" string, as seen in its trace log:
<ExecuteQueryResponse xmlns="http://tempuri.org/">
<ExecuteQueryResult>
<xs:schema id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:UseCurrentLocale="true">
<xs:complexType>
<xs:choice minOccurs="0" maxOccurs="unbounded"></xs:choice>
</xs:complexType>
</xs:element>
</xs:schema>
<diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1"></diffgr:diffgram>
</ExecuteQueryResult>
<someStuff>abc</someStuff>
</ExecuteQueryResponse>
Here is how the client proxy generates the code:
[System.ServiceModel.OperationContractAttribute
(Action="http://tempuri.org/IQueryContract/ExecuteQuery",
ReplyAction="http://tempuri.org/IQueryContract/ExecuteQueryResponse")]
[System.ServiceModel.XmlSerializerFormatAttribute()]
System.Data.DataSet ExecuteQuery(out string someStuff);
We use netTcpBinding
Do we need to do anything special in order to return DataSet and out parameters? Anyone has come across anything similar?
Thanks!!!!
WCF, as defined by SOA, must not transport an object (state and behavior), only the state and strucuture of an object. BinaryFormatter, and SoapFormatter are inadequate for SOA because:
1) Requires both ends to share type
2) cannot be used for contracts
3) both formatters require streams
DataContractSerializer only shares types not contracts. It adds support for XML readers and writers, only captures state according to the schema, and deos not support IFormatter.
All of which I took from my WCF course that I took from Juval Lowry :)
Richard
I had [XmlSerializerFormat] at the top of my contract interface. Removing it fixed the problem, as WCF starts using the default [DataSerializerFormat]. Thanks Darin for point it out.
Still not sure why XmlSerializerFormat wouldn't work.