Bug 13716 - XmlResolver (via XmlReaderSettings) is not invoked.
Summary: XmlResolver (via XmlReaderSettings) is not invoked.
Status: RESOLVED FIXED
Alias: None
Product: Class Libraries
Classification: Mono
Component: System.XML ()
Version: master
Hardware: All Mac OS
: --- normal
Target Milestone: Untriaged
Assignee: Bugzilla
URL:
Depends on:
Blocks:
 
Reported: 2013-08-02 12:13 UTC by Ian Battersby
Modified: 2013-08-08 09:04 UTC (History)
2 users (show)

Tags:
Is this bug a regression?: ---
Last known good build:


Attachments
Example solution showing issue. (3.95 KB, application/zip)
2013-08-07 17:17 UTC, Ian Battersby
Details
Screen capture of .NET 4 (as per project) hitting break points. (4.11 MB, video/x-ms-wmv)
2013-08-08 05:25 UTC, Ian Battersby
Details


Notice (2018-05-24): bugzilla.xamarin.com is now in read-only mode.

Please join us on Visual Studio Developer Community and in the Xamarin and Mono organizations on GitHub to continue tracking issues. Bugzilla will remain available for reference in read-only mode. We will continue to work on open Bugzilla bugs, copy them to the new locations as needed for follow-up, and add the new items under Related Links.

Our sincere thanks to everyone who has contributed on this bug tracker over the years. Thanks also for your understanding as we make these adjustments and improvements for the future.


Please create a new report on GitHub or Developer Community with your current version information, steps to reproduce, and relevant error messages or log files if you are hitting an issue that looks similar to this resolved bug and you do not yet see a matching new report.

Related Links:
Status:
RESOLVED FIXED

Description Ian Battersby 2013-08-02 12:13:49 UTC
Specifying a custom XmlResolver does not fire on Mono 3.2; for example;

Specifying a custom XmlResolver does not fire on Mono 3.2; for example;

namespace MyLib.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Linq;
    using System.Text;
    using System.Xml;

    public class XmlSchemaValidator : IXmlSchemaValidator
    {
        private readonly XmlUrlResolver resolver;

        public XmlSchemaValidator(XmlUrlResolver resolver)
        {
            this.resolver = resolver;
        }

        public XmlSchemaValidator()
        {
            this.resolver = new XmlUrlResolver();
        }

        public void ValidateSchema(string xmlToValidate, string schemaNamespace, string xsdPath)
        {
            var readerSettings = new XmlReaderSettings
                                     {
                                         XmlResolver = this.resolver,
                                         Schemas = { XmlResolver = this.resolver }
                                     };

            readerSettings.Schemas.Add(schemaNamespace, xsdPath);
            readerSettings.ValidationType = ValidationType.Schema;

            var errors = new List<string>();
            readerSettings.ValidationEventHandler += (sender, args) => errors.Add(args.Message);

            using (var xmlReader = XmlReader.Create(new StringReader(xmlToValidate), readerSettings))
            {
                try
                {
                    while (xmlReader.Read())
                    {
                    }
                }
                catch (Exception exception)
                {
                    errors.Add(exception.ToString());
                }
            }

            if (errors.Any())
            {
                var errorMessageBuilder = new StringBuilder();
                foreach (var error in errors)
                {
                    errorMessageBuilder.AppendLine(error);
                }

                throw new XmlException(errorMessageBuilder.ToString());
            }
        }
    }
}

namespace MyProg
{
    public void MyMethod()
    {
        // THIS IS NEVER INVOKED!
        public class FakeXmlUriResolver : XmlUrlResolver
        {
            private readonly string fakePath;

            public FakeXmlUriResolver(string fakePath)
            {
                this.fakePath = fakePath;
            }

            public override object GetEntity(System.Uri absoluteUri, string role, System.Type typeOfObjectToReturn)
            {
                if (absoluteUri.LocalPath == this.fakePath)
                {
                    return this.LoadXsd();
                }

                return base.GetEntity(absoluteUri, role, typeOfObjectToReturn);
            }

            private Stream LoadXsd()
            {
                var assembly = this.GetType().Assembly;

                var resourceStream =
                    assembly.GetManifestResourceStream("MyLib.Resources.SchemaValidatorTest.xsd");

                return resourceStream;
            }
        }
    }
}
Comment 1 Atsushi Eno 2013-08-07 03:35:57 UTC
Could you provide a reproducible code that actually compiles? For example there is no such interface named IXmlSchemaValidator.
Comment 2 Ian Battersby 2013-08-07 17:17:23 UTC
Created attachment 4570 [details]
Example solution showing issue.

As requested find attached an example solution.
Comment 3 Atsushi Eno 2013-08-08 02:33:28 UTC
Could you make sure to create a repro project that *can confirm* the problem and/or describe exact steps reproduce the problem?

I ran this project on .NET 4.5 and it also resulted in the same problem, by base.GetEntity(). Setting fakePath = "/some/path/to/xsd/my.xsd" did not make it either.
Comment 4 Ian Battersby 2013-08-08 05:25:49 UTC
Created attachment 4583 [details]
Screen capture of .NET 4 (as per project) hitting break points.

Find attached a video of the solution running in Visual Studio 2012 clearly hitting the breakpoints inside the fake resolver, which don't hit when running in Mono/Developer.

I haven't changed the solution at all.
Comment 5 Atsushi Eno 2013-08-08 06:08:29 UTC
That's not my point on comment #3, the attachment on comment #4 is NOT a reproducible steps. I don't need any "evidence" nor I have doubt that your problem is only your issue.

In other words, just open your attachment #4570 [details] on comment #2 on VS, build and run it. It WON'T run fine because there is no corresponding file to load.
Comment 6 Ian Battersby 2013-08-08 06:55:24 UTC
Well, my original submission had a code comment that said:

    public void MyMethod()
    {
        // THIS IS NEVER INVOKED!
        public class FakeXmlUriResolver : XmlUrlResolver
        {

Reproducible steps are (VS);

1. Download attachment
2. Unblock it
3. Extract the files
4. Load the solution
5. Build it
6. Breakpoint line 73 (as per the video)
7. Debug the console project (as per the video)
8. The break-point IS hit as expected (as per the video)

Reproducible steps are (MonoDevelop);
1. Download attachment
2. Extract the files
3. Load the solution
4. Build it
5. Breakpoint line 73
6. Debug the console project
7. The break-point is NOT hit as I would have expected

.. indicating the custom XMLResolver is NOT invoked.

On a side note I appreciate my original submission was only code snippet and a reproducible solution is best. I have however gone away and spent time doing both this and video to illustrate the resolver not being hit. Your last comment comes across as slightly hostile, please bare in mind I'm doing my utmost to report an issue here that benefits the mono community.
Comment 7 Atsushi Eno 2013-08-08 07:37:42 UTC
I of course doesn't mean like that. You are totally fine to misunderstand what I meant, and my comment is only about clarification. Let's please not take others replies negatively.
I ignored the comment #1 because it does not compile. Then I saw the repro at comment #2 and naturally thought it is expected to hit "We have a match!" part. I believe it is pretty much reasonable as #1 didn't compile. If it were attachment, it were marked as "obsoleted".

Anyhow I got the point and confirmed that there is likely an issue on retrieving the expected XmlResolver, so I'm reopening it and will work on a fix.
Comment 8 Ian Battersby 2013-08-08 07:46:35 UTC
Appreciated, thanks.
Comment 9 Atsushi Eno 2013-08-08 07:50:08 UTC
Minimized repro:

using System;
using System.IO;
using System.Xml;

public class Test
{
	public static void Main ()
	{
		var resolver = new FakeXmlResolver ();
		string xml = "<people xmlns='testschema'><person name='Ian'><books><book>Clean Code</book></books></person></people>";
		string ns = "testschema";
		string xsdPath = "my.xsd";

		var readerSettings = new XmlReaderSettings ();

		//readerSettings.XmlResolver = resolver;
		readerSettings.Schemas.XmlResolver = resolver;
		readerSettings.Schemas.Add (ns, xsdPath);
		readerSettings.ValidationType = ValidationType.Schema;

		using (var xr = XmlReader.Create (new StringReader (xml), readerSettings))
		{
			while (!xr.EOF)
				xr.Read ();
		}
	}
}

public class FakeXmlResolver : XmlUrlResolver
{
	public override object GetEntity(Uri absoluteUri, string role, Type typeOfObjectToReturn)
	{
		Console.WriteLine ("OK it worked");
		return new MemoryStream ();
	}
}

----

Expected result:

it fails at readerSettings.Schemas.Add (ns, xsdPath) complaining that there is no root element (because it is empty).

Actual result:

Unhandled Exception:
System.IO.FileNotFoundException: Could not find file "/home/atsushi/tests/13716/MonoXmlResolver/bin/Debug/my.xsd".
...
Comment 10 Atsushi Eno 2013-08-08 08:39:51 UTC
Fixed in git master [2cc36e3]

Thanks for the report!
Comment 11 Ian Battersby 2013-08-08 09:04:44 UTC
Awesome, good man.