SyndicationFeed Unable To Read ATOM Feed - c#

I am trying to parse the following atom XML feed:
<dealer version="1.12" xmlns:atom="http://www.w3.org/2005/Atom"><atom:link rel="self" href="http://Blah.com/dealers/1234"/><atom:link rel="http://Blah.com/rels/dealer_notification_prefs" href="http://Blah.com/dealers/1234/notification_prefs"/><atom:link rel="http://Blah.com/rels/dealer_systems" href="http://Blah.com/dealers/1234/systems"/><atom:link rel="http://Blah.com/rels/dealer_logo" href="http://Blah.com/dealers/1234/logo"/><pid>1234</pid><name>ABC Heating & Air Conditioning</name><first>X</first><last>X</last><street1>PO Box 321</street1><street2/><city>Orson</city><state>IN</state><country>United States</country><postal>46142</postal><phone>317-555-5555</phone><phoneExt/><url></url><email>someone#noemail.com</email></dealer>
The C# code I am using is:
using (var client = new HttpClient()) // Using block for disposing of HttpClient when finished
{
client.DefaultRequestHeaders.Accept.Clear();
client.BaseAddress = new Uri(_baseUriPart); // Set to core base Uri for whole Api
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("OAuth", _builtParamsString);
// Send HTTP Requests Async
try
{
bool respSuccess = false;
HttpResponseMessage response = await client.GetAsync(_resourceUriPart);
//HttpResponseMessage response = await client.SendAsync(myRequestTest);
response.EnsureSuccessStatusCode(); // Throw Exception if not a success code. // ...}
Stream stream = await response.Content.ReadAsStreamAsync();
var prereader = new StreamReader(stream);
string readContent = prereader.ReadToEnd();
string readOut = string.Empty;
TextReader tr = new StringReader(readContent);
XmlReader reader = XmlReader.Create(tr);
SyndicationFeed feed = SyndicationFeed.Load(reader);
if(null!=feed)
{
foreach(var item in feed.Items)
{
//readOut = readOut + item.Title.Text + ":" + ((TextSyndicationContent)item.Content).Text+ Environment.NewLine;
}
}
respSuccess = response.IsSuccessStatusCode;
TextBox1.Text = respSuccess.ToString();
TextBox2.Text = response.StatusCode.ToString();
TextBox3.Text = readOut;
}
catch (HttpRequestException e)
{
TextBox1.Text = "False";
TextBox2.Text = "See Content Message";
TextBox3.Text = e.Message;
}
} // End using block
I can connect to the web service, and request the dealer info as you can see. But the error I get when the SyndicationFeed begins reading the XML is:
"The element with name 'dealer' and namespace '' is not an allowed feed format. "
Can someone please shed some light on this for me? Thanks!!!

dealer isn't a valid tag for the atom feed root. See the Atom Syndication Format RFC for details. It should be atom:feed.
It's unfortunately pretty common to find invalid RSS/Atom feeds. SyndicationFeed is strict so you have to do some massaging of the input data to get it working.
It's ugly but the simple approach is to do a String.Replace for the dealer tags.
// ...
readContent = readContent.Replace("<dealer ", "<atom:feed ").Replace("</dealer>", "</atom:feed>");
TextReader tr = new StringReader(readContent);
// ...
I've also fixed feeds in the past by deriving from XmlTextReader and fixing the bad elements as they are read.

Related

Error while trying to Create New Product Listing in Shopify using HTTPWebRequest in C#

Here is my code below. Getting the token from shopify works fine. However while creating a new product it keeps giving me an error. I've tried everything possible and it still does not work. Any advice would be appreciated.
Here's how I call the CreateNewProduct method passing the access token from shopify and the shopname with the products endpoint.
CreateNewProduct(accessTokenDTO.access_token, "https://{myshopname}.myshopify.com/admin/api/2020-10/products.json");
Here's the method below.
public static void CreateNewProduct(string token, string Url)
{
Uri shopUri = new Uri(Url);
HttpWebRequest GETRequest = (HttpWebRequest)WebRequest.Create(shopUri);
GETRequest.ContentType = "application/json";
GETRequest.Headers.Add("X-Shopify-Access-Token", token);
GETRequest.PreAuthenticate = true;
GETRequest.Method = "PUT";
using (var streamWriter = new StreamWriter(GETRequest.GetRequestStream()))
{
string json = "{\"product\": { \"title\": \"Burton Custom Freestyle 151\", \"body_html\": \"<strong>Good snowboard!</strong>\", \"vendor\": \"Burton\", \"product_type\": \"Snowboard\", \"tags\": [ \"Barnes & Noble\", \"John's Fav\", \"\\Big Air\\]}";
streamWriter.Write(json);
streamWriter.Flush();
}
HttpWebResponse GETResponse = (HttpWebResponse)GETRequest.GetResponse();
var encoding = ASCIIEncoding.ASCII;
using (var reader = new System.IO.StreamReader(GETResponse.GetResponseStream(), encoding))
{
string responseText = reader.ReadToEnd();
Debug.WriteLine("Response Text: " + responseText);
}
GETResponse.Close();
}
400 BadRequest normally refers to the body you are sending with your request is not valid according to the api.
Wheni look at your string that is supposed to be a json, it shows invalid data at the end.
[ \"Barnes & Noble\", \"John's Fav\", \"\\Big Air\\]}";
You are missing closing quotes after Big Air. Also, not sure if those backslash are supposed to be there around Big Air but definitely the missing closing quotes would seem to be the issue
There was an issue with the json not being formatted correctly and method was a PUT instead of POST. See working code below.
public static void CreateNewProduct(string token, string Url)
{
Uri shopUri = new Uri(Url);
HttpWebRequest GETRequest = (HttpWebRequest)WebRequest.Create(shopUri);
GETRequest.ContentType = "application/json";
GETRequest.Headers.Add("X-Shopify-Access-Token", token);
GETRequest.PreAuthenticate = true;
GETRequest.Method = "POST";
using (var streamWriter = new StreamWriter(GETRequest.GetRequestStream()))
{
string json = "{\"product\": { \"title\": \"Burton Custom Freestyle 151\", \"body_html\": \"<strong>Good snowboard!</strong>\", \"vendor\": \"Burton\", \"product_type\": \"Snowboard\"} }";
streamWriter.Write(json);
streamWriter.Flush();
}
HttpWebResponse GETResponse = (HttpWebResponse)GETRequest.GetResponse();
var encoding = ASCIIEncoding.ASCII;
using (var reader = new System.IO.StreamReader(GETResponse.GetResponseStream(), encoding))
{
string responseText = reader.ReadToEnd();
Debug.WriteLine("Response Text: " + responseText);
}
GETResponse.Close();
}

Can't create workitem via webrequest in RTC

I'm trying to create a .NET web application integration with RTC, where I would insert new workitems using RTC change management services, as defined in this article (specifically in "Create a Change Request"). I was able to get the URL-to-be-used inside services.xml file (/oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/) and my goal is to insert data using JSON.
My code is basically the following:
CookieContainer cookies = new CookieContainer();
HttpWebRequest documentPost = (HttpWebRequest)WebRequest.Create(rtcServerUrl + "/oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/order");//"Order" is the workitem name
documentPost.Method = "POST";
documentPost.CookieContainer = cookies;
documentPost.Accept = "application/json";
documentPost.ContentType = "application/x-oslc-cm-change-request+json";
documentPost.Timeout = TIMEOUT_SERVICO;
string json = "{ \"dc:title\":\"" + title + "\", \"rtc_cm:filedAgainst\": [ { \"rdf:resource\" : \"" + rtcServerUrl + "/resource/itemOid/com.ibm.team.workitem.Category/" + idCategory + "\"} ] }"; //dc:title and rtc_cm:filedAgainst are the only two mandatory data from the workitem I'm trying to create
using (var writer = new StreamWriter(documentPost.GetRequestStream()))
{
writer.Write(json);
writer.Flush();
writer.Close();
}
Encoding encode = System.Text.Encoding.UTF8;
string retorno = null;
//Login
HttpWebRequest formPost = (HttpWebRequest)WebRequest.Create(rtcServerUrl + "/j_security_check");
formPost.Method = "POST";
formPost.Timeout = TIMEOUT_REQUEST;
formPost.CookieContainer = request.CookieContainer;
formPost.Accept = "text/xml";
formPost.ContentType = "application/x-www-form-urlencoded";
String authString = "j_username=" + userName + "&j_password=" + password; //create authentication string
Byte[] outBuffer = System.Text.Encoding.UTF8.GetBytes(authString); //store in byte buffer
formPost.ContentLength = outBuffer.Length;
System.IO.Stream str = formPost.GetRequestStream();
str.Write(outBuffer, 0, outBuffer.Length); //update form
str.Close();
//FormBasedAuth Step2:submit the login form and get the response from the server
HttpWebResponse formResponse = (HttpWebResponse)formPost.GetResponse();
var rtcAuthHeader = formResponse.Headers["X-com-ibm-team-repository-web- auth-msg"];
//check if authentication has failed
if ((rtcAuthHeader != null) && rtcAuthHeader.Equals("authfailed"))
{
//authentication failed. You can write code to handle the authentication failure.
//if (DEBUG) Console.WriteLine("Authentication Failure");
}
else
{
//login successful
HttpWebResponse responseRetorno = (HttpWebResponse)request.GetResponse();
if (responseRetorno.StatusCode != HttpStatusCode.OK)
retorno = responseRetorno.StatusDescription;
else
{
StreamReader reader = new StreamReader(responseRetorno.GetResponseStream());
retorno = "[Response] " + reader.ReadToEnd();
}
responseRetorno.Close();
formResponse.GetResponseStream().Flush();
formResponse.Close();
}
As I was managed to search for in other forums, this should be enough in order to create the workitem (I have a very similar code working to update workitems using "" URL and PUT method). However, instead of create the workitem in RTC and give me some response with item's identifier, the request's response returns a huge JSON file that ends with "oslc_cm:next":"https:///oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/%7B0%7D?oslc_cm.pageSize=50&_resultToken=_AAY50FEkEee1V4u7RUQSjA&_startIndex=50. It's a JSON representation of the XML I receive when I access /oslc/contexts/_0_iN4G09EeGGMqpyZT5XdQ/workitems/ directly from browser, like I was trying to do a simple query inside the workitem's collection (even though I'm using POST, not GET).
I also tried to use PUT method, but then I receive a 405 status code.
Does anyone have an idea of what am I missing here? My approach is wrong, even though with the same approach I'm able to update existing workitem data in RTC?
Thanks in advance.

REST HttpWebResponse not returning xml data as string

Firstly, I understand this code isn't necessarily "safe" and is VERY basic. I'm learning how to consume rest services with web forms in C# (both are new topics for me). Pretty much the only thing there is 2 textboxes for authentication credentials, a query textbox and button to send the request with a label. I just want to enter the ID1 into the textbox, and then return the First and Last name for the entry with that ID.
I have tried many different ways after thoroughly searching the web but can't seem to figure out the issue.
The Issue: The StreamReader data from the WebResponse isn't coming back as XML.
The Question: How do I return the XML tags that I want? Do I need to parse them? If so, how?
The XDoc version is returning nothing while the straight stream reader is returning a string with some data in addition to numbers that shouldn't be there and no angle brackets. Below is the code as it stands now:
if (QueryTextBox2.Text != "")
{
string tableName = "Entry";
string requestURL = "https://myUrl.com/rest/services/" + tableName;
HttpWebRequest request = WebRequest.Create(requestURL) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "text/xml; encoding:='charset=utf-8'";
request.Headers["CustomUserName"] = TextBox1.Text;
request.Headers["CustomPassword"] = TextBox3.Text;
string xml = "<Entry><ID1>" + QueryTextBox2.Text + "</ID1></Entry>";
byte[] byteArray = Encoding.UTF8.GetBytes(xml.ToString());
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
if (response.StatusCode == HttpStatusCode.OK) {
Stream postData = response.GetResponseStream();
StreamReader reader = new StreamReader(postData, Encoding.UTF8);
string result = reader.ReadToEnd();
Label2.Text = result;
} else
{
Label2.Text = "There was an error: " + response.StatusDescription;
}
}
else
{
TextBox2.Text = "Please Enter an ID";
}
}
}
I have also tried using:
XDocument doc = new XDocument();
using (Stream responseStream = response.GetResponseStream())
{
StreamReader reader = new StreamReader(responseStream, Encoding.UTF8);
doc = XDocument.Parse(reader.ReadToEnd());
string fname = doc.Root.Element("NameFirst").Value;
string lname = doc.Root.Element("NameLast").Value;
Label2.Text = fname + lname;
to replace the whole block within: if statusCode == OK.
The data returned from the firefox Poster add-on is:
<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom">
<title type="text">Search Results</title>
<id>https://myUrl.com/rest/services</id>
<updated>2015-10-07T09:51:32Z</updated>
<link rel="self" type="application/atom+xml" href="https://myUrl.com/rest/services" />
<entry>
<id>https://myUrl.com/rest/services</id>
<Entry>
<ID1>900009</ID1>
<NameLast>Smith</NameLast>
<NameFirst>Tom</NameFirst>
<NameTitle></NameTitle>
<NamePreferred>Alex</NamePreferred>
<NameWeb>tsmith</NameWeb>
<NameOther></NameOther>
<NameInitials></NameInitials>
</Entry></content></entry></feed>
I've removed a lot of the response data because it's so large and anonymized it all for the most part so keep that in mind.
I would use System.Net.Http.HttpClient, it has a much easier interface for consuming http requests.
I haven't tested the document parsing, but just follow the nested levels in until you find the element you want.
async void Main()
{
var textBox2String = "2"
if (!string.IsNullOrEmpty(textBox2String))
{
const string table = "Entry";
var client = new HttpClient();
var url = $"https://myurl.com/rest/services/{table}";
var xml = $"<Entry><ID1>{textBox2String}</ID1></Entry>";
client.DefaultRequestHeaders.TryAddWithoutValidation("CustomUserName", "username");
client.DefaultRequestHeaders.TryAddWithoutValidation("CustomPassword", "password");
var response = await client.PostAsync(url, new StringContent(xml, Encoding.UTF8, "text/xml"));
var content = await response.Content.ReadAsStringAsync();
if (response.IsSuccessStatusCode)
{
var document = XDocument.Parse(content);
var entry = document.Root.Element(table);
var firstName = entry.Element("FirstName").Value;
var lastName = entry.Element("LastName").Value;
$"{firstName} {lastName}".Dump();
}
else
{
Console.WriteLine($"An error occurred processing this request: {content}");
}
}
else
{
textBox2String = "Please enter an ID";
}
}

How do I find the text within a div in the source of a web page using C#

How can I get the HTML code from a website, save it, and find some text by using a LINQ expression?
I'm using the following code to get the source of a web page:
public static String code(string Url)
{
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(Url);
myRequest.Method = "GET";
WebResponse myResponse = myRequest.GetResponse();
StreamReader sr = new StreamReader(myResponse.GetResponseStream(),
System.Text.Encoding.UTF8);
string result = sr.ReadToEnd();
sr.Close();
myResponse.Close();
return result;
}
How do I find the text within a div in the source of the web page?
Better you can use the Webclient class to simplify your task:
using System.Net;
using (WebClient client = new WebClient())
{
string htmlCode = client.DownloadString("http://somesite.com/default.html");
}
Getting HTML code from a website. You can use code like this:
string urlAddress = "http://google.com";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(urlAddress);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
if (response.StatusCode == HttpStatusCode.OK)
{
Stream receiveStream = response.GetResponseStream();
StreamReader readStream = null;
if (String.IsNullOrWhiteSpace(response.CharacterSet))
readStream = new StreamReader(receiveStream);
else
readStream = new StreamReader(receiveStream,
Encoding.GetEncoding(response.CharacterSet));
string data = readStream.ReadToEnd();
response.Close();
readStream.Close();
}
This will give you the returned HTML from the website. But find text via LINQ is not that easy.
Perhaps it is better to use regular expression but that does not play well with HTML.
Best thing to use is HTMLAgilityPack. You can also look into using Fizzler or CSQuery depending on your needs for selecting the elements from the retrieved page. Using LINQ or Regukar Expressions is just to error prone, especially when the HTML can be malformed, missing closing tags, have nested child elements etc.
You need to stream the page into an HtmlDocument object and then select your required element.
// Call the page and get the generated HTML
var doc = new HtmlAgilityPack.HtmlDocument();
HtmlAgilityPack.HtmlNode.ElementsFlags["br"] = HtmlAgilityPack.HtmlElementFlag.Empty;
doc.OptionWriteEmptyNodes = true;
try
{
var webRequest = HttpWebRequest.Create(pageUrl);
Stream stream = webRequest.GetResponse().GetResponseStream();
doc.Load(stream);
stream.Close();
}
catch (System.UriFormatException uex)
{
Log.Fatal("There was an error in the format of the url: " + itemUrl, uex);
throw;
}
catch (System.Net.WebException wex)
{
Log.Fatal("There was an error connecting to the url: " + itemUrl, wex);
throw;
}
//get the div by id and then get the inner text
string testDivSelector = "//div[#id='test']";
var divString = doc.DocumentNode.SelectSingleNode(testDivSelector).InnerHtml.ToString();
[EDIT]
Actually, scrap that. The simplest method is to use FizzlerEx, an updated jQuery/CSS3-selectors implementation of the original Fizzler project.
Code sample directly from their site:
using HtmlAgilityPack;
using Fizzler.Systems.HtmlAgilityPack;
//get the page
var web = new HtmlWeb();
var document = web.Load("http://example.com/page.html");
var page = document.DocumentNode;
//loop through all div tags with item css class
foreach(var item in page.QuerySelectorAll("div.item"))
{
var title = item.QuerySelector("h3:not(.share)").InnerText;
var date = DateTime.Parse(item.QuerySelector("span:eq(2)").InnerText);
var description = item.QuerySelector("span:has(b)").InnerHtml;
}
I don't think it can get any simpler than that.
I am using AngleSharp and have been very satisfied with it.
Here is a simple example how to fetch a page:
var config = Configuration.Default.WithDefaultLoader();
var document = await BrowsingContext.New(config).OpenAsync("https://www.google.com");
And now you have a web page in document variable. Then you can easily access it by LINQ or other methods. For example if you want to get a string value from a HTML table:
var someStringValue = document.All.Where(m =>
m.LocalName == "td" &&
m.HasAttribute("class") &&
m.GetAttribute("class").Contains("pid-1-bid")
).ElementAt(0).TextContent.ToString();
To use CSS selectors please see AngleSharp examples.
Here's an example of using the HttpWebRequest class to fetch a URL
private void buttonl_Click(object sender, EventArgs e)
{
String url = TextBox_url.Text;
HttpWebRequest request = (HttpWebRequest) WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse) request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
richTextBox1.Text = sr.ReadToEnd();
sr.Close();
}
You can use WebClient to download the html for any url. Once you have the html, you can use a third-party library like HtmlAgilityPack to lookup values in the html as in below code -
public static string GetInnerHtmlFromDiv(string url)
{
string HTML;
using (var wc = new WebClient())
{
HTML = wc.DownloadString(url);
}
var doc = new HtmlAgilityPack.HtmlDocument();
doc.LoadHtml(HTML);
HtmlNode element = doc.DocumentNode.SelectSingleNode("//div[#id='<div id here>']");
if (element != null)
{
return element.InnerHtml.ToString();
}
return null;
}
Try this solution. It works fine.
try{
String url = textBox1.Text;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader sr = new StreamReader(response.GetResponseStream());
HtmlAgilityPack.HtmlDocument doc = new HtmlAgilityPack.HtmlDocument();
doc.Load(sr);
var aTags = doc.DocumentNode.SelectNodes("//a");
int counter = 1;
if (aTags != null)
{
foreach (var aTag in aTags)
{
richTextBox1.Text += aTag.InnerHtml + "\n" ;
counter++;
}
}
sr.Close();
}
catch (Exception ex)
{
MessageBox.Show("Failed to retrieve related keywords." + ex);
}

Reading data from an open HTTP stream

I am trying to use the .NET WebRequest/WebResponse classes to access the Twitter streaming API here "http://stream.twitter.com/spritzer.json".
I need to be able to open the connection and read data incrementally from the open connection.
Currently, when I call WebRequest.GetResponse method, it blocks until the entire response is downloaded. I know there is a BeginGetResponse method, but this will just do the same thing on a background thread. I need to get access to the response stream while the download is still happening. This just does not seem possible to me with these classes.
There is a specific comment about this in the Twitter documentation:
"Please note that some HTTP client libraries only return the response body after the connection has been closed by the server. These clients will not work for accessing the Streaming API. You must use an HTTP client that will return response data incrementally. Most robust HTTP client libraries will provide this functionality. The Apache HttpClient will handle this use case, for example."
They point to the Appache HttpClient, but that doesn't help much because I need to use .NET.
Any ideas whether this is possible with WebRequest/WebResponse, or do I have to go for lower level networking classes? Maybe there are other libraries that will allow me to do this?
Thx
Allen
I ended up using a TcpClient, which works fine. Would still be interested to know if this is possible with WebRequest/WebResponse though. Here is my code in case anybody is interested:
using (TcpClient client = new TcpClient())
{
string requestString = "GET /spritzer.json HTTP/1.1\r\n";
requestString += "Authorization: " + token + "\r\n";
requestString += "Host: stream.twitter.com\r\n";
requestString += "Connection: keep-alive\r\n";
requestString += "\r\n";
client.Connect("stream.twitter.com", 80);
using (NetworkStream stream = client.GetStream())
{
// Send the request.
StreamWriter writer = new StreamWriter(stream);
writer.Write(requestString);
writer.Flush();
// Process the response.
StreamReader rdr = new StreamReader(stream);
while (!rdr.EndOfStream)
{
Console.WriteLine(rdr.ReadLine());
}
}
}
BeginGetResponse is the method you need. It allows you to read the response stream incrementally:
class Program
{
static void Main(string[] args)
{
WebRequest request = WebRequest.Create("http://stream.twitter.com/spritzer.json");
request.Credentials = new NetworkCredential("username", "password");
request.BeginGetResponse(ar =>
{
var req = (WebRequest)ar.AsyncState;
// TODO: Add exception handling: EndGetResponse could throw
using (var response = req.EndGetResponse(ar))
using (var reader = new StreamReader(response.GetResponseStream()))
{
// This loop goes as long as twitter is streaming
while (!reader.EndOfStream)
{
Console.WriteLine(reader.ReadLine());
}
}
}, request);
// Press Enter to stop program
Console.ReadLine();
}
}
Or if you feel more comfortable with WebClient (I personnally prefer it over WebRequest):
using (var client = new WebClient())
{
client.Credentials = new NetworkCredential("username", "password");
client.OpenReadCompleted += (sender, e) =>
{
using (var reader = new StreamReader(e.Result))
{
while (!reader.EndOfStream)
{
Console.WriteLine(reader.ReadLine());
}
}
};
client.OpenReadAsync(new Uri("http://stream.twitter.com/spritzer.json"));
}
Console.ReadLine();
Have you tried WebRequest.BeginGetRequestStream() ?
Or something like this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create (http://www.twitter.com );
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string str = reader.ReadLine();
while(str != null)
{
Console.WriteLine(str);
str = reader.ReadLine();
}

Categories

Resources