c # установить время ожидания для multipartReader.ReadNextSectionAsync () - PullRequest
0 голосов
/ 23 октября 2018

Я использую ядро ​​C # .net для чтения данных о загрузке из составного сообщения пользователя, отправляющего несколько файлов.Как я могу предотвратить использование бесконечного ожидания после прочтения последнего файла в

try
{
  var cancellationTokenSource = new CancellationTokenSource();
  cancellationTokenSource.CancelAfter(1000);
  section = await multipartReader.ReadNextSectionAsync(cancellationTokenSource.Token);
}
catch (Exception ex)
{
  throw;
}

Хотя я установил CancelationToken на 1 секунду, но он будет бесконечным и не перейдет на следующую строку, если я отправлю другой запрос.

public static async Task<HttpRequest> FromHttpContextAsync(HttpContext httpContext)
        {
            bool multipart = false;
            HttpRequest retVal = new HttpRequest(httpContext);
            var sb = new StringBuilder();         
            var sr = new StreamReader(httpContext.Stream, Encoding.UTF8);
            {
                var line1 = await sr.ReadLineAsync();
                sb.AppendLine(line1);
                var Line1Parts = (line1).Split(' ');
                retVal.Methode = Line1Parts[0].ToLower();
                retVal.RawUrl = System.Net.WebUtility.UrlDecode(Line1Parts[1]).Replace("&amp;", "&");
                var urlPart = retVal.RawUrl.Split('?');
                retVal.Url = urlPart[0];
                if (urlPart.Length > 1)
                {
                    foreach (var part in urlPart[1].Split(new[] { '&' }, StringSplitOptions.RemoveEmptyEntries))
                    {
                        var tmp = part.Split(new[] { '=' }, StringSplitOptions.RemoveEmptyEntries);
                        try
                        {
                            retVal.QueryStrings.Add(tmp[0], tmp[1]);
                        }
                        catch (Exception ex)
                        {
                        }
                    }
                }
            string line = await sr.ReadLineAsync();
            sb.AppendLine(line);
            int contentLength = 0;
            while (!string.IsNullOrEmpty(line))
            {
                var tmp = line.Split(':');
                var key = tmp[0].Trim().ToLower();
                retVal.Header.Add(new KeyValuePair<string, string>(tmp[0], tmp[1]));

                switch (key)
                {

                    case "cookie":
                        {

                            foreach (var part in tmp[1].Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries))
                            {
                                var pares = part.Split('=');
                                if (pares.Length == 2)
                                {
                                    retVal.Cookies.Add(new KeyValuePair<string, string>(pares[0], pares[1]));
                                }
                            }
                            break;
                        }
                    case "content-length":
                        {
                            contentLength = int.Parse(tmp[1]);
                            break;
                        }
                }
                line = await sr.ReadLineAsync();
                sb.AppendLine(line);
            }
if (sb.ToString().Contains("Content-Type: multipart/form-data"))
{
  string boundary = FindBoundary(sb.ToString());
  MultipartReader multipartReader = new MultipartReader(boundary, httpContext.Stream);
  var section = await multipartReader.ReadNextSectionAsync();
  while (section != null)
  {
    // process each image
    const int chunkSize = 1024;
    var buffer = new byte[chunkSize];
    var bytesRead = 0;
    var fileName = GetFileName(section.ContentDisposition);

    using (var stream = new MemoryStream())
    {
      do
      {
        try
        {
          bytesRead = await section.Body.ReadAsync(buffer, 0, buffer.Length);
        }
        catch (Exception ex)
        {
          Console.Write(ex);
        }

        stream.Write(buffer, 0, bytesRead);
      } while (bytesRead > 0);
      retVal.Files.Add(new Tuple<string, string, byte[]>("", fileName, stream.ToArray()));
    }

    try
    {
      var cancellationTokenSource = new CancellationTokenSource();
      cancellationTokenSource.CancelAfter(1000);
      section = await multipartReader.ReadNextSectionAsync(cancellationTokenSource.Token);
    }
    catch (Exception ex)
    {
      throw;
    }


  }
  foreach (var file in retVal.Files)
  {
    File.WriteAllBytes("d:\\" + file.Item2, file.Item3);
  }
}

HttpContext является встроенным классом этого проекта, и это источник HttpContext:

public class HttpContext
    {
        public HttpRequest Request { get; private set; }
        public HttpResponse Response { get; private set; }
        public Stream Stream { private set; get; }
        private HttpContext(Stream networkStream)
        {
            Stream = networkStream;
        }

        public async static Task<HttpContext> FromHttpContextAsync(Stream networkStream)
        {
            var retVal = new HttpContext(networkStream);
            retVal.Request = await HttpRequest.FromHttpContextAsync(retVal);
            retVal.Response = HttpResponse.FromHttpContext(retVal);
            return retVal;
        }
    }

1 Ответ

0 голосов
/ 02 ноября 2018

Несмотря на то, что отсутствие деталей и контекста делает попытку воспроизвести эту проблему очень сложно, я подозреваю, что проблема здесь в том, что NetworkStreams (используемый под крышками вашим экземпляром MultipartReader) еще не полностью поддерживает CancellationTokens.Фактически, почти каждая операция, связанная с Socket в .NET Core, просто проверяет окончательно переданный CancellationToken, что, на мой взгляд, бесполезно.

Хорошая новость заключается в том, что команда .NET Core активно работает надэто и я считаю, что проблема будет полностью решена в .NET Core 3.0:

https://github.com/dotnet/corefx/issues/24430

В качестве временного уродливого обходного пути вы можете изменить свой код, чтобы дождаться как сфабрикованной задачи задержкии ваш вызов ReadNextSectionAsync (), при условии, что вы не хотите повторно использовать этот остановленный сокет / NetworkStream после этого:

var timeoutTask = Task.Delay(TimeSpan.FromSeconds(1)).ConfigureAwait(false);
var readNextSectionTask = multipartReader.ReadNextSectionAsync().ConfigureAwait(false);

if (await Task.WhenAny(timeoutTask, readNextSectionTask).ConfigureAwait(false) == timeoutTask)
{
    // TODO: Handle the timeout
}
else
{
    section = await readNextSectionTask;
}

Кроме того, тот факт, что вы не конфигурируете свой ожидаемый, может действовать как возможныйисточник взаимоблокировки (мне неясно, выполняете ли вы этот код на самом ASP.NET Core или на каком-либо другом провайдере контекста синхронизации).Чтобы исключить эту возможность, я бы предложил вызывать ConfigureAwait (false) сразу после ваших ожидающих вызовов, как вы можете видеть из моего предыдущего блока кода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...