Try Catch - URL link not exist - c#

I need to read some Data from URLs - but depending on the string (ICAO) - the URL does not sometimes exist (it is not valid). In this case - I should get "N/A" - but that does not work... only when all three URLs are readable - it is working.
[Invoke]
public List<Category> getWeather(string ICAO)
{
try
{
List<Category> lstcat = new List<Category>();
Category cat = new Category();
string fileString;
bool isexists = FtpDirectoryExists("ftp://tgftp.nws.noaa.gov/data/observations/metar/stations/" + ICAO);
if (isexists == true)
{
WebClient request = new WebClient();
string url = "http://weather.noaa.gov/pub/data/observations/metar/stations/" + ICAO;
byte[] newFileData = request.DownloadData(url);
fileString = System.Text.Encoding.UTF8.GetString(newFileData);
cat.Cat = "METAR";
lstcat.Add(cat);
cat = new Category();
cat.Cat = fileString;
lstcat.Add(cat);
url = "http://weather.noaa.gov/pub/data/forecasts/shorttaf/stations/" + ICAO;
newFileData = request.DownloadData(url);
fileString = System.Text.Encoding.UTF8.GetString(newFileData);
cat = new Category();
cat.Cat = "Short TAF";
lstcat.Add(cat);
cat = new Category();
cat.Cat = fileString;
lstcat.Add(cat);
url = "http://weather.noaa.gov/pub/data/forecasts/taf/stations/" + ICAO;
newFileData = request.DownloadData(url);
fileString = System.Text.Encoding.UTF8.GetString(newFileData);
cat = new Category();
cat.Cat = "Long TAF";
lstcat.Add(cat);
cat = new Category();
cat.Cat = fileString;
lstcat.Add(cat);
}
else
{
fileString = "N/A;N/A";
}
return null;
}
catch (Exception)
{
throw;
}
}

Create a method to check the remote file exists or not.
make a Heder request to the URl, if the sattus code is 200 or 302 then return true
otherwise false;
HttpWebResponse response = null;
var request = (HttpWebRequest)WebRequest.Create(/* url */);
request.Method = "HEAD";
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
/* A WebException will be thrown if the status of the response is not `200 OK` */
}
finally
{
// Don't forget to close your response.
if (response != null)
{
response.Close()
}
}

Okay, I think I see what you want to do. I re-worked your code so that it fits what's actually needed.
Right now, it seems like the first Category in lstcat has the description (such as "METAR") of the first URL, the second Category in lstcat has the fileString that matches it, and so on. This is very vague and cumbersome. Instead, make it so that one Category object contains everything you need to know about a URL:
public class Category
{
public string description;
public string fileString;
//Other fields you might use somewhere else...
public Category(string description, string fileString /*, other fields, if any...*/)
{
this.description = description;
this.fileString = fileString;
//Initialize others...
}
}
I then eliminated all the duplication in the original code, by putting all the URL download code into a separate function.
[Invoke]
public List<Category> getWeather(string ICAO)
{
bool isexists = FtpDirectoryExists("ftp://tgftp.nws.noaa.gov/data/observations/metar/stations/" + ICAO);
if (isexists)
{
List<Category> lstcat = new List<Category>();
addCategoriesToList(
lstcat,
"http://weather.noaa.gov/pub/data/observations/metar/stations/" + ICAO,
"METAR"
);
addCategoriesToList(
lstcat,
"http://weather.noaa.gov/pub/data/forecasts/shorttaf/stations/" + ICAO,
"Short TAF"
);
addCategoriesToList(
lstcat,
"http://weather.noaa.gov/pub/data/forecasts/taf/stations/" + ICAO,
"Long TAF"
);
return lstcat;
}
else
{
return null;
}
}
private static void addCategoriesToList(List<Category> lstcat, string url, string description)
{
string fileString;
//Use "using" so that `request` always gets cleaned-up:
using (WebClient request = new WebClient())
{
try
{
byte[] newFileData = request.DownloadData(url);
fileString = System.Text.Encoding.UTF8.GetString(newFileData);
}
catch
{
fileString = "N/A";
}
}
lstcat.Add(new Category(description, fileString));
}
I think this accomplishes what you want, in a much cleaner and straightforward way. Please let me know if that is indeed the case!

Related

URL not opening correctly on another browser asp.net mvc

I have an asp.net mvc application were i send sms messages with URL to clients. message and URL is sent correctly but when i click on the link it does not open correctly, example there is no data passed from database, example if you click the following url, there is no data passed to view: http://binvoicing.com/InvoiceAddlines/PaymentPreview?originalId=11&total=585.00
Here code:
public ActionResult SendSms(string cellnumber, int? id, string rt, string tenant, decimal? total, string userloggedin)
{
StreamReader objReader;
WebClient client = new WebClient();
int payid = 0;
int paypalaid = 0;
string UrL = "";
string pass = "mypassword";
//string cell = cellnumber;
string user = "username";
var pay = from e in db.PayfastGateways
where e.userId == userloggedin
select e;
var paya = pay.ToList();
foreach (var y in paya)
{
payid = y.ID;
}
var pal = from e in db.PaypalGateways
where e.userId == userloggedin
select e;
var payla = pal.ToList();
foreach (var y in payla)
{
paypalaid = y.ID;
}
string url = Url.Action("PaymentPreview", "InvoiceAddlines", new System.Web.Routing.RouteValueDictionary(new { originalId = id, total = total }), "http", Request.Url.Host);
if (payid == 0 && paypalaid == 0)
{
UrL = "";
}
else
{
UrL = url;
}
string mess = " Dear Customer, please click on the following link to view generated invoice, you can also pay your invoice online." + UrL;
string message = HttpUtility.UrlEncode(mess, System.Text.Encoding.GetEncoding("ISO-8859-1"));
string baseurl =
"http://bulksms.2way.co.za/eapi/submission/send_sms/2/2.0?" +
"username=" + user + "&" +
"password=" + pass + "&" +
"message=" + message + "&" +
"msisdn=" + cellnumber;
WebRequest wrGETURL;
wrGETURL = WebRequest.Create(baseurl);
HttpUtility.UrlEncode("http://www.vcskicks.com/c#");
try
{
Stream objStream;
objStream = wrGETURL.GetResponse().GetResponseStream();
objReader = new StreamReader(objStream);
objReader.Close();
}
catch (Exception ex)
{
ex.ToString();
}
ViewBag.cellnumber = cellnumber;
ViewBag.id = id;
ViewBag.rt = rt;
ViewBag.tenant = tenant;
ViewBag.total = total;
ViewBag.UrL = UrL;
return View();
}
SMS send url like http://binvoicing.com/InvoiceAddlines/PaymentPreview?originalId=11&total=585.00
Here Is my PaymentPreview method:
public ActionResult PaymentPreview(int? originalId, decimal? total)
{
TempData["keyEditId"] = originalId;
ViewBag.ind = originalId;
decimal totals = 0;
totals = (decimal)total;
var line = from e in db.InvoiceAddlines
where e.AddlineID == originalId
select e;
var addlines = line.ToList();
foreach (var y in addlines)
{
decimal? de = Math.Round(totals);
string tots = de.ToString();
y.Total = tots;
db.SaveChanges();
}
return View(db.InvoiceAddlines.ToList());
}
Hope someone can assist, thanks.
I think there is something wrong with the way URL is being built. See if this works -
Change this part of your code
string url = Url.Action("PaymentPreview", "InvoiceAddlines", new System.Web.Routing.RouteValueDictionary(new { originalId = id, total = total }), "http", Request.Url.Host);
To
string url = Url.Action("PaymentPreview", "InvoiceAddlines", new { originalId = id, total = total })

Get Content-Disposition parameters

How do I get Content-Disposition parameters I returned from WebAPI controller using WebClient?
WebApi Controller
[Route("api/mycontroller/GetFile/{fileId}")]
public HttpResponseMessage GetFile(int fileId)
{
try
{
var file = GetSomeFile(fileId)
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
response.Content = new StreamContent(new MemoryStream(file));
response.Content.Headers.ContentDisposition = new System.Net.Http.Headers.ContentDispositionHeaderValue("attachment");
response.Content.Headers.ContentDisposition.FileName = file.FileOriginalName;
/********* Parameter *************/
response.Content.Headers.ContentDisposition.Parameters.Add(new NameValueHeaderValue("MyParameter", "MyValue"));
return response;
}
catch(Exception ex)
{
return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
}
}
Client
void DownloadFile()
{
WebClient wc = new WebClient();
wc.DownloadDataCompleted += wc_DownloadDataCompleted;
wc.DownloadDataAsync(new Uri("api/mycontroller/GetFile/18"));
}
void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
WebClient wc=sender as WebClient;
// Try to extract the filename from the Content-Disposition header
if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"]))
{
string fileName = wc.ResponseHeaders["Content-Disposition"].Substring(wc.ResponseHeaders["Content-Disposition"].IndexOf("filename=") + 10).Replace("\"", ""); //FileName ok
/****** How do I get "MyParameter"? **********/
}
var data = e.Result; //File OK
}
I'm returning a file from WebApi controller, I'm attaching the file name in the response content headers, but also I'd like to return an aditional value.
In the client I'm able to get the filename, but how do I get the aditional parameter?
If you are working with .NET 4.5 or later, consider using the System.Net.Mime.ContentDisposition class:
string cpString = wc.ResponseHeaders["Content-Disposition"];
ContentDisposition contentDisposition = new ContentDisposition(cpString);
string filename = contentDisposition.FileName;
StringDictionary parameters = contentDisposition.Parameters;
// You have got parameters now
Edit:
otherwise, you need to parse Content-Disposition header according to it's specification.
Here is a simple class that performs the parsing, close to the specification:
class ContentDisposition {
private static readonly Regex regex = new Regex(
"^([^;]+);(?:\\s*([^=]+)=((?<q>\"?)[^\"]*\\k<q>);?)*$",
RegexOptions.Compiled
);
private readonly string fileName;
private readonly StringDictionary parameters;
private readonly string type;
public ContentDisposition(string s) {
if (string.IsNullOrEmpty(s)) {
throw new ArgumentNullException("s");
}
Match match = regex.Match(s);
if (!match.Success) {
throw new FormatException("input is not a valid content-disposition string.");
}
var typeGroup = match.Groups[1];
var nameGroup = match.Groups[2];
var valueGroup = match.Groups[3];
int groupCount = match.Groups.Count;
int paramCount = nameGroup.Captures.Count;
this.type = typeGroup.Value;
this.parameters = new StringDictionary();
for (int i = 0; i < paramCount; i++ ) {
string name = nameGroup.Captures[i].Value;
string value = valueGroup.Captures[i].Value;
if (name.Equals("filename", StringComparison.InvariantCultureIgnoreCase)) {
this.fileName = value;
}
else {
this.parameters.Add(name, value);
}
}
}
public string FileName {
get {
return this.fileName;
}
}
public StringDictionary Parameters {
get {
return this.parameters;
}
}
public string Type {
get {
return this.type;
}
}
}
Then you can use it in this way:
static void Main() {
string text = "attachment; filename=\"fname.ext\"; param1=\"A\"; param2=\"A\";";
var cp = new ContentDisposition(text);
Console.WriteLine("FileName:" + cp.FileName);
foreach (DictionaryEntry param in cp.Parameters) {
Console.WriteLine("{0} = {1}", param.Key, param.Value);
}
}
// Output:
// FileName:"fname.ext"
// param1 = "A"
// param2 = "A"
The only thing that should be considered when using this class is it does not handle parameters (or filename) without a double quotation.
Edit 2:
It can now handle file names without quotations.
You can parse out the content disposition using the following framework code:
var content = "attachment; filename=myfile.csv";
var disposition = ContentDispositionHeaderValue.Parse(content);
Then just take the pieces off of the disposition instance.
disposition.FileName
disposition.DispositionType
With .NET Core 3.1 and more the most simple solution is:
using var response = await Client.SendAsync(request);
response.Content.Headers.ContentDisposition.FileName
The value is there I just needed to extract it:
The Content-Disposition header is returned like this:
Content-Disposition = attachment; filename="C:\team.jpg"; MyParameter=MyValue
So I just used some string manipulation to get the values:
void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
{
WebClient wc=sender as WebClient;
// Try to extract the filename from the Content-Disposition header
if (!String.IsNullOrEmpty(wc.ResponseHeaders["Content-Disposition"]))
{
string[] values = wc.ResponseHeaders["Content-Disposition"].Split(';');
string fileName = values.Single(v => v.Contains("filename"))
.Replace("filename=","")
.Replace("\"","");
/********** HERE IS THE PARAMETER ********/
string myParameter = values.Single(v => v.Contains("MyParameter"))
.Replace("MyParameter=", "")
.Replace("\"", "");
}
var data = e.Result; //File ok
}
As #Mehrzad Chehraz said you can use the new ContentDisposition class.
using System.Net.Mime;
// file1 is a HttpResponseMessage
FileName = new ContentDisposition(file1.Content.Headers.ContentDisposition.ToString()).FileName

Problems with Xml parsing using C#

I am developing my first windows App and I am facing some Problems while parsing an Xml,the code is as shown below
public void TimeParsing(string lat, string lon)
{
string urlbeg = "http://api.geonames.org/timezone?lat=";
string urlmid = "&lng=";
string urlend = "&username=dheeraj_kumar";
WebClient downloader = new WebClient();
Uri uri = new Uri(urlbeg + lat + urlmid + lon + urlend, UriKind.Absolute);
downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(TimeDownloaded);
//downloader.DownloadStringCompleted += new DownloadStringCompletedEventHandler(TimeDownloaded);
downloader.DownloadStringAsync(uri);
}
private void TimeDownloaded(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Result == null || e.Error != null)
{
MessageBox.Show("Invalid");
}
else
{
XDocument document = XDocument.Parse(e.Result);
var data1 = from query in document.Descendants("geoname")
select new Country
{
CurrentTime = (string)query.Element("time"),
};
foreach (var d in data1)
{
time = d.CurrentTime;
MessageBox.Show(d.CurrentTime);
// country = d.CountryName;
}
}
}
The problem is that the Delegate TimeDownloaded is not being called. I used the same technique is parse a different URL and it was done easily but its not working in this case.Kindly Help me as I am pretty new to this field.
Thanks in advance.
Theres a few misses regarding fetching the nodes
The output is geonames/timezone/time, it's corrected below, also testable using the method DownloadStringTaskAsync instead
[TestClass]
public class UnitTest1
{
[TestMethod]
public async Task TestMethod1()
{
await TimeParsing("-33.8674869", "151.20699020000006");
}
public async Task TimeParsing(string lat, string lon)
{
var urlbeg = "http://api.geonames.org/timezone?lat=";
var urlmid = "&lng=";
var urlend = "&username=dheeraj_kumar";
var downloader = new WebClient();
var uri = new Uri(urlbeg + lat + urlmid + lon + urlend, UriKind.Absolute);
downloader.DownloadStringCompleted += TimeDownloaded;
var test = await downloader.DownloadStringTaskAsync(uri);
Console.WriteLine(test);
}
private void TimeDownloaded(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Result == null || e.Error != null)
{
Console.WriteLine("Invalid");
}
else
{
var document = XDocument.Parse(e.Result);
var data1 = from query in document.Descendants("timezone")
select new Country
{
CurrentTime = (string)query.Element("time"),
};
foreach (var d in data1)
{
Console.WriteLine(d.CurrentTime);
}
}
}
}
internal class Country
{
public string CurrentTime { get; set; }
}
}
you can use the below mentioned code.
Uri uri = new Uri(urlbeg + lat + urlmid + lon + urlend, UriKind.Absolute);
HttpWebRequest WebReq = (HttpWebRequest)WebRequest.Create(uri);
//This time, our method is GET.
WebReq.Method = "GET";
//From here on, it's all the same as above.
HttpWebResponse WebResp = (HttpWebResponse)WebReq.GetResponse();
//Now, we read the response (the string), and output it.
Stream Answer = WebResp.GetResponseStream();
StreamReader _Answer = new StreamReader(Answer);
string s = _Answer.ReadToEnd();
XDocument document = XDocument.Parse(s);
var data1 = from query in document.Descendants("geoname")
select new Country
{
CurrentTime = (string)query.Element("time"),
};
foreach (var d in data1)
{
time = d.CurrentTime;
MessageBox.Show(d.CurrentTime);
// country = d.CountryName;
}
for Windows Phone 8 you have to implement the getResponse Method.
public static System.Threading.Tasks.Task<System.Net.WebResponse> GetResponseAsync(this System.Net.WebRequest wr)
{
return Task<System.Net.WebResponse>.Factory.FromAsync(wr.BeginGetResponse, wr.EndGetResponse, null);
}

HtmlAgilityPack obtain Title and meta

I try to practice "HtmlAgilityPack ", but I am having some issues regarding this. here's what I coded, but I can not get correctly the title and the description of a web page ...
If someone can enlighten me on my mistake :)
...
public static void Main(string[] args)
{
string link = null;
string str;
string answer;
int curloc; // holds current location in response
string url = "http://stackoverflow.com/";
try
{
do
{
HttpWebRequest HttpWReq = (HttpWebRequest)WebRequest.Create(url);
HttpWReq.UserAgent = #"Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5";
HttpWebResponse HttpWResp = (HttpWebResponse)HttpWReq.GetResponse();
//url = null; // disallow further use of this URI
Stream istrm = HttpWResp.GetResponseStream();
// Wrap the input stream in a StreamReader.
StreamReader rdr = new StreamReader(istrm);
// Read in the entire page.
str = rdr.ReadToEnd();
curloc = 0;
//WebPage result;
do
{
// Find the next URI to link to.
link = FindLink(str, ref curloc); //return the good link
Console.WriteLine("Title found: " + curloc);
//title = Title(str, ref curloc);
if (link != null)
{
Console.WriteLine("Link found: " + link);
using (System.Net.WebClient client = new System.Net.WebClient())
{
HtmlDocument htmlDoc = new HtmlDocument();
var html = client.DownloadString(url);
htmlDoc.LoadHtml(link); //chargement de HTMLAgilityPack
var htmlElement = htmlDoc.DocumentNode.Element("html");
HtmlNode node = htmlDoc.DocumentNode.SelectSingleNode("//meta[#name='description']");
if (node != null)
{
string desc = node.GetAttributeValue("content", "");
Console.Write("DESCRIPTION: " + desc);
}
else
{
Console.WriteLine("No description");
}
var titleElement =
htmlDoc.DocumentNode
.Element("html")
.Element("head")
.Element("title");
if (titleElement != null)
{
string title = titleElement.InnerText;
Console.WriteLine("Titre: {0}", title);
}
else
{
Console.WriteLine("no Title");
}
Console.Write("Done");
}
Console.Write("Link, More, Quit?");
answer = Console.ReadLine();
}
else
{
Console.WriteLine("No link found.");
break;
}
} while (link.Length > 0);
// Close the Response.
HttpWResp.Close();
} while (url != null);
}
catch{ ...}
Thanks in advance :)
Go about it this way:
HtmlNode mdnode = htmlDoc.DocumentNode.SelectSingleNode("//meta[#name='description']");
if (mdnode != null)
{
HtmlAttribute desc;
desc = mdnode.Attributes["content"];
string fulldescription = desc.Value;
Console.Write("DESCRIPTION: " + fulldescription);
}
I think your problem is here:
htmlDoc.LoadHtml(link); //chargement de HTMLAgilityPack
It should be:
htmlDoc.LoadHtml(html); //chargement de HTMLAgilityPack
LoadHtml expects a string with the HTML source, not the url.
And probably you want to change:
var html = client.DownloadString(url);
to
var html = client.DownloadString(link);
Have you used a breakpoint and gone line for line to see where the error might be occurring?
If you have, then Try something like this:
string result = string.Empty;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://www.google.com");
request.Method = "GET";
try
{
using (var stream = request.GetResponse().GetResponseStream())
using (var reader = new StreamReader(stream, Encoding.UTF8))
{
result = reader.ReadToEnd();
}
}
HtmlAgilityPack.HtmlDocument htmlDoc = new HtmlAgilityPack.HtmlDocument();
htmlDoc.LoadHtml(result);
Then carry over the rest of your code below the htmlDoc.LoadHtml
[HttpPost]
public ActionResult Create(WebSite website)
{
string desc = HtmlAgi(website.Url, "description");
string keyword = HtmlAgi(website.Url, "Keywords");
if (ModelState.IsValid)
{
var userId = ((CustomPrincipal)User).UserId;
r.Create(new WebSite
{
Description = desc,
Tags = keyword,
Url = website.Url,
UserId = userId,
Category = website.Category
});
return RedirectToAction("Index");
}
return View(website);
}
public string HtmlAgi(string url, string key)
{
//string.Format
var Webget = new HtmlWeb();
var doc = Webget.Load(url);
HtmlNode ourNode = doc.DocumentNode.SelectSingleNode(string.Format("//meta[#name='{0}']", key));
if (ourNode != null)
{
return ourNode.GetAttributeValue("content", "");
}
else
{
return "not fount";
}
}

You don't have permission to post in a group

I've finished a program in C# which integrates with Facebook and posts to more than one group in a click
but I am facing a problem right now when there is a group that you don't have a permission to post to I can't complete posting to the rest
here's the post function
I put it in other Class
public static bool PostImage(Frm form,string AccessToken, string Status, string ImagePath)
{
try
{
if (form.listBox2 .SelectedItems .Count > 0)
{
string item;
foreach (int i in form. listBox2.SelectedIndices)
{
item = form.listBox2.Items[i].ToString();
groupid = item;
FacebookClient fbpost = new FacebookClient(AccessToken);
var imgstream = File.OpenRead(ImagePath);
dynamic res = fbpost.Post("/" + groupid + "/photos", new
{
message = Status,
File = new FacebookMediaStream
{
ContentType = "image/jpg",
FileName = Path.GetFileName(ImagePath)
}.SetValue(imgstream)
});
result = true;
}
}
return result;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return false;
}
}
You need to put a try catch block inside the loop. Then, in the catch block you log the error (or do whatever you want with it) then continue the loop:
foreach (int i in form. listBox2.SelectedIndices)
{
try
{
item = form.listBox2.Items[i].ToString();
groupid = item;
FacebookClient fbpost = new FacebookClient(AccessToken);
var imgstream = File.OpenRead(ImagePath);
dynamic res = fbpost.Post("/" + groupid + "/photos", new
{
message = Status,
File = new FacebookMediaStream
{
ContentType = "image/jpg",
FileName = Path.GetFileName(ImagePath)
}.SetValue(imgstream)
});
result = true;
}
catch(exception excp)
{
//Do something with the exception
}
}
Now I don't know exactly how your code works, but this should give you a rough idea.

Categories