Apparently, I'm not understanding how to use the ContinueWith method. My goal is to execute a task, and when complete, return a message.
Here's my code:
public string UploadFile()
{
if (Request.Content.IsMimeMultipartContent())
{
//Save file
MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/Files"));
Task<IEnumerable<HttpContent>> task = Request.Content.ReadAsMultipartAsync(provider);
string filename = "Not set";
task.ContinueWith(o =>
{
//File name
filename = provider.BodyPartFileNames.First().Value;
}, TaskScheduler.FromCurrentSynchronizationContext());
return filename;
}
else
{
return "Invalid.";
}
}
The variable "filename" always returns "Not set". It seems the code within the ContinueWith method is never called. (It does get called if I debug through it line by line in VS.)
This method is being called in my ASP.NET Web API controller / Ajax POST.
What am I doing wrong here?
If you're using an asynchronous operation, the best approach would be to make your operation asynchronous as well, otherwise you'll lose on the advantages of the async call you're making. Try rewriting your method as follows:
public Task<string> UploadFile()
{
if (Request.Content.IsMimeMultipartContent())
{
//Save file
MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/Files"));
Task<IEnumerable<HttpContent>> task = Request.Content.ReadAsMultipartAsync(provider);
return task.ContinueWith<string>(contents =>
{
return provider.BodyPartFileNames.First().Value;
}, TaskScheduler.FromCurrentSynchronizationContext());
}
else
{
// For returning non-async stuff, use a TaskCompletionSource to avoid thread switches
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
tcs.SetResult("Invalid.");
return tcs.Task;
}
}
The reasons for your variable not being set are:
fileName
) to finish.Your code could be fixed like this:
public string UploadFile()
{
if (Request.Content.IsMimeMultipartContent())
{
//Save file
MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/Files"));
Task<IEnumerable<HttpContent>> task = Request.Content.ReadAsMultipartAsync(provider);
string filename = "Not set";
var finalTask = task.ContinueWith(o =>
{
//File name
filename = provider.BodyPartFileNames.First().Value;
}, TaskScheduler.FromCurrentSynchronizationContext());
task.Start();
finalTask.Wait();
return filename;
}
else
{
return "Invalid.";
}
}
The additions are the following:
task.ContinueWith
to a variable called finalTask
. We need this task, because we'll wait for it to finishtask.Start();
line)finalTask.Wait();
)If possible, please consider not implementing this asynchronously, because in the end it's synchronous (you're waiting for it to finish) and the current implementation adds complexity that could probably be avoided.
Consider doing something along these lines (if possible):
public string UploadFile()
{
if (Request.Content.IsMimeMultipartContent())
{
//Save file
MultipartFormDataStreamProvider provider = new MultipartFormDataStreamProvider(HttpContext.Current.Server.MapPath("~/Files"));
Request.Content.ReadAsMultipart(provider); // don't know if this is really valid.
return provider.BodyPartFileNames.First().Value;
}
else
{
return "Invalid.";
}
}
Disclaimer: I have not actually executed the above code; I just wrote it to illustrate what should be done.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With