Xamarin.forms: [Bug] XF 4.8 SR 2 crashes at startup on UWP: UriFormatException in ButtonRenderer

Created on 17 Sep 2020  路  35Comments  路  Source: xamarin/Xamarin.Forms

Description

I have an application that uses a custom renderer for buttons. It adds a tooltip to it. Everything worked with XF 4.8 SR 1. After updating to XF 4.8 SR 2, application crashes immediately at startup on UWP. A strange thing is that the exception is UriFormatException and it is thrown when calling base.OnElementChanged(e). Why is SR 2 version doing anything with URI in the button renderer?!

Steps to Reproduce

  1. Sorry, I do not have time now to create a repro project and add steps for reproducing the crash. Please, see the code of the render below and a screenshot with the exception.

Expected Behavior

The application works with SR2 the same way as it worked with SR1.

Actual Behavior

The application crashes immediately at startup with SR2.

Basic Information

  • Version with issue: 4.8.0.1451
  • Last known good version: 4.8.0.1364
  • IDE: VS 2019
  • Platform Target Frameworks:

    • UWP: 1903

  • Nuget Packages: Just XF, Essentials, AppCenter.Crashes and System.Text.Json.

Screenshots

XF 4 8 SR 2 Crash on UWP

Reproduction Link

Sorry, I do not have time to create a full repro project now. It is very time consuming. Maybe, if it will be required, I will try to do this later.

I am using the following custom renderer:

    public class ButtonWithToolTipRenderer: ButtonRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);

            if (Control != null)
            {
                UpdateTooltip(Element as ButtonWithToolTip);
            }
        }

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);

            if (e.PropertyName == ButtonWithToolTip.TooltipProperty.PropertyName)
            {
                UpdateTooltip(sender as ButtonWithToolTip);
            }
        }

        private void UpdateTooltip(ButtonWithToolTip button)
        {
            string tooltip = button?.Tooltip;
            if (Control != null && !String.IsNullOrEmpty(tooltip))
                ToolTipService.SetToolTip(Control, tooltip);
        }
    }

Just a few more notes:

  • I am using basically the same renderer for Android (of course, it is using TooltipCompat.SetTooltipText instead of ToolTipService.SetToolTip). The Android version works without crashes.
  • The only difference between Android and UWP that I can think of is that I am using FontImageSource (standard Segoe MDL2 Assets font) for UWP and image files (XML drawables) for Android.

Workaround

Downgrade to XF 4.8 SR 1 :-(

4.8.0 embedded fonts fonts critical high regression in-progress UWP bug

Most helpful comment

By the way, I have just tested upgrading to Xamarin.Forms 5.0 pre 1 and it is also affected and crashes.

All 35 comments

I also had this issue.

I was using the old way of using fonts on uwp - outlined here https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/text/fonts#set-the-font-in-code

but I refactored it to the new way of embedding fonts outlined here: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/text/fonts#use-a-custom-font

and the bug went away.

I'm guessing you're using custom fonts and the fontfamily attribute on your button

Same here, using font the "old" way should still work.

Yea it should, for a bit more clarrification when I say the "old" way. I'm talking about adding the font as "content" to your assets folder on the UWP project and referencing it through fontfamily="assets/font.tff" similar to this: https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/text/fonts#set-font-info-per-platform

It should still work but it doesnt, I refactored it to the new embeddedfont way anyway which is cleaner and because all my font code went through a single code path, the refactor wasnt too painful.

I'd imagine this bug has been introduced because of this fix released in SR 2: https://github.com/xamarin/Xamarin.Forms/issues/10307
PR: https://github.com/xamarin/Xamarin.Forms/pull/11741

This sounds like it may be related to the problem that I am hitting with XF 4.8.0.1451 (having just updated from 4.5.0.725).

Here is one stack trace, showing the UriFormatException. Note, however, that I have not added any font files. I do, however, have FontFamily on UWP specified on some Views as "Verdana". I've been meaning to re-factor that, so perhaps now is the time, in order to see if it gets rid of this exception...

System.UriFormatException: Invalid URI: The format of the URI could not be determined.
at System.Uri.CreateThis(String uri, Boolean dontEscape, UriKind uriKind)
at Xamarin.Forms.Platform.UWP.FontExtensions.FindFontFamilyName(String fontFile)
at Xamarin.Forms.Platform.UWP.FontExtensions.GetAllFontPossibilities(String fontFamily)+MoveNext()
at System.String.Join(String separator, IEnumerable1 values) at Xamarin.Forms.Platform.UWP.FontExtensions.ToFontFamily(String fontFamily) at Xamarin.Forms.Platform.UWP.FontExtensions.ApplyFont(TextBlock self, Font font) at Xamarin.Forms.Platform.UWP.LabelRenderer.UpdateFont(TextBlock textBlock) at Xamarin.Forms.Platform.UWP.LabelRenderer.OnElementChanged(ElementChangedEventArgs1 e)
at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element) at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element) at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view) at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load() at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element)
at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load()
at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element) at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element) at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view) at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load() at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element)
at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load()
at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element) at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element) at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view) at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load() at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element)
at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load()
at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element) at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element) at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view) at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load() at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element)
at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element)
at Xamarin.Forms.Platform.UWP.VisualElementExtensions.GetOrCreateRenderer(VisualElement self)
at Xamarin.Forms.Platform.UWP.ScrollViewRenderer.UpdateContent()
at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element) at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element) at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view) at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load() at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element)
at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view)
at Xamarin.Forms.Platform.UWP.VisualElementPackager.Load()
at Xamarin.Forms.Platform.UWP.VisualElementRenderer2.SetElement(VisualElement element) at Xamarin.Forms.Platform.UWP.Platform.CreateRenderer(VisualElement element) at Xamarin.Forms.Platform.UWP.VisualElementPackager.SetupVisualElement(VisualElement view) at Xamarin.Forms.Platform.UWP.VisualElementPackager.OnChildAdded(Object sender, ElementEventArgs e) at Xamarin.Forms.Element.OnChildAdded(Element child) at Xamarin.Forms.VisualElement.OnChildAdded(Element child) at Xamarin.Forms.Page.OnInternalAdded(VisualElement view) at Xamarin.Forms.Page.InternalChildrenOnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection1.OnCollectionChanged(NotifyCollectionChangedEventArgs e)
at Xamarin.Forms.BindableObject.SetValueCore(BindableProperty property, Object value, SetValueFlags attributes, SetValuePrivateFlags privateAttributes)
at Xamarin.Forms.ContentPage.set_Content(View value)

I re-factored my codebase to remove specification of FontFamily using pre-installed fonts (which had been working on previous versions of XF dating back to XF 2 or even before). Having removed that, the exception no longer happens. Whilst it's a good idea not to rely on pre-installed fonts, if removing support (or error handling) for it is intentional, the documentation needs to make it clear that this is the case. If removal is intended to be for UWP only, that's odd, which is why I wonder if it is intentional.

Thank you for the clarification. I hope that this was not intentional and that it will be fixed properly. I don't want to embed the font in the shared project because I use it only for UWP (I am using Material Design Icons for Android instead). If I would add it to the shared project it would make the Android package needlessly larger.

Just to clarify, when I said above "it's a good idea not to rely on pre-installed fonts", that's in apps that are distributed widely. There will still be people developing apps for personal or in-house use where using pre-installed fonts is fine. IMHO, XF should continue to support use of pre-installed fonts.

What Xamarin/Microsoft should also do, which is a general problem highlighted yet again by this particular issue, is sort out exception-handling in renderers, so that apps can be informed of exceptions in renderers, but without the apps terminating with an unhandled exception. Not having sufficient exception handling in built-in renderers makes XF-based apps fragile, being vulnerable to any XF update resulting in one broken renderer making it impossible to release an updated app using that XF update.

I am using Segoe MDL2 Assets font and according to the Microsoft documentation, I can rely that it is installed on all Windows 10 systems (https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font; see chapter "How do I get this font?"). Embedding it again in my app does not provide any benefit for Windows version of my application. On contrary, because Android version uses different icons (Material Design Icons), embedding the font is undesirable because it would increase the package size. And a large package size can have negative influence on the number of installs, or even on the position in the Google Play listing.

Do you have a small repro project? It does look like it was introduced when fixing #10307

I will create a PR to fix this.

Thanks @activa let me know if you get held up at all!

It seems that this same problem occurs when using Syncfusion.Xamarin.SfRichTextEditor v18.2.0.58. I'm assuming that must use FontFamily internally.

I have prepared a two repro projects. Please test your fix on both of them because it seems that there might be actually two bugs instead of a one.

Repro 1: an application crashes at startup
ReproUwpFontIconCrash1.zip
This corresponds to the scenario when Segoe MDL2 Assets font is used for the text of the button.
Expected behavior: A button with a play icon is displayed.
Actual behavior: Application crashes.

Repro 2: an application does not crash but the icon is not displayed
ReproUwpFontIconCrash2.zip
The Segoe MDL2 Assets is not used in the button text but in a the font image source.
Expected behavior: A button with a play icon and a text is displayed.
Actual behavior: Only text is displayed. The icon is missing.

This is problem of XF 4.8.0.1451. If you downgrade to 4.8.0.1364, both projects behaves correctly.

@holecekp Both these repro projects don't include the font ("Segoe MDL2 Assets")

This is intentional. This font is present on all Windows 10. See Microsoft documentation for this font (https://docs.microsoft.com/en-us/windows/uwp/design/style/segoe-ui-symbol-font; chapter "How do I get this font?")

@holecekp ok, I see. I will test your projects with the fix

I also had this issue.

@holecekp The fix works with both your examples now.

@activa Thank you. I am looking forward to the fixed release.

@activa - Can you test that the fix allows Device.Styles to work again please?

I am assuming that the cause is the same, but on UWP currently code using a Label using Device.Styles is failing with what looks like the same error:

e.g. using the following in a UI:
new Label {Text = "Body style", Style = Device.Styles.BodyStyle}

Hi Team / @samhouts ,

Any approximate time line for the mentioned issue in UWP platform.

Regards,
Devaraj S

Hi @samhouts ,

Am also getting the same exception. Could you please tell me the exact timeline for the fix ?

Regards,
Karthik Raja

By the way, I have just tested upgrading to Xamarin.Forms 5.0 pre 1 and it is also affected and crashes.

@PureWeen any update on merging the fix? Just came back from vacation, updated XF4.8 and got this crash.

I am getting this crash only in release mode here -

 Uri uriBase = new Uri("ms-appx:///Assets/CanvasGray.mssjson");
StorageFile fileBase = await StorageFile.GetFileFromApplicationUriAsync(uriBase);

@PureWeen , @activa any ideas how to rewrite my uri to make this work? Or i guess the only solution for now is to downgrade?

well, we will test it out then)

Any confirmed date when a new build will be released? Waiting for the bug to be fixed to update a new release in Microsoft Store. Thanks.

This is now affecting third party Xamarin components, the companies latest release crashes with this bug.

Any chance of a hotfix?

I am also interested.

It's also very important for us. Thank you.

the 4.8.0-sr3, which includes the fix, is already tagged, so we can expect the update this week

I just updated to 4.8.0.1534 and it works fine

I can confirm that it works. Well done ;)

It works. Thank you very much. Have a nice weekend.

Was this page helpful?
0 / 5 - 0 ratings