I am trying to run this app (code from net)but getting error XmlException: Root element is missing. Where am I doing wrong? (I am learning to work with XML requests).
Method:
public static T postXMLData<T>(string xml)
{
Console.WriteLine(xml);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(Requests.url);
byte[] bytes;
bytes = System.Text.Encoding.ASCII.GetBytes(xml);
request.ContentType = "text/xml; encoding='utf-8'";
request.ContentLength = bytes.Length;
request.Method = "POST";
Stream requestStream = request.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);
requestStream.Close();
HttpWebResponse response;
response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
string responseStr = new
StreamReader(responseStream).ReadToEnd();
Console.WriteLine(responseStr);
var xmlSerializer = new XmlSerializer(typeof(T));
var t = (T)xmlSerializer.Deserialize(responseStream); //error here
return t;
}
throw new Exception("что то не так");
}
When I run app:
static void Main(string[] args)
{
var req = postXMLData<Responses.Response>(Requests.checkRequest());
if (req.result==0)
Console.WriteLine("ok");
Console.ReadKey();
}
Requests class:
public static string checkPaymentRequisites(string payId, string service, string account, string amount)
{
string req = authReq + $"<providers> <checkPaymentRequisites> <payment id=\"{payId}\"> <from currency=\"{currency}\" amount=\"{amount}\"/> <to currency=\"{currency}\" service=\"{service}\" amount=\"{amount}\" account=\"{account}\" moneyType=\"{moneyType}\"/> <receipt id=\"{receiptId}\" date=\"{dTime}\"/> </payment> </checkPaymentRequisites> </providers> </request>";
return req;
Responses class:
[XmlRoot(ElementName = "payment")]
public class Payment
{
[XmlAttribute(AttributeName = "date")]
public DateTime date { get; set; }
[XmlAttribute(AttributeName = "fatal")]
public string fatal { get; set; }
[XmlAttribute(AttributeName = "id")]
public string id { get; set; }
[XmlAttribute(AttributeName = "result")]
public int result { get; set; }
[XmlAttribute(AttributeName = "saved")]
public bool saved { get; set; }
[XmlAttribute(AttributeName = "status")]
public int status { get; set; }
[XmlAttribute(AttributeName = "uid")]
public long uid { get; set; }
}
[XmlRoot(ElementName = "checkPaymentRequisites")]
public class checkPaymentRequisites
{
[XmlElement(ElementName ="payment")]
public Payment Payment { get; set; }
[XmlElement(ElementName ="extras")]
public Extras Extras { get; set; }
[XmlAttribute(AttributeName ="result")]
public int result { get; set; }
}
[XmlRoot(ElementName = "providers")]
public class Providers
{
[XmlElement(ElementName = "checkPaymentRequisites")]
public checkPaymentRequisites checkPaymentRequisites { get; set; }
}
[XmlRoot(ElementName ="response")]
public class Response
{
[XmlElement(ElementName ="providers")]
public Providers Providers { get; set; }
[XmlAttribute(AttributeName ="result")]
public int result { get; set; }
//[XmlText]
//public string Text { get; set; }
}
The main goal of the app is to deserialize and to display Response from Request in XML.
This problem "XmlException: Root element is missing" is because you do not create a XML document from the response stream. The right code is as below:
...
string xml = HttpUtility.UrlDecode(responseStream.Substring(responseStream.IndexOf("XML=") + 4));
XmlDocument document = new XmlDocument();
document.LoadXml(xml);
T result = new T();
XmlNode newNode = document.DocumentElement;
result.Name = ((XmlAttribute)newNode.Attributes["Name"]).InnerText;
result.ID = ((XmlNode)newNode.FirstChild).InnerText;
using (TextReader reader = new StringReader(xml))
{
var serializer = new XmlSerializer(typeof(T));
result = (T)serializer.Deserialize(reader);
}
return result;
Your issue is that you are trying to read the response twice. The stream can only be read once.
So either you can just deserialize it
using var responseStream = response.GetResponseStream();
var xmlSerializer = new XmlSerializer(typeof(T));
var t = (T)xmlSerializer.Deserialize(responseStream);
Or you can first copy it into a string to dump to console, then deserialize from that string.
using var responseStream = response.GetResponseStream();
using var sr = new StreamReader(responseStream)
string responseStr = sr.ReadToEnd();
Console.WriteLine(responseStr);
var xmlSerializer = new XmlSerializer(typeof(T));
var t = (T)xmlSerializer.Deserialize(new StringReader(responseStr));
However you have a number of other serious issues in your code:
Use of WebRequest which is deprecated and really old. Use HttpClient instead.
You should use await to better manage responsiveness
You are not disposing the stream, nor many other IDisposable objects.
You should cache the XmlSerializer
You have a mismatch between the encoding you are using and the encod
private static HttpClient _client = new(); // cache the client and serializer
private static XmlSerializer _xmlSerializer = new(typeof(T));
public static async Task<T> postXMLData<T>(string xml)
{
Console.WriteLine(xml);
using var message = new HttpRequestMessage(HttpMethod.Post, Requests.url);
message.Content = new StringContent(xml, Encoding.UTF8, "text/xml; encoding='utf-8'");
using var response = await _client.SendAsync(message, HttpCompletionOption.ResponseHeadersRead);
response.EnsureSuccessStatusCode();
var responseStr = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseStr);
var t = (T)_xmlSerializer.Deserialize(responseStream);
return t;
}
static async Task Main(string[] args)
{
var req = await postXMLData<Responses.Response>(Requests.checkRequest());
if (req.result == 0)
Console.WriteLine("ok");
Console.ReadKey();
}
If you want to read it as a stream then use
using var responseStream = await response.Content.ReadAsStreamAsync();
using var sr = new StreamReader(responseStream);
var responseStr = await sr.ReadToEndAsync();
Related
I can able to send the push notification on my android application using the console. but using server side code, I get the successfully message send notification but actually notification does not able to receive at device end. Please, tell me what is wrong with my code:
public static string SendPushNotification() {
try {
string applicationID = "AAAA4GkXVHA:....-qRw";
string senderId = "963..28";
string deviceId = "APA91bHLV...IC4s";
WebRequest tRequest = WebRequest.Create("https://fcm.googleapis.com/fcm/send");
tRequest.Method = "post";
tRequest.ContentType = "application/json";
var data = new {
to = deviceId,
notification = new {
body = "hema",
title = "hem",
//priority = "normal",
//sound = "Enabled"
},
};
var serializer = new JavaScriptSerializer();
var json = serializer.Serialize(data);
Byte[] byteArray = Encoding.UTF8.GetBytes(json);
tRequest.Headers.Add(string.Format("Authorization: key={0}", applicationID));
tRequest.Headers.Add(string.Format("Sender: id={0}", senderId));
tRequest.ContentLength = byteArray.Length;
using (Stream dataStream = tRequest.GetRequestStream()) {
dataStream.Write(byteArray, 0, byteArray.Length);
using (WebResponse tResponse = tRequest.GetResponse()) {
using (Stream dataStreamResponse = tResponse.GetResponseStream()) {
using (StreamReader tReader = new StreamReader(dataStreamResponse)) {
String sResponseFromServer = tReader.ReadToEnd();
string str = sResponseFromServer;
return str;
}
}
}
}
}
catch (Exception ex) {
string str = ex.Message;
return str;
}
}
where I got the response in return is as follows :
{"multicast_id":8288766196764532656,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1481612825945796%6ad79a87f9fd7ecd"}]}
Sending the json in right format:
{
"to" : "APA91bHLV__P6Qer8U70j82blZt0VdDgc2zo_4DtAD4_MtE-......",
"notification" : {
"body" : "Success!",
"title" : "Hema",
"icon" : "myicon"
}
}
To check it properly, you can also use the postman:
Even I experienced the same problem. Finish all the steps in connecting the FCM from Client side. If you implement GetMessage() method from client side, only then your device is able to get the Notification from Server side
I wrote a small tutorial for this: https://www.kendar.org/?p=/tutorials/notifications with an Android app and a .Net core Server. To summarize here is the "main" server code
public NotificationResult Send(NotificationModel messageData)
{
var result = "-1";
var webAddr = "https://fcm.googleapis.com/fcm/send";
var httpWebRequest = (HttpWebRequest)WebRequest.Create(webAddr);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, "key=PROJECTSETTINGS->Cloud Messagings->Server Key");
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string strNJson = JsonConvert.SerializeObject(new NotificationMessage
{
To = "/topics/ServiceNow",
Data = new NotificationData
{
Description = messageData.Description,
IncidentNo = messageData.IncidentNo,
ShortDesc = messageData.ShortDesc
},
Notification = new Notification
{
Title = "ServiceNow: Incident No." + messageData.IncidentNo,
Text = "Notification"
}
});
streamWriter.Write(strNJson);
streamWriter.Flush();
}
var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
return new NotificationResult
{
Result = result
};
}
And the classes that wrap the message to FCM (with the Json annotations to correct the mismatch between .Net and Json naming standards)
public class NotificationData
{
public string ShortDesc { get; set; }
public long IncidentNo { get; set; }
public string Description { get; set; }
}
public class Notification
{
public Notification()
{
Sound = "default";
}
[JsonProperty("title")]
public string Title { get; set; }
[JsonProperty("text")]
public string Text { get; set; }
[JsonProperty("sound")]
public string Sound { get; set; }
}
public class NotificationMessage
{
[JsonProperty("to")]
public string To { get; set; }
[JsonProperty("data")]
public NotificationData Data { get; set; }
[JsonProperty("notification")]
public Notification Notification { get; set; }
}
I am calling an external service using GetAsync() and passing parameters in query string. When i check the content in the response, i don't see anything returned, however it returns 200 OK and in fiddler it returns me the XML response correctly. I need the XML response to get de-serialize to an C# object and then further save it to DB.
Things tried:
1) Tried this by adding this setting in global- app_start(), It didn't help
GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
2) Created an object and tried to sent it via GetAysnc, that didn't help either.
public class Request
{
[XmlElement]
public string XML { get; set; }
[XmlElement]
public List<string> ProNumber { get; set; }
}
2) Should i try passing parameters in query string and expect json result? if i add mediatyperformatter to application/json?
Here is my code:
public async Task<HttpResponseMessage> GetData()
{
string requestString = "&xml=Y&PRONumber=82040X,03117X";
string result = "";
string url = #"http://my.yrc.com/dynamic/national/servlet?CONTROLLER=com.rdwy.ec.rextracking.http.controller.PublicTrailerHistoryAPIController";
try
{
using (var client = new HttpClient())
{
client.BaseAddress = new Uri(url);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/xml"));
HttpResponseMessage response = await client.GetAsync(url+requestString);
if (response.IsSuccessStatusCode)
{
return response;
}
}
}
catch (Exception ex)
{
result = ex.Message;
}
return null;
}
EDIT:
Shipments scp = null;
XmlRootAttribute xRoot = new XmlRootAttribute();
xRoot.ElementName = "Shipment";
xRoot.IsNullable = true;
XmlSerializer serializer = new XmlSerializer(typeof(Shipment), xRoot);
using (Stream stream = response.Content.ReadAsStreamAsync().Result)
{
scp = (Shipments)serializer.Deserialize(stream);
}
Model:
public class Shipments
{
[XmlArrayItem(Type = typeof(Shipment))]
public Shipment[] Shipment;
}
public class Shipment
{
[XmlAttribute()]
public int returnCode { get; set; }
.................
..............
Getting error:<SHIPMENTS xmlns=''> was not expected.
Any help on this is much appreciated.
Thanks,
WH
This worked for me -
var client = new HttpClient();
var data = client.GetStringAsync("http://my.yrc.com/dynamic/national/servlet?CONTROLLER=com.rdwy.ec.rextracking.http.controller.PublicTrailerHistoryAPIController&xml=Y&PRONumber=82040X,03117X").Result;
var ser = new XmlSerializer(typeof(Shipments));
var t = (Shipments)ser.Deserialize(new StringReader(data));
public class Shipment
{
public string returnCode { get; set; }
public string returnMessage { get; set; }
public string freightBillNumber { get; set; }
//props
}
[XmlRoot(ElementName = "SHIPMENTS")]
public class Shipments
{
[XmlElement(ElementName = "SHIPMENT")]
public List<Shipment> SHIPMENT { get; set; }
}
EDIT
this works as well -
var data = client.GetStreamAsync("http://my.yrc.com/dynamic/national/servlet?CONTROLLER=com.rdwy.ec.rextracking.http.controller.PublicTrailerHistoryAPIController&xml=Y&PRONumber=82040X,03117X").Result;
EDIT
works as well -
var client = new HttpClient();
var data = client.GetAsync("http://my.yrc.com/dynamic/national/servlet?CONTROLLER=com.rdwy.ec.rextracking.http.controller.PublicTrailerHistoryAPIController&xml=Y&PRONumber=82040X,03117X").Result;
var ser = new XmlSerializer(typeof(Shipments));
var t = (Shipments)ser.Deserialize(data.Content.ReadAsStreamAsync().Result);
I have this XML with many names, like a list:
<apelidos>
<apelido>Casmilo</apelido>
<apelido>Castro</apelido>
</apelidos>
And I did my model like this:
namespace IdCel.Model
{
[XmlTypeAttribute(AnonymousType = true)]
public class apelidos
{
[XmlArray("apelidos")]
[XmlArrayItem("apelidos")]
public List<apelido> apelidosNomes { get; set; }
public apelidos()
{
apelidosNomes = new List<apelido>();
}
}
public class apelido
{
[XmlElement(ElementName = "apelido")]
public string apelidoNome { get; set; }
}
}
And my XmlSerializer
HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
XmlSerializer ser = new XmlSerializer(objetoLista.GetType());
WebResponse response = request.GetResponse();
var result = ser.Deserialize(response.GetResponseStream());
return result;
But it's not working, I do the same code with XML without list and it's working fine
If you just have to read the contents of the apelido tags, you are much faster when you are using Linq To XML. For example:
var xml = #"<apelidos>
<apelido>Casmilo</apelido>
<apelido>Castro</apelido>
</apelidos>";
var doc = XDocument.Parse(xml);
var apelidos = from apelido in doc.Descendants("apelido")
select apelido.Value;
This gives you an IEnumerable<string> as result containing all the names.
EDIT: To load the XML from the web you can do the following:
HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
WebResponse response = request.GetResponse();
var doc = XDocument.Load(response.GetResponseStream());
Now It's worked!
I did this:
[Serializable()]
public class apelidos
{
[System.Xml.Serialization.XmlElement("apelido")]
public List<string> apelido { get; set; }
}
And this:
HttpWebRequest request = WebRequest.Create(uri)
as HttpWebRequest;
XmlSerializer ser = new XmlSerializer(objetoLista.GetType());
WebResponse response = request.GetResponse();
var result = ser.Deserialize(response.GetResponseStream());
return result;
I have a c# application where once you press the button it will send a web request to a web API and retrieve all the Json values. These are then deserialized into a object and returned to where the function was called.
Now I am trying to access the object that was returned from the GetApi function in another class.
Cannot implicitly convert type 'object' to 'GW2_tradingPost.Listings'.
An explicit conversion exists (are you missing a cast?) line 32
i understand I am doing it wrong, but I can not grasp what is going wrong.
Form1.cs
private void button1_Click(object sender, EventArgs e)
{
Listings Listings = new Listings();
api_Request api_Request = new api_Request();
Listings richTextBox1 = api_Request.GetApi("https://api.guildwars2.com/v2/commerce/listings/19684");
}
api_Request.cs
public class api_Request
{
public Object GetApi(string url)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
try
{
WebResponse response = request.GetResponse();
using (Stream responseStream = response.GetResponseStream())
{
//StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
//return reader.ReadToEnd();
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
var jsonReader = new JsonTextReader(reader);
var serializer = new JsonSerializer();
return serializer.Deserialize<Listings>(jsonReader);
}
}
catch (WebException ex)
{
WebResponse errorResponse = ex.Response;
using (Stream responseStream = errorResponse.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.GetEncoding("utf-8"));
String errorText = reader.ReadToEnd();
// log errorText
}
throw;
}
}
}
public class Listings
{
[JsonProperty(PropertyName = "id")]
public int Id { get; set; }
public List<Buy> Buys { get; private set; }
public Listings()
{
Buys = new List<Buy>();
}
}
public class Buy
{
[JsonProperty(PropertyName = "listings")]
public int Listings { get; set; }
[JsonProperty(PropertyName = "unit_price")]
public int UnitPrice { get; set; }
[JsonProperty(PropertyName = "quantity")]
public int Quantity { get; set; }
}
Im using this to call upon the object now and return a value in the messagebox, but its returning 0 which should be 19684.
api_Request.GetApi("https://api.guildwars2.com/v2/commerce/listings/19684");
MessageBox.Show(Listings.Id.ToString());
Your signature is Object GetApi(string url). Change it to Listings GetApi(string url), as that is what you actually return from that method.
Also consider giving the "GetApi" method a more sensible name that tells what it actually does.
I can send a simple class object with some properties like this:
[DataContract]
public class DeviceInfo
{
[DataMember]
public string DeviceCode { get; set; }
[DataMember]
public string ClientKey { get; set; }
[DataMember]
[XmlIgnore]
public DateTime Timestamp { get; set; }
[DataMember]
public string Token { get; set; }
}
WindowsForm code:
string baseAddress = "http://some_webservice_url";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(baseAddress);
request.Method = "POST";
request.ContentType = "application/json";
DeviceInfo customData = new DeviceInfo();
customData.DeviceCode = "123456";
customData.ClientKey = "hfhf8djf89dfk9";
customData.Timestamp = "12-12-2013";
customData.Token = "444sdf54df544r";
byte[] byteArray = Encoding.UTF8.GetBytes(Serialize<DeviceInfo>(customData));
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
MessageBox.Show(Utility.ReadResponse(response));
}
// SERIALIZATION PART
public static string Serialize<T>(T obj)
{
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(obj.GetType());
MemoryStream ms = new MemoryStream();
serializer.WriteObject(ms, obj);
string retVal = Encoding.Default.GetString(ms.ToArray());
ms.Dispose();
return retVal;
}
public static byte[] ReadFully(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
if (input != null)
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
}
return ms.ToArray();
}
}
What it does is sending DeviceInfo to the server.
But how could I do this using a class object with Stream property:
public class PhotoData
{
public string ProductId { get; set; }
public string PhotoId { get; set; }
public System.IO.Stream FileData { get; set; }
}
This is what I have done so far and it is throwing an error, saying
Type 'System.IO.FileStream' with data contract name 'FileStream:http://schemas.datacontract.org/2004/07/System.IO'
is not expected. Consider using a DataContractResolver or add any types not known statically to the list of
known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types
passed to DataContractSerializer.
StreamReader sr = new StreamReader(openFileDialog1.FileName);
byte[] fileStream = ReadFully(sr.BaseStream);
PhotoData pd = new PhotoData();
pd.FileData = sr.BaseStream;
pd.ProductId = "121513542454545";
pd.PhotoId = textBox4.Text;
baseAddress = "http://someurl/rest/UploadPhotoStream";
request = (HttpWebRequest)WebRequest.Create(new Uri(baseAddress));
request.Method = "POST";
request.ContentType = "application/octet-stream";
byteArray = Encoding.UTF8.GetBytes(Serialize<PhotoData>(pd));
request.ContentLength = byteArray.Length;
Stream dataStream2 = request.GetRequestStream();
dataStream2.Write(byteArray, 0, byteArray.Length);
dataStream2.Close();
using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
{
MessageBox.Show(Utility.ReadResponse(response));
}
I recommend using a byte[] instead of a Stream.
public class PhotoData
{
public string ProductId { get; set; }
public string PhotoId { get; set; }
public byte[] FileData { get; set; }
}
Then you can read/write to the FileData using a MemoryStream in the conventional way. I'm not entirely sure what your method is attempting to do, but I think it would end up looking a bit like this:
byte[] fileStream = ReadFully(sr.BaseStream);
PhotoData pd = new PhotoData();
pd.FileData = fileStream;