Before you ask if I've looked at google let me answer yes, I've read page after page. Site after site, and wasn't able to get the information that I needed.
I'm trying to make a very simple update checker for my application. One that will parse the online xml file, and display the data in certain places. As well as being able to parse out the link for the download location(Will not be ftp or anything, but something like a filehost since my hosting plan doesn't allow me to ftp files over 3MBs)
Anyway here is what I got thus far:
XML Code:
<code>
<Info>
<Version>2.8.0.0</Version>
<Link>www.filehost.com</Link>
<Description>Added New Features To GUI</Description>
</Info>
</code>
Here's the application code, and what I want it to show and do.
using System;
using System.Windows.Forms;
using System.Xml;
namespace SAM
{
public partial class UpdateCheck : DevExpress.XtraEditors.XtraForm
{
public UpdateCheck()
{
InitializeComponent();
lblCurrentVersion.Text = "Current Version: " + Application.ProductVersion;
}
private void MainForm_Shown(object sender, EventArgs e)
{
BringToFront();
}
private void BtnChkUpdate_Click(object sender, EventArgs e)
{
XmlDocument doc = new XmlDocument();
doc.Load("http://www.crimson-downloads.com/SAM/UpdateCheck.xml");
}
}
}
I'm looking to have the application parse the xml in this way.
<Version>2.8.0.0</Version> Will change the text for "lblUpdateVersion" like how I got the current version label set in the InitializeComponent();
<Description>Added New Features To GUI</Description> to be parsed out into the "textDescription" Which I can probably do myself.
<Link>www.filehost.com</Link> Will parse into the button control so when pressed will open up the users default browser and follow the link.
I've done the exact thing this in an application of my own.
First, you store an XML file on your webhost that holds the updater information. Mine is at http://getquitter.com/version.xml and is structured as follows:
<versioninformation>
<latestversion>1.2.0.0</latestversion>
<latestversionurl>http://www.getquitter.com/quitter-1.2.0.zip</latestversionurl>
<filename>quitter-1.2.0.zip</filename>
</versioninformation>
Second, write a method to retrieve that xml from your host:
Public Function GetWebPage(ByVal URL As String) As String
Dim Request As System.Net.HttpWebRequest = CType(WebRequest.Create(New Uri(URL)), HttpWebRequest)
With Request
.Method = "GET"
.MaximumAutomaticRedirections = 4
.MaximumResponseHeadersLength = 4
.ContentLength = 0
End With
Dim ReadStream As StreamReader = Nothing
Dim Response As HttpWebResponse = Nothing
Dim ResponseText As String = String.Empty
Try
Response = CType(Request.GetResponse, HttpWebResponse)
Dim ReceiveStream As Stream = Response.GetResponseStream
ReadStream = New StreamReader(ReceiveStream, System.Text.Encoding.UTF8)
ResponseText = ReadStream.ReadToEnd
Response.Close()
ReadStream.Close()
Catch ex As Exception
ResponseText = String.Empty
End Try
Return ResponseText
End Function
Next, call this method to get the xml and load into an xml document.
Dim VersionInfo As New System.Xml.XmlDocument
VersionInfo.LoadXml(GetWebPage("http://www.getquitter.com/version.xml"))
With version.xml loaded, you can now parse out the individual pieces of data you need to determine whether or not you need to grab the new version.
Dim LatestVersion As New Version(QuitterInfoXML.SelectSingleNode("//latestversion").InnerText)
Dim CurrentVersion As Version = My.Application.Info.Version
If LatestVersion > CurrentVersion Then
''download the new version using the Url in the xml
End If
This is how my application does it. You can download the source code if you like (it's an open source application) if you'd like to use it as a model. It's at http://quitter.codeplex.com. Hope this helps!
using System;
using System.Windows.Forms;
using System.Xml;
using System.Net;
using System.IO;
using System.Diagnostics;
namespace SAM
{
public partial class UpdateCheck : DevExpress.XtraEditors.XtraForm
{
public UpdateCheck()
{
InitializeComponent();
lblCurrentVersion.Text = "Current Version: " + Application.ProductVersion;
}
private void MainForm_Shown(object sender, EventArgs e)
{
BringToFront();
}
public static string GetWebPage(string URL)
{
System.Net.HttpWebRequest Request = (HttpWebRequest)(WebRequest.Create(new Uri(URL)));
Request.Method = "GET";
Request.MaximumAutomaticRedirections = 4;
Request.MaximumResponseHeadersLength = 4;
Request.ContentLength = 0;
StreamReader ReadStream = null;
HttpWebResponse Response = null;
string ResponseText = string.Empty;
try
{
Response = (HttpWebResponse)(Request.GetResponse());
Stream ReceiveStream = Response.GetResponseStream();
ReadStream = new StreamReader(ReceiveStream, System.Text.Encoding.UTF8);
ResponseText = ReadStream.ReadToEnd();
Response.Close();
ReadStream.Close();
}
catch (Exception ex)
{
ResponseText = string.Empty;
}
return ResponseText;
}
private void BtnChkUpdate_Click(object sender, EventArgs e)
{
System.Xml.XmlDocument VersionInfo = new System.Xml.XmlDocument();
VersionInfo.LoadXml(GetWebPage("http://www.crimson-downloads.com/SAM/UpdateCheck.xml"));
lblUpdateVersion.Text = "Latest Version: " + (VersionInfo.SelectSingleNode("//latestversion").InnerText);
textDescription.Text = VersionInfo.SelectSingleNode("//description").InnerText;
}
private void simpleButton2_Click(object sender, EventArgs e)
{
Process process = new Process();
// Configure the process using the StartInfo properties.
process.StartInfo.FileName = "http://www.crimson-downloads.com/SAM/Refresh.htm";
process.StartInfo.Arguments = "-n";
process.StartInfo.WindowStyle = ProcessWindowStyle.Maximized;
process.Start();
}
}
}
Short and simple. Thanks man, was having trouble with something else that uses xml, but with the help you gave me I was able to apply the knowledge to that as well and got it working to.
Related
I'm trying to write a tool in C# to help QA some network issues, and am running into a problem. The program is supposed to send a query in JSON format to the server every second.
Currently, it works once, but on the second attempt to send the query, I get an exception because the
"Stream was not writable."
Here's my code:
public partial class Form1 : Form
{
Timer timer1;
String query;
String result;
HttpWebRequest request;
StreamWriter writeData;
StreamReader readData;
HttpWebResponse response;
public Form1()
{
InitializeComponent();
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 1000;
File.Delete(AppDomain.CurrentDomain.BaseDirectory + "log.txt");
logOutput.ReadOnly = true;
request = (HttpWebRequest)WebRequest.Create("a URL goes here");
request.ContentType = "application/json";
request.Method = "POST";
query = "{some json stuff goes here}";
}
private void startButton_Click(object sender, EventArgs e)
{
if (!timer1.Enabled)
{
timer1.Start();
startButton.Text = "Stop";
}
else
{
timer1.Stop();
startButton.Text = "Start";
}
}
private void timer1_Tick(object sender, EventArgs e)
{
writeData = new StreamWriter(request.GetRequestStream());
writeData.Write(query);
writeData.Flush();
writeData.Close();
response = (HttpWebResponse)request.GetResponse();
readData = new StreamReader(response.GetResponseStream());
result = readData.ReadToEnd();
logOutput.Text = result;
File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", result + "\r\n");
}
}
}
Anyone know what I'm doing wrong?
First off, Stop with the global variables. Move the streamwriter, streamreader, httpwebresponse etc into the actual tick method.
Anything that implements IDisposable, which most of that stuff does, should be very local variables that aren't hanging around and are wrapped up in using clauses.
Basically your request object is closed out once your method has finished.
Something like this will work a LOT better:
private void timer1_Tick( object sender, EventArgs e ) {
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("a URL goes here");
request.ContentType = "application/json";
request.Method = "POST";
String query = "{some json stuff goes here}";
String result = String.Empty;
using ( StreamWriter writeData = new StreamWriter(request.GetRequestStream()) ) {
writeData.Write(query);
writeData.Flush();
using ( HttpWebResponse response = (HttpWebResponse)request.GetResponse() ) {
using ( StreamReader readData = new StreamReader(response.GetResponseStream()) ) {
result = readData.ReadToEnd();
}
}
}
logOutput.Text = result;
File.AppendAllText(AppDomain.CurrentDomain.BaseDirectory + "log.txt", result + "\r\n");
}
}
So I presume it's the writeData.Write(query) that's throwing? request.GetRequestStream() should only be writeable until the request is actually sent, which I believe is done when you call request.GetResponse(). So it works on the first tick, but then sends the request and can't write the second time.
Are you trying to send the request multiple times? You would need to reinitialize the request object.
Similar issue causes if you do not reinitialize the request. As mentioned by ryachza i have pushed request initialization inside loop and it worked for me.
foreach (String item in DATA)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/json";
using (Stream webStream = request.GetRequestStream())
using (StreamWriter requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII))
{
JavaScriptSerializer json_serializer = new JavaScriptSerializer();
Object routes_list =
json_serializer.DeserializeObject(item);
requestWriter.Write(item);
}
WebResponse webResponse = request.GetResponse();
using (Stream webStream = webResponse.GetResponseStream() ?? Stream.Null)
using (StreamReader responseReader = new StreamReader(webStream))
{
response.Add(responseReader.ReadToEnd());
}
}
In my code I am sending a GET request to a server. In response of this I will get one URL which I want to store in a variable.
Can anyone help me regarding this? My code so far:
private void CreatePublicUrl()
{
String CreatePublicUrl = String.Format("{0}/DataObjectServer/data/do/getproperties?cat=do&key=baseXmlPath&t={1}", base_url.Value, token);
Debug.WriteLine("CreatePublicUrl==>" + CreatePublicUrl);
HttpSyncRequest pub_url = new HttpSyncRequest();
pub_url.sendGet(CreatePublicUrl, (urlResp) =>
{
var url = new Uri(urlResp);
// String urlresponse = JsonConvert.urlResp;
});
}
It seem you're trying to achieve it using some proprietary library.
You can achieve the same using HttpWebRequestand WebResponse.
You can also do it using WebClient class as follows
WebClient client = new WebClient();
String CreatePublicUrl = String.Format("{0}/DataObjectServer/data/do/getproperties?cat=do&key=baseXmlPath&t={1}", base_url.Value, token);
using (Stream data = client.OpenRead(CreatePublicUrl))
{
using (StreamReader reader = new StreamReader(data))
{
string content = reader.ReadToEnd();
}
}
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);
}
The following is my code for using Google Translate. I have one dll I added as a reference: Google.Apis.Translate.V2
I also bought Google Translate API key.
I have 5 errors since I don't know what dll I need more: These objects do not exist missing namespace: DataContractJsonSerializer , TranslationRootObject , TranslationRootObject
What dll reference do I need for these namespaces?
This is my code, without my API key:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.IO;
using System.Web;
namespace Google_Translate
{
public partial class Form1 : Form
{
static string apiKey = "";
static string texttotranslate = "hello world";
string text;
static String apiUrl = "https://www.googleapis.com/language/translate/v2?key={0}&source={1}&target={2}&q={3}";
static String url = String.Format(apiUrl, apiKey, "en", "ge", texttotranslate);
Stream outputStream = null;
byte[] bytes = Encoding.ASCII.GetBytes(url);
// create the http web request
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
public Form1()
{
InitializeComponent();
webRequest.KeepAlive = true;
webRequest.Method = "POST";
// Overrride the GET method as documented on Google's docu.
webRequest.Headers.Add("X-HTTP-Method-Override: GET");
webRequest.ContentType = "application/x-www-form-urlencoded";
// send POST
try
{
webRequest.ContentLength = bytes.Length;
outputStream = webRequest.GetRequestStream();
outputStream.Write(bytes, 0, bytes.Length);
outputStream.Close();
}
catch (HttpListenerException e)
{
/*...*/
}
translate();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private string translate()
{
try
{
// get the response
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
if (webResponse.StatusCode == HttpStatusCode.OK && webRequest != null)
{
// read response stream
using (StreamReader sr = new StreamReader(webResponse.GetResponseStream(), Encoding.UTF8))
{
string lista = sr.ReadToEnd();
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(TranslationRootObject));
MemoryStream stream = new MemoryStream(Encoding.UTF8.GetBytes(lista));
TranslationRootObject tRootObject = (TranslationRootObject)serializer.ReadObject(stream);
string previousTranslation = string.Empty;
//deserialize
for (int i = 0; i < tRootObject.Data.Detections.Count; i++)
{
string translatedText = tRootObject.Data.Detections[i].TranslatedText.ToString();
if (i == 0)
{
text = translatedText;
}
else
{
if (!text.Contains(translatedText))
{
text = text + " " + translatedText;
}
}
}
return text;
}
}
}
catch (HttpListenerException e)
{
/*...*/
}
return text;
}
}
}
Can someone fix my code or tell me whats wrong please ?
What I need is to translate 29-33kb text file size and I wonder if it's possible to translate it as fast as it does online when using the Google Translate site.
I also found this link Google Translate V2 cannot hanlde large text translations from C# which someone say the translation can't translate big files so I wonder if 29-33kb files are counting as big? If so maybe someone can take a look at the link and fix my code according to the answer in the link I tried a lot now and didn't understand it really. But first I need to find why my original code here doesn't work.
In your project, add a reference to this assembly:
http://msdn.microsoft.com/en-us/library/system.runtime.serialization.json.datacontractjsonserializer.aspx
There may be others you need, I just looked up this one.
I'm attempting to Create a Job and Add a Batch using the Salesforce Bulk API, but I receive an XML Parsing Error back from Salesforce.
As advised in the Connecting to SalesForce bulk API using C# question, I'm using the partner WSDL to perform the login; that and the Create Job call are working. (Before I had attempted to perform the login by POSTing XML as the documentation had mentioned; I couldn't get that to work, either.)
Unfortunately, I'm a bit rusty with C#, but here is the code I'm working with.
...
using SalesforceTest.sforce;
...
namespace SalesforceTest
{
public partial class InvokeBulkAPI : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e) { }
public string SalesforceLogin(string username, string password)
{
SforceService binding = new SforceService();
binding.Timeout = 60000;
try
{
LoginResult lr = binding.login(username, password);
binding.Url = lr.serverUrl;
return lr.sessionId;
}
catch (SoapException e) { return e.Message; }
}
public string CreateJob(string sfSessionId, string sfOperation, string sfObjectName)
{
string str = "";
string reqURL = "";
byte[] bytes;
XmlDocument reqDoc;
XmlDocument respDoc;
str = ""
+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" // added \r\n as recommended by L.B's answer
+ "<jobInfo xmlns=\"http://www.force.com/2009/06/asyncapi/dataload\">"
+ " <operation></operation>" // removed "+sfOperation+"
+ " <object></object>" // removed "+sfObjectName+"
+ " <contentType>XML</contentType>" // should be CSV, NOT XML
+ "</jobInfo>"
;
reqURL = "https://cs12-api.salesforce.com/services/async/23.0/job";
reqDoc = new XmlDocument();
reqDoc.LoadXml(str);
// added XML modifications
reqDoc.GetElementsByTagName("operation")[0].InnerText = sfOperation;
reqDoc.GetElementsByTagName("object")[0].InnerText = sfObjectName;
bytes = System.Text.Encoding.ASCII.GetBytes(reqDoc.InnerXml);
respDoc = Post(bytes, reqURL, sfSessionId); // create job
string JobId = (respDoc != null) ?
(respDoc.GetElementsByTagName("id").Count > 0) ?
(respDoc.GetElementsByTagName("id")[0].InnerText) :
"" :
""
;
return JobId;
}
public void AddBatch(string sfSessionId, string sfJobId, byte[] fileBytes)
{
string reqURL = "https://cs12-api.salesforce.com/services/async/23.0/job/" + sfJobId + "/batch";
XmlDocument respDoc = Post(fileBytes, reqURL, sfSessionId);
}
public XmlDocument Post(byte[] bytes, string reqURL, string sfSessionId)
{
WebRequest req = WebRequest.Create(reqURL);
req.Method = "POST";
req.ContentLength = bytes.Length;
req.ContentType = "application/xml; charset=UTF-8"; // should be text/csv; when passing a CSV file
req.Headers.Add("X-SFDC-Session: " + sfSessionId);
System.IO.Stream strm = req.GetRequestStream();
strm.Write(bytes, 0, bytes.Length);
strm.Close();
WebResponse resp = req.GetResponse();
System.IO.Stream respStrm = resp.GetResponseStream();
XmlDocument respDoc = new XmlDocument();
respDoc.Load(respStrm);
return respDoc;
}
protected void Button1_Click(object sender, EventArgs e)
{
string SessionId = SalesforceLogin(this.TextBox1.Text, this.TextBox2.Text);
string JobId = CreateJob(SessionId, "insert", "Contact");
if (JobId.Length > 0)
{
AddBatch(SessionId, JobId, this.FileUpload1.FileBytes);
}
}
}
}
The file I'm posting is the same as the example in the documentation.
FirstName,LastName,Department,Birthdate,Description
Tom,Jones,Marketing,1940-06-07Z,"Self-described as ""the top"" branding guru on the West Coast"
Ian,Dury,R&D,,"World-renowned expert in fuzzy logic design.
Influential in technology purchases."
My question is why would I receive an XML Parsing Error from Salesforce on Line Number 1, Column 1?
This is what I receive:
XML Parsing Error: syntax error
Location: https://####.salesforce.com/services/async/23.0/job/###/batch/###/request
Line Number 1, Column 1:
FirstName,LastName,Department,Birthdate,Description
^
Any help would be appreciated. Thanks!
First of all never create an xml with string manipulations. Use an XML parser like XmlDocument or XDocument.
Xml Declaration should be on a seperate line <?xml version=\"1.0\" encoding=\"UTF-8\"?>. you forget \r\n
Third, you should set text/csv as content type when sending csv
The example uses curl to send csv. You are sending csv to a service expecting xml. Find an example with xml data or try invoking with same params as they use for curl.