Release-only exceptions for UWP Storyboard and CallMethodAction

2

I am debugging a piece of code that uses a CallMethodAction to trigger a storyboard in a UWP app. My VS is updated to the latest (15.8.6). The error I am getting from VS 2017 is:

Cannot find method named Begin on object of type Windows.UI.Xaml.Media.Animation.Storyboard that matches the expected signature.

I have to manually turn on the exceptions in VS, otherwise it will just show:

Unhandled exception at 0x5B79DC3C (Windows.UI.Xaml.dll) in app.exe: 0xC000027B: An application-internal exception has occurred (parameters: 0x1DF30E70, 0x00000003). occurred

After a few tries I found that:

  1. The storyboard works fine in debug. Only crashing in release.
  2. I go to the definition of the Storyboard, the signature of Begin is:
public void Begin();

Which looks fine. (And it works in debugging...)

The Storyborad and the DataTriggerBehavior is setup like this:

<Storyboard x:Name="ShowOverlay">
  ... // doesn't really matter
</Storyboard>

<core:DataTriggerBehavior Binding="{Binding LogUploadStatus, Converter={StaticResource LogUploadStatusToBoolConverter}, ConverterParameter={StaticResource LogUploadStatusIdle}}" Value="False">
  <core:CallMethodAction TargetObject="{Binding ElementName=ShowOverlay}" MethodName="Begin" />
</core:DataTriggerBehavior>

Does anyone have an idea why the exception only happens in release?

c#
uwp
asked on Stack Overflow Oct 5, 2018 by laishiekai • edited Oct 6, 2018 by Martin Zikmund

1 Answer

2

In general, instead of CallMethodAction you can use ControlStoryboardAction. This is specific behavior built to support controlling Storyboard element:

<Storyboard x:Name="ShowOverlay">
  ...
</Storyboard>

<core:DataTriggerBehavior Binding="{Binding LogUploadStatus, Converter={StaticResource LogUploadStatusToBoolConverter}, ConverterParameter={StaticResource LogUploadStatusIdle}}" Value="False">
  <core:ControlStoryboardAction Storyboard="{StaticResource ShowOverlay}"
                                ControlStoryboardOption="Play" />
</core:DataTriggerBehavior>

As for why ControlMethodAction didn't work, in Release mode the .NET Native compiler strips away anything that is not used so that it can minimize the size of the resulting assembly and also optimize performance. Unfortunately this can cause problems when using reflection to access types and members which are not accessed anywhere directly.

In this case the Storyboard.Begin() method is never used directly and if you check the source code of CallMethodAction, you can find out the action uses reflection to discover methods on the TargetObject:

foreach (MethodInfo method in this.targetObjectType.GetRuntimeMethods())
{
    ...
}

Luckily there is a way to force the .NET Native compiler to include the type directly and to help you do that you can use the MissingMetadataException Troubleshooter (named by the fact that most of the time this is the exception you will get when a type is missing).

In this case I have put the full path to the Storyboard (Windows.UI.Xaml.Media.Animation.Storyboard) type in A single type section of the tool:

I reflect on a single type

And below chose Access members or activate and Public types and members only.

On the right-hand side the tool will generate the <Type> declaration you will need to add to the <Application> element in Default.rd.xml file you can find in the Properties folder of your UWP project. In our case the result could look like this (excluding comments):

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
  <Application>
    <Assembly Name="*Application*" Dynamic="Required All" />

    <Type Name="Windows.UI.Xaml.Media.Animation.Storyboard" Dynamic="Required Public" />    
  </Application>
</Directives>
answered on Stack Overflow Oct 5, 2018 by Martin Zikmund

User contributions licensed under CC BY-SA 3.0