Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading resources in DbContext constructor causes Add-Migration to fail. #28149

Closed
sjb-sjb opened this issue Jun 3, 2022 · 2 comments
Closed

Comments

@sjb-sjb
Copy link

sjb-sjb commented Jun 3, 2022

On my very first use of Add-Migration I hit this bug. Essentially, loading resources during construction of the DbContext causes Add-Migration to fail. I was doing it as part of an attribute construction, but a simpler version is described below.

Steps to reproduce:

  • Create new solution “Test” with project “App” using the “Blank App, Packaged (WinUI 3 in Desktop)” template.

  • Add Microsoft.EntityFrameworkCore.Sqlite and .Tools version 6.0.5 using NuGet package manager

  • Double-click the project to edit the .csproj file and remove the following two lines from the Microsoft.EntityFrameworkCore.Tools entry. This gets rid of the error message saying “Payload contains two or more files with the same destination path ‘App.deps.json’.

    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

  • Add a new item to the project, a .resw named AppStrings.resw, and add a resource in it with name ContextLabel and value “It works!”. Check that the build action is PRIResource.

  • Add the code shown below to the project.

using System;
using System.Diagnostics;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

using ResourceLoader = Windows.ApplicationModel.Resources.ResourceLoader;

namespace App
{
    public class Stuff { public long Id { get; private set; } }

    public class AppDbContext: DbContext
    {
        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        {
            try {
                var resourceLoader = ResourceLoader.GetForViewIndependentUse("AppStrings");
                this.Label = resourceLoader.GetString("ContextLabel");
            } catch (Exception e) {
                Debug.WriteLine($"Exception of type {e.GetType().Name}: '{e.Message}'");
            }
        }

        public string Label { get; } = "nix";

        public DbSet<Stuff> Stuff => this.Set<Stuff>();
    }


    public class AppDbContextDesignTimeFactory : IDesignTimeDbContextFactory<AppDbContext>
    {
        public AppDbContext CreateDbContext(string[] args)
        {
            var optionsBuilder = new DbContextOptionsBuilder<AppDbContext>();
            optionsBuilder.UseSqlite<AppDbContext>();
            DbContextOptions<AppDbContext> options = optionsBuilder.Options;
            return new AppDbContext(options);
        }
    }
}
  • In MainWindow.cs, in the myButton_Click method change the assignment to say:

    myButton.Content = (new AppDbContextDesignTimeFactory()).CreateDbContext(null!).Label;

  • Set Platform correctly in Build -> Configuration Manager. This will be needed for Add-Migration.

  • Build and run.

  • Observe that when you click the button the label changes to “It works!” demonstrating that the resource loading works.

  • In Package Manager Console, run the command: Add-Migration InitialCreate -Verbose

  • Observe that after printing “Using DbContext factory ‘AppDbContextDesignTimeFactory’” there is a pause and then it exits and returns back to the PM> prompt. The migration is not produced.

  • Now comment out the two lines in the try block in AppDbContext constructor, and re-do the Add-Migration. It runs to completion and the migration is produced.

@ajcvickers
Copy link
Contributor

@sjb-sjb Migrations tooling needs to be able to access metadata about your DbContext, such as the current model. This typically means that it is going to use some mechanism to create an instance of your DbContext at design time. The context implementation must be able to handle this. This can be done by moving environment-dependent code, making it resilient so that it can be run at design-time, or by using the IDesignTimeDbContextFactory to create the context in a different way. #27306 will also make this easier.

@sjb-sjb
Copy link
Author

sjb-sjb commented Jun 26, 2022

@ajcvickers I agree with your comment, I am not saying there is any need to load resources in ctor, the concern is that this causes a silent abend instead of some kind of message with a clue as to the cause.

@roji roji closed this as not planned Won't fix, can't repro, duplicate, stale Jun 27, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants