I have the following code that receives webhook messages:
// Read posted data
string requestBody;
using (var reader = new StreamReader(HttpContext.Current.Request.InputStream))
{
requestBody = reader.ReadToEnd();
}
requestBody.Log();
// Attempt to forward request
context.CopyTo(Settings.Payments.Paypal.ScirraPaypalIPNEndpoint);
requestBody contains data which is logged. I then attempt to forward the request to another URL:
public static void CopyTo(this HttpContext source, string url)
{
var destination = (HttpWebRequest) WebRequest.Create(url);
var request = source.Request;
destination.Method = request.HttpMethod;
// Copy unrestricted headers
foreach (var headerKey in request.Headers.AllKeys)
{
if (WebHeaderCollection.IsRestricted(headerKey)) continue;
destination.Headers[headerKey] = request.Headers[headerKey];
}
// Copy restricted headers
if (request.AcceptTypes != null && request.AcceptTypes.Any())
{
destination.Accept = string.Join(",", request.AcceptTypes);
}
destination.ContentType = request.ContentType;
destination.Referer = request.UrlReferrer?.AbsoluteUri ?? string.Empty;
destination.UserAgent = request.UserAgent;
// Copy content (if content body is allowed)
if (request.HttpMethod != "GET"
&& request.HttpMethod != "HEAD"
&& request.ContentLength > 0)
{
using (var destinationStream = destination.GetRequestStream())
{
request.InputStream.Position = 0;
request.InputStream.CopyTo(destinationStream);
destinationStream.Close();
}
}
if (!Settings.Deployment.IsLive)
{
ServicePointManager.ServerCertificateValidationCallback =
(sender, certificate, chain, sslPolicyErrors) => true;
}
using (var response = destination.GetResponse() as HttpWebResponse)
{
if (response == null) throw new Exception("Failed to post to " + url);
}
}
The handler that receives this forwarded request has the code:
public void ProcessRequest(HttpContext context)
{
string requestBody;
using (var reader = new StreamReader(HttpContext.Current.Request.InputStream))
{
requestBody = reader.ReadToEnd();
}
requestBody.Log();
}
However on the handler forwarded to, requestBody is always empty! What am I doing wrong here?
Both servers are hosted in Clouflare, when posting from one to the other I get a CF 1000 prohibited IP error.
Solution is to add target servers IP address into requesting servers hosts file.
Related
I have a list of URLs, and the meaning of this is that I am checking our websites if anyone is down / offline we would get a notification and that works except some of the URLs crash at this line
HttpWebResponse httpRes = (HttpWebResponse)httpReq.GetResponse();
But the rest is working just fine? can anyone tell me what I'm doing wrong? I've tried URLs with HTTPS, HTTP and even with only www...
public void CheckUrl()//List Of URLs
{
List<string> urls = new List<string>() {
"https//:www.example.com/something1/buy",
"https//:www.example.com/something2/buy",
"https//:www.example.com/something3/buy",
"https//:www.example.com/something4/buy",
};
//walks through all the URL:s
foreach (var url in urls)
{
//Creating URL Request
HttpWebRequest httpReq = (HttpWebRequest)WebRequest.Create(url);
httpReq.AllowAutoRedirect = false;
try
{
WebClient client = new WebClient();
string downloadString = client.DownloadString(url);
//Trying to find a response
HttpWebResponse httpRes = (HttpWebResponse)httpReq.GetResponse();
if ((httpRes.StatusCode != HttpStatusCode.OK || httpRes.StatusCode != HttpStatusCode.Found) && downloadString.Contains("404 -") || downloadString.Contains("Server Error"))
{
// Code for NotFound resources goes here.
SendVerificationLinkEmail(httpRes.StatusCode.ToString(), url);
foreach (var number in Numbers)
{
SendSms(url, number);
}
}
//Close the response.
httpRes.Close();
}
catch(Exception e)
{
//sending only to admin to check it out first
SendExeptionUrl(url);
foreach (var number in Numbers)
{
SendSms(url, number);
}
}
}
Application.Exit();
}
Hi I have this Asynchronous Web API, I think when I execute this in a button click, the rest of the processes won't continue until the API returns the results, Below is my API,
btnSubmit.Click += async (sender, e) =>
{
var jobId = txtJobID.Text;
if (txtJobID.Text.Length <= 0)
{
txtJobID.RequestFocus();
txtJobID.SetError("Job ID required", iconError);
}
else
{
var request = HttpWebRequest.Create(string.Format("http://192.168.79.174:90/api/test/" + jobId));
request.ContentType = "application/json";
request.Method = "GET";
using (HttpWebResponse response = await request.GetResponseAsync() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK)
Console.Out.WriteLine("Error fetching data. Server returned status code: {0}", response.StatusCode);
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
var content = reader.ReadToEnd();
dynamic arr = JsonConvert.DeserializeObject(content);
foreach (dynamic obj in arr)
{
tvJobID.Text = obj.JobID;
tvJobType.Text = obj.JobType;
tvDueDate.Text = obj.DueDate;
tvVisitTime.Text = obj.Time;
tvVisitStatus.Text = obj.VisitStatus;
tvAddress1.Text = obj.Address1;
tvAddress2.Text = obj.Address2;
tvPostCode.Text = obj.PostCode;
tvAuthority.Text = obj.Authority;
}
if (content == null || content == "" || content == "[]")
{
//Console.Out.WriteLine("Response contained empty body...");
Toast.MakeText(ApplicationContext, "Invalid Job ID or no visits for this ID. Please try again", ToastLength.Long).Show();
}
else
{
layoutController.Visibility = ViewStates.Visible;
}
}
}
}
};
When I debug the code, Specially where the foreach statement is, it takes quite a bit of time for API to return results. What am I doing wrong? Thanks a lot for any help!
I've made this webservice which relays a request to another server. It takes a request that is made to it's own url, then does the request to a different url and responses the result back to it's client.
void Application_BeginRequest(object sender, EventArgs e)
{
// Setup destination url schemes
string newAuth = "localhost:1861";
string newUrl = "http://" + newAuth + Request.Url.PathAndQuery;
// Setup the request from this server to the other server
HttpWebRequest newRequest = (HttpWebRequest)WebRequest.Create(newUrl);
newRequest.AllowAutoRedirect = false;
// Copy all needed headers
List<string> copyHeaderNames = new List<string>()
{
"Accept-Encoding",
"Accept-Language",
"Upgrade-Insecure-Requests",
"Cache-Control",
"Connection",
"Cookie"
};
foreach (var key in copyHeaderNames)
{
try
{
if (newRequest.Headers.AllKeys.Contains(key))
{
newRequest.Headers[key] = Request.Headers[key].Replace(Request.Url.Authority, newAuth);
}
else
{
newRequest.Headers.Add(key, Request.Headers[key].Replace(Request.Url.Authority, newAuth));
}
}
catch { }
}
// Then setup the constant paramenters of the new request
newRequest.KeepAlive = Request.Headers["Connection"] == "keep-alive";
newRequest.Accept = Request.Headers["Accept"];
newRequest.Expect = Request.Headers["Expect"];
newRequest.UserAgent = Request.Headers["User-Agent"];
newRequest.ContentType = Request.ContentType;
newRequest.Method = Request.HttpMethod;
newRequest.Host = newAuth;
newRequest.Referer = newUrl;
// If the request is a POST, I need to copy the inputstream.
if (Request.HttpMethod == "POST")
{
byte[] inputBytes = ReadToByteArray(Request.InputStream);
string inputString = System.Text.Encoding.Default.GetString(inputBytes);
// Replace original url with destination url
inputString = inputString.Replace(Request.Url.Authority, newAuth);
inputBytes = System.Text.Encoding.Default.GetBytes();
Stream reqStream = newRequest.GetRequestStream();
reqStream.Write(inputBytes, 0, inputBytes.Length);
reqStream.Close();
}
// Then do the request
using (var resp = (HttpWebResponse)newRequest.GetResponse())
{
// Setup response paramenters
Response.StatusCode = (int)resp.StatusCode;
Response.StatusDescription = resp.StatusDescription;
// Get the response stream
using (var respstream = resp.GetResponseStream())
{
var res = ReadToByteArray(respstream);
// And respond it in the current response
Response.BinaryWrite(res);
// Then I copy all response headers to the current response
foreach (var key in resp.Headers.AllKeys)
{
try
{
// Replace the destination url back to the current url
string value = resp.Headers[key].Replace(newAuth, Request.Url.Authority);
if (Response.Headers.AllKeys.Contains(key))
{
Response.Headers[key] = value;
}
else
{
Response.Headers.Add(key, value);
}
}
catch { }
}
}
}
// Tell the program to end the request.
Response.End();
}
public static byte[] ReadToByteArray(Stream input)
{
byte[] buffer = new byte[16 * 1024];
using (MemoryStream ms = new MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
Now everything works except the login. The other website is a asp.net mvc4 application, it uses the standard Membership with authentication cookie.
Any ideas?
Guess copying the content of the request object doesn't exactly copy it. The solution was to go 1 layer down the OSI model to the TCP layer and do the relaying on that level.
I have used SO to help with several issues in the past. However, I cannot find a solution to something I have been struggling with for 2 days now.
I am a noob, please be kind :)
I have an app that I created using Xamarin Studio, targeted for Android. It is a basic GET request from a Rest Api. It was working perfectly until I realized I was not helping myself when it came time to create the same app in IOS and Windows. Once I changed my project to utilize a PCL I started getting errors, primarily around my RestClient class (originally got from http://www.codeproject.com/Tips/497123/How-to-make-REST-requests-with-Csharp)
From my droid app class:
var apiUser = GetString(Resource.String.apiUser);
var apiPass = GetString(Resource.String.apiPass);
//Get token from API
string token = authenticate(apiUser,apiPass);
public static string authenticate(string apiUser, string apiPass)
{
Authentication Auth = new Authentication ();
try
{
// set json by passing AuthenticationUrl as endpoint, returns json data
var o = JObject.Parse(EntryRepository.getJson(PJTApiUrls.getAuthenticationUrl(apiUser,apiPass)));
Auth.Token = (string)o["Token"];
return Auth.Token;
}
catch (Exception e)
{
// Couldn't do stuff. Log the exception.
// TODO possible timeout, try again, if fails again then return error message
if (e.Message.Contains("400") || e.Message.Contains("401"))
{
string error = string.Format("Invalid credentials, please try again");
return error;
} else {
string error = string.Format ("An error occurred: \r\n{0}", e.Message);
return error;
}
}
}
getAuthenticationUrl gets the api URL.
Here is getJson (in PCL):
public static string getJson(string endpoint)
{
string apiurl = endpoint;
var client = new _RestClient();
client.EndPoint = apiurl;
client.ContentType = "application/json";
client.Method = HttpVerb.GET;
//client.Method = HttpVerb.POST;
client.PostData = "";
//client.PostData = "{postData: value}";
//client.PostData = "{'someValueToPost': 'The Value being Posted'}";
var json = client._MakeRequestAsync();
// to append parameters, pass them into make request:
//var json = client.MakeRequest("?param=0");
return json.ToString();
}
And for the _RestClient class (in PCL):
public async Task<string> _MakeRequestAsync()
{
try {
var request = _MakeRequestAsync ("");
return await request;
}
catch (Exception e){
return e.Message;
}
}
public async Task<string> _MakeRequestAsync(string parameters)
{
var uri = new Uri(EndPoint + parameters);
var request = WebRequest.Create(uri) as HttpWebRequest;
using (var response = await request.GetResponseAsync () as HttpWebResponse) {
var responseValue = string.Empty;
if (response.StatusCode != HttpStatusCode.OK) {
var message = String.Format ("Request failed. Received HTTP {0}", response.StatusCode);
throw new Exception (message);
}
// grab the response
using (var responseStream = await Task.Factory.FromAsync<Stream>(request.BeginGetRequestStream, request.EndGetRequestStream, null)) {
//using (var responseStream = response.GetResponseStream ()) {
if (responseStream != null)
using (var reader = new StreamReader (responseStream)) {
responseValue = reader.ReadToEnd ();
}
}
return responseValue;
}
}
responseValue is returning null
return await request is saying "Status = Waiting for activation"
I have also had the error: "Unexpected character encountered while parsing value: S. Path '', line 0, position 0."
But this works if the RestClient class is within Droid (Instead of the shared PCL) and contains the following:
public string MakeRequest ()
{
return MakeRequest ("");
}
public string MakeRequest (string parameters)
{
var request = (HttpWebRequest)WebRequest.Create (EndPoint + parameters);
request.Method = Method.ToString ();
request.ContentLength = 0;
request.ContentType = ContentType;
if (!string.IsNullOrEmpty (PostData) && Method == HttpVerb.POST) {
var bytes = Encoding.GetEncoding ("iso-8859-1").GetBytes (PostData);
request.ContentLength = bytes.Length;
using (var writeStream = request.GetRequestStream ()) {
writeStream.Write (bytes, 0, bytes.Length);
}
}
using (var response = (HttpWebResponse)request.GetResponse ()) {
var responseValue = string.Empty;
if (response.StatusCode != HttpStatusCode.OK) {
var message = String.Format ("Request failed. Received HTTP {0}", response.StatusCode);
throw new ApplicationException (message);
}
// grab the response
using (var responseStream = response.GetResponseStream ()) {
if (responseStream != null)
using (var reader = new StreamReader (responseStream)) {
responseValue = reader.ReadToEnd ();
}
}
return responseValue;
}
}
I cannot figure this out, any help/guidance is appreciated. Let me know if I can clarify anything.
***** UPDATE ***** Thanks to #milen-pavlov help thus far, here is where I am currently at:
in Android project:
var apiUser = GetString(Resource.String.apiUser);
var apiPass = GetString(Resource.String.apiPass);
//Get token from API
var token = await authenticate(apiUser,apiPass);
lblOutput.Text = token;
calls (also in Android project):
public static async Task<string> authenticate(string apiUser, string apiPass)
{
Authentication Auth = new Authentication ();
try
{
// set json by passing AuthenticationUrl as endpoint, returns json data
var o = JObject.Parse(await EntryRepository.getJson(PJTApiUrls.getAuthenticationUrl(apiUser,apiPass)));
Auth.Token = (string)o["Token"];
return Auth.Token;
}
catch (Exception e)
{
if (e.Message.Contains("400") || e.Message.Contains("401"))
{
string error = string.Format("Invalid credentials, please try again");
return error;
} else {
string error = string.Format ("An error occurred: \r\n{0}", e.Message);
return error;
}
}
}
Calls json class in PCL project:
public static async Task<string> getJson(string endpoint)
{
string apiurl = endpoint;
var client = new _RestClient();
client.EndPoint = apiurl;
client.ContentType = "application/json";
client.Method = HttpVerb.GET;
client.PostData = "";
var json = await client._MakeRequestAsync();
return json;
}
which then calls restclient class in PCL project:
public async Task<string> _MakeRequestAsync()
{
var request = _MakeRequestAsync ("");
return await request;
}
public async Task<string> _MakeRequestAsync(string parameters)
{
var uri = new Uri(EndPoint + parameters);
using (var client = new HttpClient())
{
var response = await client.GetAsync(uri);
return await response.Content.ReadAsAsync<string>();
};
}
End result/error:
Any guidance is appreciated!
Can you use HttpClient instead?
Sample Get request will look similar to this:
public async Task<string> _MakeRequestAsync(string parameters)
{
var uri = new Uri(EndPoint + parameters);
using (var client = new HttpClient())
{
var response = await client.GetAsync(uri);
return await result.Content.ReadAsStringAsync();
};
}
Suppose I have the following web method using C# and .NET:
[WebInvoke(UriTemplage="/users", Method="POST")]
[OperationContract]
public User AddNewUser(User u);
It is expected that when you implement POST web method you will accept a request body as part of the incoming HTTP request message. The parameter u is expected to be deserialized from the incoming HTTP message body.
My question is: how do we set this request body on the client side ? It's got to be set somewhere. It really confuses me.
Besides if I added "ResponseFormat = WebMessageFormat.Json" to WebInvoke, how can I deserialize from the returned json string into the User object ?
Thanks.
Your question doesn't reveal what you have tried. If you are using .net on the client then you can use the DataContractSerializer to get the serialized data.
You can then use an HttpWebRequest with the method set to POST.
Add the serialized data to the web request and use the GetResponse() method.
Alternatively you could use Fiddlr to test your web service using requests that you create. It gives you a concise view of exactly what is going up to the server.
To perform a POST request to your WCF Rest method:
private string UseHttpWebApproach<T>(string serviceUrl, string resourceUrl, string method, T requestBody)
{
string responseMessage = null;
var request = WebRequest.Create(string.Concat(serviceUrl, resourceUrl)) as HttpWebRequest;
if (request != null)
{
request.ContentType = "application/json";
request.Method = method;
}
if(method == "POST" && requestBody != null)
{
byte[] requestBodyBytes = ToByteArrayUsingJsonContractSer(requestBody);
request.ContentLength = requestBodyBytes.Length;
using (Stream postStream = request.GetRequestStream())
postStream.Write(requestBodyBytes, 0, requestBodyBytes.Length);
}
if (request != null)
{
var response = request.GetResponse() as HttpWebResponse;
if(response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
if (responseStream != null)
{
var reader = new StreamReader(responseStream);
responseMessage = reader.ReadToEnd();
}
}
else
{
responseMessage = response.StatusDescription;
}
}
return responseMessage;
}
private static byte[] ToByteArrayUsingJsonContractSer<T> (T requestBody)
{
byte[] bytes = null;
var serializer1 = new DataContractJsonSerializer(typeof(T));
var ms1 = new MemoryStream();
serializer1.WriteObject(ms1, requestBody);
ms1.Position = 0;
var reader = new StreamReader(ms1);
bytes = ms1.ToArray();
return bytes;
}
Now Assuming your User object as shown below:
Public Class User
{
Public int UserId {get;set;}
Public string UserName {get;set;}
Public string Password {get;set;}
}
The to call the above method i do:
User objUser = new objUser();
objUser.Username = "Test";
objUser.Password = "Test";
UseHttpWebApproach<User>(serviceBaseUrl, "users", "POST", objUser);