Что может быть причиной этого повреждения в файлах.docx во время httpwebrequest?

Я использую httpwebrequest опубликовать файл с некоторыми дополнительными данными формы из приложения MVC на классическом сайте ASP.

Если файл является.docx, он всегда приходит как поврежденный. Другие, кажется, открываются хорошо, но, возможно, их форматы более гибкие.

Когда я открывал исходные и поврежденные файлы в Sublime Text, я заметил, что в поврежденном файле отсутствует блок 0000 в конце. Когда я вручную заменяю этот блок, файл открывается нормально.

Есть ли что-то, что я делаю неправильно в моем.NET-коде, который вызывает это? Или проблема более эзотерическая?

Классический код ASP использует AspUpload от Persist для получения файла. Это используется во многих местах в других местах на принимающем сайте и никогда раньше не вызывало никаких проблем. Так что я не думаю, что ошибка лежит там. Плюс, это всего лишь простой звонок, и я не могу понять, в чем тут ошибка!

Set File = Upload.Files("fileField")

Я в растерянности относительно того, как начать отладку этой проблемы дальше.


Это код, который я использую для публикации файла:

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;
}

Проблема решена - это исправленный рабочий код

Джон получил удар своим ответом. Я добавил строку, которую он предложил, сразу после записи потока файлов, и теперь они переносятся без проблем.

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;
}

1 ответ

Решение

Я недавно поиграл с multipart/form-data и заметил, что у него есть дополнительные –- в конце конечной многочастной границы. В этом ответе stackru есть пример. Я думаю, что именно здесь вы теряете два байта.

Если это так, то решение заключается в добавлении окончательной записи в поток запроса двух байтов по 45 (ASCII -).

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

Я не могу быть уверен, но это выглядит как хорошая подгонка. Надеюсь, поможет.

Другие вопросы по тегам