将文件从ZipOutputStream上传到MVC 3操作

时间:2012-03-16 08:37:36

标签: c# asp.net-mvc-3

我正在使用 SharpZipLib 中的 ZipOutputStream ,我希望将其创建的压缩内容直接上传到我的MVC帖子操作中。我成功地将其发布,但是当我的MVC操作进入MVC操作时,我的action方法的参数为已发布的数据。

这是我用来测试它的测试代码:

    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 个答案:

答案 0 :(得分:1)

如果您想在控制器操作中使用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--

必须选择边界,使其不会出现在文件内容的任何位置。

我在博客上写了一个关于如何upload multiple files的例子。