Efcore: Tools: "Your startup project doesn't reference Design" in VS 15.7

Created on 27 Mar 2018  路  19Comments  路  Source: dotnet/efcore

The implementation of NuGet/Home#4125 broke our Microsoft.EntityFrameworkCore.Tools package. Since it uses ExcludeAssets="Runtime", .NET Core can't find Microsoft.EntityFrameworkCore.Design.dll at design time.

cc @jainaashish @rrelyea

area-external closed-fixed type-bug

Most helpful comment

It's nice that users can't compile against Microsoft.EntityFrameworkCore.Design.dll, but we still need Assembly.Load("Microsoft.EntityFrameworkCore.Design") to work...

All 19 comments

It's nice that users can't compile against Microsoft.EntityFrameworkCore.Design.dll, but we still need Assembly.Load("Microsoft.EntityFrameworkCore.Design") to work...

@bricelam Can you please help me understand your scenario in more detail and the above package?

Sure, I don't think it's an unusual scenario. Let me see if I can walk through it.

  1. You have a tool like the EF commands (Add-Migration PMC command or dotnet ef), or the xUnit.net test runner, the MVC scaffolding, etc.
  2. You need an entry point into the user's project to reflect over and invoke their code to get their DbContext model, test classes, controllers, etc. This entry point is distributed in a NuGet package with developmentDependency="true" so it doesn't get published to the server or referenced by other projects. This is our Microsoft.EntityFrameworkCore.Design package (brought in transitively by the Microsoft.EntityFrameworkCore.Tools package). You want this assembly brought in alongside the runtime assemblies so it can take advantage of NuGet's version resolution and binding redirect logic.
  3. Your tool loads the assembly (Assembly.Load()) in the context of the user's project (e.g. using it's App.config). On .NET Framework, we use a separate AppDomain with the project's App.config file to apply appropriate binding redirects. In this case, the assembly just needs to be in the bin folder to work. On .NET Core, we start a new process using the user's deps.json json file (could also be done using an AssemblyLoadContext and the deps.json file). In this case, the assembly needs to be listed in the deps.json file in order for Core CLR to find it, but since the deps.json file is generated from the assets.json file, it's missing the entry when ExcludeAssets="Runtime" is used.
  4. The design-time entry point loads and executes the user's assembly to add a migration, run tests, scaffold a view, etc.

@prafullbhosale do you set developmentDependency="true" on your Design package?

@prafullbhosale do you set developmentDependency="true" on your Design package?

Scaffolding relies on the user to specify PrivateAssets=All to not be included in the publish output.
Since it is not part of the metapackage, the scaffolding design package needs to be explicitly added to the project.

But the above approach sounds much better than expecting the user to do something, (given that VS cannot install this package PrivateAssets=All)

cc @Seancpeters, @vijayrkn

@onovotny @bradwilson Should any of the packages containing xunit.execution.* assemblies have developmentDependency="true"? The requirements are a bit different here since when you publish test projects, you probably still want everything required to run them...

@rrelyea This is the issue I mentioned in Core War. Briefly:

  • We think this will break all EF Core packages (1.0, 1.1, 2.0, and 2.1) when running on .NET Core.
  • We are very happy with the feature in general--it is only the need to still be able to load the assembly that is breaking us.
  • It is possible that other third-party tools (like xunit--see above) may also be broken.

At this time, we're hoping that this can be fixed on the NuGet side. Patching and releasing all versions of EF Core will be very expensive, and may also degrade the experience.

/cc @Eilon @divega

This is also broken in .NET Framework projects. In packages.config projects, the assemblies in packages with developmentDependency="true" were copied to the output directory. With <PackageReference>, they're not.

@bricelam

You need an entry point into the user's project to reflect over and invoke their code to get their DbContext model, test classes, controllers, etc. This entry point is distributed in a NuGet package with developmentDependency="true" so it doesn't get published to the server or referenced by other projects. This is our Microsoft.EntityFrameworkCore.Design package (brought in transitively by the Microsoft.EntityFrameworkCore.Tools package). You want this assembly brought in alongside the runtime assemblies so it can take advantage of NuGet's version resolution and binding redirect logic.

Your entry point Microsoft.EntityFrameworkCore.Design is not marked with developmentDependency=true. Only Microsoft.EntityFrameworkCore.Tools is marked as dev dependency. And given your scenario, Microsoft.EntityFrameworkCore.Design isn't really a development dependency because it needs to be there in deps.json as part of available runtime assemblies.

So the bottom line, you've a dev dependency which provides certain ps modules/ scripts which relies on loading some assemblies coming from non-dev dependencies. Shouldn't your EF design packages be explicitly added to project or make them part of your metapackage if it should always be there?

Regardless, the semantics of developmentDependency="true" have been broken.

Today with packages.config on .NET Framework, assemblies in packages with developmentDependency="true" are referenced. After migrating to <PackageReference>, they're not.

The original semantics of developmentDependency="true" were simply to prevent the dependency from propagating outside of the project it was installed into.

Not referencing the assembly is neat, but it should probably be driven by a new piece of metadata to prevent breaking developmentDependency.

Have you reviewed existing packages with developmentDependency="true"? I'm all for refining the semantics like not publishing them, and maybe even not referencing them during compilation, but it should be done with an awareness of its current usage.

Just wanted to check if the error I'm seeing is related to this issue. Running ef migrations with dotnet exec and it's complaining about the same thing:

Microsoft.EntityFrameworkCore.Tools.CommandException: Your startup project 'Web' doesn't reference Microsoft.EntityFrameworkCore.Design. This package is required for the Entity Framework Core Tools to work.

Haven't had any issues with this setup before testing the 2.1 preview, and adding the reference does not help.

@AndersSahlin Doesn't look related. Could you submit a new issue with a simplified repro attached?

@onovotny @bradwilson Should any of the packages containing xunit.execution.* assemblies have developmentDependency="true"? The requirements are a bit different here since when you publish test projects, you probably still want everything required to run them...

Publishing is blocked for test projects by default, is it not?

I realized it was a stupid question shortly after asking it. 馃槃 lol, please ignore.

Hi @bricelam , I have gone through all of your examples and solutions pertaining to above issue being discussed and they are really helpful since I am also trying to execute migrations against a dll, or a class library compiled to a dll, but unfortunately I have still not been able to implement or adapt your solution here: https://blog.bennymichielsen.be/2017/08/01/migrating-databases-with-ef-core-during-a-vsts-release/ . I would really appreciate if you can please go into more details and explain your approach. Following were the issues I encountered :
1) "exec" statement didn't work
2) which deps.json and runtimeconfig.json are you referring to and how do you package it together in the final archive
3) the ef.dll that is being copied/packaged in my project is still for .net core2.0 even though my csproj imports packages >=2.1.4 for .net core 2.1, which causes the same error as above "Your startup project doesn't reference Microsoft.EntityFrameworkCore.Design"
4) my project, containing the dbcontext, and the startup project, which contains the dbcontextfactory and migrations, are separate
5) I want to trigger migrations during install time depending upon user input and whether db exists or not and needs to be upgraded/downgraded, via migrations, or removed and created fresh

thanks in advance

@AndersSahlin, @shubhamagarwal1, have you guys found a solution?
After updating the project to .NET Core 3.1, having the same issue with applying migrations on the binaries via ef.dll.

  1. my project, containing the dbcontext, and the startup project, which contains the dbcontextfactory and migrations, are separate
  2. I want to trigger migrations during install time depending upon user input and whether db exists or not and needs to be upgraded/downgraded, via migrations, or removed and created fresh

+1

Was this page helpful?
0 / 5 - 0 ratings