1

WebApi の非同期ファイル アップロード機能に問題があります。

現在、プロバイダーを使用してファイルを保存できますが、サービス (_myService) を使用して、アップロードされたファイルのファイル名をログに記録したいと考えています。サービス内では、別のサービスを使用して現在の UserId を取得します。これは、現在の HttpContext を使用して行われます。残念ながら、現在の HttpContext は新しいタスク スレッド内で失われているようです。

TaskScheduler.FromCurrentSynchronizationContext() をタスクの 2 番目のパラメーターとして追加しようとしましたが、これは効果がありませんでした。それが私に何を与えるのか本当にわかりません。したがって、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 に答える