I am working with OAuth at the moment. The problem with the current code is it doesn't wait until the user allows the application on the site and gets the proper key and secret. I was using a threading type wait but, sometimes it not long enough...some users are slower then others. I have attached a snippet of my code. What I would like to know is where to insert a while statement, or should I even use that ?
public OAuthToken GetRequestToken(Uri baseUri, string consumerKey, string consumerSecret)
{
var uri = new Uri(baseUri, "oauth/request_token");
uri = SignRequest(uri, consumerKey, consumerSecret);
var request = (HttpWebRequest) WebRequest.Create(uri);
request.Method = WebRequestMethods.Http.Get;
var response = request.GetResponse();
var queryString = new StreamReader(response.GetResponseStream()).ReadToEnd();
var parts = queryString.Split('&');
var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
var secret = parts[0].Substring(parts[0].IndexOf('=') + 1);
return new OAuthToken(token, secret);
}
You should switch over to the newer System.Net.Http and System.Net.Http.WebRequest libraries that come with .NET now. These all use the new async programming stuff that is available with .NET 4.5.
You can call a request (returning you a task object that you can wait on) and automatically pause the thread for the response. The UI won't respond, as normal. That is probably the easiest thing to do if you don't understand how the new async and await keywords work. For more information on them, see http://msdn.microsoft.com/en-us/library/hh191443.aspx
Here is your code doing things with the new libraries:
using System.Net.Http;
public OAuthToken GetRequestToken(Uri baseUri, string consumerKey, string consumerSecret)
{
var uri = new Uri(baseUri, "oauth/request_token");
uri = SignRequest(uri, consumerKey, consumerSecret);
var message = new HttpRequestMessage(new HttpMethod("GET"), uri);
var handler = new WebRequestHandler();
var client = new HttpClient(handler);
// Use the http client to send the request to the server.
Task<HttpResponseMessage> responseTask = client.SendAsync(message);
// The responseTask object is like a wrapper for the other task thread.
// We can tell this task object that we want to pause our current thread
// and wait for the client.SendAsync call to finish.
responseTask.Wait();
// - Once that thread finishes, and the code continues on, we need to
// tell it to read out the response data from the backing objects.
// - The responseTask.Result property represents the object the async task
// was wrapping, we want to pull it out, then use it and get the content
// (body of the response) back.
// - Getting the response actually creates another async task (the
// .ReadAsStringAsync() call) but by accessing the .Result
// property, it is as if we called .ReadAsStringAsync().Wait(); Except that
// by using Result directly, we not only call Wait() but we get the resulting,
// wrapped object back. Hope that didn't confuse you much :)
var queryString = responseTask.Result.Content.ReadAsStringAsync().Result;
// And all your other normal code continues.
var parts = queryString.Split('&');
var token = parts[1].Substring(parts[1].IndexOf('=') + 1);
var secret = parts[0].Substring(parts[0].IndexOf('=') + 1);
return new OAuthToken(token, secret);
}
Why Not use a modal pop up and then call the authentication class on the submit button
Related
I'm using V2 of the Etsy Api. I know my consumer key and build up of my token is all fine because when I make a request for listings related to a receipt, I receive all details:
$"https://openapi.etsy.com/v2/receipts/{receipt.receipt_id}/listings?";
I then try to obtain all transactions for a listing:
$"https://openapi.etsy.com/v2/listings/{lineItem.listing_id}/transactions?";
this call never returns and it doesn't error. As far as I can tell, I've built the call correctly.
After the build up of the call which includes all the OAUth stuff, If I paste the whole url directly in a browser, data is sent back to the browser.
So this is the build up of the call to Etsy:
I have a generic method
public async Task<T> MakeGetCallToEtsy<T>(string requestUrl)
{
var client = new OAuthRequest
{
Method = "GET",
Type = OAuthRequestType.ProtectedResource,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ConsumerKey = _consumerKey,
ConsumerSecret = _consumerSecret,
Token = _token,
TokenSecret = _tokenSeret,
RequestUrl = requestUrl
};
var url = requestUrl + client.GetAuthorizationQuery();
var result = await url.GetStringAsync();
return JsonConvert.DeserializeObject<T>(result);
}
And this is my call to the method:
string requestUrl = $"https://openapi.etsy.com/v2/listings/{lineItem.listing_id}/transactions?";
var transactions = await _etsyComms.MakeGetCallToEtsy<EtsyTransaction>(requestUrl);
I thought the issue might be with the deserialization, but placing a breakpoint there, again it never gets to that point.
Has anybody come across this issue before, or can see anything I've missed in my build up to the call.
I've this function :
public string GetSecurityCrumb()
{
string uri = $"{Url}/crumbIssuer/api/xml";// URL where the XML is available
var client = new RestClient(uri); // define it as the actual client
var request = new RestRequest(Method.GET);
byte[] ua = Encoding.ASCII.GetBytes(Username + ":" + ApiToken); // Encoding username and token in base 64
request.AddHeader("authorization", "Basic " + Convert.ToBase64String(ua));// adding header to get the xml
IRestResponse response = client.Execute(request);
XDocument document = XDocument.Parse(response.Content);// parsing the content of the response in a document
var crumb = document.Root.Element("crumb").Value;// retrieve the content of the crumb only
return crumb;
}
I tried a lot of things to do this aynchronous, but I just don't see how I can return string value if I change my Rest call to an aynschronous one.
Maybe somebody already got this kind of problem and could help me.
EDIT 1
I tried this :
public async Task<string> GetSecurityCrumb()
{
string uri = $"{Url}/crumbIssuer/api/xml";// URL where the XML is available
var client = new RestClient(uri); // define it as the actual client
var request = new RestRequest(Method.GET);
byte[] ua = Encoding.ASCII.GetBytes(Username + ":" + ApiToken); // Encoding username and token in base 64
request.AddHeader("authorization", "Basic " + Convert.ToBase64String(ua));// adding header to get the xml
IRestResponse response = await client.ExecuteTaskAsync(request);
XDocument document = XDocument.Parse(response.Content);// parsing the content of the response in a document
var crumb = document.Root.Element("crumb").Value;// retrieve the content of the crumb only
return crumb;
}
but it seems like I need to put await before all my calls on this method and use GetSecurityCrumb().Result to get the real content. I don't know if it's the best way because I've totally 0 error handlers at the moment. A lot of my methods depend of this one so I prefer having the best solution
it seems like I need to put await before all my calls on this method and use GetSecurityCrumb().Result to get the real content
You shouldn't call .Result - that would block on the asynchronous method, removing all the benefits of asynchronous code in the first place.
It's normal to await the task returned from GetSecurityCrumb(). And using that await means that the calling method should also be marked async and return a task. Which means that its callers should use await, so they should be made async, etc. This is all perfectly normal and is the correct way to use async/await.
I have a BOT that uses QnA Maker and LUIS to answer FAQ and requests and I am trying to implement a Direct Line to another BOT. Basically whenever my BOT does not know the answer it sends the user message to the other BOT to check if it knows the answer and outputs the result. The Direct Line works fine when I step through the code with Debugger (the GET request responds with the message I sent and the reply from the BOT). However, when I just run the code normally the response only contains the message I sent and not the reply from the other BOT. I'm thinking that the GET request is just ending too fast for the BOT to respond when the code is run outside the debugger and I have no idea on how to fix or extend the request. Any ideas?
Here's the relevant code:
public class EdwardComponent
{
public static async Task<string> TalkToEdward(string userInput, string conversationID, string streamURL)
{
var DirectLineURL = ConfigurationManager.AppSettings["DirectLineURL"];
var BearerToken = ConfigurationManager.AppSettings["BearerToken"];
var DirectLineURLConversationID = ConfigurationManager.AppSettings["DirectLineURLConversationID"];
DirectLineURLConversationID = DirectLineURLConversationID.Replace("abc123", conversationID);
var postclient = new RestClient(DirectLineURLConversationID);
var postrequest = new RestRequest(Method.POST);
postrequest.AddHeader("Authorization", BearerToken);
postrequest.AddHeader("Content-Type", "application/json");
postrequest.RequestFormat = DataFormat.Json;
var idv = new { id = "user1" };
postrequest.AddBody(new { type = "message", from = idv, text = userInput });
var cancellationTokenSource = new CancellationTokenSource();
var postresponse = postclient.ExecuteAsPost(postrequest, "POST");
var getrequest = new RestRequest(Method.GET);
getrequest.AddHeader("Authorization", BearerToken);
var getresponse = await postclient.ExecuteGetTaskAsync(getrequest);
string content = getresponse.Content.ToString();
return content;
}
}
}
Here is the correct serialized response from debugging:
Activity 0 is the message sent, Activity 1 is the response from BOT
Here is the response when ran outside debugger:
Only Activity 0 returned
Fixed it by using a small delay and a loop that will continue making the GET request until the Bot responds.
During my application's Application_Start() event I want to fire off a HTTP request to an address. I absolutely do not want any cost incurred by Application_Start() and for App Start to be delayed in any fashion. I do not care about the response from the request.
What is the most correct method for firing this request in a completely non-blocking fashion?
I would do something like this:
Task.Run(() =>
{
using (var httpClient = new HttpClient())
{
httpClient.BaseAddress = new Uri("https://something.com/");
var content = new StringContent("content");
var result = httpClient.PostAsync("path/to/Service" , content);
result.Wait();
}
});
I would recommend just firing the request asynchronously
using(var client = new HttpClient())
{
client.PostAsJsonAsync("{url}",content)
}
for example will fire the request and continue
You can use WebClient.UploadStringAsync Method for this purpose
This method does not block the calling thread.
It can throw
ArgumentNullException
WebException
use it in this way
var client = new WebClient();
//remove comment from next line to execute some code after UploadString complete
//client.UploadStringCompleted += new UploadStringCompletedEventHandler(function name to execute when finish);
var data = "data to send";
client.Headers.Add("Content-Type", "content type here");
client.UploadStringAsync(new Uri("http://www.yourDomain.com"), data);
Is there a way, using HttpClient, to differentiate a time-out "when we get no response from the server" from a "time exceeded" operation?
Let me explain our issue:
Case1: If we don't get any response from the server in 10 seconds then this is an issue.
Case2: If we get a response from the server, but the server continues to transfer data and it takes a while, maybe 30 seconds or more. Then this is not an issue.
Is there a way using .NET HttpClient class to handle this scenario? From what I tested specifying a TimeOut on HttpClient will put the same time-out for case1 and case2.
Here is the solution I managed to do:
// Create the cancelation token, when we don't get any feedback from server within 20 seconds
var cancelHeadersToken = new CancellationTokenSource();
cancelHeadersToken.CancelAfter(TimeSpan.FromSeconds(20)); // if we don't receive server headers after 20 seconds then something went wrong
// We have another cancelation token, that allows the user to cancel the request, so here we create a linked token source which uses both tokens
var linkedToken = CancellationTokenSource.CreateLinkedTokenSource(userCancelToken, cancelHeadersToken.Token);
// The linked token is then used in GetAsync and we use the overload which allows to specify the HttpCompletionOption
// We only want to receive headers and not all content
var httpMessage = await customClient.CustomizedHttpClient.GetAsync(address, HttpCompletionOption.ResponseHeadersRead, linkedToken.Token).ConfigureAwait(false);
// We can then download the content, and we still allow to cancel anything by the user
using (var memoryStream = new MemoryStream(100000)) { // 100ko by default
using (var stream = await httpMessage.Content.ReadAsStreamAsync().ConfigureAwait(false)) {
await stream.CopyToAsync(memoryStream, 10000, userCancelToken).ConfigureAwait(false); // copy to memory stream 10ko per 10ko
}
string data = "";
if (memoryStream.Length > 0) {
var headers = httpMessage.Content.Headers;
Encoding encoding;
if (headers != null && headers.ContentType != null && headers.ContentType.CharSet != null) {
encoding = Encoding.GetEncoding(headers.ContentType.CharSet);
} else {
encoding = Encoding.UTF8;
}
data = encoding.GetString(memoryStream.GetBuffer(), 0, (int)memoryStream.Length);
}
// Then you do whatever you want with data
}
You can use one of the variants of the various methods that accepts a CancellationToken.
If the cancel happens after the method's Task has completed, the cancellation is ignored and you can continue with e.g. processing the content from the result.
var client = new HttpClient();
var cancel = new CancellationTokenSource();
cancel.CancelAfter(TimeSpan.FromSeconds(10));
var resp = client.GetAsync("http://www.google.co.uk", cancel.Token).Result;
So, in the above, provided we get enough back from the server for the GetAsync to complete, the cancellation has no effect.