1

我对 WebApi 的异步文件上传功能有疑问。

目前我可以使用提供程序保存文件,但是我想使用服务(_myService)来记录上传文件的文件名。在服务内部,它使用另一个服务来获取当前的 UserId。它通过使用当前的 HttpContext 来做到这一点。不幸的是,当前的 HttpContext 似乎在新任务线程中丢失了。

我尝试添加 TaskScheduler.FromCurrentSynchronizationContext() 作为任务的第二个参数,但这没有效果。不太确定这给了我什么。所以我需要某种方式将 Http 上下文传递到新线程。我将如何实现这一目标?

[ValidationFilter]
        public Task<FileUpModel> Upload([FromUri]int ReportType, [FromUri]string LocationDescription, string AdditionalInformation)
        {
            if (Request.Content.IsMimeMultipartContent())
            {
                var imagePath = HttpContext.Current.Server.MapPath("~/App_Data");

                var provider = new MyFormDataStreamProvider(imagePath);

                var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(
                t =>
                {

                    if (t.IsFaulted || t.IsCanceled)
                        throw new HttpResponseException(HttpStatusCode.InternalServerError);

                    var fileInfo = provider.FileData.FirstOrDefault();
                    if (fileInfo == null)
                        throw new HttpResponseException(HttpStatusCode.InternalServerError);

                    // httpContext is lost here...
                    _myService.LogUploadedFile(fileInfo.LocalFileName);

                    var uploadModel = new FileUpModel { success = true };
                    return uploadModel;
                }, TaskScheduler.FromCurrentSynchronizationContext());

                return task;
            }
            else
            {
                throw new HttpResponseException(Request.CreateResponse(HttpStatusCode.NotAcceptable, "This request is not properly formatted"));
            }            
        }
4

1 回答 1

4

最后我发现了一个解决方法,它看起来不像我希望的那样干净。基本上,我将上下文的副本保存在一个单独的变量中,并将其传递给闭包。不确定这是否是最佳实践,但它有效!

 var currentHttpContext = HttpContext.Current;

        var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(
        t =>
        {
            // Enquiry service requires access to authentication data which is retrieved via http context.
            // Not ideal but set the http context here so it available on the new thread.                    
            HttpContext.Current = currentHttpContext;

            if (t.IsFaulted || t.IsCanceled)
                throw new HttpResponseException(HttpStatusCode.InternalServerError);

            var fileInfo = provider.FileData.FirstOrDefault();
            if (fileInfo == null)
                throw new HttpResponseException(HttpStatusCode.InternalServerError);

            _myService.LogUploadedFile(fileInfo.LocalFileName);

            var uploadModel = new FileUpModel { success = true };
            return uploadModel;
        });

        return task;
于 2013-06-03T20:07:38.377 回答