Hung returning Follows data from Relationships endpoint - c#

I'm trying to return a list of followed users from the Instagram API. I'm on a sandbox account using the InstaSharp wrapper for .NET.
The action method is being called after user is authenticated.
public ActionResult Following()
{
var oAuthResponse = Session["InstaSharp.AuthInfo"] as OAuthResponse;
if (oAuthResponse == null)
{
return RedirectToAction("Login");
}
var info = new InstaSharp.Endpoints.Relationships(config_, oAuthResponse);
var following = info.Follows("10").Result;
return View(following.Data);
}

Try making the method async all the way through instead of making the blocking call .Result which runs the risk of causing a deadlock
public async Task<ActionResult> Following() {
var oAuthResponse = Session["InstaSharp.AuthInfo"] as OAuthResponse;
if (oAuthResponse == null) {
return RedirectToAction("Login");
}
var info = new InstaSharp.Endpoints.Relationships(config_, oAuthResponse);
var following = await info.Follows("10");
return View(following.Data);
}
depending on how info.Follows was implemented.
Looking at the Github repo, the API internally makes a call to a method defined like this
public static async Task<T> ExecuteAsync<T>(this HttpClient client, HttpRequestMessage request)
Which looks like your smoking gun as calling .Result higher up the call stack on this task would result in your experienced deadlock.
Reference Async/Await - Best Practices in Asynchronous Programming

Related

Why is HttpContext.Session status changing to disposed?

I'm trying to store token I get from external api on session.
code snippet concerning this;
[HttpPost]
public async void Post()
{
if (HttpContext.Session.GetValue<User>("Token") == null)
{
HttpContext.Session.SetValue("Token", "test");
var res = await _loginBusiness.GetToken();
HttpContext.Session.SetValue("Token", res);
}
}
HttpContext.Session.SetValue("Token", "test");
in this part, it doesn't occur any error but second the same code line give an error after GetToken().
related error
System.ObjectDisposedException: 'IFeatureCollection has been disposed.
Object name: 'Collection'.'
Also GetToken():
public async Task<User> GetToken()
{
String url = "login/login";
var client = httpClientFactory.CreateClient("VoiceScope");
var postRes = await client.PostAsync<User>(new UserLogin(), url);
return postRes;
}
The problem is that you are using async void. These promises can't be observed and their semantics end up a lot different from a normal Task. Your disposal is happening early because the infrastructure just assumes your Post method has completed (it has no way to tell otherwise).
Change the signature of Post to be:
public async Task Post()
Please note that async void should be limited to event handlers.
I am not sure about using HttpContext. You have IHttpContextAccessor in asp.net core.
I think for store token you can use this
public class UserContext
{
public UserContext(IHttpContextAccessor context)
{
Token = GetAccessToken(context);
}
private static string GetAccessToken(IHttpContextAccessor contextAccessor)
{
var identity = (ClaimsIdentity)contextAccessor?.HttpContext?.User?.Identity;
return identity?.Claims.FirstOrDefault(x => x.Type == "token")?.Value;
}
public string Token { get; }
}
And then, add this staff in your DI like scope object and use it in controllers via ServiceProvider.

Class library making api call doesn't work in specific projects

I've got a class library for talking to a logging api server, the method "chain" is this:
Entry point ->
private static bool SendChecksumToServer(Checksum checksum)
{
var res = _api.GetAsync($"Checksum?assemblyName={checksum.CurrentAssembly}&checkSum={checksum.LogFileChecksum}&fileName={checksum.FileName}");
return _api.Deserialize<bool>(res.Result.Content.ReadAsStringAsync().Result);
}
Which calls this:
public async Task<HttpResponseMessage> GetAsync(string apiCall)
{
ApiGet get = new ApiGet();
return await get.GetAsync(apiCall, client);
}
Which calls this:
public async Task<HttpResponseMessage> GetAsync(string apiCall, HttpClient client)
{
var response = await client.GetAsync(apiCall);
return response;
}
This works completely fine when I use the class library within a console app, but as soon as I move it to an actual application (MVC) it stops working, it doesn't even hit the controller action at all, I've tried everything I can think of like checking firewalls, making sure the async is correct (although I'm sure it still isn't because the api not responding freezes the app, but I can't bubble the async any higher)
Most likely experiencing a deadlock because of .Result blocking call.
Don’t mix blocking and async code
Reference Async/Await - Best Practices in Asynchronous Programming
Refactor the code to be async all the way
private static async Task<bool> SendChecksumToServer(Checksum checksum) {
var res = await _api.GetAsync($"Checksum?assemblyName={checksum.CurrentAssembly}&checkSum={checksum.LogFileChecksum}&fileName={checksum.FileName}");
String data = await res.Result.Content.ReadAsStringAsync();
return _api.Deserialize<bool>(data);
}
Ensure what ever is calling SendChecksumToServer also awaits the task,
and also not using async-await in the other calls if nothing needs to be awaited.
public Task<HttpResponseMessage> GetAsync(string apiCall) {
ApiGet get = new ApiGet();
return get.GetAsync(apiCall, client);
}
ApiGet
public Task<HttpResponseMessage> GetAsync(string apiCall, HttpClient client) {
return client.GetAsync(apiCall);
}

Web api return values for async methods

I'm a bit confused with HttpResponseMessage and Task<HttpResponseMessage>.
If I'm using the HttpClient method PostAsync() to post data I need to give the Web Service method the Task<HttpResponseMessage> instead of HttpResponseMessage as return value as far as I understood things.
If I use Request.CreateResponse(HttpStatusCode.Forbidden, myError.ToString());
then I'm only getting the Response message object but not the Task object.
So my question here is how do I have to create the Fitting return for async calls to web api methods?
(thus are my understandings there correct and if so how to best transform the message object int a Task<HttpResponseMessage> object)
The original code:
public HttpResponseMessage DeviceLogin(MyDevice device)
{
EnummyError myError = EnummyError.None;
// Authenticate Device.
myError = this.Authenticate(device);
if (myError != EnummyError.None)
{
return Request.CreateResponse(HttpStatusCode.Forbidden, myError.ToString());
}
}
The updated Method header:
public Task<HttpResponseMessage> DeviceLogin(MyDevice device)
Web Api 2 has these abstraction classes which are now recommended to use. You can still use HttpResponseMessage (easier to follow for beginners, in my opinion), but Web Api 2 recommends using IHttpActionResult.
As for the return type, just did what you did before. Task<T> works automagically that way.
You also might want to check if this.Authenticate() has an async variant.
public async Task<IHttpActionResult> DeviceLogin(MyDevice device)
{
EnummyError myError = EnummyError.None;
// Authenticate Device.
myError = this.Authenticate(device);
// Perhaps Authenticate has an async method like this.
// myError = await this.AuthenticateAsync(device);
if (myError != EnummyError.None)
{
return ResponseMessage(Request.CreateResponse(Request.CreateResponse(HttpStatusCode.Forbidden, myError.ToString()));
}
}
The ResponseMessage() method creates a ResponseMessageResult under water. This class derives from IHttpActionResult and accepts a HttpResponseMessage as a parameter in the constructor (which is made by Request.CreateResponse()).

Custom implementation of ASP.NET Identity

I'm using various resources to try and implement an Identity system with MS Access for an AngularJS app.
I created classes which implement the Identity interfaces I need, and I'm stuck at the stage of creating the Account controller (which will be the API for registeration, login, etc).
The class UserStore implements IUserStore and has the CreateAsync method:
public Task CreateAsync(TUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
var result = userTable.Insert(user);
return Task.FromResult(result);
}
AccountController implements ApiController and has the Register method:
[AllowAnonymous]
[Route("register")]
public async Task<IHttpActionResult> Register(IdentityUser user)
{
var result = await _userStore.CreateAsync(user);
if (result == 0)
{
return InternalServerError();
}
return Ok();
}
userTable.Insert(user) returns an int indicating the number of rows affected in the DB table. The line var result = await _userStore.CreateAsync(user); throws an error, saying it actually returns void, and so void cannot be assigned to var (or to anything else).
I'm having a hard time understanding how to write the Register method and the CreateAsync method so that they will work together.
BTW, I thought I should give up the whole async thing and just make CreateAsync and Register return the int value as-is, but I can't do that since UserStore implements `IUserStore'.
The issue is that the return type cannot be passed from the CreateAsync as it is simply a Task return. It would need to be Task<int> but you cannot do that since it's implementing the IUserStore interface. Why do you need the result, I'm assuming you do not?
Try this instead:
[AllowAnonymous]
[Route("register")]
public async Task<IHttpActionResult> Register(IdentityUser user)
{
await _userStore.CreateAsync(user);
return Ok();
}
Additionally, consider making userTable.Insert(user) an async call if at all possible.
I would suggest not giving up on async/await. Especially for I/O bound operations on a web site like this, they really make your application usable.
If you're really concerned about whether or not the insert might be problematic, try this instead:
public async Task CreateAsync(TUser user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
var existingUser = await this.FindByIdAsync(user.Id);
if (existingUser != null)
{
await this.UpdateAsync(user);
}
else
{
userTable.Insert(user);
}
}

async chaining blocks webapi call

I've a flow: WebApi > ServiceFramework > DBLayer > MongoDB.
Since its a new application, I ensured to have async from the ground up in all layers. However, when my DB Layer has async code, webapi never gets a response back.
API CONTROLLER
[HttpGet]
public IHttpActionResult GetAllRecords()
{
var result = FrameworkApi.GetRecords().Result;
return Ok(result);
}
above calls > FRAMEWORK API
public async Task<List<Record>> GetRecords()
{
return await FrameworkDbApi.GetRecords();
}
above calls > DB FRAMEWORK API (which Calls MongoDB)
public async Task<List<Record>> GetRecords()
{
return await Task.Run(() =>
NoSqlDocumentClient.GetDefaultDatabase().Result.
GetCollection<Record>("record").AsQueryable().ToList());
//following Synchronous version works..but defeats the purpose
//return NoSqlDocumentClient.GetDefaultDatabase().Result
// .GetCollection<Record>("record").AsQueryable().ToList();
}
However, when the operations in either DBLayer or Framework are invoked via test case, I do get result. But when invoked via WebApi controller, the asynchronous version never returns a response while synchronous version works fine.
But when invoked via WebApi controller, the asynchronous version never
returns a response while synchronous version works fine.
That's because your actual request is deadlocking. When you invoke the method via WebAPI, which has a SynchronizationContext, you're seeing the deadlock, in contrary to your test which hasn't got one, when the test runs fine. This is the reason why you shouldn't block on async code.
Your call-chain should look like this in order to avoid deadlocking (this is what it means to go "async all the way":
[HttpGet]
public async Task<IHttpActionResult> GetAllRecordsAsync()
{
var result = await FrameworkApi.GetRecordsAsync();
return Ok(result);
}
public Task<List<Record>> GetRecordsAsync()
{
return FrameworkDbApi.GetRecordsAsync();
}
public async Task<List<Record>> GetRecordsAsync()
{
var result = await NoSqlDocumentClient.GetDefaultDatabase();
return result.GetCollection<Record>("record").AsQueryable().ToList();
}

Categories