Consider setting NullabilityInfoContextSupport=true in EF's NuGet package
See original GitHub issueWhen 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:
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
dotnet new maui- Add
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="7.0.0-preview.1.22076.6" /> - Change
MainPage.xaml.csto:
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" });
}
}
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:
- Created 2 years ago
- Comments:20 (14 by maintainers)
Top Related StackOverflow Question
I have openned a new issue https://github.com/dotnet/efcore/issues/28773
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 toNullabilityInfoContextSupport=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=truein 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.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.
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
truewhen the default is alreadytruein server/desktop apps.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.