views:

338

answers:

4

I have a web form that once filled out needs to kick off a lengthy process. Since I don't want the user sitting there waiting for it to complete, I want to kick off the task and then take the user to another page to continue working.

Would doing this involve using an asynchronus process, and if so, does someone have an example of how to do this?

A: 

Check out the BackgroundWorker component: BackgroundWorker Component. The sample here shows using it to update the UI in a VB application, but the principle's universal.

Mike Hofer
He's working on the web, and BackgroundWorker doesn't apply well there, since when the request is over, where does the BackgroundWorker report to? The thread servicing the original request has moved on. Also, BackgroundWorker uses a ThreadPool thread (via BeginInvoke), so that reduces scalability of the website as ASP.Net uses ThreadPool threads to service requests.
codekaizen
Ah, missed that. Reading comprehension FTW.
Mike Hofer
The tag is what threw me. I retagged it for ASP.NET since he mentioned in the body that it's a web form using VB.NET.
Mike Hofer
+1  A: 

It depends on the process. How reliable does it need to be? Is it ok if the process crashes? Does it need to recover after it crashes? After the system crashes?

If you need some reliability, then host this long-running task in a Windows Service. Communicate between the web application and the Windows Service by using WCF to pass requests. You can even use an MSMQ connection to make sure the requests are not lost, and the service can pick them up one at a time.

The service can be configured to start when Windows starts, and to restart if it crashes.

John Saunders
A: 

I have found the quickest and lightweight solution for "heavy" background processes is to code the logic in a Console app and use windows scheduler to run the app periodically or trigger it when required.

I have found this much better than coding a windows service as it requires much less error handling (ie if the service dies it needs to recover whereas if the console app dies, just send an error notification and wait until the next run.

For any large website I code I also do one of these console apps to handle all the "non user generated" events as well as the heavy ones.

CodeKiwi
+1  A: 

Basically you need a fire-n-forget implementation where you can just fire an async operation without waiting for it to finish.

Check out the following answer on a related question.

The code is in C#.Net, but vb.net should be similar.

Edit: Vb.net Solution:

This is the vb.net solution to fire a web method asynchronously:

Consider your web method as follows:

Public Class Service1
    Inherits System.Web.Services.WebService

    <WebMethod()> _
    Public Sub LengthyProcess()
        'Perform the lengthy operation
        'Also note this doesn't return anything
        'Hence can be used safely in fire-n-forget way of asynchronous delegate
        System.Threading.Thread.Sleep(1000)
        System.IO.File.WriteAllText("C:\\MyFile.txt", "This is the content to write!", Encoding.UTF8)
        System.Threading.Thread.Sleep(1000)
    End Sub

End Class

Now to call the web method asynchronously you can do either of the following depending your version of .Net:

.Net 3.5 (I am not sure if it works in 2.0)

Make sure to set Async="true" in your Page directive

<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="Default.aspx.vb" Inherits="WebApplication1._Default" Async="true" %>

And in the code behind:

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Dim webService As MyService.Service1

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    End Sub

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
        webService = New MyService.Service1()
        webService.LengthyProcessAsync()
    End Sub

End Class

.Net 2.0/ 1.0

No need to set Async="true"

And in the code-behind:

Partial Public Class _Default
    Inherits System.Web.UI.Page

    Public Delegate Sub MyDelegateCallBack()
    Dim webService As MyService.Service1

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    End Sub

    Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button2.Click
        webService = New MyService.Service1()
        Dim del As MyDelegateCallBack
        del = New MyDelegateCallBack(AddressOf webService.LengthyProcess)
        del.BeginInvoke(Nothing, Nothing)
    End Sub
End Class
Rashmi Pandit
I definitely am looking for a fire-and-forget solution. I don't care what the result of the called webservice is, as I will be handling that in the webservice.I'm sorry, but I couldn't really follow what you're doing in that example that you referenced. If possible could you give me a short explanation? Thanks.
kirpre
I have added the vb.net solution to my answer. Let me know if you need an expln for this one.
Rashmi Pandit
Thanks so much for your help. I was able to get this to work finally. The only weird thing is that although this project is using the 3.5 framework, I could only get the 1.0/2.0 solution that you presented to work. The 3.5 solution would not continue until the webservice had completed. Thanks again.
kirpre
I was able to get this working in 3.5. Did you set Async="true" in the Page directive?
Rashmi Pandit