restsharp / RestSharp

Simple REST and HTTP API Client for .NET
https://restsharp.dev
Apache License 2.0
9.58k stars 2.34k forks source link

UseSynchronizationContext not working as expected with ASP.NET. #1324

Closed ACIStymie closed 4 years ago

ACIStymie commented 5 years ago

Expected Behavior

In an async page of an ASP.NET project, I set RestClient.UseSynchronizationContext = true. Expectation is that Thread.CurrentPrincipal will not be set to HttpContext.Current.User when the call to await ExecuteTaskAsync<> returns.

Actual Behavior

Thread.CurrentPrincipal gets set to HttpContext.Current.User on every await/async generated continuation up the stack.

I know ASP.NET will set Thread.CurrentPrincipal = HttpContext.Current.User when it re-enters the AspNetSynchronizationContext. Which is why I set UseSynchronizationContext to true to avoid leaving the context. Even if it was not executing off the ASP.Net synchronization context, .net is acting like it did.

Stepping through the RestSharp code it appears to happen when the response call back runs the ProcessResponse(...) method.

Don't know enough about other synchronization contexts to know if this is a problem for them or not.

Steps to Reproduce the Problem

  1. in ASP.NET (at least .net version 4.5), execute code on an asynchronous page that calls to the RestClient.ExecuteTaskAsync<>() method using await.
  2. Make sure to set RestClient.UseSynchronizationContext = true on the client.
  3. Make sure the page is using the AspNetSynchronizationContext (Although I would guess it would happen for the legacy sync context as well?)
  4. Make sure Thread.CurrentPrincipal and HttpContext.Current.User have different values before the ExecuteTaskAsync<>() call.
  5. After the call, Thread.CurrentPrincipal is now equal to HttpContext.Current.User.

Specifications

ACIStymie commented 5 years ago

Looks like these links might explain the issue. https://blog.stephencleary.com/2009/08/gotchas-from-synchronizationcontext.html https://blog.stephencleary.com/2009/10/synchronizationcontext-properties.html

Apparently AspNetSynchronizationContext.Post has reentrant behavior. Which causes Thread.CurrentPrincipal to be set to HttpContext.Current.User. It can be seen how when going through the .NET framework code.

If UseSynchronizationContext is not set to true, AspNetSynchronizationContext.Post is not used. And the callbacks end up executing off the sync context. Which has the same result for CurrentPrincipal when returning to the ASP.NET sync context.

It's beyond my knowledge to modify the RestSharp code to work without exiting the sync context all the way through and not having the unexpected side affect of AspNetSynchronizationContext.Post. Looks like I am stuck ripping out the async code I was trying to put into my project.

alexeyzimarev commented 4 years ago

I am sorry for not being able to help you. The WebRequest API which we use is very old and not exactly async friendly. I plan to work on moving RestSharp to HttpClient soon and I expect the majority of issues to be resolved. But it would also require a lot of RestSharp API changes, so right now I am marking a lot of methods as obsolete for that.

stale[bot] commented 4 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

repo-ranger[bot] commented 4 years ago

⚠️ This issue has been marked wontfix and will be closed in 3 days

stale[bot] commented 4 years ago

This issue has been closed because it has not had recent activity. Thank you for your contributions.