1

ある Mvc4 アプリケーションから別のアプリケーションにファイルを送信する必要があります (別のアプリケーションは Mvc4、WebApi アプリケーションです)。送信する目的で、HttpClient の PostAsync メソッドを使用しています。送信を実行するコードは次のとおりです。

public class HomeController : Controller
{
    public async Task<ActionResult> Index()
    {
        var result =
            await Upload("http://localhost/target/api/test/post", "Test", System.IO.File.Open(@"C:\SomeFile", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite));

        return View(result);
    }

    public async Task<String> Upload(String url, string filename, Stream stream)
    {
        using (var client = new HttpClient())
        {
            var formData = new MultipartFormDataContent();

            var fileContent = new StreamContent(stream);

            var header = new ContentDispositionHeaderValue("attachment") { FileName = filename };

            fileContent.Headers.ContentDisposition = header;

            formData.Add(fileContent);

            var result = await client.PostAsync(url, formData); // Use your url here

            return "123";
        }
    }
}

受け取る目的で、公式の Web API チュートリアルにある例の 1 つを使用しています。これを行うコードは次のとおりです。

public class TestController : ApiController
{
    // POST api/values
    public Task<HttpResponseMessage> Post()
    {
        if (!Request.Content.IsMimeMultipartContent())
        {
            throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
        }

        string root = HttpContext.Current.Server.MapPath("~/App_Data");


        var provider = new MultipartFormDataStreamProvider(root);


        // Read the form data and return an async task.
        var task = Request.Content.ReadAsMultipartAsync(provider).ContinueWith(t =>
        {
            if (t.IsFaulted || t.IsCanceled)
            {
                return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, t.Exception);
            }

            // This illustrates how to get the file names.
            foreach (MultipartFileData file in provider.FileData)
            {
                Trace.WriteLine(file.Headers.ContentDisposition.FileName);
                Trace.WriteLine("Server file path: " + file.LocalFileName);

            }

            return new HttpResponseMessage
            {
                Content = new StringContent("File uploaded.")
            };

            //var response = Request.CreateResponse(HttpStatusCode.OK);

            //return response;
        });

        return task;
    }
}

問題:

受信者はファイルを正常に取得しますが、次のコードで応答します。

return new HttpResponseMessage
{
    Content = new StringContent("File uploaded.")
};

送信側は、.Net の mscorlib の内部のどこかで壊れています。awaittry / catch で呼び出しをラップしても、例外は処理されません。

非同期実装を維持したいのですが、同期実装は使用したくありません。それは可能ですか? なぜ問題が発生するのですか?何かご意見は?

4

1 に答える 1

7

チュートリアル コードを再確認してください。このページについて話していると思います。その場合await、古い .NET 4.0 の例ではなく、.NET 4.5 バージョンのコード ( を使用) を使用する必要があります。

ASP.NET 組み込み ( HttpContext、要求、応答など) には、要求コンテキストからのみアクセスできます。あなたのコードは をContinueWith指定せずに使用TaskSchedulerしています。この場合、そのラムダがリクエストコンテキスト外のスレッドプールで実行されます。

asyncコードでは、絶対に使用しないでください (本当に必要なContinueWith場合を除きます)。代わりに使用してください:await

// POST api/values
public async Task<HttpResponseMessage> Post()
{
    if (!Request.Content.IsMimeMultipartContent())
    {
        throw new HttpResponseException(HttpStatusCode.UnsupportedMediaType);
    }

    string root = HttpContext.Current.Server.MapPath("~/App_Data");
    var provider = new MultipartFormDataStreamProvider(root);

    try
    {
        // Read the form data.
        await Request.Content.ReadAsMultipartAsync(provider);

        // This illustrates how to get the file names.
        foreach (MultipartFileData file in provider.FileData)
        {
            Trace.WriteLine(file.Headers.ContentDisposition.FileName);
            Trace.WriteLine("Server file path: " + file.LocalFileName);
        }

        return new HttpResponseMessage
        {
            Content = new StringContent("File uploaded.")
        };
    }
    catch (Exception ex)
    {
        return Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex);
    }
}
于 2013-06-20T12:18:07.157 に答える