2016-08-16 1 views
1

Я пытаюсь реализовать защиту HMAC для API. Все работает нормально, пока я не попытаюсь опубликовать данные вместе с файлом в файле MultipartFormDataContent.Чтение байт HttpContent не выполняется внутри DelegatingHandler, когда присутствует несколько типов контента

HttpClientDelegatingHandler не работает, когда удаляется строка с асинхронным кодом для чтения байтов.

Вот код построения запроса:

private FileOutputViewModel GetApiOutput(Uri apiResource, string filename, byte[] file, IDictionary<string, string> extraParameters) 
{ 
    FileOutputViewModel result = new FileOutputViewModel(); 

    if (file != null) 
    { 
     using (var content = new MultipartFormDataContent()) 
     { 
      if (extraParameters != null) 
      { 
       foreach (var param in extraParameters) 
       { 
        content.Add(new StringContent(param.Value), param.Key); // <- If I don't have this, everything works fine 
       } 
      } 

      var fileContent = new ByteArrayContent(file); 
      fileContent.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment") 
      { 
       FileName = filename 
      }; 
      content.Add(fileContent); 

      var response = HttpClient.PostAsync(apiResource.ToString(), content).Result; 

      result.Output = JsonConvert.DeserializeObject(response.Content.ReadAsStringAsync().Result); 

      result.Filename = Path.GetFileName(filename); 
     } 
    } 

    return result; 
} 

Если я не использовать DelegatingHandler все работает отлично, но безопасность HMAC не применяется для запроса так отвергается на конце API.

Если я не добавляю значения данных с помощью StringContent элементов вместе с файлом, тогда нет проблем с чтением байтов. Но у меня остался неполный запрос, так как мне нужно передать дополнительную информацию вместе с файлом.

Строка кода, которая не в DelegatingHandler указано ниже:

private static async Task<byte[]> ComputeHash(HttpContent httpContent) 
{ 
    using (var md5 = MD5.Create()) 
    { 
     byte[] hash = null; 
     if (httpContent != null) 
     { 
      var ms = new MemoryStream(); 
      await httpContent.CopyToAsync(ms); // <- Fails here 
      ms.Seek(0, SeekOrigin.Begin); 

      var content = ms.ToArray(); 
      if (content.Length != 0) 
      { 
       hash = md5.ComputeHash(content); 
      } 
     } 
     return hash; 
    } 
} 

Первоначально неисправного линия:

var content = await httpContent.ReadAsByteArrayAsync(); 

, но это не удалось даже с просто файл на свой собственный (предыдущая Stackoverflow question). Использование MemoryStream было одним шагом вперед, но не дошло до меня.

Любые идеи, как я мог бы обойти эту проблему?

ответ

1

Похоже, это было вызвано наличием асинхронной подписи для метода System.Net.Http.DelegatingHandler.SendAsync. Первоначально делегат переопределение был:

protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 

, когда я адаптировал код, чтобы я мог изменить его на:

protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) 

все начало работать, как ожидалось.

Кажется, что с этой частью платформы .NET должны возникать проблемы с потоками. Ниже приведены некоторые другие способы обхода, если вам нужно попробовать другие обходы: https://social.msdn.microsoft.com/Forums/vstudio/en-US/55f5571d-fe94-4b68-b1d4-bfb91fd721dd/reading-httpcontent-bytes-fails-inside-delegatinghandler-when-multiple-content-types-present?forum=wcf

Смежные вопросы