Consuming WebApi Self Host over SSL/TLS - c#

I have a WebApi self hosted console server over SSL.
The server takes care of creating the SSL certificates, adding them to the certificate store and binds the certificate to the port using netsh all on the fly.
The server has a simple controller that returns the string "Hello World" through HTTP GET.
I can access it through the browser without any problems and I am quite certain there is nothing wrong with the server code so I am only going to post the troubled client code here.
private static string url = #"https://localhost:4443/WebApi/Service/HelloWorld;
private static async Task GetHelloWorldRequest(string url)
{
using (HttpClient httpClient = new HttpClient(GetSSLHandler()))
{
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Get;
request.RequestUri = new Uri(url);
await httpClient
.SendAsync(request)
.ContinueWith((response)
=>
{
try
{
ProcessResponse(response);
}
catch (AggregateException agException)
{
throw new Exception("Error getting response: " + agException.Message);
}
}).ConfigureAwait(false);
}
}
private static void ProcessResponse(Task<HttpResponseMessage> response)
{
Console.WriteLine(response.Result.Content.ReadAsStringAsync().Result);
}
private static void ProcessResponseHeaders(Task<HttpResponseMessage> response)
{
Console.WriteLine(response.Result.Headers.ToString());
}
private static WebRequestHandler GetSSLHandler()
{
WebRequestHandler handler = new WebRequestHandler();
X509Certificate2 certificate = GetMyX509Certificate();
handler.ClientCertificates.Add(certificate);
return handler;
}
Now in my main routine I simply call this:
Console.WriteLine("Response headers:");
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
Task task = GetHelloWorldRequest(url);
task.Wait();
Now my problem is if I try to read the response content which should give me "Hello World" it gives me an empty string instead.
So I tried looking at the response headers and this is what I get:
It seems to be it is going through the negotiation phase and I don't know what to do from here.
Please advice. Thank you in advance.
EDIT:
Sorry the problem is with the server code. Simply uncomment the section calling httpBinding.ConfigureTransportBindingElement.
class SslHttpsSelfHostConfiguration : HttpSelfHostConfiguration
{
public SslHttpsSelfHostConfiguration(string baseAddress) : base(baseAddress) { }
public SslHttpsSelfHostConfiguration(Uri baseAddress) : base(baseAddress) { }
protected override BindingParameterCollection OnConfigureBinding(HttpBinding httpBinding)
{
httpBinding.Security.Mode = HttpBindingSecurityMode.Transport;
/*
httpBinding.ConfigureTransportBindingElement = (element =>
element.AuthenticationScheme =
AuthenticationSchemes.Negotiate);
*/
return base.OnConfigureBinding(httpBinding);
}
}

Please try running this:
var client = new HttpClient
{
BaseAddress = new Uri("https://localhost:4443/")
};
var result = await client.GetAsync("WebApi/Service/HelloWorld").ConfigureAwait(false);
var data = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
return data;
as your Request task.
And try changing the
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
to
ServicePointManager.ServerCertificateValidationCallback += (sender, cert, chain, sslPolicyErrors) => true;

Related

bytes[] not receiving at web api using HttpClient C#

I'm sending bytes[] to .net core web api method(from Windows application to web API) by using HttpClient with below code
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
clientHandler.UseDefaultCredentials = true;
// Pass the handler to httpclient(from you are calling api)
HttpClient client2 = new HttpClient(clientHandler);
client2.DefaultRequestHeaders.Clear();
//client2.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/octet-stream"));
client2.DefaultRequestHeaders.TryAddWithoutValidation("Content-Type", "application/octet-stream"); // octet-stream");
client2.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/octet-stream");
client2.DefaultRequestHeaders.TryAddWithoutValidation("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64; rv:19.0) Gecko/20100101 Firefox/19.0");
//client2.DefaultRequestHeaders.Add("Accept", "application/octet-stream");
var content = new ByteArrayContent(fileData);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
var response = client2.PostAsync("https://mywebsite.com/api/FileHandlingAPI/UploadFiles?filePath=abc", content).Result;
and web api method is
[Route("UploadFiles")]
[HttpPost]
public ActionResult PostDataHello([FromBody]byte[] rawData,string filePath)
{
try
{
System.IO.File.WriteAllBytes(#"C:\WordAutomation\home.zip", rawData);
return StatusCode(200);
}
catch (Exception ex)
{
return StatusCode(500, $"Error. msg: {ex.Message}");
}
}
above code working while development but after hosting in server it is not working as expected. var response receiving 200 Statuscode but bytes[] not receiving at web api method.
any suggestions or changes required above code ?
I think the Content-Type is set to JSON, which is invalid for uploading binary data in the payload.
Try
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/octet-stream");
Above code working while development but after hosting in server it is
not working as expected. var response receiving 200 Statuscode but
bytes[] not receiving at web api method. any suggestions or changes
required above code?
Well, not sure how are getting data on local server becuse, you are sending MultipartFormData means your POCO object which is file path and byte array. As you may know we can send json object in FromBody but not the files as json. Thus, I am not sure how it working in local, and getting null data is logical either in server like IIS Or Azure.
My take on this, for sending both POCO object and Files as byte or stream we need to use FromForm and beside that, we need to bind our request object as MultipartFormDataContent to resolve your null data on your PostDataHello API action.
Required Change For Http Client:
Http Client Request Model:
public class HttpClientReqeustModel
{
public string FilePath { get; set; }
public string FileName { get; set; }
public byte[] MyByteData { get; set; }
}
Http Client Request:
public async Task<IActionResult> SendByteDataToAPIControllre()
{
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
clientHandler.UseDefaultCredentials = true;
HttpClient client2 = new HttpClient(clientHandler);
client2.DefaultRequestHeaders.Clear();
//Bind Request Model
var requestMode = new HttpClientReqeustModel();
requestMode.MyByteData = System.IO.File.ReadAllBytes(#"D:\YourFile.pdf");
requestMode.FilePath = #"D:\YourFilePath.pdf";
requestMode.FileName = "YourFileNameYourWantToSet.pdf";
//Create Multipart Request
var formContent = new MultipartFormDataContent();
formContent.Add(new StringContent(requestMode.FilePath), "FilePath");
formContent.Add(new StreamContent(new MemoryStream(requestMode.MyByteData)), "MyByteData", requestMode.FileName);
var response = await client2.PostAsync("http://localhost:5094/UploadFiles", formContent);
return Ok();
}
Change For Asp.net Core Web API:
API Model:
public class APIRequestModel
{
public string FilePath { get; set; }
public IFormFile MyByteData { get; set; }
}
Controller:
[Route("UploadFiles")]
[HttpPost]
public async Task<ActionResult> PostDataHello([FromForm] APIRequestModel requestModel)
{
try
{
var path = Path.Combine(_environment.WebRootPath, "WordAutomation/",requestModel.MyByteData.FileName);
using (FileStream stream = new FileStream(path, FileMode.Create))
{
await requestModel.MyByteData.CopyToAsync(stream);
stream.Close();
}
// System.IO.File.WriteAllBytes(#"C:\WordAutomation\home.zip", rawData);
return StatusCode(200);
}
catch (Exception ex)
{
return StatusCode(500, $"Error. msg: {ex.Message}");
}
}
Output:
Update:
For WinForm and WPF App:
private async void button1_Click(object sender, EventArgs e)
{
HttpClientHandler clientHandler = new HttpClientHandler();
clientHandler.ServerCertificateCustomValidationCallback = (sender, cert, chain, sslPolicyErrors) => { return true; };
clientHandler.UseDefaultCredentials = true;
HttpClient client2 = new HttpClient(clientHandler);
client2.DefaultRequestHeaders.Clear();
//Bind Request Model
var requestMode = new HttpClientReqeustModel();
requestMode.MyByteData = System.IO.File.ReadAllBytes(#"D:\Md Farid Uddin Resume.pdf");
requestMode.FilePath = #"D:\Md Farid Uddin Resume.pdf";
requestMode.FileName = "MyFilename.pdf";
//Create Multipart Request
var formContent = new MultipartFormDataContent();
formContent.Add(new StringContent(requestMode.FilePath), "FilePath");
formContent.Add(new StreamContent(new MemoryStream(requestMode.MyByteData)), "MyByteData", requestMode.FileName);
var response = await client2.PostAsync("http://localhost:5094/UploadFiles", formContent);
}
Output:

Set AllowAutoRedirect false in existing HttpClient for just one request

This answer to the question on how to make HttpClient not follow redirects gives a solution to be set upon creating the actual client:
var handler = new HttpClientHandler { AllowAutoRedirect = false };
var client = new HttpClient(handler);
The comment below the answer is my actual question:
Is it possible to do this on a per-request basis without needing two separate HttpClient instances (i.e. one that allows redirects and one that does not)?
I have a specific reason too for now wanting separate clients: I want the client to retain its cookies from earlier requests. I'm trying to do a few requests first that include valid redirects, but only the last one in the chain I don't want to be a redirect.
I've searched, and looked through the overloads of .GetAsync(url, ...), and looked through the properties and methods of HttpClient, but found no solution yet.
Is this possible?
Yes, you can set the properties of the HttpClientHandler per each request, like so:
using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
handler.AllowAutoRedirect = false;
// do your job
handler.AllowAutoRedirect = true;
}
Just make sure that only one thread consumes the HttpClient at a time, if the client handler settings are different.
Example (note: only works in test environment)
Dummy remote server with Node.js runnin on localhost:
const express = require('express')
const app = express()
const cookieParser = require('cookie-parser')
const session = require('express-session')
const port = 3000
app.use(cookieParser());
app.use(session({secret: "super secret"}))
app.get('/set-cookie/:cookieName', (req, res) => {
const cookie = Math.random().toString()
req.session[req.params.cookieName] = cookie
res.send(cookie)
});
app.get('/ok', (req, res) => res.send('OK!'))
app.get('/redirect-301', (req, res) => {
res.writeHead(301, {'Location': '/ok'})
res.end();
})
app.get('/get-cookie/:cookieName', (req, res) => res.send(req.session[req.params.cookieName]))
app.listen(port, () => console.log(`App listening on port ${port}!`))
Tests
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;
using NUnit.Framework;
public class Tests
{
private HttpClientHandler handler;
private HttpClient client;
private CookieContainer cookieJar = new CookieContainer();
private string cookieName = "myCookie";
private string cookieValue;
[SetUp]
public void Setup()
{
handler = new HttpClientHandler()
{
AllowAutoRedirect = true,
CookieContainer = cookieJar
};
client = new HttpClient(handler);
}
[Test]
public async Task Test0()
{
using (var response = await client.GetAsync($"http://localhost:3000/set-cookie/{cookieName}"))
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
cookieValue = await response.Content.ReadAsStringAsync();
}
}
[Test]
public async Task Test1()
{
handler.AllowAutoRedirect = true;
using (var response = await client.GetAsync("http://localhost:3000/redirect-301"))
{
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.AreEqual(await response.Content.ReadAsStringAsync(), "OK!");
}
}
[Test]
public async Task Test2()
{
handler.AllowAutoRedirect = false;
using (var response = await client.GetAsync("http://localhost:3000/redirect-301"))
{
Assert.AreEqual(HttpStatusCode.MovedPermanently, response.StatusCode);
}
}
[Test]
public async Task Test3()
{
using (var response = await client.GetAsync($"http://localhost:3000/get-cookie/{cookieName}"))
{
Assert.AreEqual(await response.Content.ReadAsStringAsync(), cookieValue);
}
}
}
Output via dotnet test:
Test Run Successful.
Total tests: 4
Passed: 4
Total time: 0.9352 Seconds
The question asks whether following redirects can be done on a case-by-case basis. While certainly useful for many common cases, I found the existing answers lacking in that regard.
The following implementation allows the decision on whether to follow a redirect or not to be configured on a true case-by-case basis via a predicate.
The solution is to override the SendAsync() method of HttpClientHandler.
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace HttpClientCustomRedirectBehavior
{
static class Program
{
private const string REDIRECTING_URL = "http://stackoverflow.com/";
static async Task Main(string[] args)
{
HttpMessageHandler followRedirectAlwaysHandler = new RestrictedRedirectFollowingHttpClientHandler(
response => true);
HttpMessageHandler followRedirectOnlyToSpecificHostHandler = new RestrictedRedirectFollowingHttpClientHandler(
response => response.Headers.Location.Host == "example.com");
HttpResponseMessage response;
using (HttpClient followRedirectAlwaysHttpClient = new HttpClient(followRedirectAlwaysHandler))
{
response = await followRedirectAlwaysHttpClient.GetAsync(REDIRECTING_URL);
Console.WriteLine(response.StatusCode); // OK
}
using (HttpClient followRedirectOnlyToSpecificHostHttpClient = new HttpClient(followRedirectOnlyToSpecificHostHandler))
{
response = await followRedirectOnlyToSpecificHostHttpClient.GetAsync(REDIRECTING_URL);
Console.WriteLine(response.StatusCode); // Moved
}
followRedirectOnlyToSpecificHostHandler = new RestrictedRedirectFollowingHttpClientHandler(
response => response.Headers.Location.Host == "stackoverflow.com");
using (HttpClient followRedirectOnlyToSpecificHostHttpClient = new HttpClient(followRedirectOnlyToSpecificHostHandler))
{
response = await followRedirectOnlyToSpecificHostHttpClient.GetAsync(REDIRECTING_URL);
Console.WriteLine(response.StatusCode); // OK
}
}
}
public class RestrictedRedirectFollowingHttpClientHandler : HttpClientHandler
{
private static readonly HttpStatusCode[] redirectStatusCodes = new[] {
HttpStatusCode.Moved,
HttpStatusCode.Redirect,
HttpStatusCode.RedirectMethod,
HttpStatusCode.TemporaryRedirect,
HttpStatusCode.PermanentRedirect
};
private readonly Predicate<HttpResponseMessage> isRedirectAllowed;
public override bool SupportsRedirectConfiguration { get; }
public RestrictedRedirectFollowingHttpClientHandler(Predicate<HttpResponseMessage> isRedirectAllowed)
{
AllowAutoRedirect = false;
SupportsRedirectConfiguration = false;
this.isRedirectAllowed = response => {
return Array.BinarySearch(redirectStatusCodes, response.StatusCode) >= 0
&& isRedirectAllowed.Invoke(response);
};
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
int redirectCount = 0;
HttpResponseMessage response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
while (isRedirectAllowed.Invoke(response)
&& (response.Headers.Location != request.RequestUri || response.StatusCode == HttpStatusCode.RedirectMethod && request.Method != HttpMethod.Get)
&& redirectCount < this.MaxAutomaticRedirections)
{
if (response.StatusCode == HttpStatusCode.RedirectMethod)
{
request.Method = HttpMethod.Get;
}
request.RequestUri = response.Headers.Location;
response = await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
++redirectCount;
}
return response;
}
}
}
The Main method shows three example requests to http://stackoverflow.com (which is a URI that redirects to https://stackoverflow.com):
The first GET request will follow the redirect and therefore we see the status code OK of the response to the redirected request, because the handler is configured to follow all redirects.
The second GET request will not follow the redirect and therefore we see the status code Moved, because the handler is configured to follow redirects to the host example.com exclusively.
The third GET request will follow the redirect and therefore we see the status code OK of the response to the redirected request, because the handler is configured to follow redirects to the host stackoverflow.com exclusively.
Of course, you can substitute any custom logic for the predicate.
As you've probably discovered, you're not allowed to change the HttpClientHandler configuration after a request has been made.
Because your motivation for wanting to do this is to maintain the cookies between requests, then I propose something more like this (no exception/null reference handling included):
static CookieContainer cookieJar = new CookieContainer();
static async Task<HttpResponseMessage> GetAsync(string url, bool autoRedirect)
{
HttpResponseMessage result = null;
using (var handler = new HttpClientHandler())
using (var client = new HttpClient(handler))
{
handler.AllowAutoRedirect = autoRedirect;
handler.CookieContainer = cookieJar;
result = await client.GetAsync(url);
cookieJar = handler.CookieContainer;
}
return result;
}
Test:
static async Task Main(string[] args)
{
string url = #"http://stackoverflow.com";
using (var response = await GetAsync(url, autoRedirect: false))
{
Console.WriteLine($"HTTP {(int)response.StatusCode} {response.StatusCode}");
Console.WriteLine($"{response.Headers}");
Console.WriteLine("Cookies:");
Console.WriteLine($"{cookieJar.GetCookieHeader(new Uri(url))}\r\n");
}
Console.WriteLine(new string('-', 30));
using (var response = await GetAsync(url, autoRedirect: true))
{
Console.WriteLine($"HTTP {(int)response.StatusCode} {response.StatusCode}");
Console.WriteLine($"{response.Headers}");
Console.WriteLine("Cookies:");
Console.WriteLine($"{cookieJar.GetCookieHeader(new Uri(url))}\r\n");
}
Console.ReadLine();
}

Azure .NET Core Appservice locks up sending 502.3 because of async calls

I have this method running in a .NET Core 2.X app running in Azure app service. I have a remote server that we use this method to call from button presses in our Angular website. that calls a remote device.
Angular button --> .NET Core app service in Azure --> another app service --> internet\cell connected device. We wait for the response from the device to return a status code.
If I quickly send commands [2 or 3 in a second] to this method it causes the app service to stop responding until I restart it. I read this post and added the [, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false)].
However I can still freeze the entire app and require a restart from quickly sending commands to this method.
private async void SetEndPointValueAsync(string stunnelUrl, string username, string password)
{
try
{
//set the user name and password
var httpClientHandler = new HttpClientHandler()
{
Credentials = new NetworkCredential(username, password)
};
using (var client = new HttpClient(httpClientHandler))
{
using (var response = await client.GetAsync(stunnelUrl**, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false)**)
{
if (response.IsSuccessStatusCode)
{
LogInfo(typeof(IntegrationService), stunnelUrl, LogAction.EndpointUpdate);
}
else
{
//request failed.
LogWarning(typeof(IntegrationService), stunnelUrl, LogAction.DeviceRequest);
}
//using (var content = response.Content)
//{
// //do here your changes when required
//}
}
}
}
catch (Exception e)
{
LogErrorDetailed(e, typeof(IntegrationService), stunnelUrl, LogAction.DeviceRequest);
}
}
Generally, you don't want to create so many instances of HttpClient as you lose a lot of the benefits of the management it provides.
You could reduce some overhead by only having a single instance of it, like so...
private readonly HttpClient _client;
public ClassConstructor(HttpClient client)
{
_client = client ?? new HttpClient();
}
Then you could change your method to look something like this...
private async Task SetEndPointValueAsync(Uri stunnelUri, string username, string password)
{
if (stunnelUri == null) throw new ArgumentNullException(nameof(stunnelUri));
if (String.IsNullOrEmpty(username)) throw new ArgumentNullException(nameof(username));
if (String.IsNullOrEmpty(password)) throw new ArgumentNullException(nameof(password));
byte[] byteArray = Encoding.ASCII.GetBytes($"{username}:{password}");
string scheme = "Basic";
string parameter = Convert.ToBase64String(byteArray);
HttpRequestMessage request = new HttpRequestMessage();
request.Method = HttpMethod.Post;
request.RequestUri = stunnelUri;
request.Headers.Authorization = new AuthenticationHeaderValue(scheme, parameter);
try
{
HttpResponseMessage response = await _client.SendAsync(request);
// This will throw an HttpRequestException if there is a failure above
response.EnsureSuccessStatusCode();
// do your stuff here...
// { ... }
}
catch (HttpRequestException)
{
// { log your connection / bad request issue. }
}
catch (Exception)
{
// I don't recommend this, but since you had it...
// { handle all other exceptions }
}
}

Passing Windows Authentication to Proxy using HttpClient

I've trying to pass Windows Authentication to a WebProxy, so that a user doesn't have to type in his login data manually.
The use case is a proxy server which checks authentication against a LDAP/AD server, while the users have to change their password periodically.
I've got the following code:
private void button1_ClickAsync(object sender, EventArgs e) {
Url = "http://local.adress/test";
Execute();
}
private void button2_Click(object sender, EventArgs e) {
Url = "https://maps.googleapis.com/maps/api/timezone/json";
Execute();
}
private void Execute() {
var handler = new HttpClientHandler();
handler.DefaultProxyCredentials = CredentialCache.DefaultCredentials;
handler.UseDefaultCredentials = true;
handler.UseProxy = true;
handler.Proxy = WebRequest.DefaultWebProxy;
handler.Proxy.Credentials = new NetworkCredential("mydomainuser", "mydomainpassword");
//handler.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
var client = new HttpClient(handler);
Task<string> response = TestConnection(client, Url);
}
private async Task<string> TestConnection(HttpClient client, string url) {
try {
using (HttpResponseMessage result = await client.GetAsync(url)) {
string res = await result.Content.ReadAsStringAsync().ConfigureAwait(false);
Console.WriteLine("content: " + res);
return result.ToString();
}
} catch (Exception e) {
Console.WriteLine("error: " + e.Message);
return e.ToString();
}
}
When defining the credentials manually (as you can see in the Execute method), everythings works as expected. I've checked the proxy log files to be sure the request is really forwarded through the proxy.
Since it's my goal to spare the user to type in his probably periodically changing password, I've tried to pass the credentials via the CredentialCache.DefaultNetworkCredentials (I've also tried CredentialCache.DefaultCredentials). While executing the request the proxy logs an DENIED and my client returns HTTP error code 407.
Am I missing something obvious? I know there are countless questions on this topic but nothing seems to solve this problem.
You have to define proxy and main URL in code.
var TARGETURL = "http://en.wikipedia.org/";
HttpClientHandler handler = new HttpClientHandler()
{
Proxy = new WebProxy("http://127.0.0.1:8888"),
UseProxy = true,
};
try this.
handler.Proxy.Credentials = CredentialCache.DefaultNetworkCredentials;
handler.Credentials = CredentialCache.DefaultNetworkCredentials;
ok so your webserivces uses windows authentication.
Your desktop client is working under your credential you need impersonation
https://learn.microsoft.com/en-us/dotnet/api/system.security.principal.windowsidentity.impersonate?view=netframework-4.8
check this if it works for you if it is basic authentication.
HttpClient client = new HttpClient(handler);
**var byteArray = Encoding.ASCII.GetBytes("username:password1234");**
**client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));**

Don`t able to save token from RestSharp OAuth request Windows Phone 8.1

I trying to get Request Token from Trello with RestSharp. I got token only in request thread, but dont able to save it in variable of my app.
There some code:
private async void GetToken()
{
app.Client.Authenticator = OAuth1Authenticator.ForRequestToken(app.ConsumerKey, app.ConsumerSecret);
var request = new RestRequest("OAuthGetRequestToken", Method.POST);
app.Client.ExecuteAsync(request, HandleResponse);
}
private void HandleResponse(IRestResponse restResponse)
{
var Response = restResponse;
MessageBox.Show(Response.Content);
QueryString qs = new QueryString(Response.Content);
app.OAuthToken = qs["oauth_token"];
app.OAuthTokenSecret = qs["oauth_token_secret"];
app.Verifier = qs["verifier"];
MessageBox.Show(app.OAuthToken); //got token here, but after
MessageBox.Show(app.OAuthTokenSecret); //I don`t have anything in this variables
}
Have you any ideas?
Solution to this problem is to create class that enable me to create synchronous request.
There is code of this class:
public static class RestClientExtensions
{
public static Task<IRestResponse> ExecuteTask(this IRestClient client, RestRequest request)
{
var TaskCompletionSource = new TaskCompletionSource<IRestResponse>();
client.ExecuteAsync(request, (response, asyncHandle) =>
{
if (response.ResponseStatus == ResponseStatus.Error)
TaskCompletionSource.SetException(response.ErrorException);
else
TaskCompletionSource.SetResult(response);
});
return TaskCompletionSource.Task;
}
}
And now my code looks like this:
private async void GetToken()
{
app.Client.Authenticator = OAuth1Authenticator.ForRequestToken(app.ConsumerKey, app.ConsumerSecret);
RestRequest request = new RestRequest("OAuthGetRequestToken", Method.POST);
IRestResponse restResponse = await app.Client.ExecuteTask(request);
HandleResponse(restResponse);
GetAccesToken();
}
private void HandleResponse(IRestResponse response)
{
var Response = response;
System.Diagnostics.Debug.WriteLine(Response.Content);
QueryString qs = new QueryString(Response.Content);
app.OAuthToken = qs["oauth_token"];
app.OAuthTokenSecret = qs["oauth_token_secret"];
System.Diagnostics.Debug.WriteLine(app.OAuthToken);
System.Diagnostics.Debug.WriteLine(app.OAuthTokenSecret);
}
And after the method HandleResponse(response); performed, I have the token and token secret in my app class.
I still believe that there must be better solution for this problem, but it is the only one that I know.

Categories