ASP. NET exception asynchronous operations are not allowed in this context Solution

Source: Internet
Author: User

Yesterday I met a strange thing, the same method A (), in the consoleProgramAnd ASP. NET pages. The console program runs normally and cannot get the correct result under ASP. NET.

 

The execution process of method A () is as follows:

 

A () calls the Asynchronous Method B () of the third-party library, and calls the asynchronous WebService request in the callback method C () of the Asynchronous Method.
 
After debugging, it is found that in C (), the exception thrown by the system is swallowed up. ModifyCode, An exception is caught:

 

Asynchronous operations are not allowed in this context. Page starting an asynchronous operation has to have the async attribute set to true and an asynchronous operation can only be started on a page prior to prerendercomplete event.

 

Google found that Asp.net imposes restrictions on Asynchronous calls. To perform asynchronous operations on the page, you must set async = true for the page. However, the problem is that only method A is triggered in the page, Method B is invoked by method A, and the callback of Method B is executed by the unknown worker thread behind the scenes, the callback of C is an unknown bitter thread executed behind the scenes. Two bitter threads, and the page thread, are not a single thread at all. Therefore, whether setting async = true in the page can affect the background worker threads is questionable.
 
Adding async = true to the page still cannot produce the correct result. In desperation, I guess whether I can set an item in the configuration file to enable full-site asynchronous operations. If the search settings are fruitless, You have to seek the third path.
 
The exception source is carefully analyzed and thrown by the operationstarted () method of a system. Web. aspnetsynchronizationcontext instance. This class is not found in msdn. Use. Net reflector. It turns out to be an internal class. The operationstarted () method is as follows:

 

  Public   Override   Void Operationstarted ()
  {
If ( This . _ Invalidoperationencountered | ( This . _ Disabled && ( This . _ Pendingcount =   0 )))
{
This. _ Invalidoperationencountered= True;
Throw NewInvalidoperationexception (Sr. getstring ("Async_operation_disabled"));
}
Interlocked. increment ( Ref   This . _ Pendingcount );
}

 

Holding aspnetsynchronizationcontext is a static attribute synchronizationcontext of the static class system. componentmodel. asyncoperationmanager.
 
Use reflecter to view the code. getter of synchronizationcontext obtains the synchronizationcontext of the current thread, and its setter accesses the synchronizationcontext of the current thread. That is to say, for a thread that throws an exception, its synchronizationcontext is an aspnetsynchronizationcontext instance.
 
Writing a test program found that the synchronizationcontext of the console program uses the synchronizationcontext type system. Threading. synchronizationcontext, And the ASP. Net program uses the synchronizationcontext type system. Web. aspnetsynchronizationcontext.

 

. In the. NET program, WebService uses soaphttpclientprotocol for SOAP request, while soaphttpclientprotocol is a subclass of The WebClient class. In many asynchronous methods of the WebClient class, system is called. componentmodel. asyncoperationmanage. synchronizationcontext. operationstarted () method. if the current thread applies the aspnetsynchronizationcontext, And the aspnetsynchronizationcontext does not allow asynchronous operations, an exception occurs.
 
After learning about this, the solution is to add system. componentmodel. asyncoperationmanager. synchronizationcontext = new system. Threading. synchronizationcontext () to global. asax ();
 
Test it. Aha ~~~ Failed !!
 
The synchronizationcontext printed in page is still aspnetsynchronizationcontext.
 
Use reflector to find the reference information of asyncoperationmanager and find the method system. Web. httpapplication + threadcontext. Enter (Boolean): void. Method body:

 

Internal   Void Enter ( Bool Setimpersonationcontext)
  {
This . _ Savedcontext = Httpcontextwrapper. switchcontext ( This . _ Context );
If (Setimpersonationcontext)
{
This. Setimpersonationcontext ();
}
This . _ Savedsynchronizationcontext = Asyncoperationmanager. synchronizationcontext;
Asyncoperationmanager. synchronizationcontext =   This . _ Context. synccontext;
Guid requesttraceidentifier =   This . _ Context. workerrequest. requesttraceidentifier;
If ( ! (Requesttraceidentifier = Guid. Empty ))
{
Callcontext. logicalsetdata ("E2etrace. activityid", Requesttraceidentifier );
}
This . _ Context. resetsqldependencycookie ();
This . _ Savedprincipal = Thread. currentprincipal;
Thread. currentprincipal =   This . _ Context. user;
This . Setrequestlevelculture ( This . _ Context );
If ( This . _ Context. currentthread =   Null )
{
This. _ Setthread= True;
This. _ Context. currentthread=Thread. currentthread;
}
}

 

Synchronizationcontext was stolen here. Full.
 
You are not benevolent. I am not righteous. If you change it, I will change it. Add:
 
System. componentmodel. asyncoperationmanager. synchronizationcontext = new system. Threading. synchronizationcontext ();

 

Test passed.

 

However, the side effects of this operation are not small. For example, synchronizationcontext is often replaced by httpapplication with aspnetsynchronizationcontext. In this case, asynchronous operations may cause problems, for example, using system. threading. synchronizationcontext instead of aspnetsynchronizationcontext will cause ASP.. Net itself encountered an exception. An exception was thrown in httpapplication yesterday.
 
To reduce the side effects, replace synchronizationcontext before calling method A (). After the method is executed, replace it:
 

System. Threading. synchronizationcontext Context = System. componentmodel. asyncoperationmanager. synchronizationcontext;
Try
{
System. componentmodel. asyncoperationmanager. synchronizationcontext= NewSystem. Threading. synchronizationcontext ();
A ();
}
Finally
{
System. componentmodel. asyncoperationmanager. synchronizationcontext=Context;
}

 

Test passed. So far, no problems have been found.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.