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.
Related
I have a simple controller method like this:
public IEnumerable<IEntity> GetEntities(ParamsModel args)
{
//set break point here to examine the args
return null;
}
And here is my ParamsModel:
public class ParamsModel {
public string Test;
}
And here is my client's method to send get request:
//_client here is an instance of RestClient
public async Task<IEnumerable<T>> GetEntitiesAsync()
{
var request = new RestRequest("somePath");
var o = new {
Test = "OK"
};
request.AddJsonBody(o);
return await _client.GetAsync<List<T>>(request);
}
After running the method GetEntitiesAsync, the break point (in the controller's method) is hit. However the args is null, really?
I've also tried the following:
public async Task<IEnumerable<T>> GetEntitiesAsync()
{
var request = new RestRequest("somePath");
request.AddParameter("Test", "OK");
return await _client.GetAsync<List<T>>(request);
}
However that did not work as well (args is null in the controller's method).
If I change the controller's method to something like this (and use the client code as right above), I can see the single simple argument of string has value parsed OK ("OK") inside the controller's method:
public IEnumerable<IEntity> GetEntities(string Test)
{
//here we can see that Test has value of "OK"
return null;
}
Really I don't understand what's wrong with my code.
Actually I worked with RestSharp at least a year ago but now it seems to have some new methods (such as the GetAsync as I used in my code), as before I used the Execute and ExecuteAsync.
Could you spot anything wrong here? Thanks!
PS: I'm using RestSharp 106.6.7
Update action to state explicitly where to look for and bind data using [FromUri]
public IHttpActionResult GetEntities([FromUri]ParamsModel args) {
//...
return Ok(entities);
}
To force Web API to read a complex type from the URI, add the [FromUri] attribute to the parameter.
Reference Parameter Binding in ASP.NET Web API
The example with AddParameter
public async Task<IEnumerable<T>> GetEntitiesAsync() {
var request = new RestRequest("somePath");
request.AddParameter("Test", "OK");
return await _client.GetAsync<List<T>>(request);
}
Should work now.
Note that the model should use properties instead of fields
public class ParamsModel {
public string Test { get; set; }
}
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
I'm trying to use Entity Framework 6's Async calls, but whenever I call the FindAsync, the application hangs, and I never get the control back. Below is the method using the Find, where everything goes fine.
public CaUsuario GetUsers(RFContext db, int id)
{
CaUsuario caUsuario = db.CaUsuarios.Find(id);
if (caUsuario == null)
throw new ObjectNotFoundException("User not found");
return caUsuario;
}
Below is my attempt to use the async, with Task return a the ASync call. When the FindAsync is called, I never receive the control back, and the application hangs.
public async Task<CaUsuario> GetUsers(RFContext db, int id)
{
CaUsuario caUsuario = await db.CaUsuarios.FindAsync(id);
if (caUsuario == null)
throw new ObjectNotFoundException("User not found");
return caUsuario;
}
What am I doing wrong?
It might hang in the event of not going "async all the way". Ensure that whatever is calling into the GetUsers is doing so with the async and await keywords, and not incorrectly attempting to use the .Result or .Wait().
Assume the following is a consuming class:
public class Consumer
{
private readonly IUserService _userService;
public Consumer(IUserService userService)
{
_userService = userService;
}
public async Task ConsumeAsync()
{
// Correct
var user = await _userService.GetUsers(1);
}
public void Consume()
{
// Will hang
var user = _userService.GetUsers(1).Result;
}
}
You are probably not doing async all the way through your call chain/stack. Using a combination of Task<T>.Result and await in the call chain will cause a deadlock.
I'm building a set of APIs. One of them is a authentication API, that returns JWT tokens. I'm trying to implement a Session per Action approach, with ActionFiltersAttribute. My controller is decorated with this attribute:
public class NHibernateSessionAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
var session = NHibernateSessionManager.SessionFactory.OpenSession();
session.BeginTransaction();
CurrentSessionContext.Bind(session);
}
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
var session = CurrentSessionContext.Unbind(NHibernateSessionManager.SessionFactory)
if (session != null)
{
if (session.Transaction.IsActive)
{
try
{
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
session.Close();
}
}
}
Where is the problem? To manage the users with NHibernate istead of Entity Framework I've implemented all the needed ASP.NET Identity interfaces, and they all return a Task<T>. For example on the following action:
AccountController.cs
public async Task<IHttpActionResult> ChangePassword(ChangePasswordBindingModel model)
{
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
IdentityResult result = await UserManager.ChangePasswordAsync(User.Identity.GetUserId(), model.OldPassword,
model.NewPassword);
if (!result.Succeeded)
{
return GetErrorResult(result);
}
return Ok();
}
There ChangePasswordAsync calls internally several methods wich have code inside new tasks, where the SessionFactory.GetCurrentSession() causes a NullException. As far as I know, because that's another Thread and context.
In code, the first attempt to save executes with no fail, and the second not. The duplicated code is only to ilustrate the situation.
UserStore.cs
public System.Threading.Tasks.Task UpdateAsync(UserModel user)
{
if (user == null)
{
throw new ArgumentNullException("user");
}
//Here the Session is found
DataProviderI<UserModel, int> prov = new DataProviderImplGeneric<UserModel, int>();
prov.Save(user);
return Task.Factory.StartNew(() =>
{
//Here the Session is NOT found
DataProviderI<UserModel, int> prov2 = new DataProviderImplGeneric<UserModel, int>();
prov.Save(user);
});
}
What's the best way to deal with this and get the same ISession during all the Action ?
As far as I know NHibernate doesn't support async calls and I could refactorize the methods with a return of type Task.FromResult(0) on void cases or Task.FromResult<T>(T) where T is an object, but I would like to know if there's another solution to take advantage of parallelism
Seems like the problem you are dealing with is stemming from the HttpContext being null while inside a task and therefore cannot access the NHibernate session stored inside of the context variable.
You could work around this by getting the ISession before you call into a task.
Add in a constructor to your DataProviderImplGeneric so you manually pass one in.
DataProviderImplGeneric(ISession session) {
this.session = session;
}
just retrieve the session before you call into this from inside a task.
var session = GetCurrentNHibernateSession();
return Task.Factory.StartNew(() => {
var dataProvider = DataProviderImplGeneric<UserModel, int>(session);
return dataProvider.Save(user);
}
I'm stuck in an Async deadlock and I can't figure out the correct syntax to fix it. I've looked at several different solutions, but can't seem to quite figure out what is causing the problem.
I am using Parse as a backend and trying to use a handler to write to the table. My handler looks something like:
public class VisitorSignupHandler : IHttpHandler
{
public void ProcessRequest(HttpContext context)
{
//Get the user's name and email address
var UserFullName = context.Request.QueryString["name"].UrlDecode();
var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();
//Save the user's information
var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
TaskToken.Wait();
....
}
public bool IsReusable { get { return false; } }
}
Then it is calling my middle tier:
public static class UserSignup
{
public static async Task SaveUserSignup(string fullName, string emailAddress)
{
//Initialize the Parse client with the Application ID and the Windows key
ParseClient.Initialize(AppID, Key);
//Create the object
var UserObject = new ParseObject("UserSignup")
{
{"UserFullName", fullName},
{"UserEmailAddress", emailAddress}
};
//Commit the object
await UserObject.SaveAsync();
}
}
Although this seems to be getting stuck at Wait(). I was under the impression that Wait() would simply just wait for the task to complete, then return to normal operations. Is this not correct?
You're running into a common deadlock problem that I describe on my blog and in a recent MSDN article.
In short, await by default will resume its async method inside of a captured "context", and on ASP.NET, only one thread is allowed into that "context" at a time. So when you call Wait, you are blocking a thread inside that context, and the await cannot enter that context when it is ready to resume the async method. So the thread in the context is blocked at Wait (waiting for the async method to complete), and the async method is blocked waiting for the context to be free... deadlock.
To fix this, you should go "async all the way". In this case, use HttpTaskAsyncHandler instead of IHttpHandler:
public class VisitorSignupHandler : HttpTaskAsyncHandler
{
public override async Task ProcessRequestAsync(HttpContext context)
{
//Get the user's name and email address
var UserFullName = context.Request.QueryString["name"].UrlDecode();
var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();
//Save the user's information
var TaskToken = UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
await TaskToken;
....
}
}
Your problem is that you are mixing synchronous and async code. This can be done, but is tricky. Your best bet is to make your http handler async as well:
public class VisitorSignupHandler : HttpTaskAsyncHandler
{
public override async Task ProcessRequestAsync(HttpContext context)
{
//Get the user's name and email address
var UserFullName = context.Request.QueryString["name"].UrlDecode();
var UserEmailAddress = context.Request.QueryString["email"].UrlDecode();
//Save the user's information
await UserSignup.SaveUserSignup(UserFullName, UserEmailAddress);
..
}
}