I am trying to post a WPF form to my server, but I keep getting a 401 unauthorized response, even though I am sending the correct details.
This is my c# code
// Send the ComputerSettings to the API
String _Url = this.ApiUrl + "/api/hospitals/settings.xml";
String _Parameters = "";
_Parameters += "access_token=" + Authentication.AccessToken;
_Parameters += "&hospital_id=" + txtHospital.Text;
_Parameters += "&username=" + HttpUtility.UrlEncode(txtUsername.Text);
_Parameters += "&password=" + HttpUtility.UrlEncode(txtPassword.Password);
Debug.WriteLine(_Url + "?" + _Parameters);
WebClient _WebClient = new WebClient();
_WebClient.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
_WebClient.Encoding = System.Text.Encoding.UTF8;
_WebClient.UploadString(_Url, _Parameters);
When I run this from Visual Studio the Server returns a 401 unauthorized. But when I copy the url from Debug into into a REST Chrome Client (I use DHC in case that is important) then POST from there, the request works as expected.
My best guess is that Visual Studio is encoding the url parameters in an unexpected way. But I can't figure out what it is doing that is different. I also can't see a way to inspect the response contents, which would allow me to dump the data that the server is seeing into the response and debug it. I've tried things like
_ResponseString = _WebClient.UploadString(_Url, _Parameters);
Debug.WriteLine(_ResponseString);
But the exception is thrown before that Debug line, and when I inspect the Exception, the response has no contents.
edit:
I see my mistake, I'm sending the parameters as a query string in my REST client, but as request parameters from Visual Studio. The fix (for this example) is to change the UploadString call to
_WebClient.UploadString(_Url + "?" + _Parameters, "");
Just to make the solution to this more visible I'm going to post my edit as an answer
edit: I see my mistake, I'm sending the parameters as a query string
in my REST client, but as request parameters from Visual Studio. The
fix (for this example) is to change the UploadString call to
_WebClient.UploadString(_Url + "?" + _Parameters, "");
instead of
_WebClient.UploadString(_Url, _Parameters);
Related
I've been tasked with building a service which pulls information from a 3rd party API into our internal datawarehouse. They have a get request to pull the data I want where you specify the parameters you want via query strings. E.g.
http://www.api.com?parameter=firstname¶meter=surname
In my code the length of the URL is over 3600 characters long as the requirement is for 116 parameters.
My web request is generated using this code:
private HttpWebRequest GetWebRequest(string url, string type, int timeout)
{
var httpWebRequest = (HttpWebRequest) WebRequest.Create(_baseUrl + url);
httpWebRequest.Method = type;
httpWebRequest.Timeout = timeout;
httpWebRequest.ContentType = "application/json";
httpWebRequest.Headers.Add("Authorization", "Bearer " + _token.access_token);
httpWebRequest.ContentLength = 0;
return httpWebRequest;
}
When I run the code I am getting back a web exception with the message "Unable to connect to the remote server" with an internal exception message of "No connection could be made because the target machine actively refused it IP Address"
I have not included the entire URL in this post as I have found that if I copy and paste the url into Postman and run the request I get the response I expect so I know that the URL is formatted correctly. I have also discovered that if I cut down the length of the url to around 2100 characters the request then works.
I have been searching but have not found any definitive documentation to suggest that there is a limit to the length of the URL, but I can not explain why the whole url works in Postman but not in a c# web request and that if I cut the length of the URL it then works in the web request!
If anyone has any ideas about this I'd be greatfull.
An old post suggests that depending on the server and client the maximum request length is somewhere between 2 - 4 and 8 KB, which is consistent with your observations.
Postman is 'another' client, so it is well possible that it works there while it doesn't in your program. Bottom-line is: you should not GET such long requests. You should POST them instead. If you have control over the service, you could change it so it supports POST too, if not already (documented or not).
I am trying to send an sms from my website.
Below is the HTTP api which works perfectly.It sends the msg and returns the string
http://sms.mywebsite.com/api/sendmsg.php?user=MYID&pass=MYPASS&sender=SENDERID&phone=1234567980&text=Test Message&priority=ndnd&stype=normal
But i want to use it in C#.Accept mobile number from TextBox1 and Message from TextBox2
WebRequest webRequest = WebRequest.Create("http://sms.mywebsite.com/api/sendmsg.php?user=MYID&pass=MYPASS&sender=SENDERID&phone=" + TextBox1.Text + "&text=" + TextBox2.Text+ "&priority=ndnd&stype=normal")
The first statement is executing if i paste the http code directly in the website and i recieve the smsin my mobile .But the WebRequest statement dosent send the sms
TextBox1.Text=123456789;//some mobile number
TextBox2.Text="Thankyou for registering # MyWEBSITE. A verification email has been sent to Your email";
You seem to be only creating a web request object and not executing it.
var response = webRequest.GetResponse();
Refer to the documentation # https://msdn.microsoft.com/en-us/library/bw00b1dc(v=vs.110).aspx
I would also recommend you use a HttpClient instead.
You should use Server.UrlEncode. Probably, you have some spaces and special characters in the text message.
WebRequest webRequest = WebRequest.Create(Server.UrlEncode("http://sms.mywebsite.com/api/sendmsg.php?user=MYID&pass=MYPASS&sender=SENDERID&phone=" + TextBox1.Text + "&text=" + TextBox2.Text+ "&priority=ndnd&stype=normal"))
I have an ASP.NET MVC web site. One of my routes is a URL that takes 5 parameters. For the sake of illustration, these parameters are named parameter1, parameter2, parameter3, parameter4, and parameter5. Currently, I'm constructing a URL in some C# code that will POST to the mvc action via a WebClient. that code looks like this:
WebClient myWebClient = new WebClient();
myWebClient.UploadStringCompleted += myWebClient_UploadStringCompleted;
string url = "http://www.example.com/customer/" + parameter1 + "/orders/" + parameter2 + "/" + parameter3 + "/" + parameter4 + "/" + parameter5;
myWebClient.UploadStringAsync(new Uri(url, UriKind.Absolute));
I'm confident that the UploadString method does a POST. I need to do a POST, because my parameter values can be very long. In fact, I estimate that occasionally, the total url length may be 20000 characters long. Regardless, I get a 400 error when I attempt to post my data. In an effort to debug this, I'm trying to figure out how to simulate a POST in Fiddler.
Assuming that I am passing values via a query string as shown above, what values do I enter into Fiddler? From the Composer tab, I'm not sure what to enter for the Request Headers area. I'm also not entirely sure what to enter for the url. I'm not sure if I put the entire URL in there, including the parameter values, or if those belong in the Request Headers.
What I need to enter into Fiddler, so that I can debug my issue?
Basically all your parameters are a part of the URL, and this is the root of your problem. Here is what is going on: you are hitting the URL length limitation, and receiving a "400 Bad request" error. In real world most web browsers do not work with URLs more than 2000 characters long.
To resolve this problem I would suggest doing a bit of refactoring, so that request is posted to the URL http://www.example.com/customer/parameter1/orders or even http://www.example.com/customer/orders with parameters send in request body. Here is how test such request in Fiddler:
On Composer tab choose POST request verb
Specify the URL as
http://www.example.com/customer/parameter1/orders
or
http://www.example.com/customer/orders
In Request Headers section you can set content type header like
Content-Type: application/x-www-form-urlencoded
or any other header you might require. Or just leave it blank which will work in your case.
Finally in Request Body field list your parameters in query string form
parameter1name=parameter1value¶meter2name=parameter2value
In this new case here is how you can send such a request using WebClient:
WebClient myWebClient = new WebClient();
myWebClient.UploadStringCompleted += myWebClient_UploadStringCompleted;
string url = "http://www.example.com/customer/orders";
string data = "parameter1name=parameter1value¶meter2name=parameter2value";
myWebClient.UploadStringAsync(new Uri(url, UriKind.Absolute), data);
I simply mimic the exact request that was sent.
This is how I do it:
Open Fiddler
Go to the page that I want to re-issue the command i.e. repeat the bug step but watch for the request in the list
Select it from the list and right-click, go to replay > reissue and edit
This build a replicated request but hits a break point before it is sent (You will see the red bar on the right)
Above this you can edit the values that were sent by double-clicking on any of them in Headers, QueryString etc
Then hit Run to Complete
HELP !
I'm trying to upgrade may program to support the new oAuth that Google uses in the AdWords.
Using my website I'm able to create an accessToken and an accessTokenSecret for my users and store it in my database.
My problem is when I try to make a soap request later with those credentials.
Which information do I need to save from the website part? so far I save only the accessToken and the accessTokenSecret. is there anything else?
How do I use the accessToken, accessTokenSecret and what ever else I've saved in order to make a SOAP requests? (please be as "low level" as you can, "just use them in the request header" won't help me).
Some info on my process:
Not using the Client Library from Google (too much over head, and so far I didn't needed them).
Using the auto-generated SOAP code using VS2005 WSDL on the services I'm using.
C# code.
Any help would be highly appreciated.
Thanks!
=======================================================================================
As advised, I have extend the GetWebRequest in the following way:
protected override WebRequest GetWebRequest(Uri uri)
{
WebRequest request = base.GetWebRequest(uri);
String token = "XXXXXXXXXXX";//a valid token - changed for here.
String secret = "XXXXXXXXXXXX";//a valid secret - changed for here.
String consumerKey = "anonymous";
String consumerSecret = "anonymous";
String sigMet = "HMAC-SHA1";
String oauth_timestamp = ((DateTime.UtcNow.Ticks - new DateTime(1970, 1, 1).Ticks) / (1000 * 10000)).ToString();
String oauth_nonce = Guid.NewGuid().ToString();
Parameter[] paramArray = new Parameter[]{
new Parameter("oauth_consumer_key", consumerKey),
new Parameter("oauth_token", token),
new Parameter ("oauth_signature_method", sigMet),
new Parameter ("oauth_timestamp", oauth_timestamp),
new Parameter ("oauth_nonce", oauth_nonce)
};
String oauth_signature = CreateHMACSHA1Signature(
request.Method,
uri,
paramArray,
consumerSecret,
secret
);
request.Headers.Add(
"Authorization: OAuth " +
"realm=\"" + "https://www.google.com/" + "\"," +
"oauth_consumer_key=\"" + Parameter.EncodeParameterString(consumerKey) + "\"," +
"oauth_token=\"" + Parameter.EncodeParameterString(token) + "\"," +
"oauth_signature_method=\"" + Parameter.EncodeParameterString(sigMet) + "\"," +
"oauth_signature=\"" + Parameter.EncodeParameterString(oauth_signature) + "\"," +
"oauth_timestamp=\"" + Parameter.EncodeParameterString(oauth_timestamp) + "\"," +
"oauth_nonce=\"" + Parameter.EncodeParameterString(oauth_nonce) + "\""
);
return request;
}
the function CreateHMACSHA1Signature is the same one used to with OAuthGetRequestToken and OAuthAuthorizeToken just fine. but when used with the SOAP I'm getting the following error:
System.Web.Services.Protocols.SoapException: AuthenticationError.OAUTH_TOKEN_HEADER_INVALID # Service[ServicedAccountService.get]
Any idea why it is?
I've answered this question here in the context of the .NET client library at Google Ads API, C#, SOAP request with new oAuth 1.0?. But to answer your question in a NoClientLibrary context,
You just need the consumer key in addition to OAuth access key and secret.
You need to sign the request as if you were requesting a normal OAuth protected resource. Then put the signature in Authorization HTTP header (not the SOAP header) of your SOAP web request. However, getting hold of the underlying HttpWebRequest for a SOAPHttpClientProtocol object is not that straightforward. You need to extend SOAPHttpClientProtocol object, override the protected GetWebRequest method and set your OAuth headers at this stage: Something like:
protected override WebRequest GetWebRequest(Uri uri) {
WebRequest request = base.GetWebRequest(uri);
string oAuthHeader = SignTheRequestAndGetTheOAuthHeader(request);
if (!string.IsNullOrEmpty(oAuthHeader)) {
request.Headers["Authorization"] = oAuthHeader;
}
return request;
}
This also means that you have to manually modify the autogenerated code to change the base class of your stub service classes, something you are not going to enjoy much in the long run. Also, in case you don't know how to normally request an OAuth protected resource, the relevant documentation is at http://oauth.net/core/1.0/#anchor13.
Now, this is something that has been taken care of for you in the .NET client library. The library is not that difficult to use, there are enough wiki articles at http://code.google.com/p/google-api-adwords-dotnet/wiki to guide you. I recommend that you use the .NET client library, but in case you choose not to do so, here's a list of pitfalls you should be aware of when taking the NoClientLibrary route: http://code.google.com/p/google-api-adwords-dotnet/wiki/NoClientLibrary.
I also wanted to mention that AdWords API official discussion forum is at http://groups.google.com/group/adwords-api?pli=1, and I frequently answer developer questions there. If you have any followup questions, feel free to ask there and I'll be happy to answer your questions.
Cheers,
Anash
SUCCESS !!!
I finely found what was wrong, and it was only by a chance.
when creating the signature I've used the request.method for the method parameter.
The problem with this is that at this moment the method is "GET" but the SOAP mechanisim will change it to "POST" (so it can pass the SOAP parameters) this cause my signature to not work.
the only fix I needed to do is change:
String oauth_signature = CreateHMACSHA1Signature(
request.Method,
...
)
to:
String oauth_signature = CreateHMACSHA1Signature(
"POST",
...
)
I need to check that our visitors are using HTTPS. In BasePage I check if the request is coming via HTTPS. If it's not, I redirect back with HTTPS. However, when someone comes to the site and this function is used, I get the error:
System.Web.HttpException: Server
cannot append header after HTTP
headers have been sent. at
System.Web.HttpResponse.AppendHeader(String
name, String value) at
System.Web.HttpResponse.AddHeader(String
name, String value) at
Premier.Payment.Website.Generic.BasePage..ctor()
Here is the code I started with:
// If page not currently SSL
if (HttpContext.Current.Request.ServerVariables["HTTPS"].Equals("off"))
{
// If SSL is required
if (GetConfigSetting("SSLRequired").ToUpper().Equals("TRUE"))
{
string redi = "https://" +
HttpContext.Current.Request.ServerVariables["SERVER_NAME"].ToString() +
HttpContext.Current.Request.ServerVariables["SCRIPT_NAME"].ToString() +
"?" + HttpContext.Current.Request.ServerVariables["QUERY_STRING"].ToString();
HttpContext.Current.Response.Redirect(redi.ToString());
}
}
I also tried adding this above it (a bit I used in another site for a similar problem):
// Wait until page is copletely loaded before sending anything since we re-build
HttpContext.Current.Response.BufferOutput = true;
I am using c# in .NET 3.5 on IIS 6.
Chad,
Did you try ending the output when you redirect? There is a second parameter that you'd set to true to tell the output to stop when the redirect header is issued. Or, if you are buffering the output then maybe you need to clear the buffer before doing the redirect so the headers are not sent out along with the redirect header.
Brian
This error usually means that something has bee written to the response stream before a redirection is initiated. So you should make sure that the test for https is done fairly high up in the page load function.