Using Asyncronous Tasks In ASP.NET

ASP.NET has a limited number of threads that it uses to service incoming requests.  Thes threads from the its thread pool, and when its collection of threads are busy, requests have to queue up waiting for an open thread.

But, what happens when you have threads that are blocking waiting for another process to complete?  This could we a database call, or a webservice call, or an IO operation etc.

Well, what happens is that the thread, while doing no real work, is unavailable to service requests.

So, if your database is crunching on some long queries, other simple web requests may be sitting in the queue unable to be handled, even though the webserver CPU is idle.

One solution to this is to use Async pages/methods in ASP.NET 2 or greater.

Async operations allow the thread to be returned back to the thread pool instead of blocking, while some process is executed.

 

There is more than 1 way to do async operations like this from asp.net pages. 

One is to use RegisterAsyncTask and the other to user AddOnPreRenderCompleteAsync as well as declare the page as Async=”true”.

I won’t go into all the details, but AddOnPreRenderCompleteAsync is probably simpler, but you can’t define a timeout, you can’t call it multiple times in parallel, and in the EndAsyncOperation event handler you can’t access things like the httpcontext object.

Here are 2 examples of pages that are asynchronously serving up a PDF document (which is itself served from a page DownloadPDF.aspx, which has a 5 second thread sleep in it to simulate the processing of the report on another server.

Using AddOnPreRenderCompleteAsync:

Imports System.Net
Imports System.IO

Partial Class AsyncServer
    Inherits System.Web.UI.Page

    Dim _request As WebRequest

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        AddOnPreRenderCompleteAsync(New BeginEventHandler(AddressOf BeginAsyncOperation), _
                                    New EndEventHandler(AddressOf EndAsyncOperation))
    End Sub

    Function BeginAsyncOperation(ByVal sender As Object, ByVal e As EventArgs, ByVal cb As AsyncCallback, ByVal state As Object) As IAsyncResult
        _request = WebRequest.Create(HttpContext.Current.Request.Url.Scheme & _
                                     "://" & HttpContext.Current.Request.Url.Authority & _
                                     Page.ResolveUrl("DownloadPDF.aspx"))
        Return _request.BeginGetResponse(cb, state)
    End Function

    Sub EndAsyncOperation(ByVal ar As IAsyncResult)
        Dim reportResponse As WebResponse = _request.EndGetResponse(ar)
        Dim reader As New BinaryReader(reportResponse.GetResponseStream())

        Dim buffer(reportResponse.ContentLength) As Byte
        buffer = reader.ReadBytes(buffer.Length)
        
        Response.Clear()
        Response.ClearHeaders()
        Response.ClearContent()
        Response.ContentType = "Application/pdf"
        Response.BinaryWrite(buffer)
    End Sub

End Class

 

But I prefer to use RegisterAsyncTask.  Now, keep in mind that many operations will already support async versions (webrequests, webservice calls, databases calls, file IO etc), but if there isn’t already built in support for an async call, you can make your own method work in this framework with an async delegate.  Check out the commented code below for how you could do this, but because webrequests already support making the call in an asynchronous fashion, I don’t need to.

Imports System.Net
Imports System.IO

Partial Class RegisterAsyncTaskServer
    Inherits System.Web.UI.Page

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Page.AsyncTimeout = New System.TimeSpan(0, 0, 8)
        Dim task As New PageAsyncTask(New BeginEventHandler(AddressOf BeginGetAsyncData), _
                                      New EndEventHandler(AddressOf EndGetAsyncData), _
                                      New EndEventHandler(AddressOf TimeoutGetAsyncData), "task1", True)

        RegisterAsyncTask(task)
    End Sub

    '*************** This is one way to do this if not using an async download method by creating an async delegate
    'Dim taskDelegate As AsyncTaskDelegate
    '' Create delegate.
    'Delegate Sub AsyncTaskDelegate()
    'Private Function BeginGetAsyncData(ByVal src As Object, ByVal args As EventArgs, ByVal cb As AsyncCallback, ByVal state As Object) As IAsyncResult
    '    Dim extraData As New Object
    '    taskDelegate = New AsyncTaskDelegate(AddressOf DownloadReport)
    '    Dim result As IAsyncResult = taskDelegate.BeginInvoke(cb, extraData)
    '    Return result
    'End Function
    'Private Sub DownloadReport()
    'End Sub

    Private reportRequest As WebRequest

    Private Function BeginGetAsyncData(ByVal src As Object, ByVal args As EventArgs, ByVal cb As AsyncCallback, ByVal state As Object) As IAsyncResult
        reportRequest = WebRequest.Create(HttpContext.Current.Request.Url.Scheme & "://" & _
                                          HttpContext.Current.Request.Url.Authority & _
                                          Page.ResolveUrl("DownloadPDF.aspx"))
        Return reportRequest.BeginGetResponse(cb, state)
    End Function


    Private Sub TimeoutGetAsyncData(ByVal ar As IAsyncResult)
        Response.Write("TIMEOUT")
    End Sub

    Private Sub EndGetAsyncData(ByVal ar As IAsyncResult)
        Dim reportResponse As WebResponse = reportRequest.EndGetResponse(ar)
        Dim reader As New BinaryReader(reportResponse.GetResponseStream())

        Dim buffer(reportResponse.ContentLength - 1) As Byte
        buffer = reader.ReadBytes(buffer.Length)

        Response.Clear()
        Response.ClearHeaders()
        Response.ClearContent()
        Response.ContentType = "Application/pdf"
        Response.BinaryWrite(buffer)
        Response.Flush()
    End Sub

End Class

Nice!

Verizon tried to bill me for Quick2Net service

I spent over an hour arguing with people from Verizon about a charge on my bill for my EVDO card.

They charged me another 200 dollars for “minutes” used.  Clearly this is a mistake, as I don’t use the chip embedded in my laptop like others use a cell phone.  It’s impossible actually, seeing as how you hold a mobile phone up to your face and my device is embedded in my laptop :).

At first, they spent 20 minutes telling me that the extra charge was for VOIP calls.  This is a directly quote from the CSR: “For example, you can use Yahoo instant messenger to make VOIP calls where you talking to someone through your computer.”

I continued to argue that they don’t charge for VOIP traffic any differently than normal traffic.

3 times she told me that, yes, in fact they did, and it’s right there in my contract.  I kept asking her to show me where that was in my contract, and of course there was nothing about it.

In fact, Verizon even advertises VOIP as on of the uses of getting an EVDO card and data plan.

Anyway… so eventually they changed their tune and started saying that it was because I was using their Quick2Net network.  I tried to get them to understand that making VOIP calls, and connecting to a different data network are nothing alike, but they continued to act as if they were 1 in the same.

After 45 minutes or so we were no longer arguing about Skype usage and were fully on the topic of the Quick2Net network.  The CSR couldn’t even explain to me WHAT the Quick2Net network was, or HOW I could even connect to this network, IF I WANTED TO!

They had 2 times when they claimed I connected to the Quick2Net network for an extended period.  Both of these times conflicted with my local VZAccessManager logs of when I was connected to the BroadbandAccess Rev-A network, but the CSR didn’t seem to care about the fact that my own logs conflicted with what they were trying to bill me for.

While I was on hold I did some research and found that the Quick2Net network is the ooooooooold data network that Verizon has.  It’s speed is 14.4k, or about 100 times slower than the connection I already pay for.

In fact, when I found this screen shot, I remembered Quick2Net:

This was probably about 5 years ago when this option was available.  As you can see, you used to be able to click on Quick2Net (and it used to be free), but I haven’t had that option available to me for years.

Finally, the CSR set me to her supervisor, who agreed to refund my charge, and setup my account so that I wouldn’t connect to Quick2Net again.

But, not because I never really connected to quick to net, or because it was a billing error on their part, or because if I DID connect, it was through a fault of their software/network/switches.  No, they agreed because I wouldn’t have “benefited” from the Quick2Net services (seeing as how I already pay for a 100x faster connection).  I made a point to let him know that I never connected to this service, but accepted the resolution.

If you are unfortunate as I was, and Verizon tries to bill you for this, good luck.

I didn’t find anything online with people saying they had this same exprience, so I’m posting this in case others run into this same issue and are wondering what happened.

NeatWorks vs Paperport

I bought a cheap version of NeatWorks and downloaded a demo of Paperport from Nuance in an attempt to find a good option for digitizing all my mail.

My experience with NeatWorks isn’t great.  It mostly works, but some problems have cropped up from time to time that make me have some concern.  For example, when I first installed the application it automatically searched for updates: it found one, and I installed the newer version of the app (newer that what was on the CD).

Well, it turned out over the next few days that much of the text that it would OCR would not make it into the search index.  So when you went to search for some keywords nothing would be found.

I contacted support and after walking me through a bunch of stuff, it turned out that there was a much newer version of the app available (but somehow their auto update didn’t find it).  This new version seemed to fix this problem, but I basically had to rescan all my documents.  At that point, it was only a few, but what if I run into another problem after I have a few hundred scanned documents?

Speaking of a few hundred documents, right now I have 50 pages scanned and my database is 300MB.  This is insane!!  Even if you backup your data and compress it it ends up being like 500KB / page.  WAAAAAAY to large.  I guess it really isn’t THAT big of a deal.  I mean if I end up with 5000 pages (100x what I have now) and my database is 30GB, it will really be stupid, but it won’t really be a problem I guess. 

Another concern of mine with NeatWorks is lock-in.  What if I want to move to some other software product in the future?  How can I get my documents out of NeatWorks?  Well, it turns out not very easily.  You can export each document to a PDF, but you have to do it 1 at a time.  If you select multiple documents, it puts them into 1 giant PDF.  This is completely useless.  If you have 5000 pages and you want to start using some other PDF indexing product, it will take you forever to export all those files.  Also, you can only use the software with their scanners.

Also, last night I noticed that some receipt that I had scanned never showed up in my “inbox” (it goes from the Quick Scan to the Inbox).  This has me concerned.  I got no error message or any indication that something didn’t work right.  It just never showed up.

Paperport has some nice pluses on its side.  It uses any scanner (not just 1 like w/ NeatWorks).  It stores all images as PDFs in a folder on your file system so you can manage them as you would any other file.

Reviews for PaperPort were not good, but others claimed the newer service pack fixed a lot of problems.  I did have it lock up on me once, but otherwise it seemed to work. 

The main problem with Paperport is it is trying to do to many things.  NeatWorks is for exactly what I am doing, Paperport is trying to be a fully featured Scanner software product, helping you to manage photos and stuff like that.  The UI is pretty poor also.

Basically though, the only reason I can’t see myself using Paperport is that there is no way to attach and search by a date field.  I don’t care about the date I scan a document (the file created date), I care about the date of the document.  So when I search for Mastercard statements, I can filter out what I want by date.  I didn’t see any way to do this with Paperport.

Then when I went to submit a question to their support team asking about this, I was totally convinced to not buy their product (click for full size):

As many users have commented, it really does look like Paperport WAS a good product which has just morphed into a big, bloated, difficult to use product.

UPDATE: Now Nuance has changed me for the full product.  I’m guessing part of their trial is that they will automatically bill you for the software if you don’t cancel your trial.  Wonderful, I am really glad I didn’t pick Paperport: time to call and demand a refund…. again (they charged me 8 bucks for some BS extended download service on my free trial… these guys suck).

SQL Server encountered error 0x80070422 (FIXED)

Today we started getting this error when trying to do full text search with SQL Server 2008.

Msg 30046, Level 16, State 1, Procedure CodeMaster_GetCostCodesByCriteria_FullText, Line 47

SQL Server encountered error 0x80070422 while communicating with full-text filter daemon host (FDHost) process. Make sure that the FDHost process is running. To re-start the FDHost process, run the sp_fulltext_service ‘restart_all_fdhosts’ command or restart the SQL Server instance.

Google has NOTHING on this problem, except 1 other guy reporting it to MS, who tells him to go to some other forum.

Great.

If I find anything I will post it.

UPDATE:

Ok I figured this out.

The problem was that the actual FTS service was disabled (but not just that, so read on).

So go into your services and make sure that this one is running:

SQL Full-text Filter Daemon Launcher (MSSQLSERVER)

But even after I set this up running things weren’t working.  More research led me to find out that there was an issue with the fact that we run our SQL Server under a domain account and the full text search was not running as that same user.

So I configured this service to run as the same user and restarted the service.

Then in SQL Server I ran this:

EXEC sp_fulltext_service 'restart_all_fdhosts'

to restart things.

I also right clicked on the FTS catalog (under databasename/Storage/Full Text Catalog), picked properties, and then selected the option to rebuild catalog.

 

Regenerating the designer.vb and designer.cs files

Chances are you have had this happen to you.

You start getting compile errors on your asp.net controls in your code behind pages.  But the controls exist on the page??  Whats the deal?

Well, in VS2003 the designer would create the class level controls in your code behind.  It would created a special region where it would put all it’s autogenerated code.

2005 brought the new “Web Site Project” which used a “CodeFile” instead of “CodeBehind” attribute on the page tag.  In addition, the codefile/codebehind became a Partial Class.  VS would then put all the generated code in a seperate file so it didn’t cramp up your code behind.

In Web Application projects, the autogen code is stored in .designer.vb files:

But everynow and then, things get out of sync, or the designer files get totally lost.

Here is how you can regenerate them:

First, make sure your class names, and page attributes are right.  The Page tag should have a Codebeind attribute pointing to the aspx.vb file and an Inherits attribute that contains the fully qualified class name in the codebehind.  (This instructions are for Web App Projects, not Web Site Projects, which use Codefile instead of Codebehind).

Second, create a designer file if one doesn’t exist.  Click the “Show all files” icon in the Solution Explorer to see if you have designer files.  If not, add a class file with the right name page_name.aspx.designer.vb.  VS will automatically put it “under” the aspx page.

Make sure all namespaces are right.  Check your code beind, your designer file, and your page codebehind attribute.

Open your page in a designer and rename one of your controls.  Save everything and close the code and designer windows.  Open the designer back up and rename the control back.  Now look at your designer file, it should have a punch of controls in it, and now VS shouldn’t complain about compile errors in your code behind.

 

Copy and Paste not working in RDP?

You may notice that your clipboard will sometimes work over RDP(TS) sessions, but sometimes not.

Normally the problem is that the server has clipboard access disabled.

Just follow these instructions to enable it

1. Log into the TS (on an account that has administrator rights)
2. Run the Terminal Services Configuration program
3. Select the Connections folder (under Terminal Services Configuration on the left window pane)
4. Right-click on the RDP-tcp connection (in the right window pane) and select Properties.
5. Click the Client Setting tab
6. Un-tick the Clipboard Mapping option under the Disable the following: heading.

Presto.

Supporting People with D-Link Routers

D-Link has a nice feature on their website that really helps people like me when I am trying to support a client who users one of these devices.

Normally when I am supporting someone I login remotely so I can view their screen and make the changes for them right there on their computer.  But if their router is down, they usually can’t get internet access to allow for this to happen.

So, it can be pretty difficult to talk to someone on the phone with stuff like “Ok, do you see anywhere on the screen where it talks about setting up PPPoE information?  Maybe something regarding WAN connectivity?” 

But, if you get their D-Link model number, you can go to the device page on DLinks website and launch an emulator of their web interface.

For example: http://www.dlink.com/products/?pid=530
Click on “Emulator” on the right hand side.

This allows you to see the exact same screen they are looking at.  It also allows you to click around to find the right page w/o asking them to click every link and read you ever bit of info. 

It’s a great tool, and it probably saved me an hour of time with one of my clients today.

Showing Deleted Folders In TFS

Sometimes you might try to rename a folder in TFS Team Explorer and it tells you that you can’t rename the folder b/c an existing item exists (but it doesn’t).

The reason is that if there is a delete folder with the same name, it won’t allow you to name a current folder with the same name.

To see your deleted folders (so you can undelete, rename, and delete again) you can use the following option under Tools->Options.