异步等待web api文件io

mar*_*ine 0 c# asp.net-4.5 asp.net-web-api

我在web api控制器中使用以下异步代码来处理XML文件.一切都按预期工作,但这是正确使用async/await方法.我基本上从XML文件中提取所有图像,然后将它们保存到磁盘.我想尝试最小化文件io的影响.

public async Task<HttpResponseMessage> PostFile()
{
    await Task.WhenAll(this.ProcessProofOfPressenceImages(address, images, surveyReference), this.ProcessSketchImages(propertyPlans, images, surveyReference), this.ProcessExteriorImages(exteriorSketch, images, surveyReference));
    //db code
}

private async Task ProcessProofOfPressenceImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
    if(images != null)
    {
        await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "propertyImage"));
    }
}

private async Task ProcessSketchImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
    if(images != null)
    {
        await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "sketchPlanImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchFrontImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchRearImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchLeftSideImage"), this.ProcessImagesHelper(container, images, surveyReference, "sketchRightSideImage"));
    }
}

private async Task ProcessExteriorImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
    List<Task> tasks = new List<Task>();

    if(images != null)
    {
        await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "image1"), this.ProcessImagesHelper(container, images, surveyReference, "image2"), this.ProcessImagesHelper(container, images, surveyReference, "image3"), this.ProcessImagesHelper(container, images, surveyReference, "image4"), this.ProcessImagesHelper(container, images, surveyReference, "image5"), this.ProcessImagesHelper(container, images, surveyReference, "image6"));
    }
}

private async Task ProcessImagesHelper(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference, string image)
{
    if(container.ContainsKey(image) && !String.IsNullOrEmpty(container[image].ToString()))
    {
        using(MemoryStream memoryStream = new MemoryStream((byte[])container[image]))
        {
            string url = String.Format(@"{0}{1}{2}_{3}.jpg", EcoConfiguration.Instance.RootUrl, EcoConfiguration.Instance.SurveyImageRootUrl, surveyReference, image.SplitOnCapital("_"));

            using(FileStream fileStream = new FileStream(url, FileMode.Create, FileAccess.Write))
            {
                Dictionary<string, string> imageDetails = new Dictionary<string, string>();
                imageDetails.Add("TypeId", ((int)SurveyImageType.Exterior).ToString());
                imageDetails.Add("ImageUrl", url);
                if(container.ContainsKey(image + "Description"))
                {
                    imageDetails.Add("Description", container[image + "Description"].ToSafeString());
                }
                images.Add(imageDetails);
                await memoryStream.CopyToAsync(fileStream);
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

任何意见/建议都会非常受欢迎.

Ste*_*ary 5

关于文件流的棘手问题是你需要传递isAsync: true或者FileOptions.Asynchronous使用构造函数/工厂方法来获得真正的异步流.如果不这样做,那么底层文件流实际上是阻塞的,异步方法只是使用线程池伪造异步操作.

在你的代码中突出的另一件事是你有一些不必要的使用async.async应该只在你需要时使用.例如,这种方法:

private async Task ProcessProofOfPressenceImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
  if(images != null)
  {
    await Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "propertyImage"));
  }
}
Run Code Online (Sandbox Code Playgroud)

可以写成:

private Task ProcessProofOfPressenceImages(Dictionary<object, object> container, List<Dictionary<string, string>> images, string surveyReference)
{
  if(images != null)
  {
    return Task.WhenAll(this.ProcessImagesHelper(container, images, surveyReference, "propertyImage"));
  }

  return Task.FromResult<object>(null);
}
Run Code Online (Sandbox Code Playgroud)

这为您节省了不必要的状态机.同样的建议适用于ProcessSketchImagesProcessExteriorImages.

关于ProcessImagesHelper,它看起来很不错,但我不确定你为什么需要它MemoryStream.将字节数组(异步)写入磁盘也很容易.

如果您对async性能提示感兴趣,Stephen Toub有一个很棒的视频.