.NET - James Montemagno https://staging.montemagno.com/tag/dotnet/ https://staging.montemagno.com/content/images/2017/08/MonogramIcon_Orange_NoBuffer.png .NET - James Montemagno https://staging.montemagno.com/tag/dotnet/ Hugo -- gohugo.io Tue, 13 Oct 2026 20:48:55 GMT 60 Enabling C# 9 in Xamarin & .NET Standard Projects https://staging.montemagno.com/enabling-c-9-in-xamarin-net-standard-projects/ 5fb7f97f36813e0039c2d3b4 Fri, 20 Nov 2020 17:34:13 GMT Whoa! .NET 5 is out and C# 9 is out! This means you are ready to use records, new pattern matching, and more! But wait a second... your apps haven't been upgraded to .NET 5 yet or are a project type that don't support .NET  so you don't have access to the new C# 9 features :( Or do you!?!?!?! Yes, of course you do! Most new features in C# are compiler based and not necessarily runtime based.  When you create a new project the compiler determines a default C# language based on these rules:

Target framework version C# language version default
.NET 5.x C# 9.0
.NET Core 3.x C# 8.0
.NET Core 2.x C# 7.3
.NET Standard 2.1 C# 8.0
.NET Standard 2.0 C# 7.3
.NET Standard 1.x C# 7.3
.NET Framework all C# 7.3

So, if you are using .NET Standard 2.0 (the default for Xamarin.Forms) you only have access to C# 7.3 by default, which is sad. However, you can override the default inside of the .csproj. Simply open it up and add the property group:

<PropertyGroup>
   <LangVersion>preview</LangVersion>
</PropertyGroup>

You can also pick the specific version of C# that you would like:

<PropertyGroup>
   <LangVersion>9.0</LangVersion>
</PropertyGroup>

Now you are ready to start using C# 9 and convert all those classes over to records... almost! I say almost because there is one quirk with enabling C# 9 in non-.NET 5 project and when you use a record you will be granted with a System.Runtime.CompilerServices.IsExternalInit is no defined or imported error.

This can easily be fixed by adding the following code into any file. I like to add it into the AssemblyInfo.cs file:

namespace System.Runtime.CompilerServices
{
    public class IsExternalInit { }
}

There you go! now you can start using all those new fancy features!! Checkout these docs:

]]>
Distributing a .NET Core 3 WPF and WinForms App with MSIX https://staging.montemagno.com/distributing-a-net-core-3-wpf-and-winforms-app-with-msix/ 5c96b087b2f3d500bff4c987 Mon, 08 Apr 2019 17:55:00 GMT

I could not be more excited for .NET Core 3 that will soon power all of your WPF and WinForms apps in addition to ASP.NET Core and .NET Core apps themselves! You may be saying... James... WPF... WinForms... why even bother? Well, because you may have to support some older apps and with the power of .NET Core 3 as the runtime instead of the .NET Framework it means that we no longer have to worry about what version of .NET is installed on the users machine. It means we can deploy a WPF/WinForms app just by running a .exe on any machine, as the runtime is built right in. Checkout all the details here.

I recently had an idea for a new application for my Twitch stream that I could use when I needed to display a countdown timer. I decided that I should give WPF on .NET Core 3 a try and within a few hours, My Stream Timer was born! Watch the streams here and here,

demo

After I finished up most of the app the tough question started to sink in... how do I distribute and do automatic updates to the app. I know that Squirrel is a super popular way of doing it, but I wasn't sure if it supported .NET Core 3. So I tweeted the question out and within a few minutes was sent towards MSIX.

MSIX

What is MSIX? It is a new app packaging format for Windows applications that supports Win32, WPF, and WinForm apps! Better yet, it provides built in download page, certificate support, and most importantly... automatic updates!!! I was blown away when I read this and was determined to figure it out. Throughout the process I learned a lot about MSIX, .NET Core 3, WPF, and distribution. I have to say I AM A FAN! Before we package up an app, let's talk about the pros and cons of MSIX from my understanding:

MSIX Pros

  • Works with any Win32, WPF, or WinForms apps (regardless if it is .NET Core 3)
  • Enables seemless distribution to the Microsoft store
  • Enable Side-Loading with Easy Download & Install Page
  • Automatic App Updates
  • Easily integrates with Continuous Integration
  • Lights up some Windows 10 features like URI launching

MSIX Cons

  • Only supports Windows 10 for "seemless install mode"
  • Requires special tools on Windows 7/8 (MSIX Installer)
  • Requires side-loaded app to be signed with cert (pretty standard, but not ideal for indie dev).
  • Sandboxes app like a UWP app

With this in mind, let's package up our WPF .NET Core 3 app with MSIX!

Install UWP!

That is right! We will need to install UWP as it contains all of the templates for MSIX packaging:

UWP-INSTALL

Windows Application Packaging Project

With UWP installed we can now add in the packaging project. Simply search for package and it will pop up:

AddNew

When it is time to select the UWP platform I would recommend setting the minimum to 1803 and target to 1809.

Select

From what I can tell you can go farther back, but it is a bit more work

Add App Reference

Just like adding a normal reference to a library the package project can take a reference to another app project. This is how it knows what to bundle up:

package

Configure Platforms and Runtime Configurations

Inside of the WPF project there is a bit of work to do to configure it for x86 and x64. This is accomplished with the RuntimeIdentifiers attribute inside of the .csproj. In addition, we will want to setup a few platforms:

  <PropertyGroup>
    <!--Regular Settings-->
    <Platforms>AnyCPU;x64;x86</Platforms>
    <RuntimeIdentifiers>win-x64;win-x86</RuntimeIdentifiers>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
    <PlatformTarget>x64</PlatformTarget>
  </PropertyGroup>

  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'">
    <PlatformTarget>x86</PlatformTarget>
  </PropertyGroup>

Setup App Info

Inside of the new packaging project we will find tons of settings and configurations for the new app. This includes a title, description, icons, capabilities, and a bunch more.

Some additional things that we can setup here are declarations such as a Protocol to support URI routing to the app. Here I will set it up so mystreamtimer: opens the app.

Declarations

Distribute!

With just a few steps we are ready to distribute this app. We have a decision to make though. We can go directly to the Microsoft Store(or Business store), which only supports Windows 10, but handles all of our updates, certs, and store listing page for us. Or, we can distribute it ourselves and leverage an Azure App Service to host the app and automatically ship updates... Let's investigate and setup both! On the package project we can right click and go to Store, which gives us options on how to ship it.

Decide

Microsoft Store

This is actually the easiest part and since I have actually shipped UWP apps in the past the process was nearly identical. The first thing we will want to do is Associate App with the Store. This is a quick process once you have your Windows Dev account open. Then we can Create App Packages and say we want to create a new package for the app we just associated with from the store:

StoreAPp

From here we just need to select our architectures (x86 and x64) and click on Create.

This will re-compile the app, package it up, and give us the app we need to upload to the Microsoft Store. It will also give us a test app and power shell script that we can run to test it locally.

Web Distribution & Sideloading

Now, on to the fun part of shipping our app with MSIX and bypassing the app store all together. This is cool because you can enable automatic updates, there is no review process, and it works! At the end of it you even get a cool website that gives you an install page such as this:

Install-page

Create Sideloading Packages

Instead of creating a package for the store we wil create one for sideloading. One nice feature is the checkbox to enable automatic updates!

SideLoad

Just like the Microsoft Store version we will select x86 and x64 architectures for distribution. If you checked the box for automatic updates there is just a tiny bit more to setup such as where your hosting website or file share lives. AKA where are your storing your files for distribution. Then how often you want to check for updates.

Updates

Setup Backend

At this point you may not have your backend setup, so you will probably want to head over to Azure and setup a simple and cheap web app. It is crazy simple and only takes a few minutes to do so. They have great docs on how to configure everything on Azure. The most important part is setting the MIME types in your Web.config.

Upload Files

With the backend hosting site setup and the app package created we can upload all of the files to the server. This includes:

  • index.html
  • The full output folder for the build
  • appinstaller file

I just used FTP to drag and drop in these files, but you could easily automate this process.

Install the App

Now, we have an awesome website with a big Get the app button that will download the app, install it, and check for updates!

You can test out my test server at https://mystreamtimer.azurewebsites.net/. Since I signed it with my test cert you will need to install it. If you are an enterprise or want to do this for real, you will need to buy a cert from someone like Digicert.

Gotchas

Here are a few things that got me when packaging with MSIX since the app is sandboxed.

  1. Saving files to LocalApplicationData actually saved it in a private location that the user couldn't easily get to. I used CommonApplicationData instead.
  2. Hard to test protocal URLs in WPF... have to parse generic StartupEventArgs.
  3. WPF apps can still run multiple instances, so we need to add a Mutex to stop that.
  4. Still need to sign the app with a cert for side-load deployment

Package Up Those Apps

All in all I was really happy with how this project turned out. You can browse the full source code on GitHub and download it from the Microsoft Store today!

]]>
Introducing My Stream Timer: A Countdown Timer for OBS https://staging.montemagno.com/introducing-my-stream-timer-a-countdown-timer-for-obs/ 5ca1b6eab2f3d500bff4c99d Thu, 04 Apr 2019 20:55:00 GMT

I have been streaming on Twitch for over 6 months now. I stream both code on my personal Twitch channel and I also stream games and recordings of Nintendo Dispatch with my buddy Michael over on the official Dispatch Twitch channel. One thing that always bothered me was having to manually mess around with apps to get a simple countdown timer. They were too complex, had too many options, and had a bunch of quirks. So, I decided to build my own, which is out today on Windows 10 called My Stream Timer.

PrettyStreamTimer

My Stream Timer is an elegant and simple to use timer that can be used to count up, down, or do giveaways. It also:

  • Integrates into OBS/SLOBS by writing to disk
  • Intuitive user interface
  • Ability to add more time
  • Can be automated to use with Stream Deck

Countdown Simplified

I wanted to make this app really easy to use. There are only a few tabs that do only one thing. Count up or down. You can set just a few properties:

  • How you want the output to display
  • What you want it to say when it is finished
  • Auto start when you open app
  • File name to output
  • Start, Add Minute, or Reset

When you start a timer the app will start to update and output the results to disk so you can integrate it into OBS/SLOBS:

demo--2-

Optimized for Stream Deck

You can integrate a Open command under System to launch My Stream Timer and start a countdown from a specific amount of time. You don't need to browse for a file location at all as you can input a protocol url:

Format: mystreamtimer://countdown/?mins=6

With this simple command it will launch My Stream Timer and start a countdown from 6 minutes!

In Action

Get It Today

My Stream Timer is available today for free from the Microsoft Store. It is also completely open source on GitHub.

]]>
Multi-Targeting: Where Did My Files Go? Fixing .NET Core 2.1 SDK Issues https://staging.montemagno.com/multi-targeting-where-did-my-files-go-fixing-net-core-2-1-sdk-issues/ 5b7ade4acce53300bfd41234 Tue, 21 Aug 2018 20:45:00 GMT I love multi-targeting for creating libraries, and it is at the core of all of my plugins and Xamarin.Essentials. If you don't know what multi-targeting is don't worry as it is pretty rare that you would need to use it if you are creating apps. Most likely you will want to use multi-targeting in creating cross-platform libraries. In the past you would have to create multiple libraries for each target framework (such as iOS or Android) that you wanted to support if there was platform specific code. With the new SDK style projects you can set the TargetFrameworks property and specify as many as you would like.

Here is Xamarin.Essentials that supports iOS, Android, UWP, and .NET Standard 1.0/2.0:

<TargetFrameworks>netstandard1.0;netstandard2.0;Xamarin.iOS10;MonoAndroid71;MonoAndroid80;MonoAndroid81;uap10.0.16299</TargetFrameworks>

What is amazing is that all of your files can live together and can be conditionally compiled so only certain files get compiled for a specific platform:

<ItemGroup>
    <Compile Include="**\*.shared.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('netstandard')) ">
    <Compile Include="**\*.netstandard.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('uap10.0')) ">
    <Compile Include="**\*.uwp.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('MonoAndroid')) ">
    <Compile Include="**\*.android.cs" />
</ItemGroup>
<ItemGroup Condition=" $(TargetFramework.StartsWith('Xamarin.iOS')) ">
    <Compile Include="**\*.ios.cs" />
</ItemGroup>

This allows super beautiful project structures:

Capture

It also means that you can conditionally compile your code too:

#if NETSTANDARD1_0
    // do something for .net standard 1.0
#elif __ANDROID__
    // else for Android
#else
    // anything else.
#endif

This all works thanks to Oren Novotny's amazing library MSBuild SDK Extras, which is easily configured by adding a nuget to all projects and adding a single import at the bottom of your csproj:

<ItemGroup>
    <PackageReference Include="MSBuild.Sdk.Extras" Version="1.6.47" PrivateAssets="All" />
    <Compile Include="**\*.shared.cs" />
</ItemGroup>
<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />

Enter .NET Core SDK 2.1

Since this is sort of "unofficial" special tooling magic, sometimes things can break and recently when I installed .NET Core SDK 2.1 all my files went missing for iOS/Android/UWP. If we toggle on "show all files" they are totally there and get compiled but now intellisense stops working:

Missing

We reported it and worked with the .NET team on how to resolve it.

Fix 1: Include Workaround

The work around from the .NET team was to add an additional include at the bottom of our csproj that basically includes any .cs files and excludes defaults.

<ItemGroup>
    <PackageReference Include="MSBuild.Sdk.Extras" Version="1.6.47" PrivateAssets="All" />
    <Compile Include="**\*.shared.cs" />
</ItemGroup>
<ItemGroup>
    <None Include="**\*.cs" Exclude="$(DefaultItemExcludes);$(DefaultExcludesInProjectFolder)" />
</ItemGroup>
<Import Project="$(MSBuildSDKExtrasTargets)" Condition="Exists('$(MSBuildSDKExtrasTargets)')" />

Fix 2: Update to 1.6.47 of Sdk Extras & Project Type

I work extremely closely with Oren and whenever something happens with Essentials I freak out :) So when we had Fix 1 in place and working the next natural thing was to roll it into the official NuGet! Last week Oren did just this!

The only thing here is that we will want to ensure we upgrade to his new project type instead of using the PackageReference and Import. He outlines it great in his documentation.

In short instead of adding any nugets or imports we will replace:

<Project Sdk="Microsoft.NET.Sdk" ToolsVersion="15.0">

with

<Project Sdk="MSBuild.Sdk.Extras/1.6.47">

Of course if you are using other types of files you may need to go back to Fix 1 to add them in manually, but his system is very smart. Be sure to report any bugs over to Oren on his GitHub repo.

]]>
Installing a PCL into netstandard Libraries (Plugins & Xamarin.Forms) https://staging.montemagno.com/installing-a-pcl-into-netstandard-libraries/ 598df8f2c121b60019bf2fea Mon, 08 Aug 2016 21:54:48 GMT Last week we announced that Xamarin projects now support netstandard libraries, which is awesome! I made a short video on how to get started and upgrade a PCL to a netstandard library that any application could consume. The first question I got was if I could install Xamarin.Forms into a netstandard library, and I quickly said I don’t think so, because when I tried Visual Studio and NuGet got all mad at me.

This is because I didn’t read the documentation about the super hidden and fancy imports flag in the project.json that allows you to install PCLs into a netstandard library.

After your upgrade a PCL to netstandard you will get a project.json such as this:

VS 2015

{
  "supports": {},
  "dependencies": {
    "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
    "NETStandard.Library": "1.6.0"
  },
  "frameworks": {
    "netstandard1.4": {}
  }
}

Now, all we need to do is add a special “imports” flag and the PCLs we would like to consume under the netstandard profile

{
  "supports": {},
  "dependencies": {
    "Microsoft.NETCore.Portable.Compatibility": "1.0.1",
    "NETStandard.Library": "1.6.0"
  },
  "frameworks": {
    "netstandard1.4": {
      "imports": [
        "portable-net45+wp80+win8+wpa81"
      ]
    }
  }
}

See the difference? That little imports flag essentially tells NuGet that this package will totally work with PCLs that support this. Now you should be good to go to install any PCL NuGet that you would like.

Now, I will say that this does seem to modify around the project a bit and the properties make it look like it is a PCL again, but it isn’t. It is all pretty new and interested in the netstandard world. I’m not going to run around and change everything from a PCL just yet, but I feel like we are getting closer!

Visual Studio 2017 Update

Now in 2017 you have a new .NET Standard project is way easier. First install the Microsoft.NETCore.Portable.Compatibility NuGet… simply edit your .csproj and you will see:

aka add the $(PackageTargetFallback);portable-win+net45+wp8+win81+wpa8 to your PropertyTargets

]]>