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