Lately, we've been seeing exceptions like this in our .NET (.asmx) webservices:
System.Web.Services.Protocols.SoapException: Server was unable to read request. ---> System.InvalidOperationException: There is an error in XML document (868, -3932). ---> System.Xml.XmlException: '.', hexadecimal value 0x00, is an invalid character. Line 868, position -3932.
at System.Xml.XmlTextReaderImpl.Throw(Exception e)
at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
at System.Xml.XmlTextReaderImpl.Throw(Int32 pos, String res, String[] args)
at System.Xml.XmlTextReaderImpl.ThrowInvalidChar(Int32 pos, Char invChar)
at System.Xml.XmlTextReaderImpl.ParseNumericCharRefInline(Int32 startPos, Boolean expand, BufferBuilder internalSubsetBuilder, Int32& charCount, EntityType& entityType)
at System.Xml.XmlTextReaderImpl.ParseText(Int32& startPos, Int32& endPos, Int32& outOrChars)
at System.Xml.XmlTextReaderImpl.ParseText()
at System.Xml.XmlTextReaderImpl.ParseElementContent()
at System.Xml.XmlTextReaderImpl.Read()
at System.Xml.XmlTextReader.Read()
at System.Web.Services.Protocols.SoapServerProtocol.SoapEnvelopeReader.Read()
at System.Xml.XmlReader.ReadElementString()
at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationReader1.Read14_SendErrlog()
at Microsoft.Xml.Serialization.GeneratedAssembly.ArrayOfObjectSerializer12.Deserialize(XmlSerializationReader reader)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
--- End of inner exception stack trace ---
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle, XmlDeserializationEvents events)
at System.Xml.Serialization.XmlSerializer.Deserialize(XmlReader xmlReader, String encodingStyle)
at System.Web.Services.Protocols.SoapServerProtocol.ReadParameters()
--- End of inner exception stack trace ---
at System.Web.Services.Protocols.SoapServerProtocol.ReadParameters()
at System.Web.Services.Protocols.WebServiceHandler.CoreProcessRequest()
How can I debug this exception? This exception is getting reported to us from a SOAP filter which looks for exceptions in message.Stage = SoapMessageStage.AfterSerialize.
Is there any way to get at the original soap request? How do I get an invalid character at line 868, column -3932? How can there a negative column 3932?
This is one of the irritating things about the Microsoft web services approach -- if the request cannot be deserialized into the objects in your web method signature then the service consumer gets a cryptic message. And to top it off, the request never makes it into your web service because it cannot be deserialzied so you can't handle the error gracefully.
What I would do to help with these types of issues is to create a new SoapExtension that simply lets you output the raw XML to a destination that is convenient for you (file or Trace to be read by DebugView or whatever else you like). The code would go in the BeforeDeserialize stage. You could enable the SoapExtension via web.config in the event you wanted to investigate one of these issues. The downside of using the web.config to add the SoapExtension is that it will be active for the entire web application. You could add some additional custom configuration that would allow your service to only log information for a specific endpoint or a specific web method if you wanted.
Usually, just by seeing the incoming XML you can see what the problem is. If not, then you could try to manually run the captured XML through small program that invokes the XML serializer and see if you can find out what is going on. Another useful tool is Web Service Studio 2 which is a test harness which lets you enter data and invoke your service (and also submit any XML you want).
In terms of your specific issue, here is my take/guess. It looks like ASCII character null is getting encoded and sent to your service which is invalid according to the XML Spec. The simple answer is not to send that character. But who is sending that character? Is it a .NET client? Do you have control over the client? If you need to work around someone else's bug, then you may have to replace the offending character(s) with another character (perhaps empty string).
You should be able to get the original message by using another SoapExtension. In fact, the same extension could probably be modified to make a copy of the input, and to discard it if there is no exception. The original input would then be available to you if an exception occurred.
You could also use an external tool like Fiddler to watch what's being sent to you.
FYI: SoapException.Message is intentionally left vague to prevent exposing too much information which could potentially be used to exploit the system.
For your particular case I'd take John's advice and install Fiddler to monitor the actual HTTP traffic and view the message on the wire.
The portion of your exception that jumps out at me is the "hexadecimal value 0x00, is an invalid character" but as you mentioned the line number it points to is bunk--so it's nothing concrete.
What kind of parameters do you pass to the service? Are you doing any kind of custom encoding with a SOAP extension? Any additional SOAP headers being added?
Related
I'm playing around with AWS Translate a bit. I want AWS Translate to auto-detect the source language, when I send a TranslateTextAsync request. Apparently, there can be a DetectedLanguageLowConfidenceException, which I want to handle by getting the DetectedLanguageCode from the exception and retry the translation. I was not able to get this exception to occur, so I don't know the structure of that response exception.
For the Java SDK, I found that there is a "getDetectedLanguageCode" function, but this one doesn't exist in the .NET SDK. I'm using AWSSDK.Translate v3.3.101.12.
How do I get the language code from the DetectedLanguageLowConfidenceException?
I contacted AWS Support and they reached out to their AWS Translate team. They write that
C#/.Net does not support member variables in exceptions the way Java does. However, supplementary information about exceptions is stored in the Data dictionary of the exception
They also mention that AWS Translate will usually use even a low confidence guess before throwing a DetectedLanguageLowConfidenceException, so it seems like we don't really have to worry about it.
I still went and implemented the exception handling and have the following code to extract the detected language code data. This code is untested though:
catch (DetectedLanguageLowConfidenceException ex)
{
var dictionary = ex.Data as Dictionary<object, object>;
var detectedLanguageCode = dictionary?["DetectedLanguageCode"] as string;
// Retry here with the detected low confidence language code.
}
I am working with one soap request where we need to pass,single data in one parameter and in 2nd iteration we need to pass multiple test data in same input request.Please help me how to change input soap request as per test data,please find below soap requests for single and multiple requests.
Single Request:
<ReqDtls>
<vReqs>
<amount>1.00</amount>
<cardNo>8897654778999</cardNo>
</Reqs>
<cardType>caredit</cardType>
</ReqDtls>
Multiple Requests:In same soap input requests,it is changing dynamically from POS system but i want to perform in loadrunner.
<ReqDtls>
<vReqs>
<amount>1.00</amount>
<cardNo>8897654778999</cardNo>
</Reqs>
<vReqs>
<amount>2.00</amount>
<cardNo>890897654778999</cardNo>
</Reqs>
<cardType>caredit</cardType>
</ReqDtls>
Any code in vugen to pass this type of values from excel file for loadtesting,please help how to do this one
This is where you will use your foundation skills in programming as well as a web_custom_request() (Potentially) to send your own custom string.
Notice the repeated piece here
<vReqs>
<amount>{amount_variable}</amount>
<cardNo>{card_variable}</cardNo>
</Reqs>
You have a defined header
<ReqDtls>
And a defined footer
<cardType>caredit</cardType>
</ReqDtls>
This now becomes a matter of string concatenation in C and turning the variables into literals. Consider a loop and lowly sprintf() for this task. Note, variable declarations are not included in the code fragment
sprintf(mybigstring,"<ReqDtls>\r");
for (myloopcounter=1;myloopcounter<=mylooplimit;myloopcounter++)
{
sprintf(mybigstring,
"%s%s",
mybigstring,
lr_eval_string("<vReqs>\r<amount>{amount_variable}</amount>\r<cardNo>{card_variable}</cardNo>\r</Reqs>\r") );
lr_advance_param("amount_variable");
lr_advance_param("card_variable");
}
sprintf(mybigstring,"%s%s",mybigstring,"<cardType>caredit</cardType>\r</ReqDtls>");
The above is directly from noggin to screen so it may require a bit if fiddling, but it should give you an idea for a path.
Once you have your string, then you can use it in whatever request as needed.
I am developing webservice based on CXF. One of the requests is that client should be able to upload the optional PDF file as a part of message. This was pretty trivial:
I have added this with getter and setter to my transfer object:
#XmlMimeType("application/octet-stream")
#XmlElement(name = "InvoicePdf", required = false)
private DataHandler invoicePdf = null;
I have also enabled support for MTOM:
Endpoint endpoint = Endpoint.publish("/myWs", new WsImpl(getServletContext()));
SOAPBinding binding = (SOAPBinding) endpoint.getBinding();
binding.setMTOMEnabled(true);
And the usage:
DataHandler pdf2 = p_invoice.getInvoicePdf();
//pdf2.getInputStream();
//pdf2.writeTo(outputstream);
Everything works great. I am able to receive and process the file. However there might be the case when client do not upload the file since it is optional. The problem is that even though the client do not sent the file I am not able to notice it.
pdf2 is not null
pdf2.getInputStream() is not null
pdf2.getInputStream() contains some data. I would like to skip parsing the input stream and looking for PDF signature. Since it is a lot easier to forward the inputstrem to desired outpustream (write to file)
I have not found in DataHandler or DataSource (pdf2.getDataSource() ) API any appropriate method or field for determining file existance. I see in debug that the empty DataHandler contains DataSource which length is 9, which is a lot less then correct PDF file. Unfortunately the length property is not accessible at all.
Any idea how to determine if the file was sent or not?
The solution is to skip xml tag for this attachment in SOAP message. So my mistake was sending empty tag:
<InvoicePdf></InvoicePdf>
Then you get behavior described in question. However if you skip this tag entirely then DataHandel is null, so I am able to distinguish is file was sent or not.
We are working on a system in perl that has to communicate with multiple web services that provide SOAP endpoints to work with. They provide WSDL files to describe the services (in C# .Net, "Add Service Reference" would use these). We use wsdl2perl.pl to import these files into perl modules.
All is working, except for when the services return a fault.
We call a service like this:
my $service = OurInterfaces::OurService::OurPort->new();
my $result = $service->ourMethod({ someParameter => '1234' });
die $result->get_faultstring()->serialize() if not $result;
When we try to access the fault string, our perl script dies with this:
<Fault><faultcode>SOAP-ENV:Server</faultcode><faultstring>Error deserializing message: Cannot resolve class for Fault/detail/Errors/ErrorDetail via UPSRateTypemaps::RateService at /usr/lib/perl5/site_perl/5.8.8/SOAP/WSDL/Expat/MessageParser.pm line 147.
at line 1 at /usr/lib/perl5/site_perl/5.8.8/SOAP/WSDL/Expat/Base.pm line 82
.
Message was:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"><soapenv:Header/><soapenv:Body><soapenv:Fault><faultcode>Client</faultcode><faultstring>An exception has been raised as a result of client data.</faultstring><detail><err:Errors xmlns:err="http://www.ups.com/schema/xpci/1.0/error"><err:ErrorDetail><err:Severity>Hard</err:Severity><err:PrimaryErrorCode><err:Code>10001</err:Code><err:Description>The XML document is not well formed</err:Description><err:Digest></RateRequest> does not close tag <Request>.</err:Digest></err:PrimaryErrorCode><err:Location/></err:ErrorDetail></err:Errors></detail></soapenv:Fault></soapenv:Body></soapenv:Envelope></faultstring><faultactor>urn:localhost</faultactor></Fault>
It appears that the XML being returned for faults isn't mapped to a class (Class::Std) properly. How can we fix this?
Also is there any articles out there describing what we need to do to map the error messages? For the most part wsdl2perl.pl is just plain magic to us.
Since no answers yet. I'll post what we did to get it working.
We opened up the Typemap.pm file that has our $typemap_1, and added lines like this:
'Fault/detail' => 'UPSTrackElements::Errors'
'Fault/detail/Errors' => 'UPSTrackElements::Errors',
'Fault/detail/Errors/ErrorDetail' => 'UPSTrackTypes::ErrorDetailType',
...
wsdl2perl.pl imported the error classes we needed, but it didn't hook them up properly in the typemap file. In general, we had to append 'Fault/detail' to the front of where it mapped all of our Error classes. I'm not sure why wsdl2perl.pl couldn't map them right, when it obviously had no issue generating the classes.
We had to fill out the appropriate XPath for every single field in the fault xml. It is working for us now, but was rather ugly to figure out.
I need to design a SOAP api (my first one!). What are the best practices regarding errors returned to the caller.
Assuming an api as follow
[WebMethod]
public List<someClass> GetList(String param1)
{
}
Should I
Throw an exception. Let the SOAP infrastructure generate a SOAP fault -- and the caller would have to try/catch. This is not very explanatory to the caller
Have the return parameter be a XMLDOcument of some sort, with the first element being a return value and then the List.
Looking at the return SOAP packet I see that the response generated looks like the following
<GetListResponse>
<GetListResult>
...
...
</GetListResult>
</GetListResponse>
Can we somehow change the return packet so that the "GetListResult" element is changed to "GetListError" in case of error
Any other way?
Thanks!
Probably the most appropriate SOA pattern to follow would be a Fault Contract, which is essentially a Data Contract that is wrapped in the SOAPException.
I am posting examples in .NET, since it looks like that is what you are using (and that is what I know :) )
In WCF, you can define a DataContract, then decorate your OperationContract interface with a a "FaultContract" attribute that specifies it as the return value:
public partial interface MyServiceContract
{
[System.ServiceModel.FaultContract(typeof(MyService.FaultContracts.ErrorMessageFaultContract))]
[System.ServiceModel.OperationContract(...)]
ResponseMessage SOAMethod(RequestMessage request) {...}
}
For ASMX web services, (as it appears you are using from your code snippet), you can't use this attribute or setup. So to implement the pattern, you would need to:
Define a serializable class to hold your exception information (i.e. ErrorData)
When an exception is thrown in your service, catch it and in your error handling code, add the info to the ErrorData class
Append the serialized ErrorData class to a SoapException class:
SoapException mySoapException = new SoapException(message, SoapException.ServerFaultCode, "", serialzedErrorDataClass);
Throw the SoapException in your code
On your client side, you will need to deserialize the message to interpret it.
Kind of seems like a lot of work, but this way you have total control of what data gets returned. Incidentally, this is the pattern that is used by the ServiceFactory from Microsoft patterns & practices for ASMX web services.
There is some good information on Coding Horror.
You can cause the correct fault to be returned from old ASMX services, but it's not easy. First of all, you'll have to hand-code the WSDL, because the ASMX infrastructure will never create Fault elements in a WSDL. Then, you have to serialize the desired fault data into an XmlElement that you will then provide as the Detail property of the SoapException that you will throw.
It's much easier with WCF. You can declare a number of FaultContracts for each operation, and WCF will generate the correct WSDL to refer to them. You then simply throw a FaultException, where type T is the type of the FaultContract. Pass the T instance to the constructor, and you're all set.
I can't give you specifies for .net (which seems to be what you're asking), but SOAP provides a mechanism for expressing strongly-typed exceptions. The SOAP fault element can have an optional FaultDetail sub-element, and this can contain arbitrary XML documents, such as your GetListError. These document types should be defined in the WSDL as a wsdl:fault inside the wsdl:operation
The trick is persuading the web service stack to turn an exception (which is the "correct" way of writing your business logic) into a properly marshalled fault detail. And I can't help you with that bit.