How do I get JSON.Net to serialize my XML to camel case JSON and without the "#"?
this is what I currently have but it prepends # to the properties and does not camel case...
XmlDocument doc = new XmlDocument();
doc.LoadXml(myXmlString);
string jsonText = Newtonsoft.Json.JsonConvert.SerializeObject(doc, new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
});
Make a model of your XML data
example
public class MyClass
{
[JsonProperty("#SomeXMLProperty")]
public string MyString{ get; set; }
}
then deserialize XML to your model
XDocument xmlDocument = XDocument.Parse(xmlData);
string jsonData = JsonConvert.SerializeXNode(xmlDocument);
var myClass = JsonConvert.DeserializeObject<MyClass>(jsonData);
then just use CamelCasePropertyNamesContractResolver and Formatting.Indented
string json = JsonConvert.SerializeObject(rootObject,
Newtonsoft.Json.Formatting.Indented,
new JsonSerializerSettings { ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver() });
UPDATE:
The first solution is simple and clean (no need to write custom resolvers etc.) this is just for removing # sign
var xml = new XmlDocument();
xml.XmlResolver = null;
xml.Load("yourfilehere");
var json = JsonConvert.SerializeXmlNode(xml, Newtonsoft.Json.Formatting.Indented);
var withoutATSign = System.Text.RegularExpressions.Regex.Replace(json, "(?<=\")(#)(?!.*\":\\s )", String.Empty, System.Text.RegularExpressions.RegexOptions.IgnoreCase);
If anybody knows a better solution for both cases then the first it would be nice to look at it.
WebAPI addition
var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.Formatting = Newtonsoft.Json.Formatting.Indented;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
Related
The API Method I am calling is:
[HttpPost("PostXml")]
[Consumes("application/xml")]
[Produces("application/xml")]
public Reservation PostXml([FromBody] Reservation res) =>
repository.AddReservation(new Reservation
{
Name = res.Name,
StartLocation = res.StartLocation,
EndLocation = res.EndLocation
});
The client code:
[HttpPost]
public async Task<IActionResult> AddReservationByXml(Reservation reservation)
{
Reservation receivedReservation = new Reservation();
using (var httpClient = new HttpClient())
{
StringContent content = new StringContent(ConvertObjectToXMLString(reservation), Encoding.UTF8, "application/xml");
using (var response = await httpClient.PostAsync("http://localhost:8888/api/Reservation/PostXml", content))
{
string apiResponse = await response.Content.ReadAsStringAsync();
receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
}
}
return View(receivedReservation);
}
string ConvertObjectToXMLString(object classObject)
{
string xmlString = null;
XmlSerializer xmlSerializer = new XmlSerializer(classObject.GetType());
using (MemoryStream memoryStream = new MemoryStream())
{
xmlSerializer.Serialize(memoryStream, classObject);
memoryStream.Position = 0;
xmlString = new StreamReader(memoryStream).ReadToEnd();
}
return xmlString;
}
I am failing to call the API method and getting the error:
400One or
more validation errors
occurred.https://tools.ietf.org/html/rfc7231#section-6.5.1|f5452728-4c49abe4d88e559e.1.8095e7c1_An
error occurred while deserializing input
data.
What is wrong here?
You got error from this line
receivedReservation = JsonConvert.DeserializeObject<Reservation>(apiResponse);
Please check the validation of your Reservation Model and detail the values you past
and the content of error you got.
Your XML request should be with the correct case as the c# class. XML is case sensitive.
Try this code.
XmlSerializer xsSubmit = new XmlSerializer(typeof(Reservation));
System.IO.StringWriter sww = new System.IO.StringWriter();
XmlWriter writer = XmlWriter.Create(sww);
xsSubmit.Serialize(writer, reservation);
var xml = sww.ToString();
I am using an azure function with event grid trigger and CloudBlockBlob as input binding. The content is getting downloaded from CloudBlockBob using DownloadTextAsync(AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext)
If the file being downloaded above is being generated using XmlDocument, DownloadTextAsync returns gibberish. However, if the file is generated by using FileStream, it works fine. PFB the implementations of generating the file-
Using XmlDocument
var stringwriter = new System.IO.StringWriter();
var serializer = new XmlSerializer(typeof(List<ContractName>), new XmlRootAttribute("RootAttributeName"));
serializer.Serialize(stringwriter, contractData);
var xmlString = stringwriter.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlString);
doc.PreserveWhitespace = true;
doc.Save(fileName);
Using FileStream
var serializer = new XmlSerializer(typeof(List<ContractName>), new XmlRootAttribute("RootAttributeName"));
var file = new FileStream(fileName, FileMode.OpenOrCreate);
serializer.Serialize(file, contractData);
file.Close();
Code being used to download the content-
Using DownloadTextAsync
private static async System.Threading.Tasks.Task<string> DownloadContentAsync_DownloadTextAsync(string storageAccountConnectionString, string containerName, string blobName)
{
CloudBlobContainer container = GetContainer(storageAccountConnectionString, containerName);
ICloudBlob blob = await container.GetBlobReferenceFromServerAsync(blobName);
// Download the blob content
string xmlBlobContent =
await (blob as CloudBlockBlob).DownloadTextAsync(
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
return xmlBlobContent;
}
Using DownloadToStreamAsync
private static async System.Threading.Tasks.Task<string> DownloadContentAsync_DownloadToStreamAsync(string storageAccountConnectionString, string containerName, string blobName)
{
CloudBlobContainer container = GetContainer(storageAccountConnectionString, containerName);
ICloudBlob blob = await container.GetBlobReferenceFromServerAsync(blobName);
// Download the blob content
MemoryStream resultStream = new MemoryStream();
await (blob as CloudBlockBlob).DownloadToStreamAsync(
resultStream,
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
string xmlBlobContent = System.Text.Encoding.UTF8.GetString(resultStream.ToArray());
return xmlBlobContent;
}
Why there is a difference in response from DownloadTextAsync.
Updated 0713:
Figured it out. The root cause is that when you're using XmlDocument to generate the xml file, the encoding is utf-16. But for FileStream, it generates the xml file with encoding utf-8.
So, the solution is that, when using XmlDocument, we can specify the encoding to utf-8(no code change for FileStream). Sample code as below:
Generate xml file using XmlDocument:
//2. Using XMLDoc
serializer.Serialize(stringwriter, contractData);
var xmlString = stringwriter.ToString();
XmlDocument doc = new XmlDocument();
doc.LoadXml(xmlString);
doc.PreserveWhitespace = true;
string fileName = String.Format(#"C:\TestBlobDownloadContent\UsingXMLDoc" + count + ".xml");
//encoding as utf-8
using (TextWriter sw = new StreamWriter(fileName, false, Encoding.UTF8))
{
doc.Save(sw);
}
When read the xml file from blob storage via DownloadTextAsync() method, no need to specify the encoding option, like below:
// Download the blob content
string xmlBlobContent =
await (blob as CloudBlockBlob).DownloadTextAsync(
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
Original answer:
This is due to the encode/decode issue.
Solution:
In the DownloadTextAsync() method, add parameter System.Text.Encoding.Unicode. Like below:
string xmlBlobContent =
await (blob as CloudBlockBlob).DownloadTextAsync(
System.Text.Encoding.Unicode,
null,
new BlobRequestOptions { LocationMode = LocationMode.PrimaryThenSecondary },
new OperationContext());
The test result:
I'm trying to:
[EnableQuery]
[HttpGet]
[ODataRoute("")]
public IHttpActionResult Get(ODataQueryOptions<UserODataModel> options)
{
var users = _repository.RetrieveOData();
var serialQuery = JsonConvert.SerializeObject(options, jsonOptions);
//save serialQuery somewhere
return Ok(users);
}
But got
Newtonsoft.Json.JsonSerializationException: 'Error getting value from 'ReadTimeout' on 'Microsoft.Owin.Host.SystemWeb.CallStreams.InputStream'.'
"Timeouts are not supported on this stream."
I know there is already a question about serialize Stream:
Newtonsoft Json.net - how to serialize content of a stream?
But in this case i can't "extract stream value" from ODataQueryOptions, or can I?
Some ideia?
Since we work on the same company, if anyone is interested, we found a way, maybe not the pretty way, to serialize an ODataQueryOptions:
public static ODataQueryOptions DeserializeQueryOptions(SerializedQueryOptions options)
{
var uri = new Uri(teste.OriginalUri);
var model = ODataConfig.Model; //GetEdmModel
var segment = model.EntityContainer.FindEntitySet(options.EdmType);
var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));
var httpConfiguration = new HttpConfiguration();
httpConfiguration.EnableDependencyInjection();
var request = new HttpRequestMessage(HttpMethod.Get, uri)
{
Properties =
{
{ HttpPropertyKeys.HttpConfigurationKey, httpConfiguration },
}
};
var context = new ODataQueryContext(model, options.EntityType, newPath);
var oDataQueryOptions = new ODataQueryOptions(context, request);
return oDataQueryOptions;
}
public static SerializedQueryOptions SerializeQueryOptions(ODataQueryOptions options)
{
return new SerializedQueryOptions
{
OriginalUri = options.Request.RequestUri.AbsoluteUri,
EdmType = options.Context.NavigationSource.Name,
EntityType = options.Context.ElementClrType
};
}
After you serialize it to an object you can serialize it to a JSON string:
var queryOptionsSerialized = new SerializedQueryOptions()
{
OriginalUri = "http://localhost:25723/odata/users?$skip=0&$top=2&$orderby=fullName&$count=true",
EdmType = "users",
EntityType = typeof(UserODataModel)
};
var json = JsonConvert.SerializeObject(queryOptionsSerialized);
var deserialized = JsonConvert.DeserializeObject<SerializedQueryOptions>(json);
var options = ODataQueryOptionsHelper.DeserializeQueryOptions(deserialized);
In case One is not using OData routing or using an ApiController (not ODataController),
modify the way of Obtaining ODataPath to:
ODataUriParser parser = new ODataUriParser(model, serviceRoot, requestUri);
ODataPath path = parser.ParsePath();
//var newPath = new Microsoft.AspNet.OData.Routing.ODataPath(new EntitySetSegment(segment));
Microsoft.AspNet.OData.Routing.ODataPath newPath = new Microsoft.AspNet.OData.Routing.ODataPath(path.FirstOrDefault());
where the serviceRoot is the Url part other that the path defined in the model.
I am massively stuck with converting a PHP server request into an equivalent Java Request. This is the code that contains the JSON object that I need to replicate in JAVA and send from an Android device:
$(".unableprocess").click(function() {
if (!confirm("Confirm not able to process...!")) {
return false;
} else {
var item_id = $(this).attr('data-id');
var table_id = $(this).attr('table-id');
var data = {
BookOrders: {
item_id: item_id,
table_id: table_id
}
};
$.ajax({
url: //MY URL HERE ,
type: "POST",
data: data,
success: function(evt, responseText) {
location.reload();
}
});
}
});
And here is my Java class that attempts to perform the same functionality. The class extends AsyncTask and all network interactions occur in the doInBackground() method. Here is my code:
#Override
protected Boolean doInBackground(String... arg0) {
try{
HashMap<String, String> hashMap = new HashMap<String,String>();
JSONObject jsonObject = new JSONObject();
int statusCode;
HttpClient client = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(tableMateCannotProcessURL);
// JSON object creation begins here:
jsonObject.accumulate("item_id",this.itemId);
jsonObject.accumulate("table_id",this.tableId);
JSONObject jObject = new JSONObject();
jObject.accumulate("BookOrders", jsonObject);
// JSON object ends here
Log.v("ATOMIC BLAST",jObject.toString());
String json = jObject.toString();
StringEntity se = new StringEntity(json);
httpPost.setEntity(se);
HttpResponse response = client.execute(httpPost);
statusCode = response.getStatusLine().getStatusCode();
Integer statusCodeInt = new Integer(statusCode);
Log.v("HTTPResponse",statusCodeInt.toString());
String result= "";
StringBuilder builder = new StringBuilder();
if (statusCode == 200) {
HttpEntity entity = response.getEntity();
InputStream content = entity.getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(content));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
result = builder.toString();
}
else {
Log.e("==>", "Failed to download file");
}
}
catch(Exception e){
e.printStackTrace();
}
return null;
}
The JSON object that I created looks like this after printing it out to the console:
{"BookOrders":{"table_id":"1","item_id":"2"}}
After POSTing this object to the server I do not get the expected response. What is the proper method for converting the JSON object into an equivalent JSON object in JAVA? Any guidance, direction or a solution would be most appreciated.
Update php to version 5.4 helped me.
In this version json_encode($x, JSON_PRETTY_PRINT) works just as needed.
Your JSON seems to be correct but it's an Object in an Object.
JSONObject json = new JSONObject(yourdata);
JSONObject jsonTable = new JSONObject(json.getString("BookOrders"));
Log.d("JsonDebug", "json:" + jsonTable.toString());
If you are not sure if you have a JSONObject or an Array you can validate it by using
String data = "{ ... }";
Object json = new JSONTokener(data).nextValue();
if (json instanceof JSONObject)
//you have an object
else if (json instanceof JSONArray)
//you have an array
This is my WCF REST OperationContract
[OperationContract(Name = "SaveBasicInfoObjectById")]
[WebInvoke(Method = "POST",
ResponseFormat = WebMessageFormat.Xml,
RequestFormat = WebMessageFormat.Xml,
BodyStyle = WebMessageBodyStyle.Bare,
UriTemplate = "Core/SaveBasicInfoObjectById?ID={ID}")]
List<Response> SaveBasicInfoObjectById(string ID, BasicClass basicClass);
This is my client code
string ID= "123";
MyService.BasicClass basicClass = new MyService.BasicClass();
string sErrorMsg = "";
string sResponseStatus = "";
string URLString = "http://localhost:59133/MyService.svc/Core/SaveBasicInfoObjectById?ID=" + ID;
basicClass.FirstName = txt_Fname.Text.Trim();
basicClass.Lastname = txt_Lname.Text.Trim();
var paramContent = Serialize(basicClass);
CreateWebRequest(URLString, paramContent.ToString());
This is the Serialize Method
public static string Serialize<T>(T obj)
{
var serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
var ms = new MemoryStream();
serializer.Serialize(ms, obj);
string retVal = Encoding.Default.GetString(ms.ToArray());
ms.Dispose();
return retVal;
}
This Is The CreateWebRequest method
private string CreateWebRequest(string endPoint, string paramContent)
{
string result = string.Empty;
byte[] buffer = Encoding.UTF8.GetBytes(paramContent);
var myHttpWebRequest = (HttpWebRequest)WebRequest.Create(endPoint);
myHttpWebRequest.Method = "POST";
myHttpWebRequest.ContentLength = buffer.Length;
myHttpWebRequest.ContentType = "text/xml";
using (var request = myHttpWebRequest.GetRequestStream())
{
request.Write(buffer, 0, buffer.Length);
request.Close();
}
var myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
using (var reader = new StreamReader(myHttpWebResponse.GetResponseStream(), Encoding.UTF8))
{
result = reader.ReadToEnd();
myHttpWebResponse.Close();
}
return result;
}
*The problem here that i am facing is the Object is serialized in the following format, and when the breakpoint is hit at the service the object values are empty i.e firstname = "" and lastname = "" *
<?xml version="1.0"?>
<BasicClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="0">
<FirstName xmlns="http://tempuri.org/">James</FirstName>
<Lastname xmlns="http://tempuri.org/">Kravis</Lastname>
</BasicClass>
Can any one advice why this is happening?
I have now replaced the tempuri namespace against the firstname and lastname element as "" or empty, Now this working and the values from the client are now recieved at the service
Following is the updated code for serialize method
public string Serialize<T>(T obj)
{
//System.Xml.Serialization.XmlSerializer x = new System.Xml.Serialization.XmlSerializer(p.GetType());
var serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
var ms = new MemoryStream();
serializer.Serialize(ms, obj);
string retVal = Encoding.Default.GetString(ms.ToArray());
ms.Dispose();
return retVal.Replace("xmlns=\"http://tempuri.org/\"", "");
}
** Update to above code **
public string Serialize<T>(T obj)
{
var serializer = new System.Xml.Serialization.XmlSerializer(obj.GetType());
var ms = new MemoryStream();
serializer.Serialize(ms, obj);
string retVal = Encoding.Default.GetString(ms.ToArray());
ms.Dispose();
return retVal;
}
** Got Rid of the replace and found the way to stop the default namespace being added to the elements **
public class BasicClass
{
[XmlElement(Namespace="")]//add namespace as ""
public string Firstname{get;set;}
[XmlElement(Namespace="")]//add namespace as ""
public string Lastname{get;set;}
}
By Doing as above i am able to remove the default namespace and no need of replace
<?xml version="1.0"?>
<BasicClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" ID="0">
<FirstName>James</FirstName>
<Lastname>Kravis</Lastname>
</BasicClass>
BY default WCF uses the DataContractSerializer as its serializer, not the XmlSerializer. They produce (and expect) different formats, so you should change either the client (serialize your object using the DataContractSerializer instead of the XmlSerializer), or the service (apply the [XmlSerializerFormat] attribute to either the operation or the service contract to have WCF use that serializer).
You also shouldn't replace the "xmlns" declaration (last line in your Serialize<T> method), since by doing that you're changing the semantics of the XML produced.