PHP works fine via browser, won't work via HttpWebRequest - c#

My goal
I'm trying to read and write files from my webserver via C#.
Progress
So far, via PHP I made it to work that you can write to files with file_put_contents(). The saved files are text files, so you can easily read them. My C# program with responses works fine, and I get my desired values.
private string GetWarnInfo(string id)
{
try
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create($"http://example.com/{id}.txt");
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
return reader.ReadToEnd();
}
}
catch(Exception)
{
return null;
}
}
100% of the time it did not return null, which is a success.
The problem
Well, the writing. My PHP in example.php looks like this:
if (file_exists($_GET['id'] . '.txt'))
{
unlink($_GET['id'] . '.txt');
file_put_contents($_GET['id'] . '.txt', $_GET['info']);
} else {
file_put_contents($_GET['id'] . '.txt', $_GET['info']);
}
While it fully works via browser calls (http://example.com/example.php?id=23&info=w3), and actually makes the text file, I can't get it to work with C#:
public void ServerRequest(string id, string info)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://example.com/example.php?id=" + id + "&info=" + info);
request.Method = "GET";
}
For example, I call ServerRequest((23).ToString(), "w3"), but the file won't change, it will always be either non-existant or in it last state (if there was one).
What could cause this problem? How would I fix it?

Thanks to #Barmar
I have figured out the problem, if I don't call GetResponse(), it will never start the web request. After doing that, everything worked fine!

Related

Issues passing an Xml file to a method in console application

I am working on a c# console application where I am making a Http Post request to a web api by using xml file and I'm kind of new to XML and web services but I figured out the following code for the request but failed to pass xml data to the method
static void Main(string[] args)
{
string desturl=#"https://xyz.abcgroup.com/abcapi/";
Program p = new Program();
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
}
public string WebRequestPostData(string url, string postData)
{
System.Net.WebRequest req = System.Net.WebRequest.Create(url);
req.ContentType = "text/xml";
req.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(postData);
req.ContentLength = bytes.Length;
using (Stream os = req.GetRequestStream())
{
os.Write(bytes, 0, bytes.Length);
}
using (System.Net.WebResponse resp = req.GetResponse())
{
if (resp == null) return null;
using (System.IO.StreamReader sr = new System.IO.StreamReader(resp.GetResponseStream()))
{
return sr.ReadToEnd().Trim();
}
}
}
For obvious reasons the above code throws 404 error as I think I am not passing the xml data properly
May I know how I can fix this?
You're not posting xml, your posting the string C:\Applications\TestService\FixmlSub.xml
Change your method call from:
System.Console.WriteLine(p.WebRequestPostData(desturl, #"C:\Applications\TestService\FixmlSub.xml"));
to
var xml = XElement.Load(#"C:\Applications\TestService\FixmlSub.xml");
System.Console.WriteLine(p.WebRequestPostData(desturl, xml.ToString(SaveOptions.DisableFormatting));
If you are trying to learn post / receive, go for it. But there are open source libraries that are already well tested to use if you want to use them.
The non-free version of Servicestack.
And their older free-version. I think the older free version is great. I've never tried the newer one. You deal with objects, like say an Employee and pass that to the library and it does the translation to xml or whatever the web-service wants.
You can post whole strings if you want. They have great extension methods to help you with that too.

Retrieving website content and returning it in ASP.NET MVC 4

I have two servers. One is a private server and I don't want users to have direct access to it, and the other one is the server that public does have access to.
I can access my private server by URL like: http://xxx.xx.xxx.xxx/
What i want to do is create some kind of "proxy", only to work with my private server. My idea is to go to: http://www.domain.com/server/path/here/something
This page should show me the content of http://xxx.xx.xxx.xxx/path/here/something
I have this working, but the only way I could make it work was to return the content as a string, and then the browser would interpret the HTML.
This works fine for pages that return HTML content, but it doesn't work (of course) if I want to access a .gif or any kind of file directly.
Here's the code I currently have:
public string Index(string url)
{
string uri = "http://xxx.xx.xxx.xxx/" + url;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "GET";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader responseStream = new StreamReader(response.GetResponseStream());
string resultado = responseStream.ReadToEnd();
return resultado;
}
How can I change my code so that it works for any file ?
You can check the response content type and do what you need based on that.
You'll need to change your action to return ActionResult instead of string.
if(response.ContentType.Equals("text/html"))
{
//show html stuff
return Content(resultado);
}
else if(response.ContentType.Contains("image/"))
{
var ms = new MemoryStream();
responseStream.BaseStream.CopyTo(ms);
var imageBytes = ms.ToArray();
return File(imageBytes, response.ContentType);
}
you have to write a system which reads your html or images from resultado and do something according to that PLUS you need to control your Url as well.

C# JSON response does an second JSON request

I'm working with JSON for a while now, but this is a problem I can't solve.
The program is written in C# and has a method called CreateWebRequest():
public void CreateWebRequest()
{
CurrentTime = DateTime.Now;
target = link;
request = WebRequest.Create(target) as HttpWebRequest;
request.ContentType = "application/json; charset=utf-8";
request.Method = "PUT";
request.ServicePoint.Expect100Continue = false;
string postData = jsonString;
System.Console.WriteLine("POSTDATA: " + postData);
StreamWriter requestWriter;
using (requestWriter = new StreamWriter(request.GetRequestStream()))
{
requestWriter.Write(postData);
}
}
The other function to fetch the result is called: CreateWebResponse():
public void CreateWebResponse()
{
WebResponse response;
string text;
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException e)
{
MessageBox.Show(e.Message);
return;
}
using (var sr = new StreamReader(response.GetResponseStream()))
{
text = sr.ReadToEnd();
}
APIresult apiresult = JsonConvert.DeserializeObject<APIresult>(text); //Deserialize the text
}
These functions work all fine, there is only one problem: the code does two requests.
When I put the same JSON in the RESTClient in mozilla FireFox the JSON works fine. It also works great when I'm only using CreateWebRequest(), but when I use both of the methods it seems the code creats a second request?
Is it possible to create only a response? Combine these two functions to one which creates directly an response?
I tried other solutions and put them just together, none of them seems to work. When I call for a response the code doesn't work properly anymore and creates two requests.
Has anyone a solution?
Thanks in advance.
The JSON function I call has several if statements and work fine according to RESTClient in Firefox.
The code below shows the code which is called correct by RESTClient and twice by the C# code:
$sql = 'SELECT...';
$result = $db->sql_query($sql);//search for member id.
if($row = $db->sql_fetchrow($result)){//when found, the user has access.
$member_id = $row['member_id'];
$sql = 'SELECT ...';
$result = $db->sql_query($sql);//search for last login today.
if($row = $db->sql_fetchrow($result)){//if the user has logged in today update the row.
$row_check_in_timestamp = $row['check_in_timestamp'];
$sql = 'UPDATE ...';//update the row with the check out timestamp
$db->sql_query($sql);
break;
}else{//the user hasn't logged in yet today, log in.
$start_session_array = array(
'club_id' => (int)$club_id,
'member_id' => (int)$member_id,
'check_in_timestamp' => (int)time(),
);
$sql = 'INSERT ...';//check user in and add a new row in the database
$db->sql_query($sql);
break;
}
}else{
break;
}
SOLVED: I'm sorry every one and thanks for all the responses, but I've found the problem. I had an older version as service running all the time and made the second JSON call.
I've found it by logging on the server side the calls and blocked code which call the JSON in my own code to figure this out.

How do I intercept the output stream of the current actionresult in .NET MVC3?

Hi and thanks for looking!
Background
I am using the Rotativa pdf tool to read a view (html) into a PDF. It works great, but it does not natively offer a way to save the PDF to a file system. Rather, it only returns the file to the user's browser as a result of the action.
Here is what that code looks like:
public ActionResult PrintQuote(FormCollection fc)
{
int revisionId = Int32.Parse(Request.QueryString["RevisionId"]);
var pdf = new ActionAsPdf(
"Quote",
new { revisionId = revisionId })
{
FileName = "Quote--" + revisionId.ToString() + ".pdf",
PageSize = Rotativa.Options.Size.Letter
};
return pdf;
}
This code is calling up another actionresult ("Quote"), converting it's view to a PDF, and then returning the PDF as a file download to the user.
Question
How do I intercept the file stream and save the PDF to my file system. It is perfect that the PDF is sent to the user, but my client also wants the PDF saved to the file system simultaneously.
Any ideas?
Thanks!
Matt
I have the same problem, here's my solution:
You need to basically make an HTTP request to your own URL and save the output as a binary file. Simple, no overload, helper classes, and bloated code.
You'll need this method:
// Returns the results of fetching the requested HTML page.
public static void SaveHttpResponseAsFile(string RequestUrl, string FilePath)
{
try
{
HttpWebRequest httpRequest = (HttpWebRequest)WebRequest.Create(RequestUrl);
httpRequest.UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
httpRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
HttpWebResponse response = null;
try
{
response = (HttpWebResponse)httpRequest.GetResponse();
}
catch (System.Net.WebException ex)
{
if (ex.Status == WebExceptionStatus.ProtocolError)
response = (HttpWebResponse)ex.Response;
}
using (Stream responseStream = response.GetResponseStream())
{
Stream FinalStream = responseStream;
if (response.ContentEncoding.ToLower().Contains("gzip"))
FinalStream = new GZipStream(FinalStream, CompressionMode.Decompress);
else if (response.ContentEncoding.ToLower().Contains("deflate"))
FinalStream = new DeflateStream(FinalStream, CompressionMode.Decompress);
using (var fileStream = System.IO.File.Create(FilePath))
{
FinalStream.CopyTo(fileStream);
}
response.Close();
FinalStream.Close();
}
}
catch
{ }
}
Then inside your controller, you call it like this:
SaveHttpResponseAsFile("http://localhost:52515/Management/ViewPDFInvoice/" + ID.ToString(), "C:\\temp\\test.pdf");
And voilĂ ! The file is there on your file system and you can double click and open the PDF, or email it to your users, or whatever you need.
return new Rotativa.ActionAsPdf("ConvertIntoPdf")
{
FileName = "Test.pdf", PageSize = Rotativa.Options.Size.Letter
};
Take a look at the MVC pipeline diagram here:
http://www.simple-talk.com/content/file.ashx?file=6068
The method OnResultExecuted() is called after the ActionResult is rendered.
You can override this method or use an ActionFilter to apply and OnResultExecuted interceptor using an attribute.
Edit:
At the end of this forum thread you will find a reply which gives an example of an ActionFilter which reads (and changes) the response stream of an action. You can then copy the stream to a file, in addition to returning it to your client.
I successfully used Aaron's 'SaveHttpResponseAsFile' method, but I had to alter it, as the currently logged in user's credentials weren't applied (and so it was forwarding to MVC4's login url).
public static void SaveHttpResponseAsFile(System.Web.HttpRequestBase requestBase, string requestUrl, string saveFilePath)
{
try
{
*snip*
httpRequest.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
httpRequest.Headers.Add(HttpRequestHeader.Cookie, requestBase.Headers["Cookie"]);
*snip*</pre></code>
Then in your calling Controller method, simply add 'Request' into the SaveHttpResponseAsFile call.
You can also do it using Rotativa, which is actually quite easy.
Using Rotativa;
...
byte[] pdfByteArray = Rotativa.WkhtmltopdfDriver.ConvertHtml( "Rotativa", "-q", stringHtmlResult );
File.WriteAllBytes( outputPath, pdfByteArray );
I'm using this in a winforms app, to generate and save the PDFs from Razor Views we also use in our web apps.
I was able to get Eric Brown - Cal 's solution to work, but I needed a small tweak to prevent an error I was getting about the directory not being found.
(Also, looking at the Rotativa code, it looks like the -q switch is already being passed by default, so that might not be necessary, but I didn't change it.)
var bytes = Rotativa.WkhtmltopdfDriver.ConvertHtml(Server.MapPath(#"/Rotativa"), "-q", html);

JSON Data posted by Silverlight is not reaching the server

I have a web client I'm creating in Silverlight. I am trying to get it to communicate it with my web services on my server through GET and POST requests and JSON. The GET requests work fine and I'm able to parse the JSON on the Silverlight end. The POST requests however dont seem to work. The server reads that there is a POST request, but the POST array is empty.
Ive tried two pieces of code to send the POST requests, but both are resulting in the same response - an empty array.
The first Silverlight code I tried was:
public MainPage()
{
InitializeComponent();
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://www.dipzo.com/game/services.php"));
request.Method = "POST";
request.ContentType = "application/json";
request.BeginGetRequestStream(new AsyncCallback(OnGetRequestStreamCompleted), request);
}
private void OnGetRequestStreamCompleted(IAsyncResult ar)
{
HttpWebRequest request = (HttpWebRequest)ar.AsyncState;
using (StreamWriter writer = new StreamWriter(request.EndGetRequestStream(ar)))
{
writer.Write("name=david");
}
request.BeginGetResponse(new AsyncCallback(OnGetResponseCompleted), request);
}
private void OnGetResponseCompleted(IAsyncResult ar)
{
//this.GetResponseCoimpleted.Visibility = Visibility.Visible;
// Complete the Flickr request and marshal to the UI thread
using (HttpWebResponse response = (HttpWebResponse)((HttpWebRequest)ar.AsyncState).EndGetResponse(ar))
{
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
string results = reader.ReadToEnd();
}
}
}
The second piece I tried was:
private void WebClient_Click(object sender, RoutedEventArgs e)
{
Test t1 = new Test() { Name = "Civics", Marks = 100 };
DataContractJsonSerializer jsondata = new DataContractJsonSerializer(typeof(Test));
MemoryStream mem = new MemoryStream();
jsondata.WriteObject(mem, t1);
string josnserdata = Encoding.UTF8.GetString(mem.ToArray(), 0, (int)mem.Length);
WebClient cnt = new WebClient();
cnt.UploadStringCompleted += new UploadStringCompletedEventHandler(cnt_UploadStringCompleted);
cnt.Headers["Content-type"] = "application/json";
cnt.Encoding = Encoding.UTF8;
cnt.UploadStringAsync(new Uri("http://www.dipzo.com/game/services.php"), "POST", josnserdata);
}
void cnt_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
var x = e;
}
The code on the server to consume the service is in PHP and is essentially:
var_dump($_POST)
This should output whatever is coming into the post array. I've tested it with a simple PHP client and it works. Just can't get it to work in silverlight. In silverlight I just keep getting an empty array.
You should change the Content-type to application/x-www-form-urlencoded and not application/json which is not a known type yet.
Not that I think anyone is still paying attention tot his old question, but I'm betting that the problem was that it actually WAS getting to the server, but that the server routed the result back to the SL application. This is the behavior I'm seeing with a similar situation from SL5 usingWebClient.UploadStringAsync.
I'm about to implement/test a technique I ran across yesterday which uses a dynamically built, "real" page post from SL; I'll report my findings shortly.
UPDATE -- THIS SOLUTION WORKS:
http://www.codeproject.com/Tips/392435/Using-HTTP-Form-POST-method-to-pass-parameters-fro
I've just tested it in my application (SL5 inside MVC) and it works just fine. Make sure you check the HttpContext.Request.Form["fieldname"] to get the value(s) that you want. I used this technique to submit JSON and was able to return a generated Word document for the user.
Once I implemented this I was able to get rid of the unnecessary WebClient that I was attempting to use before.

Categories

Resources