{"id":96,"date":"2020-10-07T08:01:58","date_gmt":"2020-10-07T15:01:58","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/pax-windows\/?p=96"},"modified":"2021-02-02T09:45:43","modified_gmt":"2021-02-02T17:45:43","slug":"mvvm-toolkit-preview-3-the-journey-of-an-api","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/mvvm-toolkit-preview-3-the-journey-of-an-api\/","title":{"rendered":"MVVM Toolkit Preview 3 &#038; The Journey of an API"},"content":{"rendered":"<h2>MVVM Toolkit Preview 3<\/h2>\n<h2>TLDR;<\/h2>\n<p>\ud83c\udf89 Today we&#8217;re happy to announce a new preview of our <a href=\"https:\/\/aka.ms\/mvvmtoolkit\">MVVM Toolkit<\/a> as part of the <a href=\"https:\/\/aka.ms\/wct\">Windows Community Toolkit<\/a>. \ud83c\udf89<\/p>\n<p>This update includes changes based on feedback from our community who&#8217;ve been using the initial preview of the library. It does contain some breaking changes, so be sure to read our notes about that <a href=\"https:\/\/aka.ms\/mvvmtoolkit\/preview3notes\">here<\/a> if you are updating.<\/p>\n<p>\ud83d\udcdd The highlights for the update to the library include:<\/p>\n<ul>\n<li>Removing a direct dependency on the <code>Microsoft.Extensions.DependencyInjection<\/code> so developers are free to choose that or any library for their Inversion of Control needs.<\/li>\n<li>Switching the Messenger to use weak references by default for <strong>MVVMLight<\/strong> migrators (as well as continuing to provide the option to the strong reference initial version).<\/li>\n<li>Further optimizations and changes to the API surface for better usage and performance in different scenarios.<\/li>\n<\/ul>\n<p><div  class=\"d-flex justify-content-center\"><a class=\"cta_button_link btn-primary mb-24\" href=\"https:\/\/aka.ms\/MVVMToolkit\/Preview3Notes\" target=\"_blank\">MVVM Toolkit Preview 3 Release Notes<\/a><\/div><\/p>\n<p>The rest of this post will cover our journey on how we set out to improve the usability of one of these API calls. Early on, we discovered an issue with compiling those changes on .NET Native for UWP; however, we ended up not only working around them, but also designing an even better API surface in the process! \ud83d\ude80<\/p>\n<h2>The Beginning<\/h2>\n<p>In <em>our initial preview<\/em> of the <a href=\"https:\/\/aka.ms\/mvvmtoolkit\">MVVM Toolkit<\/a>, we provided a new API that allows a developer to more easily get notified in their UI when a Task is completed in their ViewModel. This makes it easier to directly obtain status on a task and remove <code>IsLoading<\/code> type properties to control UI flow while awaiting these Tasks. This API is called <a href=\"https:\/\/aka.ms\/mvvmtoolkit\/notifyoncompletion\"><code>SetPropertyAndNotifyOnCompletion<\/code><\/a> and had the following signature:<\/p>\n<pre><code class=\"cs\">protected bool SetPropertyAndNotifyOnCompletion&lt;TTask&gt;(\r\n    ref TTask? field,\r\n    Expression&lt;Func&lt;TTask?&gt;&gt; fieldExpression,\r\n    TTask? newValue,\r\n    [CallerMemberName] string? propertyName = null)\r\n    where TTask : Task;\r\n<\/code><\/pre>\n<p>While looking complex, it was still fairly straight-forward to use in practice as seen here:<\/p>\n<pre><code class=\"cs\">private Task&lt;string&gt; myTask;\r\npublic Task&lt;string&gt; MyTask\r\n{\r\n     get =&gt; myTask;\r\n     set =&gt; SetPropertyAndNotifyOnCompletion(ref myTask, () =&gt; myTask, value);\r\n}\r\n<\/code><\/pre>\n<p>However, you&#8217;ll note that we&#8217;re effectively passing the same task twice into the function in different ways. \ud83d\ude15 The first reference to the task, allowed the function to not need reflection in order to validate the initial task setup. The second lambda expression allows the method to check that the task is still the same upon completion (via reflection) before notifying the application that it was finished (as we couldn&#8217;t re-use the ref in the asynchronous method).<\/p>\n<p>This pattern though, was still more complex than using a standard property change setup in the normal use case which just took a reference to the backing field:<\/p>\n<pre><code class=\"cs\">private string query;\r\npublic string Query\r\n{\r\n    get =&gt; query;\r\n    set =&gt; SetProperty(ref query, value);\r\n}\r\n<\/code><\/pre>\n<h2>The Initial Refactor<\/h2>\n<p>As we set out to improve the API after our initial preview of it. We wanted to try to simplify the need for passing the task twice to the <code>SetPropertyAndNotifyOnCompletion<\/code> method. Sergio Pedri, an active community member and developer of the MVVM Toolkit library, originally came up with an optimization using a custom ref returning delegate (a relatively newer feature introduced in C# 7):<\/p>\n<pre><code class=\"cs\">protected delegate ref T FieldAccessor&lt;T&gt;();\r\n\r\nprotected bool SetPropertyAndNotifyOnCompletion&lt;TTask&gt;(\r\n    FieldAccessor&lt;TTask?&gt; fieldAccessor,\r\n    TTask? newValue,\r\n    [CallerMemberName] string? propertyName = null)\r\n    where TTask : Task;\r\n<\/code><\/pre>\n<p>This would simplify the syntax for utilizing the method by combining the <code>ref<\/code> and lambda (effectively) together:<\/p>\n<pre><code class=\"cs\">private Task&lt;string&gt; myTask;\r\npublic Task&lt;string&gt; MyTask\r\n{\r\n    get =&gt; myTask;\r\n    set =&gt; SetPropertyAndNotifyOnCompletion(() =&gt; ref myTask, value);\r\n}\r\n<\/code><\/pre>\n<p>The added benefit to this approach was that it also removed the need for reflection entirely. \ud83d\ude80 You can see how this improved the performance of this one API here:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/pax-windows\/wp-content\/uploads\/sites\/61\/2020\/10\/MVVMToolkit-PerformanceInitialImprovement.png\" alt=\"Initial API Performance Comparison\" \/><\/p>\n<p>This led to a 7-14 times improvement in execution time and over 60% improvement to memory usage! \ud83c\udf89<\/p>\n<h2>Enter .NET Native<\/h2>\n<p>Even though our library is based on .NET Standard, one of the primary target groups for the Windows Community Toolkit are UWP developers! This of course means we want to ensure the library works well for them on .NET Native. When Sergio went to push his new changes to his open PR, he found our Continuous Integration build to have failed! What could have happened with this seemingly simple update using a feature of C#?<\/p>\n<p>Unfortunately for us, we discovered the .NET Native compiler doesn&#8217;t support ref returning delegates. \ud83d\ude25<\/p>\n<p>We reached out to the .NET Native team, originally starting our discussion on GitHub <a href=\"https:\/\/github.com\/dotnet\/corert\/issues\/8273\">here<\/a> about what might be going on. They confirmed this was indeed a known issue with .NET Native.<\/p>\n<p>In order to workaround this issue, we were going to have to try and change our method signature in another way to achieve our goal of simplifying its usage. Thankfully, the .NET Native team was able to help us investigate and suggest a potential solution to our problem. \ud83c\udf89<\/p>\n<p>Their initial proposal was effectively the following API surface and usage:<\/p>\n<pre><code class=\"cs\">\/\/ API Surface\r\nprotected class TaskAccessor&lt;T&gt; where T : Task\r\n{\r\n    public T Task { get; set; }\r\n}\r\n\r\nprotected bool SetPropertyAndNotifyOnCompletion&lt;TTask&gt;(\r\n    TaskAccessor&lt;TTask&gt; accessor,\r\n    TTask newValue,\r\n    [CallerMemberName] string? propertyName = null)\r\n    where TTask : Task\r\n{\r\n    return default;\r\n}\r\n\r\n\/\/ Developer Usage\r\nprivate TaskAccessor&lt;Task&lt;string&gt;&gt; myTask = new TaskAccessor&lt;Task&lt;string&gt;&gt;();\r\npublic Task&lt;string&gt; MyTask\r\n{\r\n    get =&gt; myTask.Task;\r\n    set =&gt; SetPropertyAndNotifyOnCompletion(myTask, value);\r\n}\r\n<\/code><\/pre>\n<p>While this would resolve the issue when compiling to .NET Native, it introduced some extra overhead on the developer compared to our standard property change notification pattern.<\/p>\n<p>However, our first step was to at least implement the suggested pattern in the library to ensure it worked and compare the performance with the existing updated improvements we had already achieved.<\/p>\n<p>During this implementation, we realized the backing <code>TaskAccessor<\/code> field would probably be best marked <code>readonly<\/code> as it shouldn&#8217;t be changed after initialization. This would be another step for developers using the API to have to know to setup.<\/p>\n<p>In the end, we were concerned about having the extra wrapping type (including needing to specify Task as a generic type argument again), having to initialize the wrapper, and having to unwrap it again to retrieve it.<\/p>\n<p><em>Side note though<\/em>, this workaround did improve the memory usage even further! \ud83d\ude2e<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/pax-windows\/wp-content\/uploads\/sites\/61\/2020\/10\/MVVMToolkit-PerformanceAccessor.png\" alt=\"Accessor Performance Improvement\" \/><\/p>\n<h2>The Journey<\/h2>\n<p>What followed was over a day long quest between Sergio and I to see if we could simplify the usage pattern of the API for developers, while still maintaining the goal of working with .NET Native. We really wanted to ensure this was an easy to use API without a lot of overhead for developers to understand and discover a complex nuanced syntax. \ud83e\udd14<\/p>\n<p>The first issue we tackled was around needing to initialize the wrapper type and marking the backing field as <code>readonly<\/code>. By changing the API to accept the parameter by <code>ref<\/code> and leveraging <code>TaskAccessor&lt;T&gt;<\/code>&#8216;s parameterless constructor, the API itself could automatically initialize the field with a new instance, if needed:<\/p>\n<pre><code class=\"cs\">private TaskAccessor&lt;Task&lt;string&gt;&gt; myTask;\r\npublic Task&lt;string&gt; MyTask\r\n{\r\n    get =&gt; myTask.Task;\r\n    set =&gt; SetPropertyAndNotifyOnCompletion(ref myTask, value);\r\n}\r\n<\/code><\/pre>\n<p>Secondly, we improved the <code>get<\/code> accessor by adding an implicit cast operator to the <code>TaskAccessor&lt;T&gt;<\/code> field, which would automatically unwrap the inner <code>T<\/code> instance. This allows developers to have their property getters return the backing field directly (like a standard property setup), with the C# compiler taking care of invoking the implicit operator to retrieve the task instance stored there, if present:<\/p>\n<pre><code class=\"cs\">private TaskAccessor&lt;Task&lt;string&gt;&gt; myTask;\r\npublic Task&lt;string&gt; MyTask\r\n{\r\n    get =&gt; myTask;\r\n    set =&gt; SetPropertyAndNotifyOnCompletion(ref myTask, value);\r\n}\r\n<\/code><\/pre>\n<p>We were getting closer to our goal of simplifying this API. \ud83d\udc68\u200d\ud83d\udd2c The last thing that remained on our minds was the API still required including the generic type <code>Task<\/code> within the <code>TaskAccessor<\/code> itself. Not only was it more verbose, but it was especially odd if the Task was non-generic as you&#8217;d have to specify <code>TaskAccessor&lt;Task&gt;<\/code>. It&#8217;d be great if we could just use something like <code>TaskAccessor<\/code> directly and not re-iterate the <code>Task<\/code> within it.<\/p>\n<p>While we (or rather Sergio) worked to thinking of a solution, an interesting anecdote occurred to me at this point. Thinking of the name <code>TaskAccessor<\/code> seemed to be very monolithic and indicative of the core problem we were trying to work around. This didn&#8217;t lead to feeling great about the solution, even though we had come so far at this point to get here. \ud83e\udd14<\/p>\n<p>Lucky for us, we realized by just changing the name to <code>TaskNotifier<\/code> instead, it seemed to make things tie together more closely to the API it was related too, and just generally make us feel better about having to use it. Now, rather than seeming like a workaround to access a field, it feels like a piece of code that is actively working towards helping the developer with this scenario (even though it doesn&#8217;t actually do any of the real notifying. \ud83e\udd2b Shhhh, it&#8217;s a secret).<\/p>\n<p>Finally, to implement a solution for the embedded <code>Task<\/code> type, Sergio decoupled the handling of both the generic and non-generic tasks by introducing two separate wrapping types: <code>TaskNotifier<\/code> and <code>TaskNotifier&lt;T&gt;<\/code>. The generic <code>TaskNotifier&lt;T&gt;<\/code> type automatically maps to <code>Task&lt;T&gt;<\/code> for the internal task instance, while <code>TaskNotifier<\/code> just contains a simple <code>Task<\/code>. We then exposed two different overloads of the <code>SetPropertyAndNotifyOnCompletion<\/code> method, one accepting a <code>TaskNotifier<\/code> and one accepting a <code>TaskNotifier&lt;T&gt;<\/code> parameter. This whole procedure is completely transparent for consumers of the library, but it allows us to completely remove the need to have those two type arguments being specified, making the code much less verbose.<\/p>\n<p>\ud83d\udcdd <em>Note: There&#8217;s a bit more behind the scenes to this story in terms of implementation details and how it all functions. Of course, this is all open source code up on GitHub, so you can see how it works for yourself <a href=\"https:\/\/github.com\/windows-toolkit\/WindowsCommunityToolkit\/tree\/master\/Microsoft.Toolkit.Mvvm\">here<\/a>.<\/em><\/p>\n<h2>The Final Result<\/h2>\n<p>We finally reached a state where we were truly happy with how developers could use this API. Now, it was not only simpler to use, but just as performant (indeed more so, see below), and closely mirrored the base property change API. This is the final result to the end developer in this new preview:<\/p>\n<pre><code class=\"cs\">private TaskNotifier&lt;string&gt; myTask;\r\npublic Task&lt;string&gt; MyTask\r\n{\r\n    get =&gt; myTask;\r\n    set =&gt; SetPropertyAndNotifyOnCompletion(ref myTask, value);\r\n}\r\n<\/code><\/pre>\n<p>And when compared to the standard property backing, it becomes more apparent how nice this solution was:<\/p>\n<pre><code class=\"cs\">private string query;\r\npublic string Query\r\n{\r\n    get =&gt; query;\r\n    set =&gt; SetProperty(ref query, value);\r\n}\r\n<\/code><\/pre>\n<p>You&#8217;ll see the only change a developer needs to enable Tasks is to use <code>SetPropertyAndNotifyOnCompletion<\/code> instead of <code>SetProperty<\/code> and change their <code>Task<\/code> backing type to <code>TaskNotifier<\/code> while still being able to leverage <code>Task<\/code> in their property itself. \ud83c\udf89<\/p>\n<p>At the end of this adventure, we ended up with a better API than where we started, that was more performant, and easier to use. See the final comparison of performance metrics below.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/pax-windows\/wp-content\/uploads\/sites\/61\/2020\/10\/MVVMToolkit-PerformanceAll.png\" alt=\"Accessor Performance Improvement\" \/><\/p>\n<p>\ud83e\udd99\ud83d\udc97 We&#8217;re thankful to the .NET Native team for working with us and proposing an initial solution to workaround our issue. It&#8217;s really amazing how this journey to improve an API led us down some unexpected paths, but in the end resulted in improvements for the MVVM Toolkit. \ud83d\ude80<\/p>\n<h2>Providing Feedback<\/h2>\n<p>Be sure to checkout our preview <a href=\"https:\/\/aka.ms\/mvvmtoolkit\">MVVM Toolkit sample and doc repo here<\/a>. You can file issues against the samples and docs there, or provide input on the MVVM Toolkit code itself on our main repo&#8217;s <a href=\"https:\/\/github.com\/windows-toolkit\/WindowsCommunityToolkit\/issues\/3428\">tracking issue here<\/a>. \ud83d\udce2<\/p>\n<p>Thank you for sharing your feedback with us!<\/p>\n<p><em>Co-written with <a href=\"https:\/\/twitter.com\/SergioPedri\">Sergio Pedri<\/a>, Windows Community Toolkit member and creator of the MVVM Toolkit.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In this post, we cover the journey of creating an easier to use API, how a .NET Native issue required a workaround, and how that ultimately proved to be a greater success!<\/p>\n","protected":false},"author":41887,"featured_media":1176,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[4,2,5,3],"class_list":["post-96","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-ifdef-windows","tag-net","tag-mvvm","tag-uwp","tag-windows-community-toolkit"],"acf":[],"blog_post_summary":"<p>In this post, we cover the journey of creating an easier to use API, how a .NET Native issue required a workaround, and how that ultimately proved to be a greater success!<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/posts\/96","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/users\/41887"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/comments?post=96"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/posts\/96\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/media\/1176"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/media?parent=96"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/categories?post=96"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/ifdef-windows\/wp-json\/wp\/v2\/tags?post=96"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}