Accessing Facebook API using C# await and stuck forever - c#

I'm trying to implement Facebook login and get data in c# project.
what I'm trying to do is that user press his firstname and password then he press on the login button and login then it return his data.
the when I press on the button the program is freeze.
that's my project implementation
Account.cs
public class Account
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Birthday { get; set; }
}
Facebook.client
public interface IFacebookClient
{
Task<T> GetAsync<T>(string accessToken, string endpoint, string args = null);
Task PostAsync(string accessToken, string endpoint, object data, string args = null);
}
public class FacebookClient : IFacebookClient
{
private readonly HttpClient _httpClient;
public FacebookClient()
{
_httpClient = new HttpClient
{
BaseAddress = new Uri("https://graph.facebook.com/v2.8/")
};
_httpClient.DefaultRequestHeaders
.Accept
.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public async Task<T> GetAsync<T>(string accessToken, string endpoint, string args = null)
{
var response = await _httpClient.GetAsync($"{endpoint}?access_token={accessToken}&{args}");
if (!response.IsSuccessStatusCode)
return default(T);
var result = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(result);
}
public async Task PostAsync(string accessToken, string endpoint, object data, string args = null)
{
var payload = GetPayload(data);
await _httpClient.PostAsync($"{endpoint}?access_token={accessToken}&{args}", payload);
}
private static StringContent GetPayload(object data)
{
var json = JsonConvert.SerializeObject(data);
return new StringContent(json, Encoding.UTF8, "application/json");
}
}
FacebookService.cs
public interface IFacebookService
{
Task<Account> GetAccountAsync(string accessToken);
Task PostOnWallAsync(string accessToken, string message);
}
public class FacebookService : IFacebookService
{
private readonly IFacebookClient _facebookClient;
public FacebookService(IFacebookClient facebookClient)
{
_facebookClient = facebookClient;
}
public async Task<Account> GetAccountAsync(string accessToken)
{
var result = await _facebookClient.GetAsync<dynamic>(
accessToken, "me", "fields=id,name,birthday,email");
if (result == null)
{
return new Account();
}
var account = new Account
{
Id = result.id,
Email = result.email,
Name = result.name,
Birthday = result.Birthday
};
return account;
}
public async Task PostOnWallAsync(string accessToken, string message)
=> await _facebookClient.PostAsync(accessToken, "me/feed", new {message});
}
FacebookSettings.cs
var facebookClient = new FacebookClient();
var facebookService = new FacebookService(facebookClient);
var getAccountTask = facebookService.GetAccountAsync(FacebookSettings.AccessToken);
Task.WaitAll(getAccountTask);
var account = getAccountTask.Result;
Console.WriteLine($"{account.Id} {account.Name}");
Login form button
private void btn_facebook_Click(object sender, EventArgs e)
{
var facebookClient = new FacebookClient();
var facebookService = new FacebookService(facebookClient);
var getAccountTask = facebookService.GetAccountAsync(FacebookSettings.AccessToken);
Task.WaitAll(getAccountTask);
var account = getAccountTask.Result;
//Console.WriteLine($"{account.Id} {account.Name}");
}
it stuck on this line on the await
public async Task<Account> GetAccountAsync(string accessToken)
{
var result = await _facebookClient.GetAsync<dynamic>(accessToken, "me", "fields=id,name,birthday,email");
if (result == null)
{
return new Account();
}
var account = new Account
{
Id = result.id,
Email = result.email,
Name = result.name,
Birthday = result.Birthday
};
return account;
}
in this line
var result = await _facebookClient.GetAsync<dynamic>(accessToken, "me", "fields=id,name,birthday,email");

Here's your problem:
Task.WaitAll(getAccountTask);
Don't block on async code. Use await instead:
private async void btn_facebook_Click(object sender, EventArgs e)
{
var facebookClient = new FacebookClient();
var facebookService = new FacebookService(facebookClient);
var account = await facebookService.GetAccountAsync(FacebookSettings.AccessToken);
}

Related

ASP.NET Core - How to check if a field exists from a given third party API before sending Email

In my ASP.NET Core-6 Web API, I am given a third party API to consume and then return the account details. I am using HttpClient.
api:
https://api.thirdpartycompany.com:2233/UserAccount/api/AccountDetail?accountNumber=
In appsettings.json I have:
"Endpoints": {
"customerUrl": "https://api.thirdpartycompany.com:2233/UserAccount/api/AccountDetail?accountNumber="
}
DTO:
public class GetCustomerDetailDto
{
public class CustomerDetail
{
public string AccountNumber { get; set; }
public string Fullname { get; set; }
public string EmailAddress { get; set; }
}
}
Then I have this Data Util:
public class DataUtil : IDataUtil
{
private readonly IConfiguration _config;
private readonly ILogger<DataUtil> _logger;
private readonly HttpClient _myClient;
public DataUtil
(
IConfiguration config,
ILogger<DataUtil> logger,
HttpClient myClient
)
{
_config = config;
_logger = logger;
_myClient = myClient;
}
public CustomerDetail GetCustomerDetail(string accountNumber)
{
var responseResults = new CustomerDetail();
try
{
string custAccountNoUrl = _config.GetSection("Endpoints").GetValue<string>("customerUrl") + accountNumber;
_myClient.DefaultRequestHeaders.Accept.Clear();
_myClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = _myClient.GetAsync(custAccountNoUrl).Result;
if (response.IsSuccessStatusCode)
{
var stringResult = response.Content.ReadAsStringAsync().Result;
responseResults = JsonConvert.DeserializeObject<CustomerDetail>(stringResult);
}
}
catch (Exception ex)
{
_logger.LogError($"An Error occured " + ex.ToString());
}
return responseResults;
}
}
Then this is the implementation:
public async Task<Response<string>> CreateCustomerDetailAsync(CreateDto requestDto)
{
var response = new Response<string>();
var accDetail = _dataAccess.GetCustomerDetail(requestDto.DrAccountNumber);
if (accDetail.EmailAddress != null)
{
var accountName = accDetail.Fullname;
var emailAddress = accDetail.EmailAddress.ToLower();
var mailBody = await EmailBodyBuilder.GetCustomerEmailBody(accountName, emailTempPath: "wwwroot/files/Html/CustomerEmail.html");
var mailRequest = new MailRequest()
{
Subject = "Customer Notification",
Body = mailBody,
ToEmail = emailAddress
};
bool emailResult = await _mailService.SendEmailAsync(mailRequest);
if (emailResult)
{
response.StatusCode = (int)HttpStatusCode.OK;
response.Successful = true;
response.Message = "Successful!";
return response;
}
}
}
From the third-party API given, there are moments when the customer does not have email address, then the EmailAddress field will not even appear at all from the response.
So that made me to get error here:
bool emailResult = await _mailService.SendEmailAsync(mailRequest);
I tried
if (accDetail.EmailAddress != null)
but it's not solving the problem.
Making use of
public async Task<Response<string>> CreateCustomerDetailAsync(CreateDto requestDto)
How do I make the application not to send email at all whenever EmailAddress field does not exist or it's null?

How do I get a value associated with a user model class property for login redirection with access token?

UsuarioModel Class
public class UsuarioModel
{
public int CodUsuario { get; set; }
public string Nome { get; set; }
public string Senha { get; set; }
public string Telefone { get; set; }
public DateTime DataRegisto { get; set; }
public bool Estado { get; set; }
public int CodPerfil { get; set; }
}
Login ApiService Method
public async Task<string> LoginAsync(string nome, string senha)
{
var keyValues = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("username", nome),
new KeyValuePair<string, string>("password", senha),
new KeyValuePair<string, string>("grant_type", "password")
};
var request = new HttpRequestMessage(HttpMethod.Post, Constants.BaseApiAddress + "token");
request.Content = new FormUrlEncodedContent(keyValues);
var client = new HttpClient();
var response = await client.SendAsync(request);
var content = await response.Content.ReadAsStringAsync();
JObject jwtDynamic = JsonConvert.DeserializeObject<dynamic>(content);
var accessTokenExpiration = jwtDynamic.Value<DateTime>(".expires");
var accessToken = jwtDynamic.Value<string>("access_token");
Settings.AccessTokenExpirationDate = accessTokenExpiration;
Debug.WriteLine(accessTokenExpiration);
Debug.WriteLine(content);
return accessToken;
}
This method works correctly by generating the access token. But my question is: how can I get the value of the 'CodPerfil' of this user who received the access token to validate the Menu that he should be directed to?
ViewModel
public class LoginViewModel : BaseViewModel
{
private readonly ApiServices _apiServices = new ApiServices();
public string Nome { get; set; }
public string Senha { get; set; }
public ICommand LoginCommand
{
get
{
return new Command(async () =>
{
var accesstoken = await _apiServices.LoginAsync(Nome, Senha);
Settings.AccessToken = accesstoken;
Login();
});
}
}
public async void Login()
{
var usuario = new UsuarioModel
{
Nome = Nome,
Senha = Senha,
CodPerfil = CodPerfil
};
Settings.CodPerfil = CodPerfil;
if (CodPerfil == 1)
{
App.Current.MainPage = new MenuMorador();
}
else
{
App.Current.MainPage = new MenuRecolhedor();
}
}
public LoginViewModel()
{
Nome = Settings.Nome;
Senha = Settings.Senha;
}
When I execute this method through the breakpoints, the 'CodPerfil' variable does not receive any value. The question is: How to receive the value of the 'CodPerfil' property that is associated with the user already registered in order to validate the menu to which they will be directed after receiving the access token?
Startup Class
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
GlobalConfiguration.Configure(WebApiConfig.Register);
}
public void ConfigureAuth(IAppBuilder app)
{
//this is very important line cross orgin source(CORS)it is used to enable cross-site HTTP requests
//For security reasons, browsers restrict cross-origin HTTP requests
app.UseCors(CorsOptions.AllowAll);
var OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(10),//token expiration time
Provider = new OauthProvider()
};
app.UseOAuthBearerTokens(OAuthOptions);
app.UseOAuthAuthorizationServer(OAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
HttpConfiguration config = new HttpConfiguration();
WebApiConfig.Register(config);//register the request
}
}
OauthProvider Class
public class OauthProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
await Task.Run(() => context.Validated());
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
using (var db = new DataContext2())
{
if (db != null)
{
var user = db.Usuario.Where(o => o.Nome == context.UserName && o.Senha == context.Password).FirstOrDefault();
if (user != null)
{
identity.AddClaim(new Claim(ClaimTypes.Role, user.CodPerfil.ToString()));
identity.AddClaim(new Claim(ClaimTypes.Name, user.Nome));
identity.AddClaim(new Claim("LoggedOn", DateTime.Now.ToString()));
await Task.Run(() => context.Validated(identity));
}
else
{
context.SetError("Wrong Crendtials", "Provided username and password is incorrect");
}
}
else
{
context.SetError("Wrong Crendtials", "Provided username and password is incorrect");
}
return;
}
}
}

Non-static class get the data across other classes

I'm fairly new to C# so go easy on me.
I have a class UserData.
public class UserData
{
public int UserId { get; set; }
public string Token { get; set; }
public string ConversationID { get; set; }
}
And instantiate it in my main class.
public class Main {
var userDataObjects = new UserData();
userDataObjects.UserId = 5;
userDataObjects.Token = "sampleXh123xczx";
userDataObjects.ConversationID = "2";
protected DialogsTurn _GetDialog;
public main(){
_GetDialog = new DiagsTurn();
}
public override async Task OnTurnAsync()
{
await _GetDialog.GetNextDialog();
}
}
public class DialogsTurn : Controller
{
private readonly HttpClient client = new HttpClient();
private const string BASE_URL = "https://sample.net";
var userDataObjects = new UserData();
public async Task GetNextDialog()
{
HttpRequestMessage request = new HttpRequestMessage(
HttpMethod.Get,
$"{BASE_URL}/api/Dialogs/GetNextDialog?Id={userDataObjects.UserId}");
request.Headers.Add("Accept", "application/json");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", userDataObjects.Token);
var response = await client.SendAsync(request);
if (response.IsSuccessStatusCode)
{
var body = await response.Content.ReadAsStringAsync();
var result = JsonConvert.DeserializeObject<dynamic>(body).result;
UserDataExtractedDto.DialogTurnID = result.dialogId;
}
}
And once it was instantiated I need to call it from other classes.
Let's say in my DialogSTurn class I have a GetNextDialog method and I need the Token and UserId. I know I can that data as a parameter. But it's not the case for my application that I built.

Power Bi: Embedding Report into MVC Site

I have created a power bi report. I want to embed this report to my MVC site. Here is my code:-
private static readonly string ClientID = ConfigurationManager.AppSettings["ClientID"];
private static readonly string ClientSecret = ConfigurationManager.AppSettings["ClientSecret"];
private static readonly string RedirectUrl = ConfigurationManager.AppSettings["RedirectUrl"];
private static readonly string AADAuthorityUri = ConfigurationManager.AppSettings["AADAuthorityUri"];
private static readonly string PowerBiAPI = ConfigurationManager.AppSettings["PowerBiAPI"];
private static readonly string PowerBiDataset = ConfigurationManager.AppSettings["PowerBiDataset"];
private static readonly string baseUri = PowerBiDataset;
private static string accessToken = string.Empty;
public class PBIReports
{
public PBIReport[] value { get; set; }
}
public class PBIReport
{
public string id { get; set; }
public string name { get; set; }
public string webUrl { get; set; }
public string embedUrl { get; set; }
}
public ReportController()
{
try
{
if (Request.Params.Get("code") != null)
{
Session["AccessToken"] = GetAccessToken(
HttpContext.Request["code"],
ClientID,
ClientSecret,
RedirectUrl);
}
if (Session["AccessToken"] != null)
{
accessToken = Session["AccessToken"].ToString();
GetReport(0);
}
}
catch(Exception ex)
{
}
}
public string GetAccessToken(string authorizationCode, string clientID, string clientSecret, string redirectUri)
{
TokenCache TC = new TokenCache();
string authority = AADAuthorityUri;
AuthenticationContext AC = new AuthenticationContext(authority, TC);
ClientCredential cc = new ClientCredential(clientID, clientSecret);
return AC.AcquireTokenByAuthorizationCodeAsync(
authorizationCode,
new Uri(redirectUri), cc).Result.AccessToken;
}
protected void GetReport(int index)
{
System.Net.WebRequest request = System.Net.WebRequest.Create(
String.Format("{0}/Reports",
baseUri)) as System.Net.HttpWebRequest;
request.Method = "GET";
request.ContentLength = 0;
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));
using (var response = request.GetResponse() as System.Net.HttpWebResponse)
{
using (var reader = new System.IO.StreamReader(response.GetResponseStream()))
{
PBIReports Reports = JsonConvert.DeserializeObject<PBIReports>(reader.ReadToEnd());
if (Reports.value.Length > 0)
{
var report = Reports.value[index];
ViewBag["ReportId"] = report.id;
ViewBag["EmbedUrl"] = report.embedUrl;
ViewBag["ReportName"] = report.name;
ViewBag["WebUrl"] = report.webUrl;
}
}
}
}
public void GetAuthorizationCode()
{
var #params = new NameValueCollection
{
{"response_type", "code"},
{"client_id", ClientID},
{"resource", PowerBiAPI},
{ "redirect_uri", RedirectUrl}
};
var queryString = HttpUtility.ParseQueryString(string.Empty);
queryString.Add(#params);
Response.Redirect(String.Format(AADAuthorityUri + "?{0}", queryString));
}
public ActionResult Index()
{
GetAuthorizationCode();
return View();
}
On Redirecting to "Report Page", it goes for power bi login page and after I sign in it redirects back to this page (as homepage and redirect url are same). But Request.Params.Get("code") != null is null. HttpContext.Request is also null. Why? Is there anything wrong in the code?
In the constructor of a controller you don't have the this.HttpContext object to your disposal yet. You might have HttpContext.Current, but I am not sure of that.
What you should do is move that code to an action (for example your GetReport action), where you can make your checks.

WP8 HttpClient.PostAsync never returns result

I have a Windows Phone 8 app where I am calling await HttpClient.PostAsync and it never returns a result. It just sits there and hangs. If I run the exact same code from a console app, it returns the result almost immediately. All of the code doing the work resides in a portable class library. I would appreciate any help you may be able to give. All of the other issues I have found on this state to use await client.PostAsync, which I am already doing.
The code in my class library is as such:
public class Authenticator
{
private const string ApiBaseUrl = "http://api.fitbit.com";
private const string Callback = "http://myCallbackUrlHere";
private const string SignatureMethod = "HMAC-SHA1";
private const string OauthVersion = "1.0";
private const string ConsumerKey = "myConsumerKey";
private const string ConsumerSecret = "myConsumerSecret";
private const string RequestTokenUrl = "http://api.fitbit.com/oauth/request_token";
private const string AccessTokenUrl = "http://api.fitbit.com/oauth/access_token";
private const string AuthorizeUrl = "http://www.fitbit.com/oauth/authorize";
private string requestToken;
private string requestTokenSecret;
public string GetAuthUrlToken()
{
return GenerateAuthUrlToken().Result;
}
private async Task<string> GenerateAuthUrlToken()
{
var httpClient = new HttpClient { BaseAddress = new Uri(ApiBaseUrl) };
var timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0);
var oauthTimestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString(CultureInfo.InvariantCulture);
var oauthNonce = DateTime.Now.Ticks.ToString(CultureInfo.InvariantCulture);
var authHeaderValue = string.Format(
"oauth_callback=\"{0}\",oauth_consumer_key=\"{1}\",oauth_nonce=\"{2}\"," +
"oauth_signature=\"{3}\",oauth_signature_method=\"{4}\"," +
"oauth_timestamp=\"{5}\",oauth_version=\"{6}\"",
Uri.EscapeDataString(Callback),
Uri.EscapeDataString(ConsumerKey),
Uri.EscapeDataString(oauthNonce),
Uri.EscapeDataString(this.CreateSignature(RequestTokenUrl, oauthNonce, oauthTimestamp, Callback)),
Uri.EscapeDataString(SignatureMethod),
Uri.EscapeDataString(oauthTimestamp),
Uri.EscapeDataString(OauthVersion));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(
"OAuth",
authHeaderValue);
var content = new StringContent(string.Empty);
var response = await httpClient.PostAsync(RequestTokenUrl, content);
if (response.StatusCode != HttpStatusCode.OK)
{
throw new Exception("Request Token Step Failed");
}
var responseContent = await response.Content.ReadAsStringAsync();
var responseItems = responseContent.Split(new[] { '&' });
this.requestToken = responseItems[0];
this.requestTokenSecret = responseItems[1];
var url = string.Format("{0}?{1}&display=touch", AuthorizeUrl, this.requestToken);
return url;
}
public string CreateSignature(string url, string nonce, string timestamp, string callback)
{
// code removed
return signatureString;
}
private static byte[] StringToAscii(string s)
{
// code removed
return retval;
}
}
I have a console app that calls this library and it works with no problem:
public class Program
{
public static void Main(string[] args)
{
var o = new Program();
o.LinkToFitbit();
}
public void LinkToFitbit()
{
var authenticator = new Authenticator();
// this works and returns the url immediately
var url = authenticator.GetAuthUrlToken();
// code removed
}
}
When I run from my WP8 app, it just hangs when it gets to this line in the library:
var response = await httpClient.PostAsync(RequestTokenUrl, content);
Here is my WP8 code:
public partial class FitbitConnector : PhoneApplicationPage
{
public FitbitConnector()
{
InitializeComponent();
this.AuthenticateUser();
}
private void AuthenticateUser()
{
var authenticator = new Authenticator();
var url = authenticator.GetAuthUrlToken();
// code removed
}
}
This line is blocking the UI thread:
public string GetAuthUrlToken()
{
return GenerateAuthUrlToken().Result;
}
The code after the await httpClient.PostAsync() needs to be executed in the UI thread, but it can't be executed because is is blocked.
So, replace this:
private void AuthenticateUser()
{
var authenticator = new Authenticator();
var url = authenticator.GetAuthUrlToken();
// code removed
}
With this:
private async void AuthenticateUser()
{
var authenticator = new Authenticator();
var url = await authenticator.GenerateAuthUrlToken();
// code removed
}
Notice I am using async and await. You will need to make GenerateAuthUrlToken() public. You can erase GetAuthUrlToken().
In few words, Task<T>.Result is not asynchronous.
Can you post CreateSignature and StringToAscii code ? I am stuck at basic oAuth.
I can get Request token but get "Invalid OAuth Signature" while performing a request for Access Token.
Nexus, here you go. I created an OauthHelper class that I use to build the pieces I need. Have a look below. I hope this helps.
public static class OauthHelper
{
public const string ConsumerKey = "MyKey";
public const string ConsumerSecret = "MySecret";
public const string UriScheme = "https";
public const string HostName = "api.somePlace.com";
public const string RequestPath = "/services/api/json/1.3.0";
public const string OauthSignatureMethod = "HMAC-SHA1";
public const string OauthVersion = "1.0";
public static string BuildRequestUri(Dictionary<string, string> requestParameters)
{
var url = GetNormalizedUrl(UriScheme, HostName, RequestPath);
var allParameters = new List<QueryParameter>(requestParameters.Select(entry => new QueryParameter(entry.Key, entry.Value)));
var normalizedParameters = NormalizeParameters(allParameters);
var requestUri = string.Format("{0}?{1}", url, normalizedParameters);
return requestUri;
}
public static AuthenticationHeaderValue CreateAuthorizationHeader(
string oauthToken,
string oauthNonce,
string oauthTimestamp,
string oauthSignature)
{
var normalizedUrl = GetNormalizedUrl(UriScheme, HostName, RequestPath);
return CreateAuthorizationHeader(oauthToken, oauthNonce, oauthTimestamp, oauthSignature, normalizedUrl);
}
public static AuthenticationHeaderValue CreateAuthorizationHeader(
string oauthToken,
string oauthNonce,
string oauthTimestamp,
string oauthSignature,
string realm)
{
if (string.IsNullOrWhiteSpace(oauthToken))
{
oauthToken = string.Empty;
}
if (string.IsNullOrWhiteSpace(oauthTimestamp))
{
throw new ArgumentNullException("oauthTimestamp");
}
if (string.IsNullOrWhiteSpace(oauthNonce))
{
throw new ArgumentNullException("oauthNonce");
}
if (string.IsNullOrWhiteSpace(oauthSignature))
{
throw new ArgumentNullException("oauthSignature");
}
var authHeaderValue = string.Format(
"realm=\"{0}\"," +
"oauth_consumer_key=\"{1}\"," +
"oauth_token=\"{2}\"," +
"oauth_nonce=\"{3}\"," +
"oauth_timestamp=\"{4}\"," +
"oauth_signature_method=\"{5}\"," +
"oauth_version=\"{6}\"," +
"oauth_signature=\"{7}\"",
realm,
Uri.EscapeDataString(ConsumerKey),
Uri.EscapeDataString(oauthToken),
Uri.EscapeDataString(oauthNonce),
Uri.EscapeDataString(oauthTimestamp),
Uri.EscapeDataString(OauthSignatureMethod),
Uri.EscapeDataString(OauthVersion),
Uri.EscapeDataString(oauthSignature));
var authHeader = new AuthenticationHeaderValue("OAuth", authHeaderValue);
return authHeader;
}
public static string CreateSignature(
string httpMethod,
string oauthToken,
string oauthTokenSecret,
string oauthTimestamp,
string oauthNonce,
Dictionary<string, string> requestParameters)
{
// get normalized url
var normalizedUrl = GetNormalizedUrl(UriScheme, HostName, RequestPath);
return CreateSignature(
httpMethod,
oauthToken,
oauthTokenSecret,
oauthTimestamp,
oauthNonce,
requestParameters,
normalizedUrl);
}
public static string CreateSignature(
string httpMethod,
string oauthToken,
string oauthTokenSecret,
string oauthTimestamp,
string oauthNonce,
Dictionary<string, string> requestParameters,
string realm)
{
if (string.IsNullOrWhiteSpace(httpMethod))
{
throw new ArgumentNullException("httpMethod");
}
if (string.IsNullOrWhiteSpace(oauthToken))
{
oauthToken = string.Empty;
}
if (string.IsNullOrWhiteSpace(oauthTokenSecret))
{
oauthTokenSecret = string.Empty;
}
if (string.IsNullOrWhiteSpace(oauthTimestamp))
{
throw new ArgumentNullException("oauthTimestamp");
}
if (string.IsNullOrWhiteSpace(oauthNonce))
{
throw new ArgumentNullException("oauthNonce");
}
var allParameters = new List<QueryParameter>
{
new QueryParameter("oauth_consumer_key", ConsumerKey),
new QueryParameter("oauth_token", oauthToken),
new QueryParameter("oauth_nonce", oauthNonce),
new QueryParameter("oauth_timestamp", oauthTimestamp),
new QueryParameter("oauth_signature_method", OauthSignatureMethod),
new QueryParameter("oauth_version", OauthVersion)
};
allParameters.AddRange(requestParameters.Select(entry => new QueryParameter(entry.Key, entry.Value)));
// sort params
allParameters.Sort(new QueryParameterComparer());
// concat all params
var normalizedRequestParameters = NormalizeParameters(allParameters);
// create base string
var signatureBase = string.Format(
"{0}&{1}&{2}",
UrlEncode(httpMethod.ToUpperInvariant()),
UrlEncode(realm),
UrlEncode(normalizedRequestParameters));
var signatureKey = string.Format(
"{0}&{1}",
UrlEncode(ConsumerSecret),
UrlEncode(oauthTokenSecret));
// hash the base string
var hmacsha1 = new HMACSHA1(StringToAscii(signatureKey));
var signatureString = Convert.ToBase64String(hmacsha1.ComputeHash(StringToAscii(signatureBase)));
return signatureString;
}
public static string GenerateNonce()
{
var ts = new TimeSpan(DateTime.Now.Ticks);
var ms = ts.TotalMilliseconds.ToString().Replace(".", string.Empty);
var nonce = ms;
return nonce;
}
public static string GenerateTimeStamp()
{
var timeSpan = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0);
var timestamp = Convert.ToInt64(timeSpan.TotalSeconds).ToString(CultureInfo.InvariantCulture);
return timestamp;
}
private static string GetNormalizedUrl(string uriScheme, string hostName, string requestPath)
{
var normalizedUrl = string.Format(
"{0}://{1}{2}",
uriScheme.ToLowerInvariant(),
hostName.ToLowerInvariant(),
requestPath);
return normalizedUrl;
}
private static string NormalizeParameters(IList<QueryParameter> parameters)
{
var result = new StringBuilder();
for (var i = 0; i < parameters.Count; i++)
{
var p = parameters[i];
result.AppendFormat("{0}={1}", p.Name, p.Value);
if (i < parameters.Count - 1)
{
result.Append("&");
}
}
return result.ToString();
}
private static byte[] StringToAscii(string s)
{
var retval = new byte[s.Length];
for (var ix = 0; ix < s.Length; ++ix)
{
var ch = s[ix];
if (ch <= 0x7f)
{
retval[ix] = (byte)ch;
}
else
{
retval[ix] = (byte)'?';
}
}
return retval;
}
private static string UrlEncode(string value)
{
const string Unreserved = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
var result = new StringBuilder();
foreach (char symbol in value)
{
if (Unreserved.IndexOf(symbol) != -1)
{
result.Append(symbol);
}
else
{
result.Append('%' + string.Format("{0:X2}", (int)symbol));
}
}
return result.ToString();
}
}
public class QueryParameter
{
public QueryParameter(string name, string value)
{
this.Name = name;
this.Value = value;
}
public string Name { get; private set; }
public string Value { get; private set; }
}
public class QueryParameterComparer : IComparer<QueryParameter>
{
public int Compare(QueryParameter x, QueryParameter y)
{
return x.Name == y.Name
? string.Compare(x.Value, y.Value)
: string.Compare(x.Name, y.Name);
}
}
Since you are using .Result or .Wait or await this will end up causing a deadlock in your code.
you can use ConfigureAwait(false) in async methods for preventing deadlock
like this:
var response = await httpClient.PostAsync(RequestTokenUrl, content).ConfigureAwait(false);
you can use ConfigureAwait(false) wherever possible for Don't Block Async Code .

Categories

Resources