I have been using Visual Studio 2019 to develop desktop and mobile applications using Xamarin. I could successfully deploy my Xamarin UWP app to Microsoft Store until I upgraded my Visual Studio 2019 to 16.10.2.
Normally, before we can publish our UWP app to Microsoft Store, we need to launch WACK (Windows App Certification Kit) to validate our app package. However, in VS2019 16.10.2 (and onwards), there will be an error occurs, as shown in the screenshot below, and the validation cannot be completed.
Error 0x800B0100 in Windows App Certification Kit (WACK).
MSBuild Project Build Output
Since my code is the same, so the first thing that I suspect is that the new updates in Visual Studio 2019 are causing this issue. Hence, I changed the verbosity of the project build output to Diagnostic, as shown below. This will help us understand better about what’s happening during the build.
Setting MSBuild project build output verbosity.
By comparing the current build output with the one using the previous version of Visual Studio 2019, I realised that there is something new in the current build ouput. The parameter GenerateTemporaryStoreCertificate is set to false while BuildAppxUploadPackageForUap is true, as shown below.
1>Target "_RemoveDisposableSigningCertificate: (TargetId:293)" in file "C:\Program Files (x86)\Microsoft Visual Studio\2019\Preview\MSBuild\Microsoft\VisualStudio\v16.0\AppxPackage\Microsoft.AppXPackage.Targets" from project "...UWP.csproj" (target "_GenerateAppxPackage" depends on it):
1>Task "RemoveDisposableSigningCertificate" skipped, due to false condition; ('$(GenerateTemporaryStoreCertificate)' == 'true' and '$(BuildAppxUploadPackageForUap)' == 'true') was evaluated as ('false' == 'true' and 'true' == 'true').
1>Done building target "_RemoveDisposableSigningCertificate" in project "...UWP.csproj".: (TargetId:293)
Online Discussions
Meanwhile, there are only two discussion threads online about this issue.
Few days later, on 1st of July 2021, another developer Tautvydas Zilys also reported a similar issue as Nick Stevens’. Interestingly, the same Microsoft engineer, James Parsons, replied to them with the similar answer, i.e. adding the following property in their project file to set GenerateTemporaryStoreCertificate to true.
That’s all to fix the issue. I hope this article, which is also the 3rd in the world discussing about this Visual Studio 2019 problem, is helpful to other Xamarin UWP developers who are running into the same problem.
KOSD, or Kopi-O Siew Dai, is a type of Singapore coffee that I enjoy. It is basically a cup of coffee with a little bit of sugar. This series is meant to blog about technical knowledge that I gained while having a small cup of Kopi-O Siew Dai.
As we all know, a picture is worth 1,000 words. More and more, we see developers utilising images as the core of their app. Images play an important role in application navigation, usability, and branding. Hence, sharing images across all platforms, i.e. iOS, Android, and Windows 10, is often a task we need to work on. Today, I will share about how we do just that with Embedded Images.
Distributing images across different platforms with Embedded Images is recommended when identical images are used on each platform, and is particularly suited to creating components, as the image is bundled with the code. In this post, I will demo how we can do that in a new Xamarin.Forms blank project.
Let’s say we would like to show some images in the first screen of our app for each of the platforms. We will first have a folder called Images to store all those images. Then, we need to proceed to set the Build Action of the images to be “Embedded resource”.
Right-click the selected images and then select “Properties” to modify their Build Action.
[ContentProperty(nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
public string Source { get; set; }
public object ProvideValue(IServiceProvider serviceProvider)
{
if (Source == null) return null;
Assembly assembly = typeof(ImageResourceExtension).Assembly;
var imageSource = ImageSource.FromResource(Source, assembly);
return imageSource;
}
}
Here we use the overload of ImageSource.FromResource that specifies the source assembly in which to search for the image so that it can work on the Release mode of UWP on Windows 10.
Now we can use this extension in the XAML, as shown below, in MainPage.xaml.
The highlighted sections are the parts newly added. At this point of time, we’re still not sure the name of the image. So our app now should not show any image at that part. To find out the actual image names, we can add a debugging code (which we should remove in production) in the ImageResourceExtension class as follows.
[ContentProperty(nameof(Source))]
public class ImageResourceExtension : IMarkupExtension
{
...
public object ProvideValue(IServiceProvider serviceProvider)
{
...
foreach (var res in assembly.GetManifestResourceNames())
{
System.Diagnostics.Debug.WriteLine("found resource: " + res);
}
...
}
}
When we debug our app, the following should be shown in the Output window.
found resource: CPEI.Images.Genshin-Impact-Pic01.png
found resource: CPEI.Images.Genshin-Impact-Pic02.png
found resource: CPEI.Images.Genshin-Impact-Pic03.png
found resource: CPEI.Images.Genshin-Impact-Pic04.png
found resource: CPEI.Images.Genshin-Impact-Pic05.png
found resource: CPEI.Images.Genshin-Impact-Pic06.png
So now we know the name for each of the images. We simply update the Source in the XAML code above to correctly show the image, for example
Yay, the selected image is now displayed on our UWP app.
Access Embedded Images from Code Behind
Instead of XAML, we can access the embedded images from code behind too. For example, if we want to change the image above randomly through a click of button, we can have the following code in the click event of the button.
private void Button_Clicked(object sender, EventArgs e)
{
Random rnd = new Random();
int imageIndex = rnd.Next(1, 7);
MainImage.Source = ImageSource.FromResource(
$"CPEI.Images.Genshin-Impact-Pic{imageIndex:00}.png",
typeof(MainPage).Assembly);
}
Yay, we now can choose embedded images to be displayed in frontend from code behind.
Android and iOS
Since embedded images are shipped with those images embedded in the assembly as a resource, the images can be also displayed on Android, as demonstrated below.
Debugging our Xamarin.Forms app on Android emulator.
In order to test our app on the iOS platform, it’s easier if we choose to build our iOS app project on a Mac machine directly. Visual Studio for Mac offers the support for debugging Xamarin.iOS applications both in the iOS simulator and on iOS devices.
The topic that I delivered in the event is “Development and DevOps of Desktop Apps with .NET Core 3.0”. It is a 45-minute talk combining the content from the following three talks.
From coding, converting, to deploying. (Image Credit: .NET Conf 2019)
If you watch the videos above, the total length is about 70 minutes. So covering three of them in a 45-minute talk is a challenge to me. Luckily, I have Sabrina to help me out by co-speaking with me.
If you have watched our session, you will realise it’s quite different from the official .NET Conf. In this post, I am going to brief you through about my thoughts and development process of our talk content.
Let’s Hashtag Together!
In order to make the conference to be more engaging, after discussing with Sabrina, I came out with a desktop app which will shows the recent tweets having #dotnetconfsg hashtag, which looks like the following.
Participants tweeting about our sessions.
To make this “game” more interesting, I announced that the top four participants who earn the highest scores would receive prizes from me. The formula to calculate the score is basically
+1 point for one tweet;
+5 point for one retweet of the tweet;
+5 point for one like of the tweet.
Throughout the conference, we thus had seen a huge number of tweets about our event and speakers. Some of them even tweeted with great photos (I should have given 5 points for great photos too).
In our talk, we used this desktop app as our sample. The app is built in .NET Framework 4.7. Sabrina started the demo with showing how we can modernise it to a .NET Core desktop app. I then covered a bit about Hot Reload, the runtime tools (the small little black bar on top of locally launched WPF app), and DevOps part of desktop app.
I am using the Tweetinvi library to retrieve the tweets easily. I originally tried calling the Tweeter APIs directly from C# and it’s a painful experience. Instead of wasting resources on researching the Tweeter APIs, I change to use Tweetinvi because it allows me to easily get the tweets in just two lines of codes.
To improve the GUI, I use the Material Design in XAML Toolkit. So, I can easily change the WPF application to have dark mode. This is very important to me because I realise light mode isn’t displayed well on the projected screen during the event. So, it now looks as shown in the following screenshot.
New look with Material Design.
By clicking on the “Show Ranking” button at the top-right corner, we can easily tell the scores received by the participants.
The participants are sorted according to the score they receive.
Migrating to .NET Core 3.0
Now with many third-party libraries used in our WPF application, is the desktop app still compatible with .NET Core? Well, to answer this question, there is a tool from Microsoft called Portability Analyzer can give us a detail report on the set of APIs referenced in our apps that are not yet available in NET Core 3.0.
After downloading it and using it to check our application above, we received the following report.
This says that our WPF application is 100% portable to the .NET Core.
The Excel report comes with three tabs, i.e. Portability Summary (the one shown above), Details (empty), and Missing assemblies. There is one item in the report Missing assemblies though, as shown below.
However, if we proceed to use try-convert to migrate our WPF application from .NET Framework to .NET Core, it will be a successful conversion, as shown in the screenshot below.
Converted a .NET Framework project to .NET Core 3.0.
The following screenshot shows how the app looks like after being migrated to .NET Core 3.0. Nothing significant is changed. If you would like to find out what have been changed, please visit the commit of this project on GitHub.
This is a WPF app in .NET Core 3.0.
XAML Islands
There is another thing that I shared in my talk is about XAML Islands. In fact, I talked about XAML Islands in Microsoft Insider Dev Tour too when I was sharing about WinUI.
Microsoft Insider Dev Tour (Image Credit: Microsoft Malaysia – Insider Dev Tour Kuala Lumpur)
XAML Islands is a feature that allows us to host UWP controls in non-UWP desktop applications. The reason of having it is to improve the UX of existing Win32 apps by leveraging UWP controls.
Although the documentation says it is enabled only starting from Windows 10, version 1903. However, if you are using version 1809, XAML Islands feature is also available already, just that not yet stable. So, the best choice is still using version 1903 and above.
In my presentation, since I was using the Windows 10 image hosted on Microsoft Azure VM, the best version I could get is 1809.
You may ask why I am using version 5.1.1 of the Microsoft.Toolkit.Wpf.UI.Controls. On the day of .NET Conf Singapore, the version 6.0 (Preview 9.1) of it is already out. However, when I try to use the library, it threw the exception, as shown in the screenshot below.
Oops, app crashes with Microsoft.Toolkit.Wpf.UI.Controls 6.0 (Preview 9.1).
I could only demonstrated how I used the MapControl in a WPF app with XAML Islands.
Such a beautiful map displayed on WPF app!
Creating Build Pipeline in Azure DevOps
Now, with the codes of our WPF application on GitHub, we can create a Build pipeline for the app on Azure DevOps. This is not a new feature but it is nice to see how we can now build a .NET Core WPF app on Azure DevOps.
Benefits of DevOps (Image Credit: .NET Conf 2019)
There is a template available on Azure DevOps to build .NET Desktop app.
We can apply this template to build .NET Desktop app on Azure DevOps.
However, before we proceed to start the build, we need to make a few changes to it.
Since we will be using dotnet publish later, so the BuildPlatform variable is not necessary and can be removed.
Removing BuildPlatform variable from the pipeline.
Instead, we need to add a new variable called DOTNET_SKIP_FIRST_TIME_EXPERIENCE and set it to true. This is to speed up the build process because by default when we run any .NET Core SDK command on Azure DevOps, it does some caching. However, now we are running this on a hosted build agent, so this caching will never be useful because the agent will be discarded right after the build is completed. Thanks Daniel Jacobson for highlighting this in his video.
Daniel Jacobson (right) explains about Azure DevOps and .NET Core SDK commands. (Image source: YouTube video)
After that, we need to remove all the default steps because we need to start from scratch for .NET Core.
The first step is to install .NET Core SDK 3.0. Remember to state “3.0.x” as the version otherwise if there is a minor update to .NET Core 3.0, we will still be using the outdated one to build.
Step 1: Use .NET Core SDK 3.0
After that, we are going to do dotnet publish.
Starting with .NET Core 2.0, we don’t have to run dotnet restore because it’s run implicitly by all commands that require a restore to occur. Also dotnet publish will build the project, so we do not need to run dotnet build.
Since this is a WPF project, so we have to uncheck the “Publish Web Projects” checkbox, together with the other two checkboxes “Zip Published Projects” and “Add project name to publish path”, as shown in the screenshot below.
Now we proceed to add the next step, which is to publish the artifact. Here we specify $(Build.ArtifactStagingDirectory) as the path of the directory to publish. Then we also specify a user friendly name for the artifact.
Step 3: Publish Pipeline Artifact
Now we can click the “Save & queue” to run this pipeline.
In the published artifact, we will see the following.
Published artifact in our first attempt.
Wow, there are a lot of DLLs! The .exe file alone is only 157KB.
Fortunately, starting from .NET Core 3.0, as long as we specify the following in our csproj file, it will produce a single .exe file.
<PublishSingleFile>true</PublishSingleFile>
However, there is one more thing to take note is that if we miss out the <RuntimeIdentifier>, there will be an error NETSDK1097 which says, “It is not supported to publish an application to a single-file without specifying a RuntimeIdentifier. Please either specify a RuntimeIdentifier or set PublishSingleFile to false.”
<RuntimeIdentifier>win-x86</RuntimeIdentifier>
With this change, when we run the Build pipeline again, we get the following.
Published artifact with <PublishSingleFile>.
We now only have one .exe file but its size has grown from 157KB to 145MB!
WinForms and WPF are now available on VS App Center but still in preview.
So, the artifact generated in Azure DevOps Build pipeline cannot be automatically delivered to VS App Center even after .NET Conf 2019. We now have to do it manually.
Firstly, we need to download the actifact as a zipped file in Azure DevOps.
Secondly, we need to upload the zipped file to the VS App Center in its Releases tab, as shown in the following screenshot.
Setting Build version to 1 because this is our first release of the app.
After keying the release notes, we will be landed on a page to choose who we should distribute the app to. Normally they are our developers, business analysts, and testers. Here, in my example, I only have one group called Collaborator and I am the only one in the group.
We are not allowed to add those who are not in our App Center as testers.
Finally, we will hit the “Distribute” button to release our app to testers. As tester, I will receive the email notifying about the new release.
Yay, new release available for in-house testing.
Analytics with App Center SDK
We can also integrate our WPF desktop app with App Center SDK to further collect data to find out how people use our app as well as the crashes in our app.
To do so, firstly, we need to install the following two Nuget packages. As the support for WPF SDK is still in preview, please remember to check the “Include prerelease” checkbox.
Microsoft.AppCenter.Analytics;
Microsoft.AppCenter.Crashes.
SQLitePLCRaw is being installed when we install the App Center SDK.
Now we can proceed to put the following code in the first window that will be launched in our app. In my case, it is the MainWindow. So, right after the InitializeComponent() is called, the following codes will be executed.
Yup, if you have noticed earlier when we’re installing the App Center SDK, SQLitePCLRaw was being installed also. Just because of the bug in the SDK, this line was not added to the project file and thus we have to manually reference it. Hopefully this bug gets fixed soon.
Now when we launch our WPF app again, the nice dashboard will show there is 1 user. Yay!
+1 active user in our app!
Conclusion
That’s all so far for what I’d like to share in addition to what I have shared in .NET Conf Singapore 2019.
KOSD, or Kopi-O Siew Dai, is a type of Singapore coffee that I enjoy. It is basically a cup of coffee with a little bit of sugar. This series is meant to blog about technical knowledge that I gained while having a small cup of Kopi-O Siew Dai.
Riza’s talking about Containers. Yes, microservices are not containers!
Learning Motivation
In the beginning of Riza’s talk, he mentioned GO-JEK, an Indonesia ride-hailing phone service. Due to their rapid growth, the traditional monolithic architecture can no longer support their business. Hence, they switched to use a modern approach which includes moving apps to containers.
Hence, after the meetup, I was very excited to find out more about micro-services and Docker containers. With the ability of .NET Core to be cross-platform, as a Azure lover, I am interested to find out more how I can deploy ASP .NET Core web app to a container in Azure. So, I decided to write this short article to share with my teammates about this that they can learn while drinking a cup of coffee.
Creating New Project with Docker Support
Since I am trying it out as personal project, I choose to start it with a new ASP .NET Core project. Then in the Visual Studio, I can easily turn it to be a Docker supporting app easily by checking the “Enable Docker Support” option.
Enable Docker Support
For existing web application projects, we will not have the screen above. Luckily, it is still easy to add Docker Support to an existing ASP .NET Core project on Visual Studio.
Enabling Docker Support in existing projects.
Then by clicking on the “F5” button to run the project, I manage to get the following screen (The background is customized by me). The message is displayed using the following line.
Yay, we managed to run the web app inside a Linux container locally.
Publishing to Microsoft Azure with Continuous Delivery
Without Continuous Delivery, we also can easily right-click the web application to publish it to the Container Registry on Azure.
Creating a new Azure Container Registry which will have the Docker image published to.
Then, on Azure Portal, we will see three new resources added. Firstly, we will have the Container Registry.
Then, we will also have an app service site which is running the image downloaded from the Container Registry. Finally, we have an App Service Plan which needs to be at least B1 because free and shared SKUs are not available for apps running on Linux (The official Microsoft documentation says we should have the VM size of the App Service Plan to be S1 or larger though).
Container Registry for my new web app, Changshi.
To enable Continuous Delivery, I choose to use Github + Visual Studio Team Services (VSTS). By doing so, build and release will be automatically started whenever I check in code to Github.
Build history and details on VSTS.
Yup, this is so far what I have tried out in my first step of playing with containers. If you are interested, please check out the references listed below.