Consider setting NullabilityInfoContextSupport=true in EF's NuGet package

See original GitHub issue

When using EF in a .NET Maui Android/iOS application, developers will get a runtime error because .NET MAUI sets NullabilityInfoContextSupport=false here:

https://github.com/xamarin/xamarin-android/blob/c80dfff7a3183e21d356d2c5835aa0821fd9bd90/src/Xamarin.Android.Build.Tasks/Microsoft.Android.Sdk/targets/Microsoft.Android.Sdk.DefaultProperties.targets#L95 and https://github.com/xamarin/xamarin-macios/blob/e25163f573d31b28fa60f000ce084b8cdb0ca697/dotnet/targets/Xamarin.Shared.Sdk.targets#L136

Since this setting is set to false, when EF tries to create a NullabilityInfo object, an exception is thrown here:

https://github.com/dotnet/efcore/blob/0e1e95bce5468ca5dd657b7b3e4b4ff8aa01b640/src/EFCore/Metadata/Conventions/NonNullableConventionBase.cs#L54-L55

02-18 17:55:25.483 14402 14402 E AndroidRuntime: Process: com.companyname.mauioptimisertest, PID: 14402
02-18 17:55:25.483 14402 14402 E AndroidRuntime: android.runtime.JavaProxyThrowable: System.InvalidOperationException: NullabilityInfoContext is not supported in the current application because 'System.Reflection.NullabilityInfoContext.IsSupported' is set to false. Set the MSBuild Property 'NullabilityInfoContextSupport' to true in order to enable it.
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at System.Reflection.NullabilityInfoContext.EnsureIsSupported()
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at System.Reflection.NullabilityInfoContext.Create(PropertyInfo propertyInfo)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.NonNullableConventionBase.IsNonNullableReferenceType(IConventionModelBuilder modelBuilder, MemberInfo memberInfo)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.NonNullableReferencePropertyConvention.Process(IConventionPropertyBuilder propertyBuilder)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.NonNullableReferencePropertyConvention.ProcessPropertyAdded(IConventionPropertyBuilder propertyBuilder, IConventionContext`1 context)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnPropertyAdded(IConventionPropertyBuilder propertyBuilder)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnPropertyAddedNode.Run(ConventionDispatcher dispatcher)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.DelayedConventionScope.Run(ConventionDispatcher dispatcher)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Run()
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ConventionBatch.Dispose()
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.ImmediateConventionScope.OnModelInitialized(IConventionModelBuilder modelBuilder)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal.ConventionDispatcher.OnModelInitialized(IConventionModelBuilder modelBuilder)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Metadata.Internal.Model..ctor(ConventionSet conventions, ModelDependencies modelDependencies, ModelConfiguration modelConfiguration)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.ModelBuilder..ctor(ConventionSet conventions, ModelDependencies modelDependencies, ModelConfiguration modelConfiguration)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.ModelConfigurationBuilder.CreateModelBuilder(ModelDependencies modelDependencies)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.CreateModel(DbContext context, IConventionSetBuilder conventionSetBuilder, ModelDependencies modelDependencies)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Infrastructure.ModelSource.GetModel(DbContext context, ModelCreationDependencies modelCreationDependencies, Boolean designTime)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Internal.DbContextServices.CreateModel(Boolean designTime)
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Internal.DbContextServices.get_Model()
02-18 17:55:25.483 14402 14402 E AndroidRuntime:    at Microsoft.EntityFrameworkCore.Infrastructure.EntityFrameworkServicesBuilder.<>c.<TryAddCoreServices>b__8_4(IServiceProvider p)

We should consider defaulting NullabilityInfoContextSupport=true in EF’s NuGet package, so when a .NET Maui app starts using EF, they automatically get this support turned on and their app works out of the box.

Repro steps

  1. dotnet new maui
  2. Add <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.1.22076.6" />
  3. Change MainPage.xaml.cs to:
using Microsoft.EntityFrameworkCore;

namespace MauiOptimiserTest;

public partial class MainPage : ContentPage
{

    public MainPage()
    {
        InitializeComponent();

        var dbpath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "test.db");
        using (var context = new TestContext(dbpath))
        {
            context.Database.EnsureCreated();
            var records = context.MyRecords.ToList();
            BindingContext = records;
        }
    }

}

public class MyRecord
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public class TestContext : DbContext
{
    public DbSet<MyRecord> MyRecords { get; set; }

    public TestContext() : this(":memory:")
    {
    }

    public TestContext(string path)
    {
        sqliteConnectionString.DataSource = path;
    }

    private readonly Microsoft.Data.Sqlite.SqliteConnectionStringBuilder sqliteConnectionString = new();
    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);

        optionsBuilder.UseSqlite(sqliteConnectionString.ToString());
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<MyRecord>().HasData(new MyRecord { Id = 1, Name = "Apple" });
        modelBuilder.Entity<MyRecord>().HasData(new MyRecord { Id = 2, Name = "Banana" });
        modelBuilder.Entity<MyRecord>().HasData(new MyRecord { Id = 3, Name = "Coconut" });
    }
}
  1. dotnet build -f net6.0-android -r android-arm64 -t:Run

The app will crash with the above exception when it is loaded.

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:20 (14 by maintainers)

github_iconTop GitHub Comments

2reactions
RobertoGFilhocommented, Aug 18, 2022
2reactions
eerhardtcommented, Feb 22, 2022

Can you provide a bit more context on this?

Sure. Check out https://github.com/dotnet/runtime/issues/55860 and https://github.com/dotnet/runtime/pull/56475.

Some app models (like Blazor WASM and Maui) want to produce as small of applications as possible. One of the ways to make it smaller is to trim out unnecessary attributes, like the Nulalble attributes: AllowNull, MaybeNullWhen, Nullable, etc. In order to support that we added a “feature switch” in .NET 6 that allows apps to trim these nullable attributes. When that switch is set to NullabilityInfoContextSupport=false, calling NullabilityInfoContext with throw the exception listed above in the OP.

By default, Maui iOS and Android applications have this setting NullabilityInfoContextSupport=false. So by default, if you create a Maui iOS or Android app and use EF, you get this exception.

To workaround this, the developer can explicitly set NullabilityInfoContextSupport=true in their .csproj.

My proposal here is that just by referencing the EntityFramework NuGet packages, we should consider setting NullabilityInfoContextSupport=true, which will override the default value set in Maui and Blazor WASM projects.

Is this simply a property we’d add to our csproj to get rid of the problem?

It is a property that would need to be set in a .props/.targets file in your NuGet package. This would then set the property in consumer’s projects.

Does it have any downsides/potential issues?

The only downside I can see is that when you aren’t in a Maui or Blazor WASM app, and reference the EF package, you would get an extra property that is explicitly setting the value to true when the default is already true in server/desktop apps.

Any reason why this standard .NET feature isn’t just available by default and needs this opt-in?

It is available by default in a lot of app models. It is just turned off in app models that are concerned with app size.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Manually installing the Amazon EFS client
The following procedure describes how to install amazon-efs-utils from the Amazon Linux and Amazon Linux 2 AMI package repositories. You can also install...
Read more >
Using Amazon EFS (Elastic File System) with Posit Team
This document explains how to set up Amazon Elastic File System (EFS) with Posit ... Install and use the Amazon package efs-utils to...
Read more >
aws/efs-utils: Utilities for Amazon Elastic File System (EFS)
This will install amazon-efs-utils on your EC2 Mac Instance running macOS Big Sur, macOS Monterey and macOS Ventura in the directory /usr/local/Cellar/amazon- ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found