MultipartFormDataStreamProvider并保留当前的HttpContext

时间:2013-05-29 20:38:40

标签: asp.net-web-api httpcontext

我对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"));
            }            
        }

1 个答案:

答案 0 :(得分: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;