Saving a .docx breaks the file when editing/overwriting an existing file.

I have a strange issue using the Document Editor with MS Word files that I hope someone can point me in the right direction to solve. My use case is loading a Word document into the browser from a server, allowing the user to edit the document, then saving the changes back to the server.

In principal, this mostly works. However, my problem is that when saving the document on the server, if it overwrites an existing file, the file becomes corrupted and can't be opened either by the Document Editor, or MS Word. If I try to open it, the error I get is "Zip exception. Can't find local header signature - wrong file format or file is corrupt.".

If I open an existing file, edit it, then delete it from the server before saving it, a new file is created that does not have any issues. Likewise, if I save the edited document with a different name, a new file is again created with no issues. The problem only occurs when saving the changes back over an existing document.

This happens even with a brand new, blank Word document. I have updated my NuGet packages and JS CDN links to the latest version (26.2.8).


This is my javascript for uploading the document:


    $("#SaveDocument").on("click", function () {

        $.post({

            url: "/assessmentreports/savereport/" + document.getElementById("assessment-id").value,

            contentType: "application/json; charset=utf-8",

            data: JSON.stringify(documentEditor.serialize()),

            headers: { 'RequestVerificationToken': $("input[name = __RequestVerificationToken]").val() }

        }).done(function () {

            alert("Report saved.");

        }).fail(function (xhr, status, error) {

            alert("There was a problem saving the report.");

        });

    });


This is the C# code that writes the file to disk:

            try

            {

                string filePath = Globals.ReportsPath + OrganisationId + Path.DirectorySeparatorChar + AssessmentId + ".docx";

                using Stream document = Syncfusion.EJ2.DocumentEditor.WordDocument.Save(Report, Syncfusion.EJ2.DocumentEditor.FormatType.Docx);

                using FileStream file = new(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite);

                await document.CopyToAsync(file).ConfigureAwait(false);

                return true;

            }

            catch (Exception e)

            {

                Log.Error($"{GetType().Name}.{nameof(SaveReportAsync)}: {e.Message}");

                return false;

            }


Any ideas?

Thanks.


10 Replies

DS Dhanush Sekar Syncfusion Team August 12, 2024 06:02 PM UTC

Hi Jon, 


Currently we are checking this scenario and will update the details on August 13, 2024.


Regards,

Dhanush S



JL Jon Le Long August 13, 2024 10:23 AM UTC

Thanks for taking a look.

In the meantime, I have found that this does work properly if I convert the .sfdt string to a DocIO WordDocument object first, and save it that way. eg.


                string filePath = Globals.ReportsPath + OrganisationId + Path.DirectorySeparatorChar + AssessmentId + ".docx";

                using Syncfusion.DocIO.DLS.WordDocument docIODocument = Syncfusion.EJ2.DocumentEditor.WordDocument.Save(Report);

                using FileStream outputStream = new(filePath, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.ReadWrite);

                docIODocument.Save(outputStream, Syncfusion.DocIO.FormatType.Docx);


I don't know if there's much overhead converting it this way, but it does allow me to overwrite any existing file without corrupting it.



DS Dhanush Sekar Syncfusion Team August 13, 2024 05:53 PM UTC

Hi Jon, 


The issue of file corruption when overwriting an existing file in your code is likely due to the use of FileMode.OpenOrCreate in the FileStream constructor. This mode opens the file if it exists, or creates a new file if it doesn't. However, when you open an existing file with this mode and overwrite it, the new content may not completely overwrite the old content, especially if the new content is smaller than the original file. This can leave leftover data from the original file, leading to corruption.


To ensure that the file is correctly overwritten, you should use FileMode.Create instead of FileMode.OpenOrCreate. FileMode.Create will always create a new file. If the file already exists, it will be overwritten and truncated to zero length before writing the new content. This ensures that there is no leftover data from the original file.


Code :

public async Task<bool> Export([FromBody] CustomParameter param)

{

    try

    {

        string path = this.hostEnvironment.ContentRootPath + "\\Files\\" + param.fileName;


        using Stream document = Syncfusion.EJ2.DocumentEditor.WordDocument.Save(param.documentData, Syncfusion.EJ2.DocumentEditor.FormatType.Docx);


        // Use FileMode.Create to ensure the file is properly overwritten

        using FileStream file = new(path, FileMode.Create, FileAccess.Write);


        await document.CopyToAsync(file).ConfigureAwait(false);


        return true;

    }

    catch (Exception e)

    {

        // Handle exception, log it if necessary

        return false;

    }

}




Regards,

Dhanush S



JL Jon Le Long August 14, 2024 06:24 AM UTC

Hi Dhanush,


This does indeed fix the problem. I didn't expect DocIO.DLS.WordDocument.Save and  EJ2.DocumentEditor.WordDocument.Save to produce different results with the same FileMode setting, although I expect that's a limitation of writing to a file using a Stream for the source.


Thanks for your help!

Jon



DS Dhanush Sekar Syncfusion Team August 14, 2024 11:52 AM UTC

Hi Jon,


We haven't experienced any issues on our end by switching the code from asynchronous to synchronous. Could you please clarify your requirements and let us know if you still wish to proceed with asynchronous coding?


Regards,

Dhanush S



JL Jon Le Long August 14, 2024 12:04 PM UTC

Hi Dhanush,


I'm not quite sure what you mean. The suggestion you gave to use the "Create" mode when opening the FileStream solved my issue. I am able to use the CopyToAsync() method after that.


I was just pointing out that the  DocIO.DLS.WordDocument behaves differently and does not corrupt files when using the "FileMode.OpenOrCreate" option to overwrite an existing file.


My issue is resolved so you can close this ticket.


Thanks once again,

Jon



DS Dhanush Sekar Syncfusion Team August 16, 2024 04:23 PM UTC

Hi Jon,


Thank for your update

We are currently validating our process to ensure it produces the same results as the DocIO save API when saving with a stream. we will update the details on August 20, 2024.


Regards,

Dhanush S



DS Dhanush Sekar Syncfusion Team August 20, 2024 12:21 PM UTC

Hi Jon,


Could you please confirm that whether you are facing issue after adding below highlighted code in your document exporting endpoint?

image


Regards,

Dhanush S



JL Jon Le Long August 23, 2024 09:35 AM UTC

Hi Dhanush,


I didn't try SetLength(0), but since using the "Create" mode when opening the FileStream solved my issue, I'm happy to move on.


Regards,

Jon



DS Dhanush Sekar Syncfusion Team August 26, 2024 07:02 AM UTC

Hi Jon,


Thanks for the update.

Please create a new ticket if you need any assistance. We would be happy to assist you as always.


Regards,

Dhanush S


Loader.
Up arrow icon