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

Comments

@natemcmaster
Member

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 dotnet/cli#2645 and/or dotnet/cli#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

This comment has been minimized.

Show comment
Hide comment
@Kurira

Kurira May 19, 2016

Hi,

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

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

This comment has been minimized.

Show comment
Hide comment
@natemcmaster

natemcmaster May 19, 2016

Member

@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

Member

natemcmaster commented May 19, 2016

@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

This comment has been minimized.

Show comment
Hide comment
@Kurira

Kurira 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.

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

This comment has been minimized.

Show comment
Hide comment
@kjbetz

kjbetz May 24, 2016

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

kjbetz commented May 24, 2016

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

@natemcmaster natemcmaster referenced this issue May 24, 2016

Closed

CLI Commands: usability improvements #5188

5 of 7 tasks complete

@bricelam bricelam added the area-tools label May 25, 2016

@ToddThomson

This comment has been minimized.

Show comment
Hide comment
@ToddThomson

ToddThomson May 25, 2016

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.

ToddThomson commented May 25, 2016

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

This comment has been minimized.

Show comment
Hide comment
@natemcmaster

natemcmaster May 25, 2016

Member

@ToddThomson you are probably hitting dotnet/cli#3164. Try setting the top-level emitEntryPoint build option to true.

Member

natemcmaster commented May 25, 2016

@ToddThomson you are probably hitting dotnet/cli#3164. Try setting the top-level emitEntryPoint build option to true.

@ToddThomson

This comment has been minimized.

Show comment
Hide comment
@ToddThomson

ToddThomson commented May 25, 2016

@natemcmaster Yes. That was it.

@rowanmiller

This comment has been minimized.

Show comment
Hide comment
@rowanmiller

rowanmiller May 26, 2016

Member

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.

Member

rowanmiller commented May 26, 2016

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

This comment has been minimized.

Show comment
Hide comment
@ToddThomson

ToddThomson 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.

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.

@divega divega modified the milestones: 1.0.1, 1.0.0 Jun 10, 2016

arthot pushed a commit to arthot/weather-archive that referenced this issue Jun 11, 2016

arthot
Upgrade DAL to RC2
Notes:
* Temporary converted to console, as dotnet doesn't support class library yet. See [issue](aspnet/EntityFrameworkCore#5320)
* Table names now named like DbSets
@HamidMosalla

This comment has been minimized.

Show comment
Hide comment
@HamidMosalla

HamidMosalla Jun 27, 2016

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

HamidMosalla commented Jun 27, 2016

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

@natemcmaster

This comment has been minimized.

Show comment
Hide comment
@natemcmaster

natemcmaster Jun 27, 2016

Member

We are still blocked on .NET Core CLI support for this. dotnet/cli#2645.

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

Member

natemcmaster commented Jun 27, 2016

We are still blocked on .NET Core CLI support for this. dotnet/cli#2645.

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

@arielcloud

This comment has been minimized.

Show comment
Hide comment
@arielcloud

arielcloud Jun 28, 2016

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!

arielcloud commented Jun 28, 2016

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

This comment has been minimized.

Show comment
Hide comment
@natemcmaster

natemcmaster Jun 28, 2016

Member

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

Member

natemcmaster commented Jun 28, 2016

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

@arielcloud

This comment has been minimized.

Show comment
Hide comment
@arielcloud

arielcloud Jun 28, 2016

@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!

arielcloud commented Jun 28, 2016

@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!

@rahamohebbi

This comment has been minimized.

Show comment
Hide comment
@rahamohebbi

rahamohebbi Nov 20, 2016

I would like to be able to have my repository (Entity Framework) classes in a separate class library. Is this possible right now ? if not, when should I expect this to be added to Entity Framework Core library ?

rahamohebbi commented Nov 20, 2016

I would like to be able to have my repository (Entity Framework) classes in a separate class library. Is this possible right now ? if not, when should I expect this to be added to Entity Framework Core library ?

@bricelam

This comment has been minimized.

Show comment
Hide comment
@bricelam

bricelam Nov 20, 2016

Member

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.

Member

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

This comment has been minimized.

Show comment
Hide comment
@mehmetilker

mehmetilker Nov 22, 2016

@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...

mehmetilker commented Nov 22, 2016

@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

This comment has been minimized.

Show comment
Hide comment
@bricelam

bricelam Nov 29, 2016

Member

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.
Member

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

This comment has been minimized.

Show comment
Hide comment
@bricelam

bricelam Nov 29, 2016

Member

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.

Member

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

This comment has been minimized.

Show comment
Hide comment
@rowanmiller

rowanmiller Nov 29, 2016

Member

We'll go with the warning approach

Member

rowanmiller commented Nov 29, 2016

We'll go with the warning approach

@esargent

This comment has been minimized.

Show comment
Hide comment
@esargent

esargent Nov 29, 2016

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.

esargent commented Nov 29, 2016

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

This comment has been minimized.

Show comment
Hide comment
@jmevel

jmevel 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?

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

This comment has been minimized.

Show comment
Hide comment
@bricelam

bricelam Nov 30, 2016

Member

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

Member

bricelam commented Nov 30, 2016

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

@bricelam

This comment has been minimized.

Show comment
Hide comment
@bricelam

bricelam Nov 30, 2016

Member

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.

Member

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

This comment has been minimized.

Show comment
Hide comment
@ErikEJ

ErikEJ Nov 30, 2016

Contributor

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

Contributor

ErikEJ commented Nov 30, 2016

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

@rowanmiller

This comment has been minimized.

Show comment
Hide comment
@rowanmiller

rowanmiller Nov 30, 2016

Member

@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.

Member

rowanmiller commented Nov 30, 2016

@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 referenced this issue Dec 1, 2016

Closed

Update dotnet-ef #28

@bricelam bricelam closed this Dec 2, 2016

@bricelam

This comment has been minimized.

Show comment
Hide comment
@bricelam

bricelam Jan 4, 2017

Member

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.

Member

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

This comment has been minimized.

Show comment
Hide comment
@bricelam

bricelam Jan 5, 2017

Member

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

Member

bricelam commented Jan 5, 2017

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

@Bartmax

This comment has been minimized.

Show comment
Hide comment
@Bartmax

Bartmax 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 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

This comment has been minimized.

Show comment
Hide comment
@Bartmax

Bartmax 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"

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

This comment has been minimized.

Show comment
Hide comment
@qdxiayongming

qdxiayongming Sep 25, 2017

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命令,就可以看到独角兽了。

qdxiayongming commented Sep 25, 2017

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