ASP.NET Webforms with async/await - asp.net

My Webforms application which is based on .Net 4.6 has to use the async/await-functionality quite extensively. Because I'm quite new to this async/await topic I read quite a lot of best practices like this or this. But I still have some questions for which I haven't found any clear informations.
Regarding Page-Lifecycle-Events: I know that e.g. for the Page_Load-Event it's best practice to avoid async void-methods and register such methods like this:
protected void Page_Load(object sender, EventArgs e)
{
PageAsyncTask pageAsyncTask = new PageAsyncTask(SomeAsyncMethod);
Page.RegisterAsyncTask(pageAsyncTask);
//Method to invoke the registered async-methods immedietly and not after the PreRender-Event
Page.ExecuteRegisteredAsyncTasks();
}
My problem is that I want to call the async-method as soon as I registered it and not after the OnPreRender-event. This should be achieved by calling the ExecuteRegisteredAsyncTasks()-method. But in my case this has no effect and the async-method is still invoked after the PreRender-event. But why?
Regarding Control-Events: Is it better to register async-methods the same way I mentioned in the code-example above or can I use the async-void signature like:
protected async void OnClick(object sender, EventArgs e)
{
await SomeAsyncMethod();
}
I found both examples but no clear informations which is the better solution and why.
Regarding Context and ConfigureAwait, it seems to be best practice to use await SomeAsyncMethod.ConfigureAwait(false) for a better performance and where the context is not important and not to use it where the context e.g. when manipulating GUI elements. But in my case it seems to make no difference if I call await SomeAsyncMethod.ConfigureAwait(false) in my click-event. I can still manipulate my GUI-elements wihtout any problems. The example which I uses was this:
private async void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
try
{
await SomeAsyncMethod().ConfigureAwait(false);
}
finally
{
//Manipulating still works even it's another context
button1.Enabled = true;
}
}
So I wonder why the manipulating of the GUI-elements still work and if I really should use ConfigureAwait(false) on every async-method where the context is not important, which is quite tedious. I wonder if this has something to do with the usage of the Ajax-Functionality by Telerik which I use for my Webapplication. But this is just an assumption.

ASP.NET WebForms has it's own asynchronous execution engine. Please refer to the documentation.
In any case, you typically want (or need) to get back to the current synchronization context on methods such as event handlers, so you shouldn't call ConfigureAwait(false) inside button1_Click, but you should call it inside SomeAsyncMethod.

My simple method for Asp.net 4.5 webforms:
1) declare aspx page with this attribute
<%# Page ..... Async="true" ValidateRequest="false" EnableEventValidation="false" %>
2) Create this void method in code:
void MyAsyncMethod( ... list parameters )
{
//Insert this on end method code
var objThread = Session["MyAsyncMethod"] as Thread;
if (objThread != null) objThread.Abort();
}
3) Call method MyAsyncMethod:
var objThread = new Thread(
() => MyAsyncMethod(parameters..)) {IsBackground = true};
objThread.Start();
Session["MyAsyncMethod"] = objThread;

Related

AsyncLocal Value is Null after being set from within Application_BeginRequest()

In the following example, I am setting a value to an AsyncLocal<string> variable on my HttpApplication subclass (i.e. Global.asax) from within Application_BeginRequest():
public class Global : System.Web.HttpApplication
{
public static AsyncLocal<string> AsyncLocalState = new AsyncLocal<string>();
protected void Application_BeginRequest(object sender, EventArgs e)
{
AsyncLocalState.Value = HttpContext.Current.Request.Path;
}
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
var path = AsyncLocalState.Value;
}
protected void Application_EndRequest(object sender, EventArgs e)
{
var path = AsyncLocalState.Value;
}
}
Later on, I will attempt to access the value of this AsyncLocal variable from within a handler, such as an MVC action method, or even just a plain IHttpHandler.
If I send a large enough request (e.g. a POST with more than 15KB of data -- the larger the request, the easier it is to observe), there is a very good chance that the value of AsyncLocalState is NULL when accessed from a handler even though it was set on BeginRequest.
This is reproducible from a brand-new ASP.NET project without any other libraries/modules/handlers loaded.
Is this a bug? Or maybe I'm doing something wrong? Or is ASP.NET just too unstable for this?
Addition note: the exact same behavior is observed if I instead use CallContext.LogicalGetData/CallContext.LogicalSetData.
Platform: ASP.NET, .NET 4.6.2, on Windows 7
Update: After trying to dig around, I've found a lot of references to, but nothing authoritatively saying that the ExecutionContext does not flow between ASP.NET pipeline events (except when it does?). And both AsyncLocal and the logical call context are based on the ExecutionContext.
The closest thing to an authoritative answer is this comment by David Fowl on GitHub.
The ExecutionContext does not flow between ASP.NET pipeline events if these events do not execute synchronously. Therefore, don't use AsyncLocal or the logical CallContext to persist state; use HttpContext.Items.
Update: .NET 4.7.1 adds a new callback method, HttpApplication.OnExecuteRequestStep, which per documentation "provides extensibility to the ASP.NET pipeline to make it easy for developers to implement features in ambient context scenarios and build libraries that care about ASP.NET execution flow (for example, tracing, profiling, diagnostics, and transactions)."
This is precisely what someone would need in order to restore the AsyncLocal state or the logical CallContext between ASP.NET pipeline events.

How to update value in textBox in ASP.NET from other threads?

I'm using ASP.NET 4.0 on IIS7.5 and WCF Callback technique. I have no problem with callback. The wcf service can fire callback method in web client but it seems it's on another thread with the UI thread.
public partial class _Default : System.Web.UI.Page, IServiceCallback
{
private IService proxy = null;
private static TextBox _textBoxtest;
protected void Page_Load(object sender, EventArgs e)
{
_textBoxtest = TextBox1;
}
protected void Button1_Click(object sender, EventArgs e)
{
//then server will call back to FireCallBackFromServer
proxy.CallService(type, "someObject");
}
#region IServiceCallback Members
public void FireCallBackFromServer(string txt)
{
TextBox1.Text = txt; <-- the value does not update on textBox
}
#endregion
}
Please help me to think how to update my textBox from callback event.
Thank you.
It is how WCF callback works. Each callback call is served by its own thread. I think the reason why this happens is because you don't have SynchronizationContext which will point incomming request back to current thread (and hopefully current instance of your page). The contrary example are callbacks used in WPF or WinForm applications. UI thread in these applications by default has SynchronizationContext so if you open service proxy in UI thread, requests to callback are routed back to UI thread - it sometimes causes another problems so you can turn off usage of SynchronizationContext in ServiceBehaviorAttribute.
But even if you solve this problem you will deal with the same problem in ASP.NET. Each request to ASP.NET creates new instance of handler. So each request from your browser will create new instance of page.
I believe that if client is ASP.NET then WCF callback doesn't make sense because I still didn't see any working implementation.
I've run into this issue, where only the UI thread can perform UI updates, in a WPF application using WCF callbacks. I don't do much work in ASP.NET, so I'm not 100% sure the answer is the same but the problem looks very similar.
The way I solved the problem was to use the Dispatcher and lambdas to send the change to the UI thread. Put into the context of your code, it would look something like
public void FireCallBackFromServer(string txt)
{
Dispatcher.CurrentDispatcher.BeginInvoke(new Action(() => TextBox1.Text = txt;));
}
This should update your textbox's content to the text provided in the callback. Give it a try and see how you go.

WCF Service Reference in ASP.net Page - When to Dispose?

I have an ASP.net page that is creating a service reference to a WCF service and making calls in multiple places in my page. I instantiate the service reference in Page_Load and have an instance variable to store it:
private FooClient _serviceClient;
protected void Page_Load(object sender, EventArgs e)
{
_serviceClient = nwe FooClient();
_serviceClient.GetAllFoos();
}
protected void btnSave_Click(object sender, EventArgs e)
{
_serviceClient.SaveFoo();
}
I just discovered that I need to be disposing of the service reference when I am done using it or else the connections will be kept alive and will block incoming connections if I reach the max number of connections. Where would the best place to dispose of these references be? I was thinking of doing it on the OnUnLoad event.
Is there a better way of doing this?
Personally, I would open FooClient when I need it, so not in Page_Load but in the methods that do web service calls. This way, you know exactly what happens to it. I usually take the following approach:
var client = OpenClient();
try
{
// Perform operation(s) on client.
}
finally
{
CloseClient(client);
}
This way you are sure you close your proxy, whatever happens (if there are exceptions you need to catch, simply add a catch clause). The CloseClient method should look like the one in PaulStack's answer.
Another benefit you get when you do this is that multiple calls don't interfere with eachother. Suppose one of you web service calls leads to an unexpected exception. The client channel is now in a faulted state and therefore unusable for any other calls.
And third, suppose an exception does occur that you can not catch or do not want to catch, I'm not sure Page_Unload is actually called (and I don't know what page method will be called in that event). This will also leave connections open.
according to MSDN documentation and personal experience do something as follows:
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
this would allow the correct closing or abortion of the service when necessary rather than leaving them to be disposed at a predefined time - only keep the connection open as long as you definately have to. personally i dont like inheriting from IDisposable as its very heavy in performance

How do I crash the App Pool?

Our ASP.NET 2 web application handles exceptions very elegantly. We catch exceptions in Global ASAX in Application_Error. From there we log the exception and we show a friendly message to the user.
However, this morning we deployed the latest version of our site. It ran ok for half an hour, but then the App Pool crashed. The site did not come back up until we restored the previous release.
How can I make the app pool crash and skip the normal exception handler? I'm trying to replicate this problem, but with no luck so far.
Update: we found the solution. One of our pages was screenscraping another page. But the URL was configured incorrectly and the page ended up screenscraping itself infinitely, thus causing a stack overflow exception.
The most common error that I have see and "pool crash" is the loop call.
public string sMyText
{
get {return sMyText;}
set {sMyText = value;}
}
Just call the sMyText...
In order to do this, all you need to do is throw any exception (without handling it of course) from outside the context of a request.
For instance, some exception raised on another thread should do it:
protected void Page_Load(object sender, EventArgs e)
{
// Create a thread to throw an exception
var thread = new Thread(() => { throw new ArgumentException(); });
// Start the thread to throw the exception
thread.Start();
// Wait a short while to give the thread time to start and throw
Thread.Sleep(50);
}
More information can be found here in the MS Knowledge Base
Aristos' answer is good. I've also seen it done with a stupid override in the Page life cycle too when someone change the overriden method from OnInit to OnLoad without changing the base call so it recursed round in cirlces through the life cycle: i.e.
protected override void OnLoad(EventArgs e)
{
//some other most likely rubbish code
base.OnInit(e);
}
You could try throwing a ThreadAbortException.

How to add common code (specifically to methods marked WebMethod())

I have some ASP.NET page and webservice WebMethod() methods that I'd like to add some common code to. For example:
<WebMethod()> _
Public Function AddressLookup(ByVal zipCode As String) As Address
#If DEBUG Then
' Simulate a delay
System.Threading.Thread.Sleep(2000)
#End If
Return New Address()
End Function
I currently have the #If Debug code in all of my WebMethod() methods, but I am thinking there must be a better way to do this without having to actually type the code in.
Is there a way to determine if a request is to a WebMethod in Application_EndRequest so that I can add this delay project wide?
Note that some methods are Page methods and some are web service methods.
You can check the request URL in Application_EndRequest to determine whether it is a web method call. E.g. something like this (sorry it's in C#):
protected void Application_EndRequest(Object sender, EventArgs e)
{
if (Request.Url.ToString().IndexOf("MyWebService.asmx") > 0)
{
// Simulate a delay
System.Threading.Thread.Sleep(2000);
}
}
Encapsulate the #if DEBUG code in a method and mark it with <Conditional("DEBUG")>. This way, you just write a method call in each <WebMethod>. Might be useful.

Resources