I'm trying to send a quite simple JSON message from BizTalk.
{
"Value": 1
}
I set the type of the "Value" field to xs:int in my xml schema
<xs:element minOccurs="1" maxOccurs="1" name="Value" type="xs:int" />
But it keeps generating the wrong JSON message.
{
"Value": "1"
}
Not sure what I'm doing wrong here. Does anybody have some tips?
There can be multiple issues at work here.
Your XML payload is not going through a XML Dissasembler or Assembler before reaching the JSON Encoder, and hence the Message Type isn't set correctly, in which case it is not using the schema to determine the correct date types.
You have another earlier element in your schema with the same name but a different type. It will use the type from the first one for all elements with the same name. This was a bug in BizTalk 2013 R2, and I think it was still there in BizTalk 2016 and could cause some strange errors, especially if you had a Records (complex types) and Element (simple types) with the same name. e.g FIX: JSON encoder unable to handle XML schema with the same name for record and one of its elements in CU 7
Biztalk Embedded JSON Encoder has the ability to recognize schema of XML processed and should recognize xs:int value from schema and encoded without quotes.
But sometimes (as Sandro Pereira indicates even often) this encoder throws the error:
Reason: Value cannot be null.
Parameter name: key
That was my case. I had to use a custom JSON Encoder that recognizes XML datatype somehow.
My solution was:
Use this build of Newtonsoft.Json library that uses json:Type argument as indicator of XML tag datatype.
Create a custom JSON Encoder that uses the previous library
Create custom Complex Type in separate schema with targetNamespace = "http://james.newtonking.com/projects/json"
Note that attribute Type need to be Qualified
Import above schema in Your target schema using prefix json
Use this type as Data Structure Type and rename Your parameter.
Map this checking logical existance, to avoid putting argument without value or custom xslt tranform
Usefull sites:
Adding name to attribute
I have a SQL Server (2012) database schema which is somewhat similar to that of a Shopping Website or Social website in that there are multiple 'items' that each have multiple images, although for each image I store about 10 different sizes of that image.
My plan was to have one table to hold all image data, one row for each original image eg. with column names of:
ImageID
PostID (foreign key)
OriginalImageWidth
OriginalImageHeight
OriginalImageFileUrl
ImageSizesJSON (nvarchar(MAX))
The last column ImageSizesJSON would store an array of JSON objects representing the various (auto-sized-on-upload) resized images for that item. For example like:
[{ "height": 1536, "width": 2048, "source": "images/post/1/2048x1536.jpg" },
{ "height": 960, "width": 720, "source": "images/post/1/960x720.jpg" },
{ "height": 720, "width": 540, "source": "images/post/1/720x540.jpg" }]
This is particularly to avoid all of the following:
excessive database calls/table joins (as won't need to query the various sizes) - ie. denormalising the database for the original-image to image-sizes data
unnecessary reading of the file system for all image sizes, and
the associated disconnection of (meta)data storage locations (DB and Filesystem)
unnecessary application code to handle the various image sizes (all that needs to be done to handle all image sizes can be done on upload and in a batch script (including serialising the image size array to JSON and saving it to the DB)).
I am using .NET (4.5), the Entity Framework (most recent - 5.0 I believe (numbering is confusing)) and the Web API to return JSON AJAX web services to my web based and mobile app.
However, I am having problems combining the JSON returned from the SQL Server column 'ImageSizesJSON' with the JSON output by the Web API after/during serialisation of my POCO.
I've tried various ways to combine them but each has issues I can't surmount, and I'm not sure which is the best way either:
Simply treating the column as a CLR string. The problem with this method is that when the JSON is returned by the webservice, the JSON is treated (as expected) as a string, and double quotes are escaped, the whole JSON has quotes around it etc., and I can't find a way to have it output as pure JSON, and am unsure of any other way to get around the way it is output. Maybe this can be handled suitably in JavaScript though..?
Serialising the JSON back to the POCO object, and then 'appending' it to my LINQ to EF query for the Web API to then reserialise for output as JSON (even though I realise this is an unnecessary double overhead). When I try to do this, I get various errors appending the serialised JSON in the LINQ to EF query, such as 'this method cannot be translated into a store expression' or 'Unable to create a constant value of type Only primitive types or enumeration types are supported in this context.' I understand why these errors occur but I am unsure how to get around them (elegantly) either.
After a lot of Googling I am almost at the point of giving up the denormalised image-size table schema for the moment just to progress at this point, however the approach seems like the best app architecture to me and I'd like to know how to do it (plus I think other people would find it handy too), so I'd greatly appreciate pointers towards a solution or ideally code to handle either of the problems I've mentioned.
Thanks for any input.
I found the answer to my problem, using option #1 (treating the column holding the JSON string as a .NET string type). In the JavaScript/AJAX that calls the Web API webservices, all I needed to do was reference the ImageSizesJSON column using JSON.parse() eg:
var imagesJson = JSON.parse(ImageSizesJSON);
This converts the escape string of JSON to a JSON object, so that it can be worked with correctly as an object in JavaScript.
We have an employee whose surname is Null. Our employee lookup application is killed when that last name is used as the search term (which happens to be quite often now). The error received (thanks Fiddler!) is:
<soapenv:Fault>
<faultcode>soapenv:Server.userException</faultcode>
<faultstring>coldfusion.xml.rpc.CFCInvocationException: [coldfusion.runtime.MissingArgumentException : The SEARCHSTRING parameter to the getFacultyNames function is required but was not passed in.]</faultstring>
Cute, huh?
The parameter type is string.
I am using:
WSDL (SOAP)
Flex 3.5
ActionScript 3
ColdFusion 8
Note that the error does not occur when calling the webservice as an object from a ColdFusion page.
Tracking it down
At first I thought this was a coercion bug where null was getting coerced to "null" and a test of "null" == null was passing. It's not. I was close, but so very, very wrong. Sorry about that!
I've since done lots of fiddling on wonderfl.net and tracing through the code in mx.rpc.xml.*. At line 1795 of XMLEncoder (in the 3.5 source), in setValue, all of the XMLEncoding boils down to
currentChild.appendChild(xmlSpecialCharsFilter(Object(value)));
which is essentially the same as:
currentChild.appendChild("null");
This code, according to my original fiddle, returns an empty XML element. But why?
Cause
According to commenter Justin Mclean on bug report FLEX-33664, the following is the culprit (see last two tests in my fiddle which verify this):
var thisIsNotNull:XML = <root>null</root>;
if(thisIsNotNull == null){
// always branches here, as (thisIsNotNull == null) strangely returns true
// despite the fact that thisIsNotNull is a valid instance of type XML
}
When currentChild.appendChild is passed the string "null", it first converts it to a root XML element with text null, and then tests that element against the null literal. This is a weak equality test, so either the XML containing null is coerced to the null type, or the null type is coerced to a root xml element containing the string "null", and the test passes where it arguably should fail. One fix might be to always use strict equality tests when checking XML (or anything, really) for "nullness."
Solution
The only reasonable workaround I can think of, short of fixing this bug in every damn version of ActionScript, is to test fields for "null" and escape them as CDATA values.
CDATA values are the most appropriate way to mutate an entire text value that would otherwise cause encoding/decoding problems. Hex encoding, for instance, is meant for individual characters. CDATA values are preferred when you're escaping the entire text of an element. The biggest reason for this is that it maintains human readability.
On the xkcd note, the Bobby Tables website has good advice for avoiding the improper interpretation of user data (in this case, the string "Null") in SQL queries in various languages, including ColdFusion.
It is not clear from the question that this is the source of the problem, and given the solution noted in a comment to the first answer (embedding the parameters in a structure) it seems likely that it was something else.
The problem could be in Flex's SOAP encoder. Try extending the SOAP encoder in your Flex application and debug the program to see how the null value is handled.
My guess is, it's passed as NaN (Not a Number). This will mess up the SOAP message unmarshalling process sometime (most notably in the JBoss 5 server...). I remember extending the SOAP encoder and performing an explicit check on how NaN is handled.
#doc_180 had the right concept, except he is focused on numbers, whereas the original poster had issues with strings.
The solution is to change the mx.rpc.xml.XMLEncoder file. This is line 121:
if (content != null)
result += content;
(I looked at Flex 4.5.1 SDK; line numbers may differ in other versions.)
Basically, the validation fails because 'content is null' and therefore your argument is not added to the outgoing SOAP Packet; thus causing the missing parameter error.
You have to extend this class to remove the validation. Then there is a big snowball up the chain, modifying SOAPEncoder to use your modified XMLEncoder, and then modifying Operation to use your modified SOAPEncoder, and then moidfying WebService to use your alternate Operation class.
I spent a few hours on it, but I need to move on. It'll probably take a day or two.
You may be able to just fix the XMLEncoder line and do some monkey patching to use your own class.
I'll also add that if you switch to using RemoteObject/AMF with ColdFusion, the null is passed without problems.
11/16/2013 update:
I have one more recent addition to my last comment about RemoteObject/AMF. If you are using ColdFusion 10; then properties with a null value on an object are removed from the server-side object. So, you have to check for the properties existence before accessing it or you will get a runtime error.
Check like this:
<cfif (structKeyExists(arguments.myObject,'propertyName')>
<!--- no property code --->
<cfelse>
<!--- handle property normally --->
</cfif>
This is a change in behavior from ColdFusion 9; where the null properties would turn into empty strings.
Edit 12/6/2013
Since there was a question about how nulls are treated, here is a quick sample application to demonstrate how a string "null" will relate to the reserved word null.
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009"
xmlns:s="library://ns.adobe.com/flex/spark"
xmlns:mx="library://ns.adobe.com/flex/mx" minWidth="955" minHeight="600" initialize="application1_initializeHandler(event)">
<fx:Script>
<![CDATA[
import mx.events.FlexEvent;
protected function application1_initializeHandler(event:FlexEvent):void
{
var s :String = "null";
if(s != null){
trace('null string is not equal to null reserved word using the != condition');
} else {
trace('null string is equal to null reserved word using the != condition');
}
if(s == null){
trace('null string is equal to null reserved word using the == condition');
} else {
trace('null string is not equal to null reserved word using the == condition');
}
if(s === null){
trace('null string is equal to null reserved word using the === condition');
} else {
trace('null string is not equal to null reserved word using the === condition');
}
}
]]>
</fx:Script>
<fx:Declarations>
<!-- Place non-visual elements (e.g., services, value objects) here -->
</fx:Declarations>
</s:Application>
The trace output is:
null string is not equal to null reserved word using the != condition
null string is not equal to null reserved word using the == condition
null string is not equal to null reserved word using the === condition
Translate all characters into their hex-entity equivalents. In this case, Null would be converted into E;KC;C;
Stringifying a null value in ActionScript will give the string "NULL". My suspicion is that someone has decided that it is, therefore, a good idea to decode the string "NULL" as null, causing the breakage you see here -- probably because they were passing in null objects and getting strings in the database, when they didn't want that (so be sure to check for that kind of bug, too).
As a hack, you could consider having a special handling on the client side, converting 'Null' string to something that will never occur, for example, XXNULLXX and converting back on the server.
It is not pretty, but it may solve the issue for such a boundary case.
Well, I guess that Flex' implementation of the SOAP Encoder seems to serialize null values incorrectly. Serializing them as a String Null doesn't seem to be a good solution. The formally correct version seems to be to pass a null value as:
<childtag2 xsi:nil="true" />
So the value of "Null" would be nothing else than a valid string, which is exactly what you are looking for.
I guess getting this fixed in Apache Flex shouldn't be that hard to get done. I would recommend opening a Jira issue or to contact the guys of the apache-flex mailinglist. However this would only fix the client side. I can't say if ColdFusion will be able to work with null values encoded this way.
See also Radu Cotescu's blog post How to send null values in soapUI requests.
It's a kludge, but assuming there's a minimum length for SEARCHSTRING, for example 2 characters, substring the SEARCHSTRING parameter at the second character and pass it as two parameters instead: SEARCHSTRING1 ("Nu") and SEARCHSTRING2 ("ll"). Concatenate them back together when executing the query to the database.
I have a Biztalk orchestration that posts to a http site. the response that comes back is of xmlDocument type, but it only contains a 0, no html/xml at all. All I want to do is set that 0 to a string or something to output it, but I cannot use any of the xmldocument functions because the xml is not well formed, and I cant use maps because there is no schema to work with. Trying to use any xml function returns an "invalid root level" error.
You can use a string variable and use Xpath to set the value from the response message in an Expression Shape.
You can use a XMLDocument Message and create it in an Assign Shape. You can assign the string variable to an element in the message.
You might look at using a Pipeline Component to wrap the response - e.g. have a look at the Flat File samples here
To show this fundamental issue in .NET and the reason for this question, I have written a simple test web service with one method (EditString), and a consumer console app that calls it.
They are both standard web service/console applications created via File/New Project, etc., so I won't list the whole code - just the methods in question:
Web method:
[WebMethod]
public string EditString(string s, bool useSpecial)
{
return s + (useSpecial ? ((char)19).ToString() : "");
}
[You can see it simply returns the string s if useSpecial is false. If useSpecial is true, it returns s + char 19.]
Console app:
TestService.Service1 service = new SCTestConsumer.TestService.Service1();
string response1 = service.EditString("hello", false);
Console.WriteLine(response1);
string response2 = service.EditString("hello", true); // fails!
Console.WriteLine(response2);
[The second response fails, because the method returns hello + a special character (ascii code 19 for argument's sake).]
The error is:
There is an error in XML document (1, 287)
Inner exception: "'', hexadecimal value 0x13, is an invalid character. Line 1, position 287."
A few points worth mentioning:
The web method itself WORKS FINE when browsing directly to the ASMX file (e.g. http://localhost:2065/service1.asmx), and running the method through this (with the same parameters as in the console application) - i.e. displays XML with the string hello + char 19.
Checking the serialized XML in other ways shows the special character is being encoded properly (the SERVER SIDE seems to be ok which is GOOD)
So it seems the CLIENT SIDE has the issue - i.e. the .NET generated proxy class code doesn't handle special characters
This is part of a bigger project where objects are passed in and out of the web methods - that contain string attributes - these are what need to work properly. i.e. we're de/serializing classes.
Any suggestions for a workaround and how to implement it?
Or have I completely missed something really obvious!!?
PS. I've not had much luck with getting it to use CDATA tags (does .NET support these out of the box?).
You will need to use byte[] instead of strings.
I am thinking of some options that may help you. You can take the route using html entities instead of char(19). or as you said you may want to use CDATA.
To come up with a clean solution, you may not want to put the whole thing in CDATA. I am not sure why you think it may not be supported in .NET. Are you saying this in the context of serialization?