farlee2121 / ResXResourceReader.NetStandard

ResXResourceReader and ResXResourceWriter adapted for .Net Standard

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Fails to read Visual Studio generated RESX

DumboJet opened this issue · comments

When I use this to read a Visual Studio generated RESX, I get this exception:

ResX input is not valid. Cannot find valid "resheader" tags for the ResX reader and writer type names.

   at System.Resources.NetStandard.ResXResourceReader.ParseXml(XmlTextReader reader)
   at System.Resources.NetStandard.ResXResourceReader.EnsureResData()
   at System.Resources.NetStandard.ResXResourceReader.GetEnumerator()
   at System.Resources.NetStandard.ResXResourceReader.System.Collections.IEnumerable.GetEnumerator()
...

Looking at the code here:

readerTypeName.Equals(readerType.FullName) &&

...I see that it checks the full type name of the reader class against the RESX resheader[name="reader"] tags.
Since they don't match, it fails.
Any idea what can be done to fix this, apart from preprocessing the RESX file or generating a new assembly for the ResXReader library that mimics the System.Windows.Forms in all its names and namespaces?

I have found this related post:
https://stackoverflow.com/questions/23226794/how-can-i-resolve-the-invalid-resx-file-cannot-find-valid-resheader-tags-fo

Hm...
This is more complex to use than what I anticipated.
I think I will just use a normal XML reader/writer, since I am only reading and updating existing RESX files.

Thanks for putting some research into it!
I'm not deep enough in the problem to suggest a way forward at the moment.

We can revisit if needed, but I'd guess the general XML tooling is a good path.

commented

I also encountered this problem :/

Cloned the repo and removed the validation. Why is this project still running if it can't be used to read resx files?
Or at the very least have some way to mitigate this breaking issue.

It can be used to read RESX files, and I use it for such.

This project is simply a rip of the .NET resx reader out of the winforms repo to make it portable across netstandard projects.

You are welcome to contribute a fix for format incompatibilities or release your own version.

commented

I worked around this by modifying the resx file header before reading it, and modifying it back after done so.

The function that does that:

// This is what is written in the header attributes in the first place. it may differ in your project, but this works for net 4.7+ projects.
private const string DefaultResxReaderType = "System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";
private const string DefaultResxWriterType = "System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089";


private void ModifyResxHeader(string filePath, string? readerType = DefaultResxReaderType, string? writerType = DefaultResxWriterType)
{
    var doc = new XmlDocument();
    doc.Load(filePath);

    var nodes = doc.SelectNodes("/root/resheader");

    if (nodes == null)
        return;

    foreach (XmlNode resheaderNode in nodes)
    {
        var nameAttribute = resheaderNode.Attributes?["name"];
        if (nameAttribute is { Value: "reader" })
            if (resheaderNode.FirstChild != null)
                resheaderNode.FirstChild.InnerText = readerType ?? DefaultResxReaderType;
        if (nameAttribute is { Value: "writer" })
            if (resheaderNode.FirstChild != null)
                resheaderNode.FirstChild.InnerText = writerType ?? DefaultResxWriterType;
    }

    doc.Save(filePath);
}

Usage:

// Make readable for us
ModifyResxHeader(file, typeof(ResXResourceReader).AssemblyQualifiedName, typeof(ResXResourceWriter).AssemblyQualifiedName); 

using var resourceReader = new ResXResourceReader(file) { UseResXDataNodes = true };
foreach (DictionaryEntry d in resourceReader)
{
    // read and/or modify things...
}

// Make readable for dotnet 4.7 project
ModifyResxHeader(file);

@genyx Good find! That's something that we should be able to bake in a work around for.

What is the header that you're temporarily replacing?

I think I found the cause of the issue and pushed a general solution as package version 1.1.0. I also added some more tests