在 httpwebrequest 期间,什么可能导致 .docx 文件损坏?

What could be causing this corruption in .docx files during httpwebrequest?

我正在使用 httpwebrequest 到 post 一个文件,其中包含从 MVC 应用程序到经典 ASP 站点的一些附加表单数据。

如果文件是 .docx,它总是以损坏的形式到达。其他人似乎打开得很好,但可能是他们的格式更灵活。

当我在 Sublime Text 中打开原始文件和损坏的文件时,我注意到损坏的文件末尾缺少一个 0000 块。当我手动替换此块时,文件可以正常打开。

是不是我在 .NET 代码中做错了什么导致了这种情况的发生?还是问题更深奥?

经典的ASP代码使用Persist's AspUpload接收文件。这用于接收站点其他地方的许多地方,并且以前从未引起过任何问题。所以我认为错误不在那里。另外,这只是一个简单的调用,我看不出有什么问题!

Set File = Upload.Files("fileField")

我不知道如何开始进一步调试这个问题。


这是我用来 post 文件的代码:

public async Task<string> TestFileSend()
{
    string result;

    var postToUrl = "https://www.mywebsite.com/receive-file.asp";

    Dictionary<string, string> extraData = new Dictionary<string, string>();
    extraData.Add("colour", "red");
    extraData.Add("name", "sandra");

    var filePath = "/path-to-file/file.docx";
    byte[] fileAsByteArray = File.ReadAllBytes(filePath);


    // setup data  to send
    var dataBoundry = "---------------------------9849436581144108930470211272";
    var dataBoundryAsBytes = Encoding.ASCII.GetBytes(Environment.NewLine + "--" + dataBoundry + Environment.NewLine);

    var startOfFileData = "--" + dataBoundry + Environment.NewLine +
        @"Content-Disposition: form-data; name=""fileField""; filename=""file.docx""" + Environment.NewLine;

    startOfFileData += @"Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document" + Environment.NewLine + Environment.NewLine;
    var startOfFileDataAsBytes = Encoding.UTF8.GetBytes(startOfFileData);
    var endOfRequest = "--" + dataBoundry + "--";
    byte[] endOfRequestAsBytes = Encoding.UTF8.GetBytes(endOfRequest);


    // perform request
    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(postToUrl);
    httpWebRequest.ContentType = "multipart/form-data; boundary=" + dataBoundry;
    httpWebRequest.Method = "POST";
    using (var stream = await httpWebRequest.GetRequestStreamAsync())
    {
        foreach (KeyValuePair<string, string> item in extraData)
        {
            var dataItemBytes = DataItemAsBytes(item.Key, item.Value);
            stream.Write(dataBoundryAsBytes, 0, dataBoundryAsBytes.Length);
            stream.Write(dataItemBytes, 0, dataItemBytes.Length);
        }
        stream.Write(startOfFileDataAsBytes, 0, startOfFileDataAsBytes.Length);
        stream.Write(fileAsByteArray, 0, fileAsByteArray.Length);
        stream.Write(endOfRequestAsBytes, 0, endOfRequestAsBytes.Length);
    }
    try
    {
        using (WebResponse response = httpWebRequest.GetResponse())
        {
            HttpWebResponse httpResponse = (HttpWebResponse)response;
            using (Stream myData = response.GetResponseStream())
            using (var reader = new StreamReader(myData))
            {
                result = reader.ReadToEnd();
            }
        }
    }
    catch (WebException e)
    {
        result = e.Message;
    }

    return result;
}

问题已解决 - 这是修改后的工作代码

Jon 继续回答。我在写入文件流后立即添加了他建议的行,现在它们传输没有任何问题。

public async Task<string> TestFileSend()
{
    string result;

    var postToUrl = "https://www.mywebsite.com/receive-file.asp";

    Dictionary<string, string> extraData = new Dictionary<string, string>();
    extraData.Add("colour", "red");
    extraData.Add("name", "sandra");

    var filePath = "/path-to-file/file.docx";
    byte[] fileAsByteArray = File.ReadAllBytes(filePath);


    // setup data  to send
    var dataBoundry = "---------------------------9849436581144108930470211272";
    var dataBoundryAsBytes = Encoding.ASCII.GetBytes(Environment.NewLine + "--" + dataBoundry + Environment.NewLine);

    var startOfFileData = "--" + dataBoundry + Environment.NewLine +
        @"Content-Disposition: form-data; name=""fileField""; filename=""file.docx""" + Environment.NewLine;

    startOfFileData += @"Content-Type: application/vnd.openxmlformats-officedocument.wordprocessingml.document" + Environment.NewLine + Environment.NewLine;
    var startOfFileDataAsBytes = Encoding.UTF8.GetBytes(startOfFileData);
    var endOfRequest = "--" + dataBoundry + "--";
    byte[] endOfRequestAsBytes = Encoding.UTF8.GetBytes(endOfRequest);


    // perform request
    HttpWebRequest httpWebRequest = (HttpWebRequest)WebRequest.Create(postToUrl);
    httpWebRequest.ContentType = "multipart/form-data; boundary=" + dataBoundry;
    httpWebRequest.Method = "POST";
    using (var stream = await httpWebRequest.GetRequestStreamAsync())
    {
        foreach (KeyValuePair<string, string> item in extraData)
        {
            var dataItemBytes = DataItemAsBytes(item.Key, item.Value);
            stream.Write(dataBoundryAsBytes, 0, dataBoundryAsBytes.Length);
            stream.Write(dataItemBytes, 0, dataItemBytes.Length);
        }
        stream.Write(startOfFileDataAsBytes, 0, startOfFileDataAsBytes.Length);
        stream.Write(fileAsByteArray, 0, fileAsByteArray.Length);
        // *** THIS ADDITIONAL LINE IS THE KEY 
        stream.Write(new byte[] { 45, 45 }, 0, 2);
        // ***
        stream.Write(endOfRequestAsBytes, 0, endOfRequestAsBytes.Length);
    }
    try
    {
        using (WebResponse response = httpWebRequest.GetResponse())
        {
            HttpWebResponse httpResponse = (HttpWebResponse)response;
            using (Stream myData = response.GetResponseStream())
            using (var reader = new StreamReader(myData))
            {
                result = reader.ReadToEnd();
            }
        }
    }
    catch (WebException e)
    {
        result = e.Message;
    }

    return result;
}

我最近玩过 multipart/form-data 并注意到它在最终多部分边界的末尾有一个额外的 –-。在这个Whosebug answer中有一个例子。我 认为 这就是你丢失两个字节的地方。

如果是这样,解决方案是向请求流添加一个最终写入的两个字节 45 (ASCII -)。

stream.Write(new byte[]{45, 45}, 0, 2);

我不确定,但看起来很合适。希望对你有帮助。