Example of Asynchronous page processing in ASP.net webforms (.NET 2.0) - asp.net

Can someone provide me with a simple example of Asynchronous page processing in ASP.NET Webforms 2.0 (I'm using VS 2010, so new syntax like lambdas are ok)?
I have some long running requests that I don't want tying up IIS threads.
For simplicity's sake, let's say my current code looks like this:
protected void Page_Load(object sender, EventArgs e)
{
string param1 = _txtParam1.Text;
string param2 = _txtParam2.Text;
//This takes a long time (relative to a web request)
List<MyEntity> entities = _myRepository.GetEntities(param1, param2);
//Conceptually, I would like IIS to bring up a new thread here so that I can
//display the data after it has come back.
DoStuffWithEntities(entities);
}
How can I modify this code so that it is asynchronous? Let's assume that I already set async="true" in the aspx page.
EDIT
I think I figured out how to get what I'm looking for. I've put the example code in an answer here. Feel free to point out any flaws or changes that can be made.

I asked some folks on the ASP.NET team. Here's their emailed response to me, and now, to you.
All that code ends up doing is spinning up a new thread and performing delegate invocation on that thread. So now there are two threads running: the request thread and the new thread. Hence this sample actually has worse performance than the original synchronous code would have had.
See http://www.asp.net/web-forms/tutorials/aspnet-45/using-asynchronous-methods-in-aspnet-45 for a sample on how to write and consume async methods in ASP.NET.

Here is a simple example of asynchronous processing.
protected void Page_Load(object sender, EventArgs e)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadProc));
ThreadPool.QueueUserWorkItem(state => Dokimes_Programming_multithread_QueryWorkThead.ThreadProc2());
Debug.Write("Main thread does some work, then sleeps.");
// If you comment out the Sleep, the main thread exits before
// the thread pool task runs. The thread pool uses background
// threads, which do not keep the application running. (This
// is a simple example of a race condition.)
// Thread.Sleep(4000);
txtDebug.Text += "ended";
Debug.Write("end.");
}
// This thread procedure performs the task.
static void ThreadProc(Object stateInfo)
{
// No state object was passed to QueueUserWorkItem, so stateInfo is null.
Debug.Write(" Hello from the thread pool 1.");
}
static void ThreadProc2()
{
// No state object was passed to QueueUserWorkItem, so stateInfo is null.
Debug.Write("Hello from the thread pool 2.");
}
Other way
You can use the PageAsyncTask, see here a full example:
http://msdn.microsoft.com/en-us/library/system.web.ui.pageasynctask.aspx
Something like
clAsynCustomObject oAsynRun = new clAsynCustomObject();
PageAsyncTask asyncTask = new PageAsyncTask(oAsynRun.OnBegin, oAsynRun.OnEnd, oAsynRun.OnTimeout, null, true);
Page.RegisterAsyncTask(asyncTask);
Page.ExecuteRegisteredAsyncTasks();

I think I discovered how to do what I wanted to accomplish... though it may not be the best way, feel free to chime in.
At the time of writing there was only one answer in this thread, by Aristos. While he gave an example of executing an asynchronous request, what I wanted was a way to tell ASP.NET to execute some long running method, release the IIS thread so it can be available to service other requests, and then come back when the method finished.
Here's what I came up with, using the same (or similar) example in the question:
using System;
using System.Collections.Generic;
using System.Threading;
using System.Web.UI;
namespace WebApplication2
{
public class MyEntity
{
public string Name { get; set; }
}
public class MyRepository
{
public List<MyEntity> GetEntities(string param1, string param2)
{
Thread.Sleep(10000);
return new List<MyEntity> {new MyEntity {Name = "John Smith"}};
}
}
public partial class Default : Page
{
private readonly MyRepository _myRepository = new MyRepository();
private List<MyEntity> _myEntities;
protected void Page_Load(object sender, EventArgs e)
{
}
private void DoStuffWithEntities()
{
Response.Write("<br/><br/><b>" + _myEntities[0].Name + "</b><br/><br/>");
}
protected void _btnProcess_Click(object sender, EventArgs e)
{
AddOnPreRenderCompleteAsync(BeginExecution, EndExecution, null);
}
private void GetEntities()
{
string param1 = _txtParam1.Text;
string param2 = _txtParam2.Text;
//This takes a long time (relative to a web request)
_myEntities = _myRepository.GetEntities(param1, param2);
}
private IAsyncResult BeginExecution(object sender, EventArgs e, AsyncCallback callback, object state)
{
var t = new ThreadStart(GetEntities);
return t.BeginInvoke(callback, null);
}
private void EndExecution(IAsyncResult result)
{
//Conceptually, I would like IIS to bring up a new thread here so that I can
//display the data after it has come back.
DoStuffWithEntities();
}
}
}

Related

Independent thread in Asp.net 4.5

protected void Button1_OnClick(object sender, EventArgs e)
{
FineTuneDB();// Long Task running in db
SendSMStoAllClients();// Using Twolio API to send sms to all client long task
lblText.Text = "Button click is completed our system threads working on your request";
}
Is this possible that on button click I can response to client and independent long task going on separately.
If you don't care about whether task is completed or not, you call FineTuneDB method like this.
Action fineTuneDB = FineTuneDB;
fineTuneDB.BeginInvoke(null, null);
Asynchronous Method Invocation
Updated:
Action<int, string> fineTuneDB = FineTuneDB;
fineTuneDB.BeginInvoke((int)Session["id"],
Session["name"].ToString(), null, null);
// Your method will be like this
public void FineTuneDB(int id, string)
{
}

ASP.NET Response.Filter

I need to create filter that replace tags <h2> in the HTML to <h3>:
My filter
public class TagsFilter:Stream
{
HttpContext qwe;
public TagsFilter(HttpContext myContext)
{
qwe = myContext;
}
public override void Write(byte[] buffer, int offset, int count)
{
string html = System.Text.Encoding.UTF8.GetString(buffer);
html = html.Replace("<h2>", "<h3>");
qwe.Response.Write(html.ToCharArray(), 0, html.ToCharArray().Length);
}
My module
public class TagsChanger : IHttpModule
{
public void Init(HttpApplication context)
{
context.Response.Filter = new TagsFilter(context.Context);
}
I get error System.Web.HttpException:In this context, the answer is not available.
Look at Rick Strahl's post about "Capturing and Transforming ASP.NET Output with Response.Filter".
Response.Filter content is chunked. So to implement a Response.Filter effectively requires only that you implement a custom stream and handle the Write() method to capture Response output as it’s written. At first blush this seems very simple – you capture the output in Write, transform it and write out the transformed content in one pass. And that indeed works for small amounts of content. But you see, the problem is that output is written in small buffer chunks (a little less than 16k it appears) rather than just a single Write() statement into the stream, which makes perfect sense for ASP.NET to stream data back to IIS in smaller chunks to minimize memory usage en route.
Unfortunately this also makes it a more difficult to implement any filtering routines since you don’t directly get access to all of the response content which is problematic especially if those filtering routines require you to look at the ENTIRE response in order to transform or capture the output as is needed for the solution the gentleman in my session asked for.
So in order to address this a slightly different approach is required that basically captures all the Write() buffers passed into a cached stream and then making the stream available only when it’s complete and ready to be flushed.
As I was thinking about the implementation I also started thinking about the few instances when I’ve used Response.Filter implementations. Each time I had to create a new Stream subclass and create my custom functionality but in the end each implementation did the same thing – capturing output and transforming it. I thought there should be an easier way to do this by creating a re-usable Stream class that can handle stream transformations that are common to Response.Filter implementations.
Rick Strahl wrote own implementation of stream filter that permits text replacing in right way.
I did a small example. I think you have to access the original stream, rather than accessing the httpContext.
public class ReplacementStream : Stream
{
private Stream stream;
private StreamWriter streamWriter;
public ReplacementStream(Stream stm)
{
stream = stm;
streamWriter = new StreamWriter(stream, System.Text.Encoding.UTF8);
}
public override void Write(byte[] buffer, int offset, int count)
{
string html = System.Text.Encoding.UTF8.GetString(buffer);
html = html.Replace("<h2>", "<h3>");
streamWriter.Write(html.ToCharArray(), 0, html.ToCharArray().Length);
streamWriter.Flush();
}
// all other necessary overrides go here ...
}
public class FilterModule : IHttpModule
{
public String ModuleName
{
// Verweis auf Name in Web.config bei Modul-Registrierung
get { return "FilterModule"; }
}
void context_BeginRequest(object sender, EventArgs e)
{
HttpContext context = HttpContext.Current;
context.Response.Filter = new ReplacementStream(context.Response.Filter);
}
public void Init(HttpApplication context)
{
context.BeginRequest += new EventHandler(context_BeginRequest);
}
}
Found the solution at this post on SO. Worked for me.
The problem is that you are applying the filter in the Init event, which only occurs once per application instance (it is essentially close to App_Start).
What you need to do is hook in the BeginRequest event from the Init event, and then apply the filter on BeginRequest.
public void Init(HttpApplication application)
{
application.BeginRequest += BeginRequest;
}
private void BeginRequest(object sender, EventArgs e)
{
var app = (HttpApplication)sender;
var context = app.Context;
context.Response.Filter = new TagsFilter(context);
}

How to make a ASP.NET Webforms application testable?

I am looking at a legacy enterprise application, which written using ASP.NET. No controls or web forms. This is how it works:
EmployeeList.aspx:
<%# Page Language="C#" AutoEventWireup="true" CodeFile="EmployeeList.aspx.cs" Inherits="EmployeeList" %>
EmployeeList.aspx.cs:
protected void Page_Load(object sender, EventArgs e)
{
// Security Check
// Load Template, get version 1.4 of active employee list
StringBuilder template = GetTemplate("Employee", "ActiveList", "1.4", true);
// Get list from database
using(SqlDataReader objReader = GetListFromDB())
{
while(objReader.Read())
{
//fills data
TUtils.Replace(template, ROW, "%name%", objReader[0]);
}
}
// return response
Response.Write(template.ToString());
}
private StringBuilder GetTemplate(string x, string y, string v, bool z);
{
// returns template
}
private SqlDataReader GetListFromDB() {
// returns data reader
}
My question is, since we are not using web forms, is there a way to introduce NUnit in this event driven model (as shown above)?
Also, please avoid suggestions to move to ASP.NET MVC or other patterns, which we are considering, but wondering is there any way to convert this enterprise application testable.
This is absolutely possible. You should have a look on implementing MVP pattern with ASP.NET Webforms. There are several open source implementations but you can do a smaller specialized on your your own.
The basics are to move your code behind logic to a presenterclass. The presenter class has a reference to the page implementing an interface. The trick in your case will be to Mock the Page.Response object for your test. Thats why it´s hard to unit test it right way. The PageResponse Property contains a object deriving from HttpResponseBase and that´s the baseclass you should Mock in your tests and do your asserts on with your example. You could start with that and then extend your presenter with functionalty like Session, Request etc.
If you don´t have any markup at all probably you can just create the presenter in the view constructor and don´t bother of having and reference to the view.
To clarify: The big trick is to get the code out of the aspx.cs file. That beast is not testable.
Sample base class for Presenters:
public class Presenter<T> where T : class, IView
{
protected readonly T View;
protected Presenter(T view, ILogger logger)
{
View = view;
}
public virtual void page_PreRender(object sender, EventArgs e)
{
}
public virtual void page_Init(object sender, EventArgs e)
{
}
public virtual void page_Load(object sender, EventArgs eventArgs)
{
}
public HttpContextBase HttpContext { protected get; set; }
protected HttpRequestBase Request
{
get { return HttpContext.Request; }
}
}
Since most of your code is in the code-behind, I dont think that the usual testing approach with NUnit / Visual Studio testing framework will work well.
However, I think one possible approach is to use UI Testing frameworks like WATIN / Selenium. This will enable you to still write tests for the various functionality.
I have done something similar in the past by basically writing a test case for every UI action that results in a server postback. May not be ideal but it does allow you to automate your testing.

System.Windows.Forms.WebBrowser inside Asp.net WebForm DocumentCompleted not fired

Yeah some people would say "Are you crazy using winforms controls inside asp forms"... and I think they are right. But I would say.. "I'm not the only one!!, take a look"
http://www.eggheadcafe.com/tutorials/aspnet/b7cce396-e2b3-42d7-9571-cdc4eb38f3c1/build-a-selfcaching-asp.aspx
So...
Doing some kind of stuff like the previous link. I did the following:
using System;
using System.Threading;
using System.Windows.Forms;
namespace XXXX.aspx.Print
{
public partial class Drucker : System.Web.UI.Page
{
private ManualResetEvent mre = new ManualResetEvent(false);
protected void Page_Load(object sender, EventArgs e)
{
Threading();
}
private void Threading()
{
Thread t = new Thread(new ThreadStart(GoAhead));
t.SetApartmentState(ApartmentState.STA);
t.Start();
mre.WaitOne();
t.Abort();
}
private void GoAhead()
{
DateTime time = DateTime.Now;
WebBrowser webBrowser = new WebBrowser();
webBrowser.Navigate(Request.UrlReferrer.ToString());
webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(webBrowser_DocumentCompleted);
while (true)
{
Thread.Sleep(0);
TimeSpan elapsedTime = DateTime.Now - time;
if (elapsedTime.Seconds >= 13)
{
mre.Set();
}
System.Windows.Forms.Application.DoEvents();
}
}
void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
WebBrowser webBrowser = (WebBrowser)sender;
if (e.Url.AbsolutePath != webBrowser.Url.AbsolutePath) return;
webBrowser.Print();
}
}
}
Now...
the DocumentCompleted event is not fired (neither ProgressChanged) and I've tried the next:
Add the library MsHtml.dll to my project and place the file into my lib folder... I did it... No changes.
Try to handle the state of the WebBrowser.ReadyState... I did it... No changes (Actually after receive the WebBrowserReadyState.Complete I tried to print the document with
webBrowser.Print(); but I receive a weird IE pop up telling me: "'dialogArguments.__IE_PrintType' is Null or a not an object'"... ok so doing some research I got: a microsoft topic about dcomcnfg and some com security settings
I did it... No changes.
...
By the way I´m working in 64bits, Win7...
So before I format the whole computer...
Any suggestions?
WebBrowser is never inplace-activated by its ActiveX container, which you don't have. Try put it on a form first.
By the way, you know you are in the unsupported territory when you use WinInet, the network layer of webbrowser control, in a Windows Service, right?

RhinoMocks Event Subscription

Being new to RhinoMocks and Unit Testing, I have come accross an issue that I cannot seem to find a resolution to (no matter how much documentation I read).
The issue is this: I have created an Interface that exposes 5 Events (to be used for a view in ASP.NET and the MVP Supervisory Controller pattern..... I know, I should be using MVC, but that's a whole other issue). Anyway, I want to test that when a certain event fires on the view, we'll call it "IsLoaded", that a method inside of my Presenter is called and, using Dependency Injection, a value is returned from the Dependency and set to the view. Here is where the problem starts: when I use Expect.Call(Dependency.GetInfo()).Return(SomeList), the Call never executes (without the mock.ReplayAll() method being invoked). Well, when I invoke the ReplayAll method, I get ExpectationExceptions because of the Subscription by the Presenter object to the other Events exposed by the View Interface.
So, for me to test that IView.IsLoaded has fired, I want to verify that IView.ListOfSomething has been updated to match the list I passed in via the Expect.Call(). However, when I set the expectation, the other Event subscriptions (which occur straight out of the constructor for the Presenter) fail the #0 Expectations of the test. What I get is, view.Save += this.SaveNewList tosses up a RhinoMocks ExpectationViolationException.
My million dollar question is this: Is it necessary I set expectations for ALL of my events (via [Setup]), or is there something that I'm missing/not understanding about how Unit Testing or RhinoMocks works?
Please bear in mind I am extremely new to Unit Testing, and therefore RhinoMocks. If it appears I don't know what I'm talking about, please feel free to point that out.
I'm working on a project where we used MVP and rhino mocks as well. What we did was simply expect all event subscriptions in every test.
private void SetupDefaultExpectations()
{
_mockView.Initializing += null; LastCall.IgnoreArguments();
_mockView.SavingChanges += null; LastCall.IgnoreArguments();
}
Then we built a extension method on IMockedObject (from RhinoMocks) to trigger events in the unit tests and un-wrap exceptions so that they can be expected in the standard NUnit way.
static class IMockedObjectExtension
{
public static void RaiseEvent(this IMockedObject mockView, string eventName, EventArgs args)
{
EventRaiser eventraiser = new EventRaiser(mockView, eventName);
try
{
eventraiser.Raise(mockView, args);
}
catch (TargetInvocationException ex)
{
throw ex.InnerException;
}
}
public static void RaiseEvent(this IMockedObject mockView, string eventName)
{
RaiseEvent(mockView, eventName, EventArgs.Empty);
}
}
This could then be used from the unit test like this
using(_mocks.Record())
{
Expect.Call(dependency.GetInfo()).Return(someList);
}
using(_mocks.Playback())
{
Presenter presenter = new Presenter(_mockView, dependency);
(_mockView as IMockedObject).RaiseEvent("SavingChanges");
}
To eliminate duplication between presenter tests we have refactored this to a BasePresenterTest base class which sets up this basic structure for all presenter tests and exposes helper methods to the sub class.
public abstract class BasePresenterTest<VIEW> where VIEW : IBaseView
{
protected MockRepository _mocks;
protected VIEW View { get; private set; }
protected abstract void SetUp();
protected abstract void TearDown();
protected abstract void SetupDefaultExpectations();
[SetUp]
public virtual void BaseSetUp()
{
_mocks = new MockRepository();
View = _mocks.CreateMock<VIEW>();
SetUp();
}
[TearDown]
public virtual void BaseTearDown()
{
TearDown();
View = null;
_mocks = null;
}
protected virtual void BaseSetupDefaultExpectations()
{
//Setup default expectations that are general for all views
SetupDefaultExpectations();
}
protected virtual IDisposable Record()
{
IDisposable mocksRecordState = _mocks.Record();
BaseSetupDefaultExpectations();
return mocksRecordState;
}
protected virtual IDisposable Playback()
{
return _mocks.Playback();
}
protected void RaiseEventOnView(string eventName)
{
(View as IMockedObject).RaiseEvent(eventName);
}
}
This eliminates alot of code from the tests in our project.
We still use a old version of RhinoMocks but I will try to update this once we move to a later version.

Resources