5

显然,我不明白如何使用 ContinueWith 方法。我的目标是执行一项任务,完成后返回一条消息。

这是我的代码:

    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.";
        }
    }

变量“文件名”总是返回“未设置”。似乎从未调用 ContinueWith 方法中的代码。(如果我在 VS 中逐行调试,它会被调用。)

此方法在我的 ASP.NET Web API 控制器/Ajax POST 中被调用。

我在这里做错了什么?

4

4 回答 4

7

如果您使用的是异步操作,最好的方法是使您的操作也异步,否则您将失去正在进行的异步调用的优势。尝试如下重写您的方法:

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;
    }
}
于 2012-05-08T21:16:02.167 回答
2

未设置变量的原因是:

  • 任务被实例化,但不运行。
  • 即使任务运行了,该函数也可能在它们完成运行之前返回,所以它仍然会返回“未设置”。解决此问题的方法是等待最终任务(一个设置fileName)完成。

您的代码可以这样修复:

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.";
    }
}

新增内容如下:

  • 将 的返回值分配给task.ContinueWith名为 的变量finalTask。我们需要这个任务,因为我们会等待它完成
  • 开始任务(task.Start();行)
  • 等待最后的任务完成后再返回 ( finalTask.Wait();)

如果可能,请考虑不要异步实现它,因为最终它是同步的(您正在等待它完成)并且当前的实现增加了可能可以避免的复杂性。

考虑按照这些思路做一些事情(如果可能的话):

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.";
    }
}

免责声明:我并没有实际执行上述代码;我只是写它来说明应该做什么。

于 2012-05-08T16:36:46.147 回答
1

您应该Task<T>从方法中返回类型,在这种情况下它将是一个Task<string>.

于 2012-05-08T16:19:19.913 回答
0

您正在使用异步操作。如果要等待其完成,则必须使用Wait任务的其他方法:

task.ContinueWith(o =>
        {
            //File name
            filename = provider.BodyPartFileNames.First().Value;
        ).Wait();

return filename;

编辑: 一些异步方法在创建任务后立即启动,而另一些则要求您显式启动它们。您必须查阅每个文档以确定。在这种情况下,任务似乎会自动启动。

于 2012-05-08T16:20:14.910 回答