I'm pulling together some services in C# that have to match specific data format; e.g. string lengths, various enumerations and formatting. I have the back-up approach to validate post the SOAP call and respond with friendly messages and pre-defined error codes, but I would like to place additional information into the WDSL (so it is clear that field x can only be 15 alpha characters only with no numbers or punctuation for example).
Is this possible, if so are there any examples and or tutorials?
Take a SOAP message, generate a XSD out of it, and then edit the XSD until all your validation things are in there. Provide the XSD along with the WSDL to your customer.
When you both validate the messages using the same XSD the problem should be gone.
First of all, you should be aware that .NET does not validate SOAP messages against the schema in a WSDL. For instance, if part of your input message shows a maxLength of 50, there will be no error or exception when you are sent 51 instead.
Second, it is not possible to adjust your classes in such a way that you can control the exact schema. For instance, you cannot cause a maxLength attribute into the WSDL.
Third, if you must completely control the WSDL, then you need to write it by hand. You will never have complete control over the WSDL that .NET generates.
Finally, you seen to be talking about ASMX web services here. You should not be using ASMX web services for new development - they have been replaced with WCF.
Related
Apologies if this has been asked before but it seems I cannot find the answer.
I am trying to consume a SOAP Web Service using WCF. I've used Visual Studio 2015's Add Service Reference to add the service reference and generate all code.
The service call fails with the following CommunicationException error:
System.ServiceModel.CommunicationException : Error in deserializing body of reply message for operation 'XYZ'.
---- System.InvalidOperationException : There is an error in XML document (2, 979).
-------- System.FormatException : Input string was not in a correct format.
I understand the error; I understand that something (an element value, probably) in the XML response document cannot be deserialized according to what the svcutil's generated code dictates.
I am logging the XML response document. Also, I am comparing it with the SoapUI response and they both look identical.
SO how can I figure out exactly where the problem is in the XML document? Is there any method, technique or trick to step through the deserialization process and pinpoint the faulty bit? It is a rather long XML document ...
IMHO, at this point the WCF behaves like a black box that I cannot look inside it.
TIA,
Turn on WCF Trace:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/diagnostics/tracing/configuring-tracing
Use the following application to view the results:
https://learn.microsoft.com/en-us/dotnet/framework/wcf/service-trace-viewer-tool-svctraceviewer-exe
Well, it seems one cannot really find exactly where such a deserialization error lies. Things get even worse if the service developer is not the same person as the service client developer.
In my case, the error was due to a mismatch of a data type between the service and the generated client code. The origin of the problem was the erroneous XSD. In order to find the error, I had to contact the service developer who managed to locate it.
Generally speaking, this is one of those things that make you feel you are losing control over your code; much like that point in a project when you want to look the source code of a library but you just can't because you don't own it. This is something all developers who decide to work on web services consuming project should be aware of.
For debugging, you can use Fiddler2 easily to capture any web traffic, including the full xml of a SOAP request/response (and it even handles SSL easily, unlike Wireshark)
For logging... I wish I knew. Sorry.
Also, dupe of In C#, How to look at the actual SOAP request/response in C#
I want to create a wsdl by using 3 xsd-files. How do you that?
I tried this in the command prompt:
wsdl.exe /language:cs /parameters: c:\myService\Contract\HeaderData.xsd c:\myService\Contract\MyData.xsd c:\myService\Contract\Messages.xsd /out: MyWsdl.wsdl
What do I wrong?
I believe that there's a misunderstanding here. Most likely the wsdl.exe in your illustration refers to Microsoft's tool, which is described as:
The Web Services Description Language tool generates code for XML Web services and XML Web service clients from WSDL contract files, XSD schemas, and .discomap discovery documents.
From what you seem to imply by asking the output to be a WSDL file, I can safely assume that you really try to create a WSDL file starting from XSD files. Below I am trying to explain why you cannot do that that easy, and what options you have.
The diagram below shows you the model behind the WSDL 1.1 specification.
Your XSDs fit exactly, and only under types. It WSDL terms, types represent your type system used to describe the parts that make up messages, which are then used to describe input/output and faults of operations organized as ports (abstract interfaces) bound to application/transport protocols, and ultimately made (physically) accessible as services at one or more network endpoints.
To generate WSDL(s) out of XSD(s), you realized by now that you need to provide some more data to a tool that would automatically generate a WSDL for you. For example, what operations you want to describe in your WSDL? For each one of them, what's the input, most likely the output and maybe one or more faults? How would you group them (portType = interface)? What binding do you want to use: HTTP, SOAP? What version of SOAP? SOAP over: HTTP, MQ? SOAPAction? How many WSDL files: 1, or maybe 3?
Some tools may ask you a series of questions (data entry/wizards) along the above lines and then create the WSDL(s) for you. Others, use predefined patterns in the implementation of XSD schema constructs (for example, IFX has a certain way to define Request/Response elements) so based on those assumptions a specialized tool such as QTAssistant (I am associated with it) would ask you less questions, while still creating the WSDLs.
I remember one or two online tools that were able to allow the user to upload XSD files and then create WSDL after prompting you a couple of questions, but I can't seem to find them anymore... kind of like this one...
From my understanding, you don't go xsd->wsdl, but I could be wrong.
Generating a WSDL from an XSD file might help clear it up for you though.
You cannot auto-generate a WSDL from an XSD in this manner. In order to create the WSDL, you need to start with a new WSDL and import this XSD.
The XSD defines the types of data that are available for services. Some XSD is usually embedded in a WSDL, some are imported specifically.
An alternate way is to use the XSD in C# to generate a service, and then extract the concrete WSDL from that service, but this is not preferred as many teams prefer contract first web services.
I am looking for a proper framework to implement the (web)service tier in .NET. I am a little bit familiar with WCF and wondering, if it can be customized the way I want it.
1)There is an industry standard for messages to be sent/recieved by the system, which defines the operations, types used, etc. It is XML based. It requires all requests/responses to be wrapped in an envelope, e.g.:
<xxx:Message>
<xxx:Header>
//some header data
</xxx:Header>
<xxx:Body>
<xxx:Command>
//request data
</xxx:Command>
<xxx:Command>
//request data
</xxx:Command>
<xxx:Body>
</xxx:Message>
The xxx:Command element actually identifies the operation to be performed and parameters, or contains the command execution result.
The WCF wraps everything to SOAP envelope. Can it be customized to send all requests using the envelope in the sample above, instead of SOAP? How should I code my services, so that all outgoing and incoming messages are parsed correctly. Should I look to [MessageContract] or [DataContract] attributes or both?
2)One-way operations. The industry standard states that the services should respond with the "acknowledgment" message, that the request has been received. I was looking at the one-way operations, that implement the similar approach - they notify the client as soon as the message is received by the server. I am wondering, how can I customize the "acknowledgment" message being sent to conform to the industry standard.
If WCF does not allow that, can you forward me to any other possible solution out there - Remoting, maybe some other web-services libraries?
1) Neither attribute will help you. Those attributes are interpreted by the binding (e.g., WS-HttpBinding) to determine how to actually create your messages. You're going to have to write a custom binding to do this, and possibly a custom serializer depending on how "request data" fields are structured.
2) Again, you're going to need to write a custom binding.
A quick search didn't show any existing implementations of a GSA S2S binding for WCF.
There are existing engines for S2S (for example S2SConnect). The licensing costs may or may not be worth the time savings from having to develop your own implementation.
My company is developing an application that receives data from another company via TCP sockets and xml messages. This is delivered to a single gateway application which then broadcasts it to multiple copies of the same internal application on various machines in our organisation.
WCF was chosen as the technology to handle the internal communications (internally bi-directional). The developers considered two methods.
Individual methods exposed by the
WCF service for each different
message received by the gateway
application. The gateway
application would parse the incoming
external message and call the
appropriate WCF service method. The
incoming XML would be translated
into DataContract DTO’s and supplied
as argument to the appropriate WCF
method.
The internal application
exposed a WCF service with one
method “ProcessMessage” which
accepted an Xml string message as
argument. The internal app would
parse then deserialize the received
xml and process it accordingly.
The lead developer thought option two was the better option as it was “easier” to serialized/deserialize the xml. I thought the argument didn’t make sense because DataContracts are serialized and deserialized by WCF and by using WCF we had better typing of our data. In option 2 someone could call the WCF service and pass in any string. I believe option 1 presents a neater interface and makes the application more maintainable and useable.
Both options would still require parsing and validation of the original xml string at some point, so it may also be a question where is the recommended place to perform this validation.
I was wondering what the current thoughts are for passing this kind of information and what people’s opinions on both alternatives are.
Option 1 is suited if you can ensure that the client always sends serialized representations of data contracts to the server.
However if you need some flexibility in the serialization/deserialization logic and not get tightly coupled with DataContracts, then option 2 looks good. Particularly useful when you want to support alternate forms of xml (say Atom representations, raw xml in custom format etc)
Also in option 2 inside the ProcessMessage() method, you have the option of deciding whether or not to deserialize the incoming xml payload (based on request headers or something that is specific to your application).
In option 1, the WCF runtime will always deserialize the payload.
I recently asked a couple of questions around this area: XML vs Objects and XML vs Objects #2. You'll find the answers to those questions interesting.
For our particular problem we've decided on a hybrod approach, with the interface looking something like this:
// Just using fields for simplicity and no attributes shown.
interface WCFDataContract
{
// Header details
public int id;
public int version;
public DateTime writeDateTime;
public string xmlBlob;
// Footer details
public int anotherBitOfInformation;
public string andSoemMoreInfo;
public book andABooleanJustInCase;
}
The reason we use an xmlBlob is because we own the header and footer schema but not the blob in the middle. Also, we don't really have to process that blob, rather we just pass it to another library (created by another department). The other library returns us more strongly typed data.
Good luck - I know from experience that your option 2 can be quite seductive and can sometimes be hard to argue against without being accused of being overly pure and not pragmatic enough ;)
I hope I understood this right. I think it might make sense to have your gateway app handle all the deserialization and have your internal app expose WCF services that take actual DataContract objects.
This way, your deserialization of the TCP-based XML is more centralized at the gateway, and your internal apps don't need to worry about it, they just need to expose whatever WCF services make sense, and can deal with actual objects.
If you force the internal apps to do the deserialization, you might end up with more maintenance if the format changes or whatever.
So I think I would say option 1 (unless I misunderstood).
Using Visual Studio 2008, I setup a client that uses Web Services.
It has nothing to do with buffer sizes (as that is a typical response, all appropriate sizes were increased).
I was using a List as the parameter of the Method.
After much experimentation, I used the System.Net.WebClient to manually create a Soap 1.1 and a Soap 1.2 request to test test the result.
using (var webCtx = new System.Net.WebClient())
{
webCtx.Headers.Add(System.Net.HttpRequestHeader.ContentType, "text/xml");
webCtx.Headers.Add("SOAPAction", "http://tempuri.org/HelloWorld");
var uri = new Uri("http://localhost:12345/MyProject/WebService.asmx");
MessageBox.Show(webCtx.UploadString(uri, xml));
}
Where the xml is a string variable of the xml with actual data.
The problem is when one of the fields has a special character. Here is the example of the message body of the xml.
<PocoClass>
<UnicodeString>123</UnicodeString>
</PocoClass>
If the value of UnicodeString was something simple (i.e. 123), but once the special character appeared, I got 400 Bad Request.
Now, I have found a Microsoft Knowledge Base Article describing the bug kb911276, which basically states, install a hot fix. That really isn't something that can be a solution to the problem, so I was wondering if there are any ideas of how to solve this problem?
Are the only solutions to write some sort of custom encoding/decoding or custom bindings to be implemented by the server and client? Are there any easier ideas?
Thanks
Edited:
The use of a List is not an issue as it is handled by VS. Here is a more complete (but still partial) contents of the soap message.
<HelloWorld xmlns="http://tempuri.org/">
<pocoList>
<PocoClass>
<UnicodeString>123</UnicodeString>
</PocoClass>
</pocoList>
</HelloWorld>
I had a similar problem with a webservice we had that users of our app run online account searches. I found a VS Feedback item about this, but it appears MS considers this behaviour by-design.
What we ended up doing was writing a method that replaced all characters that are not allowed when serializing to XML with question marks.
The allowed list was: 0x09, 0x0a, 0x0d, 0x20-0xd7ff, and 0xe000-0xfffd. Everything else, we turned to "?".
I guess if you can't do that, the data should be base64-encoded in transit to avoid this issue. Seems a bit odd to me, as it breaks the ability to losslessly route a call through a web service.
My concern is where you state that you are using a List as the parameter to a method. Web services don't directly support lists. You need to use an array as the parameter. Then internally you can convert it to a list using .ToList(). This may not be your issue directly!
That KB article was referring to unicode character sets within a request URL, not actual data being posted to the server.
That being said; i'd verify that your headers are well formed.
Also, if VS generated the client proxy for you; right click on the service reference and then on "Update Service Reference"
Just noticed one more thing; you said that you are passing in a list as a parameter; from the snippet of xml shown, that doesn't look like something that would be serialized from a list (by any of the .NET xml serializers); if you want to debug using the webclient approach; try verifying that the format of the xml is valid.
Where are you seeing ? In the raw XML or the serialized data? XML is defined to contain only human-readable characters and is the XML entity for the unreadable ASCII Shift-Out character. If you're looking at the raw XML and it contains the XML entity code, that's allowed, but if you are looking at serialized data and your XML document contains raw control characters it is invalid and will be rejected.