I'm designing a web interface that is responsible for communicating with a piece of hardware. The hardware contacts the web page and sends an HTTP Request using POST that contains specific data in the body of http package using a "key=value" format.
Server-side I have code that does the following:
public override void ProcessRequest(HttpContext curContext)
{
if (curContext != null)
{
HttpResponse response = curContext.Response;
response.Clear();
response.ContentType = "text/plain";
response.BufferOutput = true;
response.StatusCode = 200; // HttpStatusCode.OK;
response.Write(response.StatusCode.ToString());
response.End();
}
}
But what I really need is the necessary code to review the Body and retrieve the data (which is in text/plain format). I'm fairly new to this type of web programming so I don't know exactly what code to write to look in the curContext to get this information, or if I even have my override method correct.
I was expecting to have something available like curContext.Request.Body but this isn't the case. How can I see the raw POST data in body of the Request? Can anyone point me in the right direction?
Thanks
You'll want to use the InputStream property on the HttpRequest instance returned by the Request property exposed by the HttpContext passed to your ProcessRequest method.
This will give you the contents of the POST request (which you can verify with a call to the HttpMethod property on the same HttpRequest).
Note that you'll have to use a StreamReader in order to convert the byte stream into strings which you'd then decode (since those key/value pairs should be url-encoded).
Fortunately, this is already done for you. On the HttpRequest instance, you can use the NameValueCollection returned by the Form property to check for the values passed as part of a POST request with url-encoded key/value pairs like so:
public override void ProcessRequest(HttpContext curContext)
{
if (curContext != null) return;
string value = curContext.Form["key"];
// Do other processing.
...
Note that you can also use the indexer on the HttpRequest, but that combines everything exposed by the QueryString, Form, Cookies and ServerVariables collections which I would say in this case is a bad idea, as you are specifically posting information and expecting that on the other side.
If you are putting the data in the body of the request in "key=value" format, it sounds like you are URL encoding form data (as long as you are delimiting the key/value pairs with an ampersand (&).
If that's the case, you should be able to use:
curContext.Request["key"]
And it will give you "value" in your example.
Related
So, I configured an external (3rd party) service to send me data through push requests. There aren't many documentation on the format of this data, they just say to point for a URL that accepts POST.
So, I want to capture this message and add to a variable that I can add to a temporary database, and analyse it to create a proper treatment later.
All examples I saw show how to send and capture the response, but I just want to capture a random message that I don't know.
Any Hints?
Regardless of the format of the request they send to your application, everything will be contained within the HttpRequest object (which, if you're just talking about a Page or something similar, would/should be built-in as the .Request property of that page).
If the request has form values, the .FormData property on that object will be a NameValueCollection of those values. If it has something in the POST body, the .InputStream property on that object will contain that data. Files, headers, query string values, etc. will all be on that object.
You can copy whatever you like from that object into your data, inspect what you get, tinker to more specifically target the values they send you, etc. Without knowing the format of the data they're going to send you, anything more specific will require inspecting what they send you and reverse-engineering its format from there. But all the data will be in that HttpRequest object.
You can use the InputStream property of the Request object. This will give you the raw data of the HTTP request.
if (Request.RequestType == "POST")
{
using (StreamReader reader = new StreamReader(Request.InputStream))
{
var wholeRequest = reader.ReadToEnd();
}
}
If you just want the request body, you can use Request.Form.ToString().
if (Request.RequestType == "POST")
{
var wholeForm = Request.Form.ToString();
}
I would not use the .FormData NameValueCollection unless you know they will be using a content-type of application/x-www-form-urlencoded multipart/form-data. Other content types will not properly populate that collection.
Can a httphandler in .net return a value? If yes how?
Thanks,
Subrat
The IHttpHandler interface only implements two things:
Boolean IsReusable {get;}
void ProcessRequest(HttpContext context);
So no... in the strictest sense it is not meant to return a value. Now, you can shape your response to look however you want it to (SOAP/XML/JSON). So in effect, you can return anything your heart desires so long as HTTP can support it, and the client consuming it knows how to deal with it.
However, it is ill-advised to go about trying to implement your own services via an HttpHandler as there are simpler and more efficient ways to accomplish the same thing.
The HttpHandler responses by its ProcessRequest(HttpContext context) method, in which you can modify the parameter context to tell what do you want to send back as an response. context.Response.ContentType specifies the MIME type of the response,for example the reponse is text/html so the browser will render it to an html page.Or the reponse is video/mp4 the browser will try to open it and in most circumstances the browser will show a download dialog. Unfortunately there is no text/array in the MIME type(and i think there won't be in the future). But you can pass your array value as plain text with special formats and deserialize it at client side. Here is a simple example:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("[1,2,3,4]");
}
and at client side in javascript:
var response = GetTheResponse(); //maybe via ajax or something equivalent.
var myArray = eval(response); //myArray[0]=1,myArray[1]=2...
In a real project, you may want to get an array with complex objects in it(not just simple numbers). So you need systematized serialization/deserialization standards, for example, you serialize your array of Person object into json strings and write it to the reponse, and you deserialize them back at client side using some json utils.
I'm using HttpListener to provide a web server to an application written in another technology on localhost. The application is using a simple form submission (application/x-www-form-urlencoded) to make its requests to my software. I want to know if there is already a parser written to convert the body of the html request document into a hash table or equivalent.
I find it hard to believe I need to write this myself, given how much .NET already seems to provide.
Thanks in advance,
You mean something like HttpUtility.ParseQueryString that gives you a NameValueCollection? Here's some sample code. You need more error checking and maybe use the request content type to figure out the encoding:
string input = null;
using (StreamReader reader = new StreamReader (listenerRequest.InputStream)) {
input = reader.ReadToEnd ();
}
NameValueCollection coll = HttpUtility.ParseQueryString (input);
If you're using HTTP GET instead of POST:
string input = listenerRequest.Url.QueryString;
NameValueCollection coll = HttpUtility.ParseQueryString (input);
The magic bits that fill out HttpRequest.Form are in System.Web.HttpRequest, but they're not public (Reflector the method "FillInFormCollection" on that class to see). You have to integrate your pipeline with HttpRuntime (basically write a simple ASP.NET host) to take full advantage.
If you want to avoid the dependency on System.Web that is required to use HttpUtility.ParseQueryString, you could use the Uri extension method ParseQueryString found in System.Net.Http.
Make sure to add a reference (if you haven't already) to System.Net.Http in your project.
Note that you have to convert the response body to a valid Uri so that ParseQueryString (in System.Net.Http)works.
string body = "value1=randomvalue1&value2=randomValue2";
// "http://localhost/query?" is added to the string "body" in order to create a valid Uri.
string urlBody = "http://localhost/query?" + body;
NameValueCollection coll = new Uri(urlBody).ParseQueryString();
I first posted this: HttpWebRequest: How to find a postal code at Canada Post through a WebRequest with x-www-form-enclosed?.
Following AnthonyWJones suggestions, I changed my code following his suggestions.
On a continuation of my inquiry, I have noticed with time that the content-type of Canada Post is more likely to be "application/xhtml+xml, text/xml, text/html; charset=utf-8".
My questions are:
How do we webrequest against such a content-type website?
Do we have to keep on going with the NameValueCollection object?
According to Scott Lance who generously provided me with precious information within my preceding question, the WebRequest shall return the type of information whatever the content-type may be, am I missing something here?
Do I have to change my code because of the content-type change?
Here is my code so that it might be easier to understand my progress.
internal class PostalServicesFactory {
/// <summary>
/// Initializes an instance of GI.BusinessSolutions.Services.PostalServices.Types.PostalServicesFactory class.
/// </summary>
internal PostalServicesFactory() {
}
/// <summary>
/// Finds a Canadian postal code for the provided Canadian address.
/// </summary>
/// <param name="address">The instance of GI.BusinessSolutions.Services.PostalServices.ICanadianCityAddress for which to find the postal code.</param>
/// <returns>The postal code found, otherwise null.</returns>
internal string FindPostalCode(ICanadianCityAddress address) {
if (address == null)
throw new InvalidOperationException("No valid address specified.");
using (ServicesWebClient swc = new ServicesWebClient()) {
var values = new System.Collections.Specialized.NameValueCollection();
values.Add("streetNumber", address.StreetNumber.ToString());
values.Add("numberSuffix", address.NumberSuffix);
values.Add("suite", address.Suite);
values.Add("streetName", address.StreetName);
values.Add("streetDirection", address.StreetDirection);
values.Add("city", address.City);
values.Add("province", address.Province);
byte[] resultData = swc.UploadValues(#"http://www.canadapost.ca/cpotools/apps/fpc/personal/findByCity", "POST", values);
return Encoding.UTF8.GetString(resultData);
}
}
private class ServicesWebClient : WebClient {
public ServicesWebClient()
: base() {
}
protected override WebRequest GetWebRequest(Uri address) {
var request = (HttpWebRequest)base.GetWebRequest(address);
request.CookieContainer = new CookieContainer();
return request;
}
}
}
This code actually returns the HTML source code of the form one must fill with the required information in order to process with the postal code search. What I wish is to get the HTML source code or whatever it may be with the found postal code.
EDIT: Here's the WebException I get now: "Unable to send a content body with this type of verb." (This is a translation from the French exception "Impossible d'envoyer un corps de contenu avec ce type de verbe.")
Here's my code:
internal string FindPostalCode(string url, ICanadianAddress address) {
string htmlResult = null;
using (var swc = new ServiceWebClient()) {
var values = new System.Collections.Specialized.NameValueCollection();
values.Add("streetNumber", address.StreetNumber.ToString());
values.Add("numberSuffix", address.NumberSuffix);
values.Add("suite", address.Suite);
values.Add("streetName", address.StreetName);
values.Add("streetDirection", address.StreetDirection);
values.Add("city", address.City);
values.Add("province", address.Province);
swc.UploadValues(url, #"POST", values);
string redirectUrl = swc.ResponseHeaders.GetValues(#"Location")[0];
=> swc.UploadValues(redirectUrl, #"GET", values);
}
return htmlResult;
}
The line that causes the exception is pointed with "=>". It seems that I can't use GET as the method, yet this is what has been told me me to do...
Any idea what I'm missing here? I try to do what Justin (see answer) recommended me to do.
Thanks in advance for any help! :-)
As an introduction to the world of screen-scraping, you've picked a very hard case! Canada post's lookup page works like this:
the first page is a form which accepts the address values
this page POSTs to a second URL.
that second URL in turn redirects (using an HTTP 302 redirect) to a third URL which actually shows you the HTML response containing the postal code.
Making matters worse, the page in step #3 needs to know the cookie set in step #1. So you need to use the same CookieContainer for all three requests (although it may possibly be sufficient to send the same CookieContainer to #2 and #3 only).
Furthermore, you may need to send additional HTTP headers in these requests as well, like Accept. I suspect where you're running into problems is that HttpWebRequest by default handles redirect transparently for you-- but when it transparently redirects it may not add the right HTTP headers necessary to impersonate a browser.
The solution is to set the HttpWebRequest's AllowAutoRedirect property to false, and handle the redirect yourself. In other words, once the first request returns a redirection, you'll need to pull out the URL in the HttpWebResponse's Location: header. Then you'll need to create a new HttpWebRequest (this time a regular GET request, not a POST) for that URL. Remeber to send the same cookie! (the CookieContainer class makes this very easy)
You also may need to make an additional request (#1 in my list above) in order to set up the session cookie. If I were you, I'd assume that this is required, simply to eliminate it as a problem, and try removing that step later and see if your solution still works.
You'll want to download and use Fiddler (www.fiddlertool.com) to help you with all this. Fiddler allows you to watch the HTTP requests going over the wire, and allows you (via the request builder feature) allows you to create HTTP requests so you can see which headers are actually required.
Forgive me if this is a stupid question. I am not very experienced with Web programming.
I am implementing the payment component of my .net mvc application. The component interacts with an external payment service. The payment service accepts http post request in the following form
http://somepaymentservice.com/pay.do?MerchantID=xxx&Price=xxx&otherparameters
I know this is dead easy to do by adding a form in View. However, I do not want my views to deal with third party parameters. I would like my view to submit information to my controller, then controller generates the required url and then send out the request. Following is the pseudo code.
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult PayForOrder(OrderForm order)
{
var url = _paymentService.GetUrlFromOrder(order);
SendPostRequest(url);
return View("FinishedPayment");
}
Is it possible to do so? Does c# have built-in library to generate http request?
Thanks in advance.
You'll want to use the HttpWebRequest class. Be sure to set the Method property to post - here's an example.
There certainly is a built in library to generate http requests. Below are two helpful functions that I quickly converted from VB.NET to C#. The first method performs a post the second performs a get. I hope you find them useful.
You'll want to make sure to import the System.Net namespace.
public static HttpWebResponse SendPostRequest(string data, string url)
{
//Data parameter Example
//string data = "name=" + value
HttpWebRequest httpRequest = HttpWebRequest.Create(url);
httpRequest.Method = "POST";
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.ContentLength = data.Length;
var streamWriter = new StreamWriter(httpRequest.GetRequestStream());
streamWriter.Write(data);
streamWriter.Close();
return httpRequest.GetResponse();
}
public static HttpWebResponse SendGetRequest(string url)
{
HttpWebRequest httpRequest = HttpWebRequest.Create(url);
httpRequest.Method = "GET";
return httpRequest.GetResponse();
}
It realy makes a difference if ASP.NET makes a request or the the client makes a request.
If the documentation of the the provider says that you should use a form with the given action that has to be submited by the client browser then this might be necessary.
In lots of cases the user (the client) posts some values to the provider, enters some data at the providers site and then gets redirected to your site again. You can not do this applicationflow on the serverside.