I'm struggling a bit to figure out how to use Trello's OAuth API calls from my Windows Phone 7 app. The API isn't really documented, aside from a listing of the endpoints.
Here's what I have so far:
public void OnAuthenticateClicked(object sender, EventArgs e)
{
const string consumerKey = "mykey";
const string consumerSecret = "mysecret";
const string baseUrl = "https://trello.com/1";
var client = new RestClient(baseUrl)
{
Authenticator = OAuth1Authenticator.ForRequestToken(consumerKey, consumerSecret)
};
var request = new RestRequest("OAuthGetRequestToken", Method.POST);
var response = client.ExecuteAsync(request, HandleResponse);
}
private void HandleResponse(IRestResponse restResponse)
{
var response = restResponse;
Console.Write(response.StatusCode);
}
I'm getting a 404 response, so something's not right, obviously.
Any suggestions?
Not using the ExecuteAsync seems to make it work:
RestRequest request = new RestRequest("OAuthGetRequestToken", Method.POST);
IRestResponse response = client.Execute(request);
Console.Write(response.StatusCode);
At one point "oAuth1 is not yet supported in async scenarios (SL and WP)", according to this post by John Sheehan.
I think your base url is incorrect.
Please try the following:
const string baseUrl = "https://api.trello.com/1";
Replace OAuthGetRequestToken with authorize.
Related
Im creating a list of components in Blazor, each one of these components need to request some data from a webpage. The list are created as follows on a .razor page:
#foreach(stringcomp in Complist){
<myComponent />
}
around 100 components are created. On all of these components the following URL request is preformed (using this code):
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await GetUrl("some url here");
}
}
public async Task<string> GetUrl(string url)
{
HttpClient client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("User-Agent", "get data service");
var response = await client.SendAsync(request).ConfigureAwait(false);
string res = null;
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false);
var streamReader = new StreamReader(responseStream);
res = await streamReader.ReadToEndAsync().ConfigureAwait(false);
}
return res;
}
Doing this I'm running in to some problems where most of my calls to SendAsync never returns a value. I have come to understand that this is because of a lock-state but for the life of me can't figure out how to solve it. most similar answers suggest setting .ConfigureAwait(false) but this does not yeald a different result in my case.
So my question is: Hos can i request webbpages simultaneously in different components and be sure that they won't hang/lookup. As theres many requests that some times takes a long time (5-10 sec) to complete it's not an alternative to do them synchronously.
It might also be of importance to mention that me code and pages are separated, every .razor page are using #inherits to get its functions/logic
Try to use IHttpClientFactory as follows:
[Inject] public IHttpClientFactory clientFactory { get; set;}
using System.IO;
Your GetUrl method:
public async Task<string> GetUrl(string url)
{
var request = new HttpRequestMessage(HttpMethod.Get, url);
request.Headers.Add("Accept", "application/json");
request.Headers.Add("User-Agent", "get data service");
var client = clientFactory.CreateClient();
var response = await client.SendAsync(request);
string res = null;
if (response.IsSuccessStatusCode)
{
using var responseStream = await response.Content.ReadAsStreamAsync();
var streamReader = new StreamReader(responseStream);
res = await streamReader.ReadToEndAsync().ConfigureAwait(false);
}
return res;
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddHttpClient();
// More code here...
}
Hope this works...
I am attempting to use LinqToTwitter to search twitter. It works fine as run in an NUnit test but it does not work with ASP.NET or as a WinForm app. I am not sure what Authorizer to use.
public async Task<Search> SearchTwitter(string searchWords)
{
var twitterCtx = BuildTwitterContext();
Task<Search> searchResponse = (from search in twitterCtx.Search
where search.Type == SearchType.Search &&
search.Query == searchWords
select search)
.SingleOrDefaultAsync();
return await searchResponse;
}
private static TwitterContext BuildTwitterContext()
{
IAuthorizer authorizer;
if (HttpContext.Current == null)
authorizer = new PinAuthorizer();
else
authorizer = new AspNetSignInAuthorizer();
InMemoryCredentialStore credentialStore = new InMemoryCredentialStore();
credentialStore.ConsumerKey = consumerKey;
credentialStore.ConsumerSecret = consumerSecret;
credentialStore.OAuthToken = accessToken;
credentialStore.OAuthTokenSecret = accessTokenSecret;
authorizer.CredentialStore = credentialStore;
var twitterCtx = new TwitterContext(authorizer);
return twitterCtx;
}
ASP.NET is different because of the page redirections where you start the authorization and then finish after Twitter redirects back. Here's the LINQ to Twitter documentation that will explain how OAuth works and give you a better idea on which authorizers to use:
https://github.com/JoeMayo/LinqToTwitter/wiki/Learning-to-use-OAuth
The L2T source code also has demos. Here's an OAuth controller demo:
https://github.com/JoeMayo/LinqToTwitter/blob/master/New/Linq2TwitterDemos_Mvc/Controllers/OAuthController.cs
public class OAuthController : AsyncController
{
public ActionResult Index()
{
return View();
}
public async Task<ActionResult> BeginAsync()
{
//var auth = new MvcSignInAuthorizer
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"]
}
};
string twitterCallbackUrl = Request.Url.ToString().Replace("Begin", "Complete");
return await auth.BeginAuthorizationAsync(new Uri(twitterCallbackUrl));
}
public async Task<ActionResult> CompleteAsync()
{
var auth = new MvcAuthorizer
{
CredentialStore = new SessionStateCredentialStore()
};
await auth.CompleteAuthorizeAsync(Request.Url);
// This is how you access credentials after authorization.
// The oauthToken and oauthTokenSecret do not expire.
// You can use the userID to associate the credentials with the user.
// You can save credentials any way you want - database,
// isolated storage, etc. - it's up to you.
// You can retrieve and load all 4 credentials on subsequent
// queries to avoid the need to re-authorize.
// When you've loaded all 4 credentials, LINQ to Twitter will let
// you make queries without re-authorizing.
//
//var credentials = auth.CredentialStore;
//string oauthToken = credentials.OAuthToken;
//string oauthTokenSecret = credentials.OAuthTokenSecret;
//string screenName = credentials.ScreenName;
//ulong userID = credentials.UserID;
//
return RedirectToAction("Index", "Home");
}
}
Notice that it uses a WebAuthorizer/SessionStateCredentials pair and separates the start of authorization with a separate action method (specified via callback) for completion.
The following demo shows how to perform OAuth in a WinForms app:
https://github.com/JoeMayo/LinqToTwitter/blob/master/New/Demos/Linq2TwitterDemos_WindowsForms/OAuthForm.cs
public partial class OAuthForm : Form
{
PinAuthorizer pinAuth = new PinAuthorizer();
public OAuthForm()
{
InitializeComponent();
}
async void OAuthForm_Load(object sender, EventArgs e)
{
pinAuth = new PinAuthorizer
{
// Get the ConsumerKey and ConsumerSecret for your app and load them here.
CredentialStore = new InMemoryCredentialStore
{
ConsumerKey = ConfigurationManager.AppSettings["consumerKey"],
ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"]
},
// Note: GetPin isn't used here because we've broken the authorization
// process into two parts: begin and complete
GoToTwitterAuthorization = pageLink =>
OAuthWebBrowser.Navigate(new Uri(pageLink, UriKind.Absolute))
};
await pinAuth.BeginAuthorizeAsync();
}
async void SubmitPinButton_Click(object sender, EventArgs e)
{
await pinAuth.CompleteAuthorizeAsync(PinTextBox.Text);
SharedState.Authorizer = pinAuth;
// This is how you access credentials after authorization.
// The oauthToken and oauthTokenSecret do not expire.
// You can use the userID to associate the credentials with the user.
// You can save credentials any way you want - database, isolated storage, etc. - it's up to you.
// You can retrieve and load all 4 credentials on subsequent queries to avoid the need to re-authorize.
// When you've loaded all 4 credentials, LINQ to Twitter will let you make queries without re-authorizing.
//
//var credentials = pinAuth.CredentialStore;
//string oauthToken = credentials.OAuthToken;
//string oauthTokenSecret = credentials.OAuthTokenSecret;
//string screenName = credentials.ScreenName;
//ulong userID = credentials.UserID;
//
Close();
}
}
In this case, you can use a PinAuthorizer with an InMemoryCredentialStore. If you look at that demo, it uses a Web Browser control to navigate to Twitter and manage the OAuth flow.
Look at the URL above for the Learning to use OAuth for examples of other IAuthorizer derived types that you can use in different scenarios. Also, download the source code and step through with the debugger to get a feel for the OAuth workflow.
I have a WP7 app where I'm trying to reconstruct an HTTPWebRequest that I have successfully written elsewhere using the synchronous methods (pasted at end) but which doesn't work in WP7, I assume because I'm doing something wrong with the Asynchronous versions of these methods.
I believe the issue stems from the fact that the non-working code on the Compact Framework can only send a bytearray[] - I don't have the option of sending the json string. If I send a bytearray in the code that works, I get an error there too. Is there a different option?
Here is my code - this does not work. The exception is thrown on the 2nd line of the last method - "Using(var respons ...)":
public void CreateUser()
{
var request = (HttpWebRequest)WebRequest.Create("http://staging.cloudapp.net:8080/api/users/");
request.Method = "POST";
request.ContentType = "text/json; charset=utf-8";
request.BeginGetRequestStream(new AsyncCallback(RequestCallback), request);
}
private static void RequestCallback(IAsyncResult result)
{
HttpWebRequest request = (HttpWebRequest)result.AsyncState;
using (Stream postStream = request.EndGetRequestStream(result))
{
User user = new User("Windows", "Phone", "USCA");
Formatting formatting = new Formatting();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(user, formatting, settings);
byte[] byteArray = Encoding.UTF8.GetBytes(json);
postStream.Write(byteArray, 0, json.Length);
}
request.BeginGetResponse(new AsyncCallback(ResponseCallback), request);
}
private static void ResponseCallback(IAsyncResult result)
{
var request = (HttpWebRequest)result.AsyncState;
using (var response = (HttpWebResponse)request.EndGetResponse(result))
{
using (Stream streamResponse = response.GetResponseStream())
{
StreamReader reader = new StreamReader(streamResponse);
string responseString = reader.ReadToEnd();
reader.Close();
}
}
}
This code works (non-compact framework version of the same request):
HttpWebRequest request = HttpWebRequest.Create("http://staging.cloudapp.net/api/users/") as HttpWebRequest;
request.Method = "POST";
request.ContentType = "text/json";
using (var writer = new StreamWriter(request.GetRequestStream()))
{
User user = new user("Other", "Guy", "USWC");
Formatting formatting = new Formatting();
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
string json = JsonConvert.SerializeObject(user, formatting, settings);
writer.Write(json);
}
var response = request.GetResponse() as HttpWebResponse;
using (var reader = new StreamReader(response.GetResponseStream()))
{
var responseText = reader.ReadToEnd();
return responseText;
}
thanks for any help!
looks like the server is responding with a "404 not found". Does the resource you are requesting exist at the server?
Does your JSON contain any non 7-bit ASCII characters, as you are currently doing:
byte[] byteArray = Encoding.UTF8.GetBytes(json);
postStream.Write(byteArray, 0, json.Length);
The number of bytes might not be identical to the number of characters in your string, which could lead to a malformed request.
It would be worthwhile using something like Fiddler to verify what is actually going over the wire from the emulator or phone (there are instructions on the Fiddler website for how to do this)
Well - I'm not sure why this problem went away. I liked #RowlandShaw's suggestion, but I didn't actually change anything in the json. Wish I could give a better solution.
I am new to this forum as well as Windows Phone Development. I am currently developing an app in which I am working with a Web-Service and I need to make a POST request to a web service.
I am trying to accomplish a user login functionality here for which,
-> http://abc.com/login (URI)
-> (PARAMETERS)
apikey: 32 byte long alpha-numeric
username: 3-15 characters
password: 3-15 characters
So for this I am trying to use WebClient class' UploadStringSync method in order to POST the data. My code is as follows.
WebClient wc1 = new WebClient();
wc1.UploadStringAsync(new Uri("http://abc.com/login"),"POST","?apikey=" + Apikey + "&username=username&password=password");
wc1.UploadStringCompleted += new UploadStringCompletedEventHandler(wc1_UploadStringCompleted);
void wc1_UploadStringCompleted(object sender, UploadStringCompletedEventArgs e)
{
MessageBox.Show(e.Result);
}
Execution stops here at MessageBox line and throws message saying 'The remote server returned an error: NotFound.'
Is there any problem with the way I am passing the parameters? I tried to search for the working implementation everywhere but was unable to find it.
Can anybody help me with this? This is a starting point of my project and really need help on this one. Any help would be much appreciated.
try this:
public void Post(string address, string parameters, Action<string> onResponseGot)
{
Uri uri = new Uri(address);
HttpWebRequest r = (HttpWebRequest)WebRequest.Create(uri);
r.Method = "POST";
r.BeginGetRequestStream(delegate(IAsyncResult req)
{
var outStream = r.EndGetRequestStream(req);
using (StreamWriter w = new StreamWriter(outStream))
w.Write(parameters);
r.BeginGetResponse(delegate(IAsyncResult result)
{
try
{
HttpWebResponse response = (HttpWebResponse)r.EndGetResponse(result);
using (var stream = response.GetResponseStream())
{
using (StreamReader reader = new StreamReader(stream))
{
onResponseGot(reader.ReadToEnd());
}
}
}
catch
{
onResponseGot(null);
}
}, null);
}, null);
}
I did this and it worked
WebClient web = new WebClient();
web.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
web.UploadStringAsync((new Uri("http://www.something.com/?page=something")), "POST", string.Format("v1=onevalue&v2=anothervalue"));
web.UploadStringCompleted += web_UploadStringCompleted;
and after upload is complete to get the html i used htmlagilitypack, you can just get the whole html using e.Result
HtmlDocument doc = new HtmlDocument();
doc.LoadHtml(e.Result);
HtmlNode node = doc.DocumentNode.SelectSingleNode("//body//table");
MessageBox.Show(node.InnerText);
I have this example working but I want to know how manage timeout for this example exactly. Please help me.
Thanks in advance
public void callREST()
{
Uri uri = new Uri("http://www.domain.com/RestService");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "application/xml";
request.BeginGetRequestStream(sendXML_RequestCallback, request);
}
private void sendXML_RequestCallback(IAsyncResult result)
{
var req = result.AsyncState as HttpWebRequest;
byte[] toSign = Encoding.GetEncoding("ISO-8859-1").GetBytes("<xml></xml>");
using (var strm = req.EndGetRequestStream(result))
{
strm.Write(toSign, 0, toSign.Length);
strm.Flush();
}
req.BeginGetResponse(this.fCallback, req);
}
private void fCallback(IAsyncResult result)
{
var req = result.AsyncState as HttpWebRequest;
var resp = req.EndGetResponse(result);
var strm = resp.GetResponseStream();
//Do something
}
Timeout isn't supported as part of HttpWebRequest in Silverlight / Windows Phone 7.
You'll need to create a Timer and start that at the same time you start the request. If the timer fires before the HWR returns then Abort() the request and assume it timed out.
For more details and an example, see: HttpWebRequest Timeout in WP7 not working with timer