2014-07-22 14 views
8

Sono abbastanza sicuro che sto creando un deadlock nella mia applicazione e non sono sicuro di come risolvere il problema. Ho alcune parti mobili e sono nuovo a async e await quindi per favore abbiate pazienza con me.Async Deadlock?

Ho un cliente che consente di caricare un file come segue:

public static async Task<string> UploadToService(HttpPostedFile file, string authCode, int id) 
{ 
    var memoryStream = new MemoryStream(); 
    file.InputStream.CopyTo(memoryStream); 

    var requestContent = new MultipartFormDataContent(); 
    var fileContent = new ByteArrayContent(memoryStream.ToArray()); 
    fileContent.Headers.ContentType = MediaTypeHeaderValue.Parse(file.ContentType); 
    requestContent.Add(fileContent, "file", file.FileName); 

    using (var httpClient = new HttpClient()) 
    { 
     httpClient.BaseAddress = new Uri(BaseUrl); 
     httpClient.DefaultRequestHeaders.Accept.Clear(); 

     var message = 
      await 
       httpClient.PostAsync(
        string.Format("Upload?authCode={0}&id={1}", authCode, id), 
        requestContent); 

     return await message.Content.ReadAsStringAsync(); 
    } 
} 

Il pezzo che riceve il file:

[HttpPost] 
public Task<HttpResponseMessage> Upload(string authCode, int id) 
{ 
    var request = Request; 

    var provider = new CustomMultipartFormDataStreamProvider(root); 

    var task = 
     request.Content.ReadAsMultipartAsync(provider) 
      .ContinueWith(o => 
      { 
       // ... 
       // Save file 
       // ... 

       return new HttpResponseMessage() 
       { 
        Content = new StringContent("File uploaded successfully"), 
        StatusCode = HttpStatusCode.OK 
       }; 
      }); 

    return task; 
} 

Tutto è iniziato con il seguente:

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (IsPostBack) 
    { 
     var file = HttpContext.Current.Request.Files[0]; 

     var response = UploadToService(file, hiddenAuthCode.Value, int.Parse(hiddenId.Value)); 
    } 
} 

Tutto sembra funzionare, tranne che lo PostAsync non riconosce mai che task è stato restituito. Vedo che lo stato del task await ... PostAsync ... è WaitingForActivation ma non sono completamente sicuro di cosa significhi (ricorda, sono un n00b per questa roba). Il mio file viene salvato nella posizione corretta ma l'applicazione non riconosce mai la risposta dal mio servizio.

Se qualcuno potesse indicarmi la giusta direzione, sarebbe molto apprezzato.

risposta

6

Penso che il problema è che è sufficiente chiamare UploadToService in modo ignifugo all'interno di Page_Load. L'elaborazione della richiesta termina semplicemente prima del completamento di questa attività.

È necessario utilizzare <%@ Page Async="true" ...> in questa pagina Web Form e includere <add key="aspnet:UseTaskFriendlySynchronizationContext" value="true" /> nel proprio web.config.

Quindi utilizzare RegisterAsyncTask, il codice sarebbe simile a questa:

protected void Page_Load(object sender, EventArgs e) 
{ 
    if (IsPostBack) 
    { 
     var file = HttpContext.Current.Request.Files[0]; 

     RegisterAsyncTask(new PageAsyncTask(() => UploadToService(file, 
      hiddenAuthCode.Value, int.Parse(hiddenId.Value)))); 
    } 
} 

Su un lato nota, si potrebbe migliorare questa parte:

file.InputStream.CopyTo(memoryStream); 

come questo:

await file.InputStream.CopyToAsync(memoryStream); 

e sostituire ContinueWith con async/await:

[HttpPost] 
public async Task<HttpResponseMessage> Upload(string authCode, int id) 
{ 
    var request = Request; 

    var provider = new CustomMultipartFormDataStreamProvider(root); 

    await request.Content.ReadAsMultipartAsync(provider); 

    return new HttpResponseMessage() 
    { 
     Content = new StringContent("File uploaded successfully"), 
     StatusCode = HttpStatusCode.OK 
    }; 
} 

Correlato: "Using Asynchronous Methods in ASP.NET 4.5".

+0

Dopo averlo modificato in "RegisterAsyncTask', ho ottenuto il tipo di argomento System.Threading.Task.Task non è assegnabile al tipo di parametro System.Web.UI.PageAsyncTask'. Ho provato a cambiare il mio tipo di reso, ma questo ha causato altri errori. Qualche idea? – Joe

+0

@Joe, un altro tweak: 'new PageAsyncTask (() => UploadToService (file, ...))', l'argomento è un 'Func '. – Noseratio

+1

Grazie! Dopo aver apportato le modifiche, non più deadlock. – Joe