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

Tools: Support .NET Core Class Library projects #5320

Closed
natemcmaster opened this issue May 10, 2016 · 43 comments
Closed

Tools: Support .NET Core Class Library projects #5320

natemcmaster opened this issue May 10, 2016 · 43 comments
Assignees
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug

Comments

@natemcmaster
Copy link
Contributor

natemcmaster commented May 10, 2016

Add support for running "dotnet ef" on a .NET Standard and desktop .NET class library project.

This is blocked by https://github.com/dotnet/cli/issues/2645 and/or https://github.com/dotnet/cli/issues/4005 (depending on our implementation approach).

Short explanation

If you cannot do dotnet run, you also cannot use dotnet ef on your project.

More explanation

.NET Core, unlike .NET Framework, does not have a globally installed framework. All .NET Core apps need to reference an app framework (e.g. Microsoft.NETCore.App) in order to run. .NET Core class library projects are built without a framework, so dotnet-ef cannot run on these projects.

Workarounds

See https://docs.efproject.net/en/latest/miscellaneous/cli/dotnet.html#targeting-class-library-projects-is-not-supported for workarounds.

@Kurira
Copy link

Kurira commented May 19, 2016

Hi,

Just to be sure, we can't use EF within a class library project (aka tests project) in RC2?

@natemcmaster
Copy link
Contributor Author

@Kurira you can use EF within a class library. You can't use EF .NET Core CLI commands on a class library. See https://docs.efproject.net/en/latest/cli/dotnet.html more info

@Kurira
Copy link

Kurira commented May 19, 2016

So I would use tools from my web project and apply them to test context which resides in test project?
Your link talks about transforming it into an app, but I always get System.IO.FileNotFoundException: Could not load file or assembly 'Newtonsoft.Json, Version=7.0.0.0, even then used from web project template.

@kjbetz
Copy link

kjbetz commented May 24, 2016

I need to test this more, but here is my solution that seems to be working: #5460 (comment)

@ToddThomson
Copy link

Is there a published workaround for this issue? I've added:

"frameworks": {
    "net451": {
        "buildOptions": {
            "emitEntryPoint": true
        }
    },
    "netcoreapp1.0": {
        "imports": [ "portable-net451+win8" ],
        "buildOptions": {
            "emitEntryPoint": true
        },
        "dependencies": {
            "Microsoft.NETCore.App": {
                "type": "platform",
                "version": "1.0.0-*"
            }
        }
    }
},

and a main() in program.cs, but I still get the "..Entity Framework tools does not support targeting class library projects.." message.

@natemcmaster
Copy link
Contributor Author

@ToddThomson you are probably hitting https://github.com/dotnet/cli/issues/3164. Try setting the top-level emitEntryPoint build option to true.

@ToddThomson
Copy link

@natemcmaster Yes. That was it.

@rowanmiller
Copy link
Contributor

When we have this implemented we need to verify that the right-click->Publish migrations feature works when the context/migrations is in a class library - I suspect it is not going to work by default because it will likely need to specify some of the target/startup project parameters.

@ToddThomson
Copy link

ToddThomson commented May 26, 2016

Additionally, if your DbContext takes a parameter then you also need to add a simple startup.cs to the class library. I added:

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        Configuration = builder.Build();
    }

    public IConfigurationRoot Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices( IServiceCollection services )
    {
        // Add Identity framework services.
        services.AddDbContext<SecurityDbContext>( options =>
             options.UseSqlServer( Configuration.GetConnectionString( "DefaultConnection" ) ) );

    }

This was sufficient for me to add an initial migration for Identity services.

@HamidMosalla
Copy link

@natemcmaster Any change in this regard in latest tooling preview 2?

@natemcmaster
Copy link
Contributor Author

We are still blocked on .NET Core CLI support for this. https://github.com/dotnet/cli/issues/2645.

Preview 2 added --startup-project which may mitigate the limitation for some project setups (#5680).

@arielcloud
Copy link

Hi, where can i use this "--startup-project" to fix that?
I'm trying install EntityFrameworkCore.Tools on class library and get "Package Microsoft.EntityFrameworkCore.Tools 1.0.0-preview2-final is not compatible with netstandard1.6"
10x!

@natemcmaster
Copy link
Contributor Author

@arielcloud did you upgrade your version of .NET Core CLI to preview 2?

@arielcloud
Copy link

@natemcmaster i dont sure I have CLI at all.

I downloaded .net core by "Visual Studio users: The best way to develop with .NET Core on Windows is using Visual Studio. You will need Visual Studio 2015 Update 3 and then download the .NET Core for Visual Studio official MSI Installer"
https://www.microsoft.com/net/core#windows

where can i see if i have CLI and it's version? 10x!

@natemcmaster
Copy link
Contributor Author

@arielcloud execute dotnet.exe --version from the command line. Also, Microsoft.EntityFrameworkCore.Tools only supports "netcoreapp1.0". It cannot be installed into a class library. https://docs.efproject.net/en/latest/miscellaneous/cli/dotnet.html#targeting-class-library-projects-is-not-supported

@bricelam
Copy link
Contributor

bricelam commented Nov 20, 2016

Yes, you can have your model or DbContext in a class library. This issue is about making the Migrations tooling experience a little better. Right now, you have to use an app (non-library) startup project for them to work at all.

I'm working on changes that will largely remove this restriction, although maybe not always for dotnet ef database update.

@mehmetilker
Copy link

@bricelam Which means we still have to reference EF Core to the web project ?
Is there any open issue related with this problem we can follow ?
Lots of people are waiting to remove EF references from their web projects I guess...

@bricelam
Copy link
Contributor

bricelam commented Nov 29, 2016

So there's good news and bad news...

The good news is that I got it "working".

The bad news is that, in practice, it doesn't really "work" because the .NETStandard framework isn't intended for execution. It will work if everything down the execution path has a pure .NETStandard implementation that doesn't depend on a runtime. So basically the only command that will always work is:

  • dotnet ef dbcontext list

None of the other commands will work on SQL Server because SqlClient is too framework-and-runtime-specific. You get:

Could not load file or assembly 'System.Data.SqlClient, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'. The system cannot find the file specified.

SQLite is a little better because anything that doesn't actually open a connection will work:

  • dotnet ef migrations list
  • dotnet ef migrations add (& Add-Migration)
  • dotnet ef migrations script (& Script-Migration)
  • dotnet ef migrations remove --force (& Remove-Migration)

Anything else will throw:

Unable to load DLL 'sqlite3': The specified module could not be found. (Exception from HRESULT: 0x8007007E)

So, the question is, do we...

  1. Allow execution and warn:

    The project 'ClassLibrary1' targets .NETStandard. This framework is not intended for execution and may fail to find runtime dependencies. If so, specify a --startup-project that references this project and targets a different framework (e.g. .NETCoreApp).

  2. Prevent execution entirely and force you to use --startup-project.

@bricelam bricelam removed this from the 1.2.0 milestone Nov 29, 2016
@bricelam
Copy link
Contributor

bricelam commented Nov 29, 2016

If we do allow execution, we should consider automatically add -Force to Remove-Migration like we do on UWP. Although, it theoretically may be able to check the database if the provider is purely managed.

@rowanmiller rowanmiller added this to the 1.2.0 milestone Nov 29, 2016
@rowanmiller
Copy link
Contributor

We'll go with the warning approach

@esargent
Copy link

As a developer trying to use EFcore and having to deal with this issue because we are leveraging a common data model across multiple web portals and even a Xamarin project for Android - my team would prefer to have the option and the warning message.

It feels a lot more natural to do data modeling and schema work against the Data project, not the application.

@bricelam bricelam modified the milestones: 1.2.0, tools-1.0.0 Nov 29, 2016
@jmevel
Copy link

jmevel commented Nov 30, 2016

@bricelam so you are saying there will be no issues with a .NET Core class library targeting only full .NET Framework instead of .NET Standard?

@bricelam
Copy link
Contributor

Correct. Class libraries targeting .NET Framework or .NET Core App should work just fine without specifying a separate startup project.

@bricelam
Copy link
Contributor

bricelam commented Nov 30, 2016

To ellaborate, there are two projects when you invoke a command:

The target project that you are operating on. Files will be added to this project.

The startup project. This is the runtime environment we'll emulate at design time. This project's config will be loaded; it's Startup.ConfigureServices() will be used if it's an ASP.NET Core project; etc.

In PMC, the target project defaults to the selected Default project and can be overridden using -Project. The startup project defaults the the selected startup project (the one that runs when you click Start with debugging) and can be overridden using -StartupProject.

On CLI, the target project defaults to the one in the working directory and can be overridden using --project. The startup project defaults to the target project and can be overridden using --startup-project.

@ErikEJ
Copy link
Contributor

ErikEJ commented Nov 30, 2016

For the first time I kind of understand this, how about adding this to the docs?

@rowanmiller
Copy link
Contributor

@ErikEJ good idea. We don't really have any detailed docs on the commands at the moment, just a reference on what parameters are available etc.

@bricelam bricelam added the closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. label Dec 1, 2016
@bricelam bricelam closed this as completed Dec 2, 2016
@bricelam
Copy link
Contributor

bricelam commented Jan 4, 2017

Bad news
The solution I had stopped working. You will have to use a separate startup project when working directly with .NET Standard projects. You will receive the following error.

Startup project 'ClassLibrary1' targets framework '.NETStandard'. This framework is not intended for execution. Specify a project that targets a concrete framework like '.NETCoreApp' or '.NETFramework' using the --startup-project option and try again.

Good news
They're adding a .NET Core (in addition to the .NET Standard) Class Library in Visual Studio 2017. The Entity Framework Core Tools will work as expected on these projects.

@bricelam
Copy link
Contributor

bricelam commented Jan 5, 2017

Scratch that. It was an unrelated issue. .NET Standard class libraries will "work" (as much as they can)

@Bartmax
Copy link

Bartmax commented May 28, 2017

Can we add a way to persist the startup project in our class library so we don't need to pass the argument on every call and also we can share which startup project should be used in source control ? (Thinking in multiple project sharing (or not) the same dbcontext.

maybe dotnet ef --set-startup-project ..\MyApp, a key on csproj like user secrets or just a StartupProject.txt file :)

@Bartmax
Copy link

Bartmax commented May 29, 2017

discard my last comment. I found a better way that I think it should be the official way because it's easy and afaik there's no downside.

To make your class library be able to run dotnet ef it's as simple as targeting both frameworks.

Example:

<TargetFrameworks>netcoreapp1.1;netstandard1.4</TargetFrameworks>

this is also mentioned on the "workarounds"

@qdxiayongming
Copy link

6 hours.... worked....

  1. edit *.csproject add ....EntityFrameworkCore.Tools&...EntityFrameworkCore.Tools.Design With "" tag. (PackageReference and DotNetCliToolReference)
  2. in PMC ,use "cd" command rederict to project floder.
  3. use "dotnet ef" command ,you'll see unicorn.
    中文:
    1)修改项目文件,添加项目Nuget包引用以及Cli引用:EFCore.Tools&EFCore.Tools.Design.
    2)在PMC中(程序包控制台)通过cd命令将目录转移到对应的项目目录下(解决方案默认打开的都是比项目更高一级的解决方案目录,此时应该通过CD转换到项目目录下。
    3)使用 dotnet ef命令,就可以看到独角兽了。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
closed-fixed The issue has been fixed and is/will be included in the release indicated by the issue milestone. type-bug
Projects
None yet
Development

No branches or pull requests