Загрузить файл из ZipOutputStream в действие MVC 3 - PullRequest
0 голосов
/ 16 марта 2012

Я использую ZipOutputStream из SharpZipLib , и я хочу загрузить заархивированное содержимое, которое он создает, непосредственно в мое действие публикации MVC. Я успешно получаю его для публикации, однако параметр моего метода действия имеет значение null в качестве опубликованных данных, когда он попадает в мое действие MVC.

Вот мой тестовый код, который я использую, чтобы проверить это:

    public void UploadController_CanUploadTest()
    {
        string xml = "<test>xml test</test>"
        string url = "http://localhost:49316/Api/DataUpload/Upload/";

        WebClient client = new WebClient();

        var cc= new CredentialCache();
        cc.Add(new Uri(url),
              "Basic", 
              new NetworkCredential("Testuser", "user"));

        client.Credentials = cc;

        string _UserAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)";
        client.Headers.Add(HttpRequestHeader.UserAgent, _UserAgent);
        client.Headers["Content-type"] = "application/x-www-form-urlencoded";

        using (var stream = client.OpenWrite(url, "POST"))
        {
            Zipped zip = new Zipped(stream, Encoding.UTF8, false);

            FileContent content = new FileContent("Upload", xml);

            var uploads = new List<FileContent>();
            uploads.Add(content);

            zip.Compress(uploads);

            stream.Flush();
            stream.Close();
        }
    }

Это мой упакованный класс:

    public class Zipped : ICompression, IDisposable
{
    private Stream _stream = null;
    private bool _closeStreamOnDispose = true;
    private Encoding _encoding;

    public Zipped()
        : this(new MemoryStream())
    {

    }

    public Zipped(Stream stream)
        : this(stream, Encoding.UTF8, true)
    {
    }

    public Zipped(Stream stream, Encoding encoding)
        : this(stream, encoding, true)
    {
    }

    public Zipped(Stream stream, Encoding encoding, bool closeStreamOnDispose)
    {
        _stream = stream;
        _closeStreamOnDispose = closeStreamOnDispose;
        _encoding = encoding;
    }

    public Stream Compress(IList<FileContent> dataList)
    {
        ZipOutputStream outputStream = new ZipOutputStream(_stream);
        outputStream.SetLevel(9);

        foreach (var data in dataList)
        {
            ZipEntry entry = new ZipEntry(data.Name);
            entry.CompressionMethod = CompressionMethod.Deflated;

            outputStream.PutNextEntry(entry);

            byte[] dataAsByteArray = _encoding.GetBytes(data.Content);

            outputStream.Write(dataAsByteArray, 0, dataAsByteArray.Length);
            outputStream.CloseEntry();
        }

        outputStream.IsStreamOwner = false;
        outputStream.Flush();
        outputStream.Close();

        return _stream;
    }

    public List<FileContent> DeCompress()
    {
        ZipInputStream inputStream = new ZipInputStream(_stream);
        ZipEntry entry = inputStream.GetNextEntry();

        List<FileContent> dataList = new List<FileContent>();

        while(entry != null)
        {
            string entryFileName = entry.Name;

            byte[] buffer = new byte[4096];     // 4K is optimum

            // Unzip file in buffered chunks. This is just as fast as unpacking to a buffer the full size
            // of the file, but does not waste memory.
            // The "using" will close the stream even if an exception occurs.                
            using (MemoryStream tempMemoryStream = new MemoryStream())
            {
                StreamUtils.Copy(inputStream, tempMemoryStream, buffer);

                string copied = _encoding.GetString(tempMemoryStream.ToArray());
                dataList.Add(new FileContent(entry.Name, copied));
            }

            entry = inputStream.GetNextEntry();
        }

        return dataList;

    }

    public void Dispose()
    {
        if(_closeStreamOnDispose)
            _stream.Dispose();
    }

Вот мое простое действие MVC:

    [HttpPost]
    public ActionResult Upload(HttpPostedFileBase uploaded)
    {
        // uploaded is null at this point
    }

1 Ответ

1 голос
/ 16 марта 2012

Если вы хотите использовать HttpPostedFileBase в своем действии контроллера, вам нужно отправить от клиента multipart/form-data запрос, а не application/x-www-form-urlencoded.

Фактически вы устанавливаете тип контента на application/x-www-form-urlencoded, но вы не соблюдаете это, потому что вы напрямую записываете необработанные байты в запрос, который является недействительным. Ну, на самом деле это не соответствует стандарту протокола HTTP, но он все равно может работать, если вы прочитаете поток необработанных запросов из контроллера вместо использования HttpPostedFileBase. Я бы не советовал вам идти по этому маршруту.

Итак, правильный HTTP-запрос, который вы отправляете, должен выглядеть так:

Content-Type: multipart/form-data; boundary=AaB03x

--AaB03x
Content-Disposition: form-data; name="uploaded"; filename="input.zip"
Content-Type: application/zip

... byte contents of the zip ...
--AaB03x--

Граница должна быть выбрана так, чтобы она нигде не появлялась в содержимом файла.

Я написал в блоге пример того, как можно загрузить несколько файлов .

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