Reputation: 2516
I converted a project from MVC3 to MVC4 and also from Entity Framework 5 to EF 6.1. In the code there is a VBHTML page that has a code section "Using Html.BeginForm.... end using". in this page, a user can select a file and click submit. That calls a POST method in a controller. The method in the controller uploads the selected file to Google drive using resumable uploader (aynchronous) of GData API. ResumableUploader has to be used (GData API restrictions for uploading PDF and big files). Now, this code has always worked in the past in MVC3. As soon as the platform was changed to MVC4, started getting this exception:
An asynchronous operation cannot be started at this time. Asynchronous operations may only be started within an asynchronous handler or module or during certain events in the Page lifecycle. If this exception occurred while executing a Page, ensure that the Page is marked <%@ Page Async="true" %>
at System.Web.AspNetSynchronizationContext.OperationStarted() at Google.GData.Client.ResumableUpload.ResumableUploader.AsyncStarter
(AsyncResumableUploadData data, WorkerResumableUploadHandler workerDelegate,
Object userData)
I did put @Page Async="true" in the VBHTML page, but that did not help. I am 100% sure this is related to MVC4 and/or .Net 4.5 because no other change has been done in the code (other than moving to MVC4 and moving to .Net4.5). I have two code branches now, one on MVC3 and one on MVC4. When I compile MVC3 and copy the output DLL in the app, the above issue does not surface. When I replace that DLL by MVC4 version, the above issue comes up. How to handle this?
This is the code that causes this issue:
Dim auth As Authenticator = New AuthSubAuthenticator("MyToken", authFactory.Token)
Dim uploader As New ResumableUploader(10485760)
AddHandler uploader.AsyncOperationCompleted, AddressOf UploaderCompleted
uploader.InsertAsync(auth, file, New Object())
The trace shows that the exception was thrown from the last line (uploader.InsertAsync)
I understand there is a await method that I could use. Did not try, instead, changed uploader.InsertAsync
to uploader.Insert
and the code works ok. But but the user has to wait until the upload is complete (for bigger files, for quite a while).
Upvotes: 0
Views: 4483
Reputation: 457302
I am 100% sure this is related to MVC4 and/or .Net 4.5
Yes, this is a change in ASP.NET 4.5. However, it's important to note that the code was technically wrong before. ASP.NET 4.5 adds several safeguards to catch improper asynchronous usage. So, the MVC3 code was actually improper; it just wasn't getting caught and reported as such.
changed uploader.InsertAsync to uploader.Insert and the code works ok. But but the user has to wait until the upload is complete (for bigger files, for quite a while).
This is the "proper" way to do it on ASP.NET (on a side note, using await
would be more efficient than Insert
). ASP.NET is not designed to do work without a user connection.
Consider, for example, what would happen if the upload errors out; there's no way to notify the user that the upload in fact did not complete. For that matter, there's no way to notify the user that the upload did complete. Also, ASP.NET may recycle your application, which can kill an in-progress upload. For these reasons, doing "fire and forget" work is not recommended on ASP.NET.
However, if you're willing to live with those limitations, I describe on my blog a variety of ways to do fire and forget on ASP.NET. Note that ASP.NET 4.5.2 added a built-in way to do this: HostingEnvironment.QueueBackgroundWorkItem
.
Upvotes: 1