简体   繁体   English

从响应消息 C# .NET 4.8 解析多部分文件

[英]Parsing Multipart files from Response Message C# .NET 4.8

My HttpClient receives an Multipart Response (in an HttpResponseMessage object) and i need to parse/readout the Files from the Response.我的HttpClient收到一个多部分响应(在HttpResponseMessage对象中),我需要从响应中解析/读出文件。

The requirements are to solve it with an .NET standard library (not higher than .NET 4.8).要求是使用 .NET 标准库(不高于 .NET 4.8)解决它。

Previously i did this with the now pepreciated System.Net.Http.Formating assembly or the Microsoft.AspNet.WebApi.Client assembly.以前我使用现在备受推崇的System.Net.Http.Formating程序集或Microsoft.AspNet.WebApi.Client程序集来执行此操作。 Like this:像这样:

            List<byte[]> lbaFiles = new List<byte[]>();

            StreamContent strCont = new StreamContent(response.Content.ReadAsStreamAsync());
            strCont.Headers.Add("Content-Type", response.Content.Headers.ContentType);

            MultipartMemoryStreamProvider multipart = await strCont.ReadAsMultipartAsync();

            foreach (HttpContent cont in multipart.Contents)
            {
                byte[] baFile = await cont.ReadAsByteArrayAsync();
                lbaFiles.Add(baFile);
            } 

Is there any other .NET standard library (not higher than .NET 4.8) that can read out the Files like the code above?是否有任何其他 .NET 标准库(不高于 .NET 4.8)可以像上面的代码一样读取文件? I only found MultipartContent , but this class can only create an MultipartForm to send to an Webserver.我只找到了MultipartContent ,但是这个 class 只能创建一个MultipartForm来发送到 Web 服务器。

Any help is highly appreciated.非常感谢任何帮助。

Yes, you can use MimeKitLite to do this.是的,您可以使用MimeKitLite来执行此操作。

The easiest way to accomplish this with MimeKitLite v3.0 will look something like this:使用 MimeKitLite v3.0 完成此任务的最简单方法如下所示:

using (var contentStream = await response.Content.ReadAsStreamAsync ()) {
    var header = string.Format ("Content-Type:{0}\r\n\r\n", response.Content.Headers.ContentType);
    using (var headerStream = new MemoryStream (Encoding.UTF8.GetBytes (header), false)) {
        using (var chainedStream = new ChainedStream ()) {
            chained.Add (headerStream);
            chained.Add (contentStream);

            var reader = new MyMimeReader (chainedStream);

            await reader.ReadEntityAsync ();
        }
    }
}

MyMimeFilter.cs: MyMimeFilter.cs:

public class MyMimeReader : MimeReader
{
    static readonly byte[] EmptyInput = new byte[0];
    IMimeFilter _decoder;
    Stream _fileStream;
    string _fileName;

    public MyMimeReader (Stream stream) : base (stream, MimeFormat.Entity)
    {
    }

    protected override void OnHeadersBegin (long beginOffset, int beginLineNumber, CancellationToken cancellationToken)
    {
        // This marks the start of a new MIME entity, so reset our state.
        _decoder = DecoderFilter.Create (ContentEncoding.Default);
        _fileStream = null;
        _fileName = null;
    }

    protected override void OnHeaderRead (Header header, int beginLineNumber, CancellationToken cancellationToken)
    {
        switch (header.Id) {
        case HeaderId.ContentDisposition:
            // If the header is the Content-Disposition header, parse the
            // value to get the filename parameter value.
            if (ContentDisposition.TryParse (header.RawValue, out var disposition)) {
                if (!string.IsNullOrEmpty (disposition.FileName)) {
                    // Make sure to only use the file name and not a full path.
                    _fileName = Path.GetFileName (disposition.FileName);
                }
            }
            break;
        case HeaderId.ContentTransferEncoding:
            // If the header is the Content-Transfer-Encoding header,
            // parse the value so that we can decode the content.
            _decoder = DecoderFilter.Create (header.Value);
            break;
        }
    }

    protected override void OnMimePartBegin (ContentType contentType, long beginOffset, int beginLineNumber, CancellationToken cancellationToken)
    {
        // If there was a Content-Disposition header, then we'll use that filename.
        // Otherwise, check to see if there is a name parameter on the 
        // Content-Type header and use that. If all else fails, generate a
        // new filename.
        if (string.IsNullOrEmpty (_fileName)) {
            if (string.IsNullOrEmpty (contentType.Name)) {
                // Generate a new filename.
                _fileName = GenerateRandomFileName ();
            } else {
                _fileName = Path.GetFileName (contentType.Name);
            }
        }
    }

    protected override void OnMimePartContentBegin (long beginOffset, int beginLineNumber, CancellationToken cancellationToken)
    {
        // Create the file stream that we'll save the content to.
        _fileStream = File.Create (_fileName);
    }

    protected override Task OnMimePartContentReadAsync (byte[] buffer, int startIndex, int count, CancellationToken cancellationToken)
    {
        int outputIndex, outputLength;
        byte[] decoded;

        decoded = _decoder.Filter (buffer, startIndex, count, out outputIndex, out outputLength);

        await _currentFileStream.WriteAsync (decoded, outputIndex, outputLength, cancellationToken);
    }

    protected override Task OnMimePartContentEndAsync (long beginOffset, int beginLineNumber, long endOffset, int lines, NewLineFormat? newLineFormat, CancellationToken cancellationToken)
    {
        int outputIndex, outputLength;
        byte[] decoded;

        decoded = _decoder.Flush (EmptyInput, 0, 0, out outputIndex, out outputLength);

        if (outputLength > 0)
            await _fileStream.WriteAsync (decoded, outputIndex, outputLength, cancellationToken);

        await _fileStream.FlushAsync (cancellationToken);
        _fileStream.Dispose ();
        _fileStream = null;
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM