Skip to content

Commit

Permalink
[xamlc] stop using pack:// with System.Uri in .NET 7 (#7859)
Browse files Browse the repository at this point in the history
This reverts the XamlC changes in b8646cb.

Originally we were hitting:

    XamlApp.xaml Invalid URI: The hostname could not be parsed. [D:\a\_work\1\s\src\Controls\samples\Controls.Sample\Maui.Controls.Sample.csproj]
    at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind, UriCreationOptions& creationOptions)
    at System.Uri..ctor(String uriString, UriKind uriKind)
    at Microsoft.Maui.Controls.ResourceDictionary.RDSourceTypeConverter.GetResourcePath(Uri uri, String rootTargetPath)
    at Microsoft.Maui.Controls.XamlC.RDSourceTypeConverter.ConvertFromString(String value, ILContext context, BaseNode node)+MoveNext()
    at Microsoft.Maui.Controls.Build.Tasks.NodeILExtensions.PushConvertedValue(ValueNode node, ILContext context, TypeReference targetTypeRef, TypeReference typeConverter, IEnumerable`1 pushServiceProvider, Boolean boxValueTypes, Boolean unboxValueTypes)+MoveNext()
    at Microsoft.Maui.Controls.Build.Tasks.SetPropertiesVisitor.Set(VariableDefinition parent, String localName, INode node, IXmlLineInfo iXmlLineInfo, ILContext context)+MoveNext()
    at Microsoft.Maui.Controls.Build.Tasks.ILProcessorExtensions.Append(ILProcessor processor, IEnumerable`1 instructions)
    at Microsoft.Maui.Controls.Build.Tasks.SetPropertiesVisitor.Visit(ValueNode node, INode parentNode)
    at Microsoft.Maui.Controls.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
    at Microsoft.Maui.Controls.Build.Tasks.SetResourcesVisitor.Visit(ElementNode node, INode parentNode)
    at Microsoft.Maui.Controls.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
    at Microsoft.Maui.Controls.Xaml.ElementNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
    at Microsoft.Maui.Controls.Xaml.RootNode.Accept(IXamlNodeVisitor visitor, INode parentNode)
    at Microsoft.Maui.Controls.Build.Tasks.XamlCTask.TryCoreCompile(MethodDefinition initComp, ILRootNode rootnode, String xamlFilePath, Exception& exception)

I added some logging around this location, and the PR build was
green... So we merged, but then the build on the `net7.0` branch
failed with:

    XamlApp.xaml(11,37): error XFC0128: GetResourcePath failed: uri=AppResources.xaml, rootTargetPath=XamlApp.xaml

What is weird is a test like this works fine!

    [Test]
    public void GetResourcePath()
    {
        var result = ResourceDictionary.RDSourceTypeConverter.GetResourcePath(new Uri("AppResources.xaml", UriKind.Relative), "XamlApp.xaml");
        Assert.IsNotNull(result);
        Assert.IsNotEmpty(result);
    }

So this must be something that doesn't fail every time. I was able to
reproduce it locally *once*, but then not again...

After some discussion in: dotnet/runtime#70443 (comment)

It appears that usage of `pack://` is *sometimes* picking up a custom
`UriParser`, such as:

https://github.com/dotnet/runtime/blob/eef6c7f6cb7f73163313d349fbb796f37b4c3996/src/libraries/System.IO.Packaging/src/System/IO/Packaging/PackUriHelper.PackUriScheme.cs#L226-L229

If we just use something else, like `maui://`, I believe it will work
around this issue. I'll leave it up to the MAUI team if they want to
rewrite this method using `System.IO.Path` in the future.
  • Loading branch information
jonathanpeppers authored Jun 9, 2022
1 parent 0c38215 commit 40f40e7
Show file tree
Hide file tree
Showing 4 changed files with 7 additions and 17 deletions.
1 change: 0 additions & 1 deletion src/Controls/src/Build.Tasks/BuildException.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ class BuildExceptionCode
public static BuildExceptionCode ResourceDictDuplicateKey = new BuildExceptionCode("XFC0125", nameof(ResourceDictDuplicateKey), "");
public static BuildExceptionCode ResourceDictMissingKey = new BuildExceptionCode("XFC0126", nameof(ResourceDictMissingKey), "");
public static BuildExceptionCode XKeyNotLiteral = new BuildExceptionCode("XFC0127", nameof(XKeyNotLiteral), "");
public static BuildExceptionCode GetResourcePath = new BuildExceptionCode("XFC0128", nameof(GetResourcePath), "");

public string Code { get; private set; }
public string ErrorMessageKey { get; private set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,17 +40,9 @@ public IEnumerable<Instruction> ConvertFromString(string value, ILContext contex
module = currentModule.AssemblyResolver.Resolve(ar).MainModule;
}
}

var uri = new Uri(value, UriKind.Relative);
string resourcePath;
try
{
resourcePath = ResourceDictionary.RDSourceTypeConverter.GetResourcePath(uri, rootTargetPath);
}
catch (Exception exc)
{
throw new BuildException(BuildExceptionCode.GetResourcePath, node, exc, uri, rootTargetPath);
}

var resourcePath = ResourceDictionary.RDSourceTypeConverter.GetResourcePath(uri, rootTargetPath);

//fail early
var resourceId = XamlCTask.GetResourceIdForPath(module, resourcePath);
Expand Down
3 changes: 0 additions & 3 deletions src/Controls/src/Build.Tasks/ErrorMessages.resx
Original file line number Diff line number Diff line change
Expand Up @@ -248,8 +248,5 @@
<data name="XKeyNotLiteral" xml:space="preserve">
<value>x:Key expects a string literal.</value>
</data>
<data name="GetResourcePath" xml:space="preserve">
<value>GetResourcePath failed: uri={0}, rootTargetPath={1}</value>
</data>

</root>
8 changes: 5 additions & 3 deletions src/Controls/src/Core/ResourceDictionary.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ namespace Microsoft.Maui.Controls
/// <include file="../../docs/Microsoft.Maui.Controls/ResourceDictionary.xml" path="Type[@FullName='Microsoft.Maui.Controls.ResourceDictionary']/Docs" />
public class ResourceDictionary : IResourceDictionary, IDictionary<string, object>
{
const string GetResourcePathUriScheme = "maui://";
static ConditionalWeakTable<Type, ResourceDictionary> s_instances = new ConditionalWeakTable<Type, ResourceDictionary>();
readonly Dictionary<string, object> _innerDictionary = new Dictionary<string, object>();
ResourceDictionary _mergedInstance;
Expand Down Expand Up @@ -383,10 +384,11 @@ object IExtendedTypeConverter.ConvertFromInvariantString(string value, IServiceP

internal static string GetResourcePath(Uri uri, string rootTargetPath)
{
//need a fake scheme so it's not seen as file:// uri, and the forward slashes are valid on all plats
// GetResourcePathUriScheme is a fake scheme so it's not seen as file:// uri,
// and the forward slashes are valid on all plats
var resourceUri = uri.OriginalString.StartsWith("/", StringComparison.Ordinal)
? new Uri($"pack://{uri.OriginalString}", UriKind.Absolute)
: new Uri($"pack:///{rootTargetPath}/../{uri.OriginalString}", UriKind.Absolute);
? new Uri($"{GetResourcePathUriScheme}{uri.OriginalString}", UriKind.Absolute)
: new Uri($"{GetResourcePathUriScheme}/{rootTargetPath}/../{uri.OriginalString}", UriKind.Absolute);

//drop the leading '/'
return resourceUri.AbsolutePath.Substring(1);
Expand Down

0 comments on commit 40f40e7

Please sign in to comment.