.NET Standard - James Montemagno https://staging.montemagno.com/tag/net-standard/ https://staging.montemagno.com/content/images/2017/08/MonogramIcon_Orange_NoBuffer.png .NET Standard - James Montemagno https://staging.montemagno.com/tag/net-standard/ 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:

]]>
Use C# 8 In Any .NET Project Today https://staging.montemagno.com/use-csharp-8-everywehre/ 5dc6fee984e2c7003870dfab Mon, 11 Nov 2019 18:34:00 GMT C# 8 was officially released in September at .NET Conf along side .NET Core 3 & Visual Studio 16.3 (8.3 on Mac). It is packed with tons of amazing new features that truly everyone should be using. However, there is a lot of confusing as to if you can actually use C# 8 if you aren't using .NET Core 3 or .NET Standard 2.1.

  • Short answer: YES! You can use it today.
  • Long answer: YES! You just have to turn it on and perhaps add a NuGet package or two for certain features.

When you create a new app or library there is a "default" version of C# that is used. .NET Core 3 and .NET Standard 2.1 both use 8.0, but everything else basically defaults to 7.3. If you are like me, this is an issue because I use .NET Standard 2.0, which defaults to 7.3 :(. Don't worry though because if you are building on Visual Studio 2019 16.3 (or 8.3 on Mac) it includes the C# 8 compiler, which means you can use C# 8. If it compiles it should just work.

So, just go into your csproj where you want to use C# 8 and change the LangVersion to 8.0:

<LangVersion>8.0</LangVersion>

Here is what my .NET Standard Library looks like for my Xamarin.Forms apps:

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

  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <ProduceReferenceAssembly>true</ProduceReferenceAssembly>
    <LangVersion>8.0</LangVersion>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Xamarin.Forms" Version="4.3.0.947036" />
    <PackageReference Include="Xamarin.Essentials" Version="1.3.1" />
  </ItemGroup>
</Project>

All Types Not Included

Nearly all of the C# 8 features are just syntax that can be compiled, but there are a few new types such as IAsyncEnumerable. Don't worry though as you can just install a NuGet package to get this new type similar to how we brought in ValueTuple in the past.

A Few Limitations

There are actually a few limitation to using C# 8 in non-.NET Core 3/.NET Standard 2.1 projects. A few of the features such and indexes & ranges are runtime features, which means they will not be available. That is alright though because if you try to use them, they wont compile! If you need them then you will actually need to upgrade, however there are very few limitations.

Xamarin & C# 8

One last thing that I should mention is that Xamarin apps already support all C# 8 features as of Visual Studio 16.3. This means if you turn on C# 8 in a Xamarin iOS or Android projects all of the features should be available to you. In a future update the default will be updated to 8.0 so you won't have to worry about this.

Listen

If you need more reasons to upgrade to C# 8, then listen to last week's Merge Conflict. Frank and I talked about all of our favorite features of C# 8 that you need right now.

]]>
Add ASP.NET Core's Dependency Injection into Xamarin Apps with HostBuilder https://staging.montemagno.com/add-asp-net-cores-dependency-injection-into-xamarin-apps-with-hostbuilder/ 5cc7df16b2f3d500bff4c9d0 Tue, 18 Jun 2019 21:53:00 GMT

Dependency injection(DI) and inversion of control (IoC), have been a recurring theme in questions that I have received over the last six years. Sometimes it is around using constructor injection(), simple service containers, and often around full frameworks such as Prism or MVVM Light. I will be honest with you, I have never been a fan of DI/IoC when building mobile apps. My main reason is that there has never been any official pattern or recommendations from Google or Apple (or Microsoft/Xamarin) when building Android and iOS apps. Also, I have always been worried around startup performance in my apps and didn't want to introduce another dependency. However, it is 2019 and I think that my concerns have finally been resolved after talking with my friend Glenn Condron, and here is why:

  1. There is a new official library from Microsoft that handles everything for you.
  2. Using this model gives you other powerful features like logging, HTTPClientFactory, and more.
  3. These devices are crazy powerful and the frameworks we use such as Xamarin.Forms, have really matured.

So, what is this magical library? It is the Microsoft.Extensions framework, but specifically the Generic Host framework that lives inside of Microsoft.Extensions.Hosting. It is a platform independent implementation of ASP.NET Core's extensibility framework.

Microsoft.Extenions

The cool part about this library is that if you already have been building ASP.NET Core applications, then you already know exactly how to use the library. Additionally, it means that just about every other library that extends it works with your Xamarin apps like app configuration, logging, HTTPClientFactory, Polly, and more! Let's start with the basics and first setup a HostBuild, which is the base for the Extensions library and then setup some dependency injection with constructor injection.

Installation and Setup

The first thing to do is to install the v3 pre-release Micosoft.Extensions.Hosting NuGet into all of our projects. This will give our projects access to the base foundation and also includes the ability to use the built-in logging framework and application configuration via a json file.

With the library installed we will create two files in our shared code (also if you are building a single iOS/Android app this will also work):

Startup.cs

Will host all of our HostBuilder configuration and setup all of the dependencies in our application. Here is the base foundation for the file with all of the using statements we will need:

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Xamarin.Essentials;

namespace MyApp
{
    public static class Startup
    {
        public static IServiceProvider ServiceProvider { get; set; }
        public static void Init()
        {

        }

        static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
        {

        }
    }
}

appsettings.json

This file will need to be set as an EmbeddedResource and will host configuration properties and settings. Here is a generic default appsettings file:

{
  "Hello": "World",
  "Environment": "Development",
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}

Host Builder setup

The extensions library has a few main concepts to understand:

  1. HostBuilder: Acts as a builder for adding services (logging, app config, etc.) onto the app.
  2. IServiceProvider: Handles all dependency injection & acts as a service locator and comes from the HostBuilder.

Our Init method must be called from either the main Xamarin.Forms or platform specific app startup. We will fill in the Init method by getting a stream to the app settings file so the HostBuilder can read it, configure services, and setup the built in logging service:

var a = Assembly.GetExecutingAssembly();
using var stream = a.GetManifestResourceStream("MyAssemblyName.appsettings.json");

var host = new HostBuilder()
            .ConfigureHostConfiguration(c =>
            {
                // Tell the host configuration where to file the file (this is required for Xamarin apps)
                c.AddCommandLine(new string[] { $"ContentRoot={FileSystem.AppDataDirectory}" });

                //read in the configuration file!
                c.AddJsonStream(stream);
            })
            .ConfigureServices((c, x) =>
            {
                // Configure our local services and access the host configuration
                ConfigureServices(c, x);
            })
            .ConfigureLogging(l => l.AddConsole(o =>
            {
                //setup a console logger and disable colors since they don't have any colors in VS
                o.DisableColors = true;
            }))
            .Build();

//Save our service provider so we can use it later.
ServiceProvider = host.Services;

Configure Dependencies

We have setup our HostBuilder and called ConfigureServices, but we haven't done anything yet. So let's do it!

Let's say we have the following code for a ViewModel and a service that it needs to use:

public interface IDataService
{
    void DoStuff();
}

public class MyDataService : IDataService
{
    // We need access to the ILogger from Microsoft.Extensions so pass it into the constructor
    ILogger<MyDataService> logger;
    public MyDataService(ILogger<MyDataService> logger)
    {
        this.logger = logger;
    }

    public void DoStuff()
    {
        logger.LogCritical("You just called DoStuff from MyDataService");
    }
}

public class MockDataService : IDataService
{
    // We need access to the ILogger from Microsoft.Extensions so pass it into the constructor
    ILogger<MyDataService> logger;
    public MockDataService(ILogger<MyDataService> logger)
    {
        this.logger = logger;
    }

    public void DoStuff()
    {
        logger.LogCritical("You just called DoStuff from MockDataService");
    }
}

public class MyViewModel
{
    IDataService dataService;
    public MyViewModel(IDataService dataService)
    {
        this.dataService = dataService;
    }

    public void DoIt()
    {
        dataService.DoStuff();
    }
}

Here we have a ViewModel that needs access to the IDataService and one of the implementations needs access to a ILogger. This is where the ServiceCollection comes in allowing us to configure all of our dependencies. Let's setup the ConfigureServices method in the Startup.cs again and configure these new classes.

static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
    // The HostingEnvironment comes from the appsetting.json and could be optionally used to configure the mock service
    if (ctx.HostingEnvironment.IsDevelopment())
    {
        // add as a singleton so only one ever will be created.
        services.AddSingleton<IDataService, MockDataService>();
    }
    else
    {
        services.AddSingleton<IDataService, MyDataService>();
    }

    // add the ViewModel, but as a Transient, which means it will create a new one each time.
    services.AddTransient<MyViewModel>();

    //Another thing we can do is access variables from that json file
     var world = ctx.Configuration["Hello"];
}

HostingEnvironment

Access Dependencies

With our HostBuilder and dependencies configured, we can now access them from anywhere. Since we only went up to the ViewModel level we will need to grab it from the ServiceProvider in the code behind from our page:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
        BindingContext = Startup.ServiceProvider.GetService<MyViewModel>();
    }

    protected override void OnAppearing()
    {
        base.OnAppearing();
        ((MyViewModel)BindingContect).DoIt();
    }
}

When we call GetService the Microsoft.Extensions framework will handle creating and injecting any dependencies including our IDataService and the ILogger that came for free just by using the library. When we call DoIt in the OnAppering our app ill print out a message to the console using the logger that will have info of what data service it was using.

HTTPClientFactory In Your Xamarin App!

That's right, if you are using Microsoft.Extensions you can use the awesome HTTPClientFactory class that is essentially HTTPClient done right! It handles caching, retries, logging, and all other sorts of awesome! It is really easy to put into your app with just a few lines of code.

First, we will need to install the v3 prerelease Microsoft.Extensions.Http NuGet to get access to HTTPClientFactory. Then in the ConfigureServices method add the following line of code:

services.AddHttpClient();

With this single line of code in place it is now time to get access to the HTTPClientFactory from one of our classes. This is handled like our interface that was passed in as a parameter to the constructor. Microsoft.Extensions takes care of everything for you:

public class MyDataService : IDataService
{
    ILogger<MyDataService> logger;
    HttpClient client;
    public MyDataService(ILogger<MyDataService> logger, IHttpClientFactory httpClientFactory)
    {
        this.logger = logger;
        client = httpClientFactory.CreateClient();
    }

    public void DoStuff()
    {
        logger.LogCritical("You just called DoStuff from MyDataService");
    }
}

If you don't need access to the IHttpClientFactory at all this code can be simplified down to just passing in the HttpClient itself:

ILogger<MyDataService> logger;
HttpClient client;
public MyDataService(ILogger<MyDataService> logger, HttpClient client)
{
    this.logger = logger;
    this.client = client;
}

What is cool now is that when you make any calls with this HttpClient you will automatically get console logging, which is super helpful:

Response

To top it off you can even extend the HttpClient beyond just logging and introduce Polly into the mix with the Microsoft.Extenions.Http.Polly library that will enable you to automatically setup retries and other really cool features. You can find an example of this in my "First App Example" with ASP.NET Core + Xamarin

Platform Specific Dependencies

At this point you are probably like WOW, this is amazing, but what about platform specific implementations that I may need to get access to. Do not fear because it is totally possible and pretty easy to setup. Instead of calling the Init from your shared code, you can call it from your iOS/Android project and pass in a configuration Action like this:

First, let's modify the Init:

public static App Init(Action<HostBuilderContext, IServiceCollection> nativeConfigureServices)
{
    // Resource code

    var host = new HostBuilder()
                    //ConfigureHostConfiguration
                    .ConfigureServices((c, x) =>
                    {
                        //Add this line to call back into your native code
                        nativeConfigureServices(c, x);
                        ConfigureServices(c, x);
                    })
                    // Logging
                    .Build();
}

Then from inside of the Android project's MainActivity and iOS project's AppDelegate you can call this Init method:

Android Example

public class MainActivity : FormsAppCompatActivity
{
    protected override void OnCreate(Bundle savedInstanceState)
    {
        TabLayoutResource = Resource.Layout.Tabbar;
        ToolbarResource = Resource.Layout.Toolbar;

        base.OnCreate(savedInstanceState);

        //setup code

        Startup.Init(ConfigureServices);
        LoadApplication(new App());
    }

    void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
    {
        services.AddSingleton<INativeCalls, NativeCalls>();
    }
}

public class NativeCalls : INativeCalls
{
    public void OpenToast(string text)
    {
        Toast.MakeText(Application.Context, text, ToastLength.Long).Show();
    }
}

iOS Example

[Register("AppDelegate")]
public partial class AppDelegate : FormsApplicationDelegate
{
    public override bool FinishedLaunching(UIApplication app, NSDictionary options)
    {
        //Init Code:

        Startup.Init(ConfigureServices)

        LoadApplication(new App();

        return base.FinishedLaunching(app, options);
    }

    void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
    {
        services.AddSingleton<INativeCalls, NativeCalls>();
    }
}

public class NativeCalls : INativeCalls
{
    public void OpenToast(string text)
    {
        var vc = UIApplication.SharedApplication.KeyWindow.RootViewController;
        var okAlert = UIAlertController.Create(string.Empty, text, UIAlertControllerStyle.Alert);
        okAlert.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
        vc.PresentViewController(okAlert, true, null);
    }
}

Inject The Entire App

As you can see this framework is extremely flexible and allows for optimal extensibility, but you can go even further. As I was trying out this API Glenn challenged me to see how far I could take this dependency/constructor injection madness... so I took it all the way up to the app level. That is right, I injected the entire app, pages, and view models.... because why not! Well maybe you shouldn't do this, but it is pretty cool.

Keeping the same dependencies and view models from above all we need to do is update our MainPage, App, and Init calls:

MainPage

public partial class MainPage : ContentPage
{
    //simply pass in the view model you desire!
    public MainPage(MyViewModel viewModel = null)
    {
        InitializeComponent();
        BindingContext = viewModel;
    }
}

App

There are a few ways to do this. You could pass in the page that you desire into the App constructor or you could have some logic and grab it from the ServiceProvider:

public App()
{
    InitializeComponent();
    MainPage = ServiceProvider.GetService<MainPage>();
}

Update Init

This is where it gets pretty cool, we will create Transient and Singletons of all of the services, view models, pages, and the app itself and have the method return the App intead of being a void method.

public static App Init(Action<HostBuilderContext, IServiceCollection> nativeConfigureServices)
{
    //all of the same code from before
    return ServiceProvider.GetService<App>();
}

static void ConfigureServices(HostBuilderContext ctx, IServiceCollection services)
{
    services.AddHttpClient();
    services.AddSingleton<IDataService, MyDataService>();
    services.AddTransient<MyViewModel>();
    services.AddTransient<MainPage>();
    services.AddSingleton<App>();
}

Then, call Init from the LoadApplication method instead of calling Init randomly in the iOS/Android project:

LoadApplication(Startup.Init(ConfigureServices));

Just like that we dependency injected our entire application and that is crazy! If you want to try it yourself, you can grab my sample project from GitHub that shows off just about everything in this blog post.

Required Versions of Xamarin/VS

As of today, you should be able to develop and debug iOS/Android apps with all these goodies using any version of Visual Studio 2019 or Visual Studio for Mac 2019. However, if you want to use ship your app and turn on the Linker you will need to have a newer version of mono, which ships with Visual Studio 2019 16.2 (preview 2) and Visual Studio for Mac 2019 8.2 (preview). If you are on Windows you can easily install VS 2019 Preview side by side the normal release.

Watch The Build Session

I had the honor of presenting how ASP.NET and Xamarin can come closer in app model with Glenn in a 20 minute theater session. It is available on the Xamarin Developers YouTube channel:

Learn More

This stuff is super fun and I really hope that it takes off and we can encorporate it into user testing, and perhaps one day into the official templates! Until then it is easy to setup and can lead to some really clean and powerful code. Be sure to read through all of the great docs for Generic Host and through any of the extensions documentation. Enjoy!

]]>
Optimizing Xamarin Apps & Libraries with the Linker https://staging.montemagno.com/optimizing-xamarin-apps-libraries-with-the-linker/ 5b398519a4b3dd00bfb1cdad Thu, 13 Jun 2019 20:30:00 GMT The Xamarin linker is one of the most important pieces of technology when building mobile apps, that no one knows exists. It does all of the hard work for you, stripping out all unused code from libraries that you include in your apps. It should only be used in release mode as it takes extra time to compile your app, but means that your app will be smaller:

Capture

The linker has specific implementations for both iOS and Android and is completely customizable.

Linking for App Developers

Before I get to how to optimize libraries, let me go through when the linker actually kicks in and how app developers use it.

For the large majority of developers, all you need to know is turn on Link SDK Assemblies Only when your app is in Release (it is the default). This will only look to link and remove libraries that ship with Xamarin.iOS and Xamarin.Android. The other option is Link All Assemblies, which will look at every assembly and library that your app uses and attempt to link them. I always recommend Link SDK Assemblies Only as it is the safest and easiest to understand. The difference between the two in terms of application size is usually minimal and often when linking everything you can get in trouble as the linker can be aggressive and will remove more than needed, especially if you use reflection.

The linker is pretty customizable and you can tell it to ignore specific libraries in the project settings. For instance if you are building an app with Xamarin.Forms you probably want to leave all of Xamarin.Forms in there so you could add some flags to iOS and Android:

// iOS
 <MtouchExtraArgs>--linkskip=Xamarin.Forms.Platform.iOS --linkskip=Xamarin.Forms.Platform --linkskip=Xamarin.Forms.Core --linkskip=Xamarin.Forms.Xaml --linkskip=Samples</MtouchExtraArgs>

// Android
<AndroidLinkSkip>Xamarin.Forms.Platform.Android;Xamarin.Forms.Platform;Xamarin.Forms.Core;Xamarin.Forms.Xaml;Samples;FormsViewGroup;</AndroidLinkSkip>

You can learn more about this on the iOS and Android documentation.

Linking for Library Creators

For library creators it is super important to understand how the linker works, and how you can optimize your libraries for app developers. You never know when a developer may flip on Link All Assemblies or when the linker may get aggressive and link away some of your library.

Preserve Everything

There are instances where you are creating a library and always want to ensure that NOTHING is ever removed regardless of the linker setting. The [Preserve (AllMembers = true)] can be added to any class in your iOS or Android library and then the linker will ignore that class. I like to always test my library in Link ALL Assemblies mode and if something goes wrong and gets removed then I slap this on the class.

Linker Safe

Sometimes it is really important that unused code in your library is properly removed. This is where the [assembly:LinkerSafe] attribute comes in to inform the linker to include this library in ALL linking modes. This is cool because you are telling the linker that you have done the work to test your library and want it to be treated as if it was part of Xamarin.iOS or Xamarin.Android.

A great example of this is Xamarin.Essentials which is completely optimized with this property. It means that if you only use the Compass then that will be the ONLY chunk of code that is included in the app. This library was built and structured with the linker in mind with very little overlapping code, and each feature is implemented in it's own class.

When I started to look at my other cross-platform libraries I noticed that the PermissionsPlugin was starting to cause people some submission issues on iOS. This was because the library itself checks all sorts of different permissions and since I didn't optimize it for the linker, Apple was detecting usage of the APIs and started to require the info.plist to add permissions that weren't actually being used.

So, I turned on the [assembly:LinkerSafe] and thought everything was going to be fine... until I packaged up an app, extracted the dll from the final package and put it into dotPeek on Windows and found out that NOTHING was getting linked out:

AllItems

This fuzzy photo (sorry about that) shows that even though my code was only requesting one permission, all of the code was still there. Well, let's look at the code:

public async Task<Dictionary<Permission, PermissionStatus>> RequestPermissionsAsync(params Permission[] permissions)
{
    var results = new Dictionary<Permission, PermissionStatus>();
    foreach (var permission in permissions)
    {
        if (results.ContainsKey(permission))
            continue;

        switch (permission)
        {
            case Permission.Calendar:
                results.Add(permission, await RequestEventPermission(EKEntityType.Event));
                break;
            case Permission.Camera:
                results.Add(permission, await RequestAVPermissionStatusAsync(AVMediaType.Video));
                break;
            case Permission.Contacts:
                results.Add(permission, await RequestContactsPermission());
                break;
            case Permission.LocationWhenInUse:
            case Permission.LocationAlways:
            case Permission.Location:
                results.Add(permission, await RequestLocationPermission(permission));
                break;
            case Permission.MediaLibrary:
                results.Add(permission, await RequestMediaLibraryPermission());
                break;
            case Permission.Microphone:
                results.Add(permission, await RequestAVPermissionStatusAsync(AVMediaType.Audio));
                break;
            case Permission.Photos:
                results.Add(permission, await RequestPhotosPermission());
                break;
            case Permission.Reminders:
                results.Add(permission, await RequestEventPermission(EKEntityType.Reminder));
                break;
            case Permission.Sensors:
                results.Add(permission, await RequestSensorsPermission());
                break;
            case Permission.Speech:
                results.Add(permission, await RequestSpeechPermission());
                break;
        }

        if (!results.ContainsKey(permission))
            results.Add(permission, PermissionStatus.Granted);
    }

    return results;
}

At first, you are probably thinking like me that the linker obviously knows what Permission my app is passing in, so it would remove any case that wasn't being used. Nope, that linker is smart, but not that smart. If I call this method at all, the linker will include any method that is being used inside of it. This means that I would need to re-structure the entire library to make it linker safe. James Clancey came up with the amazing idea of breaking the mega method into smaller individual classes that compartmentalized functionality.

This is where the BasePermission came in:

public class BasePermission
{
    protected Permission permission;
    public BasePermission(Permission permission)
    {
        this.permission = permission;
    }

    public virtual Task<PermissionStatus> CheckPermissionStatusAsync() =>
#if __IOS__
        throw new NotImplementedException();
#else
        CrossPermissions.Current.CheckPermissionStatusAsync(permission);
#endif

    public virtual async Task<PermissionStatus> RequestPermissionAsync()
    {
#if __IOS__
        throw new NotImplementedException();
#else
        var results = await CrossPermissions.Current.RequestPermissionsAsync(permission);
        if (results.ContainsKey(permission))
            return results[permission];

        return PermissionStatus.Unknown;
#endif
    }
}

The code looks a little funny, but it has two virtual methods that on iOS have no implementation at all and must be implemented in a parent class. This means that when the linker sees the BasePermission on iOS it wont have any implementation and will get removed. Now, all I needed to do is create classes for each of the permissions such as this:

public class CameraPermission : BasePermission
{
    public CameraPermission() : base(Permission.Camera)
    {

    }
#if __IOS__
    public override Task<PermissionStatus> CheckPermissionStatusAsync() =>
        Task.FromResult(PermissionsImplementation.GetAVPermissionStatus(AVFoundation.AVMediaType.Video));

    public override Task<PermissionStatus> RequestPermissionAsync() =>
        PermissionsImplementation.RequestAVPermissionStatusAsync(AVFoundation.AVMediaType.Video);
#endif
}

public class ContactsPermission : BasePermission
{
    public ContactsPermission() : base(Permission.Contacts)
    {

    }
#if __IOS__
    public override Task<PermissionStatus> CheckPermissionStatusAsync() =>
        Task.FromResult(PermissionsImplementation.ContactsPermissionStatus);

    public override Task<PermissionStatus> RequestPermissionAsync() =>
        PermissionsImplementation.RequestContactsPermission();
#endif
}

On iOS you can see that I am calling into specific implementations for each permission check and request. This now means that even though the library contains 15 different permission classes if the calling app only uses 1 of them then it will be the only code that is included and there will be no more issues with app store submissions!

Some

The linker is pretty complex, but pretty awesome when you figure out how to optimize for it. If you are a library creator I encourage you to flip on this flag for your iOS and Android projects and give it a test drive. This will ensure that you always know if your library will work regardless of any linker setting.

Be sure to read through all the documentation I linked to and also check out [Jon Douglas' blog]9https://www.jon-douglas.com/2017/09/22/linker-analyzer/) on using the linker analyzer for Android. You can also watch me struggle on my live stream from a month back where I figured out all of this.

]]>
Super Simple Git Tagging & Releases in Azure DevOps https://staging.montemagno.com/super-simple-git-tagging-releases-in-azure-devops/ 5c13e3d958056200bf4c25ae Mon, 21 Jan 2019 16:30:00 GMT I am going to be honest with all of you, I never really understood Git tags and releases inside of GitHub. In my old TFVC days I would just create a branch with the name of the release and call that my "tag" so I could always go back to it. What sparked my interest was seeing a bunch of popular projects that I was using combine tags with the GitHub releases. I started reading the documentation and still wasn't sold on it because I have a full CI/CD pipeline setup for all of my projects and I wasn't sure how this would fit in. Then the lightbulb went off when I saw Jon Dick implement an amazing tagging scheme that would fire off a build, compile a NuGet, and then release the artifacts to NuGet automatatically...

mindblown

Even though this was the coolest thing ever I didn't want to go changing all of my pipelines, but it did encourage me stop doing random branches for releases and streamline my tagging and releases when publishing NuGets. This is surprisingly easy to do with the new GitHub Release task. It is a very nice extension that allows you to create a tag, or re-use a tag, add a changelog file, specify release name, add artifacts, and a bunch more.

In my continuous delivery pipeline I have the following workflow:

Pipeline

My strategy here is to ensure that when I go to NuGet (beta) I create a pre-release tag and release and then when I go to full production I simply update that existing release/tag with updated information.

Uploading a Changelog

Traditionally I never uploaded anything to the drop folder except for the NuGet packages, but a nice thing with the the release task is that you can attach a changelog file (or manually enter it). Since I have a changelog file checked in to each of my repositories that I regularly update, I can just add it to the drop folder in my CI pipeline. In the Copy Files task I simply added:

**\bin\$(BuildConfiguration)\**
**\CHANGELOG.md

Adding a Pre-Release Tag & Release

After I release my pre-release package to NuGet, I want to create my very first Tag and Release. First step is to simply add the GitHub Release task:

Task

Now, it is time to fill in the information for the tag and release:

  • Select GitHub connection
  • Select GitHub repository
  • Action: Create
  • Target: $(Build.SourceVersion)
  • Tag Source: User Specified Tag (if you want to you can have it use an existing tag)
  • Tag: v$(Build.BuildNumber)
  • Release Title: v$(Build.BuildNumber)
  • Release note source: Release notes file
  • Release notes file path: $(System.DefaultWorkingDirectory)/**/CHANGELOG.md
  • Assets:
$(System.DefaultWorkingDirectory)/**/drop/beta-public/*.nupkg
  • Options: Pre-release & Add changelog

Editing a Release

Now, when I go into my final phase to publish my packages to stable on NuGet I want to modify the release I just created. You could optionally create a new release and different tag, but this makes no sense to me currently (leave comments below to let me know what you think).

You can simply add the same exact Task and instead of specifying Create for the Action specify Edit. You will fill in all of the same information except at the end:

  • Assets: Instead of beta-public folder, I change it to public
  • Replace existing assets
  • Uncheck pre-release

And just like that you will have beautiful releases automatically when you publich to NuGet in pre-release or stable:

Capture

]]>
Real Time Communication for Mobile with SignalR (Core) https://staging.montemagno.com/real-time-communication-for-mobile-with-signalr/ 5bdf571ff3421000bf604cfb Mon, 12 Nov 2018 20:30:00 GMT

Real Time Communication or RTC as the cool kids call it has always been a hot topic, especially for mobile. In normal mobile development when we wanted to get updates of data we would make a web request to a server, pull down data, and update our user interface. If you wanted to get bits of data on demand and in real time you would have to integrate WebSockets or some sort of push notifications to receive data as it is happening. However, it doesn't have to be anymore with the latest version of SignalR (ASP.NET Core SignalR) which is fully compatible with .NET Standard 2.0 for ASP.NET, UWP, WPF, WinForms, and Xamarin!

download

I have been pretty obsessed with trying to learn SignalR so I started doing a weekly Twitch Stream every Saturday where I am building an app with it. You can find the latest streams on YouTube where I build the server backend and then integrate into a mobile app. In this blog I will walk you through the basics to do it all locally only on your machine.

Why SignalR (Core)

SignalR has been around for a long time and yes technically did work with Xamarin after a bunch of work. Now, with ASP.NET Core SignalR as they call it, everything has been simplified into a few simple packages for your backend server and client apps. At the center of SignalR is a "Hub" that handles incoming and outgoing messages. A client sends a message to the Hub and the Hub distributes the message to all clients that are connected:

signalr-diagram

SignalR handles all of the complex stuff for you:

  • Handles connection management automatically.
  • Sends messages to all connected clients simultaneously. For example, a chat room.
  • Sends messages to specific clients or groups of clients.
  • Scales to handle increasing traffic.
  • Supports WebSocketss, Server-Sent Events, & Long Polling and figures out which to use automatically.

Here is the introduction documentation to browse through.

Hub Backend

The code is extremely simple for the ASP.NET Core backend web application. The SignalR server library is already part of an ASP.NET Core app, so there isn't anything for the Hub besides writing a few lines of code:

using Microsoft.AspNetCore.SignalR;
using System;
using System.Threading.Tasks;

namespace SignalRChat.Hubs
{
    public class ChatHub : Hub
    {
        public async Task SendMessage(string user, string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", user, message);
        }
    }
}

This code handles all messages that are sent to the "SendMessage", which when received by the Hub will send a message with the key "ReceiveMessage" to everyone connected.

Besides this Hub code we will need to configure the service and route in the Startup.cs file.

In ConfigureServices add the following code at the end of the method:

services.AddSignalR();

Then in Configure we will want to add a route for the Hub that our clients will connect to (right before UseMvc):

app.UseSignalR(routes =>
{
    routes.MapHub<ChatHub>("/chatHub");
});

A few important notes here. If you are developing on localhost you may want to disable UseHttpsRedirection until you publish to Azure. This will ensure the mobile apps can communicate on the local machine. Also if you want to integrate a web client there is a javascript/typescript library that you can use.

Client NuGet

For our mobile .NET client we simply need to install the Microsoft.AspNetCore.SignalR.Client into our iOS, Android, UWP, and .NET Standard projects and we are ready to code!

Connecting to the Hub

Everything revolves around a HubConnection, which can be found by bringing in the SignalR namespace:

using Microsoft.AspNetCore.SignalR.Client;

After that we are able to create our local instance and connect to it. We are going to connect directly to localhost since I ran it on my local machine, but you can swap out the IP if you published your backend to Azure:

HubConnection hubConnection;
public ChatViewModel()
{
    // localhost for UWP/iOS or special IP for Android
    var ip = "localhost";
    if (Device.RuntimePlatform == Device.Android)
        ip = "10.0.2.2";

    hubConnection = new HubConnectionBuilder()
        .WithUrl($"http://{ip}:5000/chatHub")
        .Build();
}

Now, all we need to do is connect to the hub. This should be done only when you need the real time connection and you should disconnect when you don't need it or when your application goes into the background:

async Task Connect()
{
    try
    {
        await hubConnection.StartAsync();
    }
    catch (Exception ex)
    {
        // Something has gone wrong
    }
}

Once connected we can start to send and receive messages.

Sending Messages

This code could not be any easier by using the InvokeAsync method on our connection:

async Task SendMessage(string user, string message)
{
    try
    {
        await hubConnection.InvokeAsync("SendMessage", user, message);
    }
    catch (Exception ex)
    {
        // send failed
    }
}

Notice here we are sending a strongly typed key to our backend, which matches the name of the method in our Hub. SignalR figures out how to invoke this method automatically.

Important note here is that there is also a SendAsync method which is what you first think that you want to use. As explained to me by Damian Edwards SendAsync is a fire and forget type of send and only ensures that the send happens from the connection and does not wait for a response at all. SendAsync is usually used by the server, whereas InvokeAsync actually ensures that the message was sent and that the server received the message.

Receiving Messages

This may be my favorite part of the API because it is really beautiful in its implemenation. You just register functions using the On method that passes in any type of arguments to a stringly typed key:

 hubConnection.On<string, string>("ReceiveMessage", (user, message) =>
{
    var finalMessage = $"{user} says {message}";
    // Update the UI
});

You don't even need to be connected to register these methods, which means you have a really clean seperation of the connection and handling of the messages.

That's it! The mobile app and server are done!!! If you want a full finished sample then I have you covered as everything that I have been doing on my stream can be found on my GitHub!

signalr-in-action

Considerations for Mobile

SignalR is the first step in helping developers create awesome applications for mobile with Real Time Communciation. There are a few considerations that you should think about when implementing this type of functionality.

Connect and Disconnect

Always ensure that you connect and disconnect when appropriate. When your application goes into the background or your users leave the page that it is on.

Backgrounding

Each platform has different limitations when an app goes into the background or is fully closed by the user. You should not depend on this at all and always have a good fallback for push notifications or different polling based on the state of your app.

Handle Disconnects and Reconnects

Use Xamarin.Essentials to help out with connection state of your device and make sure to fallback gracefully when there is no internet or spotty internet.

]]>
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.

]]>
Continuous Integration & Delivery for Xamarin & .NET Libraries with Azure DevOps (VSTS) https://staging.montemagno.com/continuous-integration-delivery-for-net-libraries-with-vsts/ 5af5cc81dc592200bfc9400b Mon, 21 May 2018 19:20:00 GMT I build a lot of .NET libraries that include simple .NET Standard libraries to fully cross-platform plugins for Xamarin and Windows that target up to 10 different platforms. When I got started building libraries and shipping them to NuGet I went down a simple path of just building everything locally on my machine and manually uploading them to NuGet. This worked great for a single library, but as soon as I took on a second... third... forth... and so on, things got out of hand and I knew I had to put some sort of CI/CD in place. I went down many paths over the years and have now settled on using Visual Studio Team Services to fully automate the build of every library I create and a full distribution pipe line that goes to MyGet then to NuGet preview, and finally NuGet public release with a click of a button. Now I can develop and let VSTS handle everything for me so I can be productive:

If you look at this screenshot from VSTS it is everything that I wanted for so long in my development cycle. I push code, things are built, and automatically packages are pushed. In this post I am going to show you how I set this up for my projects and how you can too in just a few minutes.

.NET Standard and Multi-Target Projects

Before we start to setup our CI/CD for libraries I highly recommend you move your projects to SDK style projects. You can read my full guide on how to convert a PCL to .NET Standard or how to convert a Xamarin.iOS or Xamarin.Android project to SDK Style.

Everything that I develop now is based on a single .NET Standard 2.0 library or a Multi-Targeted project for plugins. I have previously written on how to convert your PCLs to .NET Standard and also have templates for Visual Studio 2017 to create Multi-Target projects for plugins.

SDKStyle

The reason to use these types of projects is that they include full NuGet packaging including all metadata and dependencies. This also means you can fully delete the .nuspec file that always gets out of sync. It is worth your time to update any and all projects to these types of projects to simplify your life.

If you need to learn more about multi-targeting be sure to check out Oren's amazing MSBuildSdkExtras package which is the core of my templates and all of my projects.

If you are building only an iOS or Android library do not fear as you can still just convert your existing library over to an SDK Style. Take a look at my MonoDroid.Toolkit csproj on GitHub.

Build Definition in VSTS

My builds inside of VSTS are actually really simplistic and only contain 6 steps to fully build my libraries. You can use the Hosted Visual Studio 2017 machines, however I have a small Intel NUC that runs a local VSTS agent so all my NuGets are cached which reduces my build times to seconds instead of minutes.

Empty Definition

Select New and pick your source code that you would like to build. I then like to select Empty process because we can easily fill it in.

Empty

NuGet Steps

Under Phase 1 we are going to add two NUGet steps.

First is the NuGet Tool Installer task and change the Version to 4.5.1

NuGetInstaller

Second will be the regular NuGet task which we will use the restore command on our solution that we are going to build. I like to pick the specific .sln or folder where it lives (no need to build other stuff).

NuGetRestore

Build Steps

I build my libraries twice! That is right twice! Once for a "beta" NuGet and once again for "public" NuGet. They are super quick and all it is really doing is changing the version flags. The reason I do this is for my release definition that will allow me to have a single release that goes from beta to public easily. We will be building the .csproj specifically using the MSBuild task:

MSBuild

We will add it twice so we can build the beta and public releases. Name the first Build Beta and the second Build Public. For each of them set the following:

  • Project: Select the .csproj specifically
  • Configuration: $(BuildConfiguration)

For MSBuild Arguments user the following for Beta:

/t:restore;build;pack /p:PackageVersion=$(Build.BuildNumber)-beta /p:PackageOutputPath=$(build.artifactstagingdirectory)/beta /p:AssemblyFileVersion=$(Build.BuildNumber)

For Public use:

/t:restore;build;pack /p:PackageVersion=$(Build.BuildNumber) /p:PackageOutputPath=$(build.artifactstagingdirectory)/public  /p:AssemblyFileVersion=$(Build.BuildNumber)

This will ensure that the build numbers are configured correctly and copy the artifacts to different folders.

Optionally, you may have some additional unit tests or device runners that may need to be run here.

Copy and Publish

The next thing to add is the Copy Files task to stage the NuGet packages for release.

Set these properties:

  • Source Folder: $(build.sourcesdirectory)
  • Contents: **\bin\$(BuildConfiguration)\**\*.nupkg
  • Target Folder: $(build.artifactstagingdirectory)

Finally, add the Publish Build Artifacts task and set the following:

  • Path to publish: $(build.artifactstagingdirectory)
  • Artifact name: drop
  • Artifact public location: Visual Studio Team Services/TFS

This will pull only .nupkg files that we will distribute into a folder that release can pick up.

All in all the definition should look like:

AllDone

Configure Version Number

Under the Options tab in the build definition I like to format the Build number format such as: 4.5.0$(rev:.r)

This means that the next version would be: 4.5.0.1 and then 4.5.0.2.

Now if you change this to: 5.0.0$(rev:.r) it will reset the revision so it will be 5.0.0.1.

Other things!

You will probably want to setup *Triggers so CI and PR validation are configured. This means that every time master is pushed to a package is generated.

Release Definition in VSTS

Now we have our full build complete it is time to setup our release. Our goal for me was to automatically have every build of master go to MyGet and then manually approve the next release to go to NuGet (beta) and finally another approval to go to NuGet with the public non-beta package.

Battery-CD-1

Head over to the Releases section and create a new release definition with an Empty process. Think of Environments as the stages of release. We can create three of them to define each release of the artifacts. Inside of each environment are a sequence of tasks, just like our build definition, that will be run. For my libraries it is really simple as each has just one task. However, before the NuGet beta and production environments I turn on pre-deployment approval steps.

Push to MyGet

In our first environment we will want to push to MyGet. Add the NuGet task with the following settings:

  • Command: push
  • Path to NuGet package: $(System.DefaultWorkingDirectory)/**/drop/beta/*.nupkg
  • Target Feed: External NuGet server

For this step you will want to configure the feed information from MyGet:

MyGet

Push NuGet Beta

For this step you can select Clone or if you already create the new environment simply add the NuGet task again. The settings will be the same as above:

  • Command: push
  • Path to NuGet package: $(System.DefaultWorkingDirectory)/**/drop/beta/*.nupkg
  • Target Feed: External NuGet server

However, we will now want to select or configure NuGet as our destination:

NuGet

Head back to Pipeline and for this environment we don't want it to automatically trigger, we want to approve this release. You will see a lightning bolt and a person shape on the left side of the environment to configure pre-deployment conditions. I turn on pre-deployment approvals and select myself and turn off the policies since I am a solo developer:

predeploy

There is all sorts of rad stuff you can do here on pre and post-deployment so you should totally look into that for larger projects.

Push NuGet Production

Add or clone another environment for after the Beta environment. This is going to be almost the same as the previous step but we are going to change our Path to NuGet package:

  • Command: push
  • Path to NuGet package: $(System.DefaultWorkingDirectory)/**/drop/public/*.nupkg
  • Target Feed: External NuGet server

Notice I am using public here :)

Add Artifact

Finally, click the big Add artifact button on the left side and select the build definition that you created earlier. Also tap on that little lightning bolt and turn on the Continuous deployment trigger so this flow automatically happens!

CI/CD Pro!

You did it! You are totally a Continuous integration and delivery pro!! Enjoy a seamless deployment of every push to master to MyGet and then approval steps to push to NuGet for any and all of your .NET Libraries. <3 Feel free to ask questions below.

]]>
Converting Xamarin Libraries to SDK Style & Multi-Targeted Projects https://staging.montemagno.com/converting-xamarin-libraries-to-sdk-style-multi-targeted-projects/ 5af9d3b5dc592200bfc94017 Mon, 14 May 2018 22:00:00 GMT If you are like me you may have a lot of standard Xamarin.iOS and Xamarin.Android libraries sitting around. They aren't plugins, but they do extend a single platform with custom functionality and controls. Wouldn't it be great if you could update them to the new SDK Style projects which use Package References, auto-NuGet packaging, and load WAY faster?!?!? It is all crazy simple to do just like converting old PCLs to .NET Standard. If you are setting up CI this is going to be a huge time saver as you can set it up in VSTS in minutes (blog coming this week).

Unload that Project

First things first, we need to get at that raw .csproj madness. Right click on the project and click Unload Project. Then right click again and select Edit *.csproj:

UnloadProject

Delete Everything!

That is right! Delete it all because we don't need it at all!

Replace it with my base project information. It is a bit verbose but based on the type of library you are creating there are some special things that you may want to include such as Android resources.

Note: I like to only compile items that end in .shared.cs, .ios.cs, or .android.cs to keep it tidy, but you can easily change what you compile into your library in the project structure.

Right click and re-load the project!

New-project

Spice it up

Now you can go in and any NuGets you may need with the PackageReference node in the ItemGroup of your choosing. Additionally, you can also turn on Multi-Targeting to generate both an iOS and Android (or whatever else like UWP and netstandard) by change TargetFramework to TargetFrameworks and specifying more frameworks.

Multi-Target

NuGet that Library

What is great about the SDK style projects is that you don't need a .nuspec at all for your NuGet and it can be generated automatically at build time! Whoa! Amazing Yes! You can also see the contents with the NuGet Package Explorer

All you need to do is turn on GeneratePackageOnBuild in the Release property group and then add the following items to the main PropertyGroup for the NuGet's information:

You can read more about these attributes over on the NuGet documentation.

Now when you compile in release mode you get a full NuGet with your library:

NuGet-1

SDK and Multi-Target Everything

If you have multiple libraries like me or building multiple libraries from a single solution you can also look into Directory.Build.props and Directory.Build.targets that enable you to group common properties together for a full solution.

I have gone through just about every project I have created and switched over to this new style of project because CI is so simple with it that I can manage a full CI/CD cycle for all of my libraries from one location:

Release

Check back later this week for my blog on how to take the SDK style projects that we have here and set them up for CI in VSTS.

See Me Convert a Library Live!

Because I love seeing things in action I walk through the exact steps here in this short video:

]]>
How to Convert a Portable Class Library to .NET Standard and Keep Git History https://staging.montemagno.com/how-to-convert-a-pcl-library-to-net-standard-and-keep-git-history/ 5a78e84dda32ce0022cbd5fe Tue, 13 Feb 2018 22:00:00 GMT I have had a lot of developers telling me that they have wanted to switch to .NET Standard Libraries, but that they are worried about losing git history. I have also heard fears of compatibility with existing packages. Do not fear! It is so simple to switch over to .NET Standard and takes minutes!

Why .NET Standard 2.0

There is simply no reason not to be using .NET Standard 2.0 at this point (you can still target 1.4 if you need older UWP support, but just do 2.0!). It supports all of your favorite platforms including every single Xamarin platform, offers 20K+ more APIs than 1.X, and has a 70% API compatibility with NuGet packages today (it will also consume non-.NET Standard libraries in a compat mode). On top of that it is the future! It replaces PCL and Shared Projects (with multi-targeting, which I will save for another blog post) and will make your life as a cross-platform developer much more enjoyable.

Easy as 1,2,3,4 🐒

  1. Unload your PCL project (right click -> unload), and start editing it (right -> click edit)
  2. Delete Everything in the csproj and insert this:
<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <!--<PackageReference Include="" Version=""/>-->
  </ItemGroup>

</Project>
  1. Add back NuGets (simply open packages.config, and add the package references above, or via the NuGet package manager.
  2. Delete AssemblyInfo.cs (this is now in the csproj) and packages.config (also in csproj via PackageReference)

That is it! You are done! Welcome to the wonderful world of .NET Standard 2.0! If you had any reference to other projects you will want to add those back in!

So Easy Let Me Show You

That is right, it is so easy that I shot an entire 6 minute video where I do this in real time!

Learn More

To learn more about .NET Standard head over to the documentation and to follow along with my Git commits you can find the source code to the library I converted in the video over on my GitHub.

Additionally, Frank and I discussed .NET Standard on Merge Conflict:

]]>
Data Caching Made Simple with Monkey Cache 🐒 for .NET https://staging.montemagno.com/data-caching-made-simple-with-monkey-cache/ 5a6226bb6115b1002d4563b4 Fri, 19 Jan 2018 20:00:00 GMT Let's be honest, every application needs to store data. Sometimes it is settings, configuration, HTTP requests, or a full database. What I was recently looking to accomplish was to make a web request, cache the request locally, and have it expire after a given amount of time. There are a lot of great solutions out there for storing data, but nothing seemed to fit exactly what I was looking for with a minimal amount of dependencies. So I figured I would tweet about it:

From the results (and controversy) there still wasn't anything that completely fit the bill. And of course my good friend Frank told me that he basically had an implementation of what I was looking for and to create a GitHub repo so we could collaborate. Just like that Monkey Cache was born! The easiest way to cache data in any .NET application.

MonkeyCacheSmall

What is Monkey Cache?

When we were building Monkey Cache we wanted to make a drop dead simple way to store any type of data with a minimal amount of dependencies. In addition to this, we also wanted to give developers an easy way to make web requests that would automatically use the ETag headers to smartly cache data only when needed.

Installing Monkey Cache

Monkey Cache consists of one core NuGet package with three backing store providers. That's right, you can pick the backend that best fits your needs and application. As of today we support SQLite-net, LiteDB (supports encryption), and a simple File Store (no additional dependencies). If you are already using one of these databases in your application then it is a clear choice to pick that implementation, else the choice is yours!

MonkeyCacheNuGets

When you pick a backend it will automatically pull in the Monkey Cache core library which contains the core data models and all of the HTTP helpers. Monkey Cache is built against .NET Standard 2.0, which means it can be installed essentially in any .NET application, not just mobile!

Storing Objects in Barrels

Once Monkey Cache is installed in your project, it is time to start storing objects. Everything is stored in a "Barrel" or IBarrel. There is only one thing to do before we can store items, which is setup our application Id on the barrel:

Barrel.ApplicationId = "your_unique_name_here";

There is 1 barrel that items get stored in and Monkey Cache provides a singleton method that returns an IBarrel:

var currentBarrel = Barrel.Current;

What is an IBarrel?

Great question! This is where items get cached, updated, deleted, and checked for expiration:

    public interface IBarrel
    {
        void Add(string key, string data, TimeSpan expireIn, string eTag = null);
        void Add(string key, T data, TimeSpan expireIn, string eTag = null);
        void Empty(params string[] key);
        void EmptyAll();
        void EmptyExpired();
        bool Exists(string key);
        string Get(string key);
        T Get(string key);
        string GetETag(string key);
        bool IsExpired(string key);
    }

The Add method (which also updates the item) takes in a unique key, some data, a time span, and an optional eTag for metadata (nifty for web requests). Notice that there is a generic version of the method. This is so we can automatically serialize the object with Json.NET. I like to store the string manually for the web request itself, but the option is yours. On top of the normal Add and Get there are options to empty specific items, expired items, or the entire barrel. We have also added on some nifty helpers to check if the key is expired.

Caching a Web Request

Monkey Cache offers a nice drop in solution for caching data, which means there is no need to re-structure your entire app. Here is what an updated generic Get would look like for caching a web request:

There you have it! So simple! Now all of our web requests will be cached for any amount of time that we want and can optionally force a refresh if we need to!

You can learn more over on the Monkey Cache GitHub page, and also be sure to listen to our Merge Conflict episode on the how and why of Monkey Cache:

]]>
Moving Plugins for Xamarin to .NET Standard https://staging.montemagno.com/plugins-for-xamarin-go-dotnet-standard/ 598df8f2c121b60019bf2fc3 Thu, 29 Jun 2017 17:27:13 GMT I could never imagine the amazing response to Plugins for Xamarin, those amazing little libraries that abstract away all that platform specific code into a lovely cross-platform API for iOS, Android, and Windows. They sure have grown, with hundreds of plugins being generated by the community and with tons of installs. My plugins alone have now hit 3 Million installations! With all this momentum it is a great time to look to the future, simplify plugins, and take the leap to .NET Standard.

Plugins

What is .NET Standard?

Great question! Essentially think of .NET Standard as the defacto way of sharing code across all .NET Platforms including Xamarin, .NET Framework, .NET Core, and others. Essentially all of these .NET Platforms implement a standard set of APIs so you as a developer can just create a library and share it everywhere. They are the evolution, improvement, and replacement for Portable Class Libraries, and I could not be more excited about it.

.NET Standard

I highly recommend you checkout our podcast episode of Merge Conflict, which you should totally listen to:

Merge Conflict 38: One Library to Rule Them All

The Big Move & More Platforms

There are actually two large changes that I have done to my plugins. First, each and every plugin’s “Abstractions” and Core for bait and switch have moved to .NET Standard 1.0. This means that you can easily add them into any .NET Standard library and are 100% backwards compatible with your PCL libraries! The other switch was more on the development side of the plugins, which I have moved fully to Visual Studio 2017 and C# 7. This means that all new versions of my plugins will no longer support Windows Phone 8 Silverlight, Phone 8.1 RT, or Windows Store RT (8.1). I additionally will no longer be accepting any new issues or fixing any bugs for those operating systems in any of my plugins. I don’t have the environment to maintain them so I can’t support them.

What will you support?

With the loss of these platforms comes the rise of other platforms being added into several of my plugins. All plugins today already support iOS, Android, and UWP, and I have done my best to add in macOS, tvOS, and watchOS support to plugins where they make sense, such as Settings, Connectivity, and Text to Speech.

The Brand New IsSupported Boolean!

Previously, when you installed a plugin on a platform that wasn’t supported (or you forgot to install the NuGet in the core project) and you tried to call the method it would simply throw an exception. This is still the case, but I tried to figure out a better way for developers to check to see if an implementation exists before making calls.

You can simply now call CrossPluginName.IsSupported to check if it exists. For instance:

There you have it, super simple way of checking!

Updated Android Support Libraries

In this big move I also took a big risk on deciding to make the break away from defaulting to version 23.3.0 of the Android Support Libraries in a few of my plugins. These libraries are now almost 3 years old and it is simply time to update them to the latest and greatest 25.3.1. Since you can update them now in Xamarin.Forms applications it is time! I even show you how to do it in this small Snack Pack episode of The Xamarin Show

It should be known that I don’t use Support libraries unless I absolutely have to, but if you are using Permissions, Media, Share, or Geolocator then you are going to have to update. Here is what you need to know:

Before you install or update your NuGets, ensure you have Android SDK for API 25 installed. You can watch my video on The Xamarin Show or simply click Tools->Android SDK Manager, deselect everything, and then select Android SDK 25, that is all you will need. Next, you need to go into your Android project settings and under General/Build make sure you select Android 7.0 and then go into your Manifest and set the Target to 25 too!

Set API Android

If you don’t do this you will see an error when trying to install the Android NuGet that you aren’t targeting the correct version of Android. That is what this error means. Go update!

Can I Haz NuGets?

As of the time of writing this article each and every Plugin for Xamarin that I have created now has a pre-release version available that introduces these changes. Over the next two weeks I will be transitioning all of them to the stable branch after a bit more testing and feedback from you!

]]>
Creating & Consuming .NET Standard Libraries https://staging.montemagno.com/creating-and-consuming-net-standard-libraries-with-xamar/ 598df8f2c121b60019bf2feb Tue, 02 Aug 2016 21:13:02 GMT ]]>