|
Adding New VB .NET Module
At this stage we already completed the VB .NET web service project. Next, let add another project for the asynchronous web access. Add a new project.
Select Class Library project template and you can use AsyncModuleVB as the project name.
|
Change the default given class name to AsyncModule to reflect the application to be developed.
Add/edit the code. In this class we define the IHttpModule interface which includes event handler and asynchronous callback.
Imports System Imports System.Web Imports System.Threading Imports System.Text.RegularExpressions
Public Class AsyncModule Implements IHttpModule ' shared data members Shared counter As Integer = 0 Shared modCounter As Integer = 0
Const RedirectLocation As String = "accessdenied.aspx" ' instance data members Dim instanceCounter As Integer Dim isAuthorized As Boolean Dim ctx As HttpContext Dim locationRegex As Regex = New Regex(RedirectLocation, RegexOptions.IgnoreCase)
Public Sub Dispose() Implements IHttpModule.Dispose ' nothing to do End Sub
Public Sub Init(ByVal app As HttpApplication) Implements IHttpModule.Init ' register for our async event app.AddOnAuthorizeRequestAsync(New BeginEventHandler(AddressOf AsyncBeginHandler), New EndEventHandler(AddressOf AsyncEndHandler)) ' add a sync EndRequest handler to explain what happened if ' access is denied AddHandler app.EndRequest, New EventHandler(AddressOf OnEndRequest)
Dim modCount As Integer = Interlocked.Increment(modCounter) TraceHelper.WriteLine("AsyncModule.Init: Initializing the module instance...", modCount) End Sub
Public Function AsyncBeginHandler(ByVal src As Object, ByVal e As EventArgs, ByVal cb As AsyncCallback, ByVal extraData As Object) As IAsyncResult Dim app As HttpApplication = CType(src, HttpApplication) ' per-request init instanceCounter = Interlocked.Increment(counter) isAuthorized = False ctx = app.Context ' let anyone into the access denied page Dim m As Match = locationRegex.Match(ctx.Request.FilePath) ' is it something other than accessdenied.aspx? Check authorization... If Not m.Success Then ' create service proxy, async result, and callback Dim authServ As New AuthorizationService.Service1 Dim myAr As MyAsyncResult = New MyAsyncResult(cb, authServ, instanceCounter) Dim myCb As New AsyncCallback(AddressOf WebServiceAsyncCallback) ' start async call TraceHelper.WriteLine("AsyncModule.AsyncBeginHandler: Begin the authorization...", instanceCounter) authServ.BeginIsAuthorized(ctx.User.Identity.Name, myCb, myAr) Return myAr ' otherwise, complete synchronously Else isAuthorized = True TraceHelper.WriteLine("AsyncModule.AsyncBeginHandler: Request for accessdenied.aspx page, skipping...", instanceCounter) Return New MyAsyncResult(Nothing, Nothing, True, True, Nothing, instanceCounter) End If End Function
Public Sub AsyncEndHandler(ByVal ar As IAsyncResult) Dim myAr As MyAsyncResult = CType(ar, MyAsyncResult) TraceHelper.WriteLine("AsyncModule.AsyncEndHandler: Ending the authorization...", instanceCounter) ' if this user isn't authorized, then bail out If Not isAuthorized Then ctx.Response.StatusCode = 403 ctx.ApplicationInstance.CompleteRequest() TraceHelper.WriteLine("AsyncModule.AsyncEndHandler: Request Rejected...", instanceCounter) End If ' clear variables ctx = Nothing instanceCounter = -1 isAuthorized = False myAr.EndOp() ' throw if necessary End Sub
Public Sub WebServiceAsyncCallback(ByVal ar As IAsyncResult) Dim myAr As MyAsyncResult = CType(ar.AsyncState, MyAsyncResult) Dim authServ As AuthorizationService.Service1 = CType(myAr.AsyncState, AuthorizationService.Service1) ' get back result isAuthorized = authServ.EndIsAuthorized(ar) TraceHelper.WriteLine("AsyncModule.WebServiceAsyncCallback: WebService call completed...", instanceCounter) ' tell ASP.NET we're done Dim cnt As Integer = instanceCounter TraceHelper.WriteLine("AsyncModule.WebServiceAsyncCallback: Begin notifing ASP.NET...", cnt) myAr.Complete(False, isAuthorized, Nothing) TraceHelper.WriteLine("AsyncModule.WebServiceAsyncCallback: End notifing ASP.NET...", cnt) End Sub Public Sub OnEndRequest(ByVal src As Object, ByVal E As EventArgs) Dim app As HttpApplication = CType(src, HttpApplication) ' did we block someone? If app.Response.StatusCode = 403 Then app.Response.Redirect(RedirectLocation, False) End If End Sub End Class |
Next, add a new module for the IAsyncResult interface implementation.
You can use the MyAsyncResult as the module name.
|
|
Add/edit the code as shown below. This code implements the IAsyncResult interface.
Imports System Imports System.Threading Imports System.Diagnostics
' Implementation of IAsyncResult Public Class MyAsyncResult Implements IAsyncResult ' data members Dim cb As AsyncCallback Dim state As Object Dim completed As Boolean Dim completedSync As Boolean Dim result As Object Dim err As Exception Dim counter As Integer
Public Sub New(ByVal callb As AsyncCallback, ByVal st As Object, ByVal cnt As Integer) Me.cb = callb Me.state = st Me.counter = cnt End Sub ' constructor with predefined results, ' useful for errors that occur before async work is done Public Sub New(ByVal callb As AsyncCallback, ByVal st As Object, ByVal complete As Boolean, ByVal res As Object, ByVal e As Exception, ByVal cnt As Integer) Me.cb = callb Me.state = st Me.completed = complete Me.completedSync = Me.completed Me.result = res Me.err = e Me.counter = cnt
If Not IsNothing(cb) Then cb(Me) End If
If Me.completed Then TraceHelper.WriteLine("MyAsyncResult.New: MyAsyncResult completed sync", counter) End If End Sub
Public ReadOnly Property AsyncState() As Object Implements System.IAsyncResult.AsyncState Get Return state End Get End Property
Public ReadOnly Property AsyncWaitHandle() As System.Threading.WaitHandle Implements System.IAsyncResult.AsyncWaitHandle Get Return Nothing ' Wait not Supported End Get End Property
Public ReadOnly Property CompletedSynchronously() As Boolean Implements System.IAsyncResult.CompletedSynchronously Get Return completedSync End Get End Property
Public ReadOnly Property IsCompleted() As Boolean Implements System.IAsyncResult.IsCompleted Get Return completed End Get End Property ' non IAsyncResult Stuff Public ReadOnly Property AsyncError() As Exception Get Return err End Get End Property
Public Sub Complete(ByVal sync As Boolean, ByVal res As Object, ByVal e As Exception) TraceHelper.WriteLine("MyAsyncResult.Complete: MyAsyncResult.Complete called", counter) completed = True completedSync = sync result = res err = e If Not IsNothing(cb) Then cb(Me) End If End Sub
Public Function EndOp() As Object If Not IsNothing(err) Then Throw New Exception("AsyncOperation failed", err) End If Return result End Function End Class |
Next, add the helper class that will dump messages. You can use TraceHelper as the class name.
Add/edit the code as given below. This code just printing a message related to the asynchronous operations.
Imports System Imports System.Threading Imports System.Diagnostics
Public Class TraceHelper Public Shared Sub WriteLine(ByVal msg As String, ByVal cnt As Integer) Dim tid As Integer = Thread.CurrentThread.ManagedThreadId Trace.WriteLine(String.Format("TraceHelper.WriteLine: ThreadId: {0} Counter: {1} Msg: {2}", tid, cnt, msg)) End Sub End Class |