Skip to content

Commit

Permalink
Document design-time services
Browse files Browse the repository at this point in the history
  • Loading branch information
bricelam committed Oct 22, 2020
1 parent 7a625bc commit 8aec4c9
Show file tree
Hide file tree
Showing 11 changed files with 167 additions and 30 deletions.
4 changes: 2 additions & 2 deletions entity-framework/core/miscellaneous/cli/dbcontext-creation.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ If your startup project uses the [ASP.NET Core Web Host][3] or [.NET Core Generi

The tools first try to obtain the service provider by invoking `Program.CreateHostBuilder()`, calling `Build()`, then accessing the `Services` property.

[!code-csharp[Main](../../../../samples/core/Miscellaneous/CommandLine/ApplicationService.cs)]
[!code-csharp[Main](../../../../samples/core/Miscellaneous/CommandLine/ApplicationService.cs#ApplicationService)]

> [!NOTE]
> When you create a new ASP.NET Core application, this hook is included by default.
Expand All @@ -32,7 +32,7 @@ If the DbContext can't be obtained from the application service provider, the to

You can also tell the tools how to create your DbContext by implementing the `IDesignTimeDbContextFactory<TContext>` interface: If a class implementing this interface is found in either the same project as the derived `DbContext` or in the application's startup project, the tools bypass the other ways of creating the DbContext and use the design-time factory instead.

[!code-csharp[Main](../../../../samples/core/Miscellaneous/CommandLine/BloggingContextFactory.cs)]
[!code-csharp[Main](../../../../samples/core/Miscellaneous/CommandLine/BloggingContextFactory.cs#BloggingContextFactory)]

> [!NOTE]
> Prior to EFCore 5.0 the `args` parameter was unused (see [this issue][8]).
Expand Down
42 changes: 41 additions & 1 deletion entity-framework/core/miscellaneous/cli/services.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,44 @@ uid: core/miscellaneous/cli/services

Some services used by the tools are only used at design time. These services are managed separately from EF Core's runtime services to prevent them from being deployed with your app. To override one of these services (for example the service to generate migration files), add an implementation of `IDesignTimeServices` to your startup project.

[!code-csharp[Main](../../../../samples/core/Miscellaneous/CommandLine/DesignTimeServices.cs)]
[!code-csharp[Main](../../../../samples/core/Miscellaneous/CommandLine/DesignTimeServices.cs#DesignTimeServices)]

## Referencing Microsoft.EntityFrameworkCore.Design

Microsoft.EntityFrameworkCore.Design is a DevelopmentDependency package. This means that the dependency won't flow transitively into other projects, and that you cannot, by default, reference its types.

In order to reference its types and override design-time services, update the PackageReference item's metadata in your project file.

```xml
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9">
<PrivateAssets>all</PrivateAssets>
<!-- Remove IncludeAssets to allow compiling against the assembly -->
<!--<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>-->
</PackageReference>
```

If the package is being referenced transitively via Microsoft.EntityFrameworkCore.Tools, you will need to add an explicit PackageReference to the package and change its metadata.

## List of services

The following is a list of the design-time services.

Service | Description
------------------------------------------------------------------------------------ | -----------
<xref:Microsoft.EntityFrameworkCore.Design.IAnnotationCodeGenerator> | Generates the code for corresponding model annotations.
<xref:Microsoft.EntityFrameworkCore.Design.ICSharpHelper> | Helps with generating C# code.
<xref:Microsoft.EntityFrameworkCore.Design.IPluralizer> | Pluralizes and singularizes words.
<xref:Microsoft.EntityFrameworkCore.Migrations.Design.IMigrationsCodeGenerator> | Generates code for a migration.
<xref:Microsoft.EntityFrameworkCore.Migrations.Design.IMigrationsScaffolder> | The main class for managing migration files.
<xref:Microsoft.EntityFrameworkCore.Scaffolding.IDatabaseModelFactory> | Creates a database model from a database.
<xref:Microsoft.EntityFrameworkCore.Scaffolding.IModelCodeGenerator> | Generates code for a model.
<xref:Microsoft.EntityFrameworkCore.Scaffolding.IProviderConfigurationCodeGenerator> | Generates OnConfiguring code.
<xref:Microsoft.EntityFrameworkCore.Scaffolding.IReverseEngineerScaffolder> | The main class for scaffolding reverse engineered models.

## Using services

These services can also be useful for creating your own tools. For example, when you want to automate part of you design-time workflow.

You can build a service provider containing these services using the AddEntityFrameworkDesignTimeServices and AddDbContextDesignTimeServices extension methods.

[!code-csharp[](../../../../samples/core/Miscellaneous/CommandLine/CustomTools.cs#CustomTools)]
7 changes: 7 additions & 0 deletions samples/core/Miscellaneous/CommandLine/ApplicationService.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;

#region ApplicationService
public class Program
{
public static void Main(string[] args)
Expand All @@ -23,3 +29,4 @@ public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
{
}
}
#endregion
11 changes: 10 additions & 1 deletion samples/core/Miscellaneous/CommandLine/BloggingContextFactory.cs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Infrastructure;

namespace MyProject
{
#region BloggingContextFactory
public class BloggingContextFactory : IDesignTimeDbContextFactory<BloggingContext>
{
public BloggingContext CreateDbContext(string[] args)
Expand All @@ -14,4 +14,13 @@ public BloggingContext CreateDbContext(string[] args)
return new BloggingContext(optionsBuilder.Options);
}
}
#endregion

public class BloggingContext : DbContext
{
public BloggingContext(DbContextOptions<BloggingContext> options)
: base(options)
{
}
}
}
12 changes: 12 additions & 0 deletions samples/core/Miscellaneous/CommandLine/CommandLine.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.9" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.9" PrivateAssets="all" />
</ItemGroup>

</Project>
37 changes: 37 additions & 0 deletions samples/core/Miscellaneous/CommandLine/CustomTools.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.IO;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Migrations.Design;
using Microsoft.Extensions.DependencyInjection;

namespace CommandLine
{
public class CustomTools
{
public static void AddMigration(string migrationName)
{
var projectDir = Directory.GetCurrentDirectory();
var rootNamespace = "ConsoleApp1";
var outputDir = "Migraitons";

#region CustomTools
var db = new MyDbContext();

// Create design-time services
var serviceCollection = new ServiceCollection();
serviceCollection.AddEntityFrameworkDesignTimeServices();
serviceCollection.AddDbContextDesignTimeServices(db);
var serviceProvider = serviceCollection.BuildServiceProvider();

// Add a migration
var migrationsScaffolder = serviceProvider.GetService<IMigrationsScaffolder>();
var migration = migrationsScaffolder.ScaffoldMigration(migrationName, rootNamespace);
migrationsScaffolder.Save(projectDir, migration, outputDir);
#endregion
}
}

class MyDbContext : DbContext
{
}
}
16 changes: 16 additions & 0 deletions samples/core/Miscellaneous/CommandLine/DesignTimeServices.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.EntityFrameworkCore.Migrations.Design;
using Microsoft.Extensions.DependencyInjection;

#region DesignTimeServices
class MyDesignTimeServices : IDesignTimeServices
{
public void ConfigureDesignTimeServices(IServiceCollection services)
=> services.AddSingleton<IMigrationsCodeGenerator, MyMigrationsCodeGenerator>();
}
#endregion

class MyMigrationsCodeGenerator : CSharpMigrationsGenerator
{
public MyMigrationsCodeGenerator(
MigrationsCodeGeneratorDependencies dependencies,
CSharpMigrationsGeneratorDependencies csharpDependencies)
: base(dependencies, csharpDependencies)
{
}
}
42 changes: 20 additions & 22 deletions samples/core/Samples.sln
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,19 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "QueryFilters", "Querying\Qu
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RelatedData", "Querying\RelatedData\RelatedData.csproj", "{CE9050E2-48AE-4CC4-8CCB-E19EE3102C0A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SimpleLogging", "Miscellaneous\Logging\SimpleLogging\SimpleLogging.csproj", "{6A67BD7F-86AA-4F18-ACAF-0420482189AE}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SimpleLogging", "Miscellaneous\Logging\SimpleLogging\SimpleLogging.csproj", "{6A67BD7F-86AA-4F18-ACAF-0420482189AE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CompiledQueries", "CompiledQueries\CompiledQueries.csproj", "{077C2862-467F-4DE0-8412-0F0670C36593}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompiledQueries", "CompiledQueries\CompiledQueries.csproj", "{077C2862-467F-4DE0-8412-0F0670C36593}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Intro", "Intro\Intro.csproj", "{937D4D99-A6FE-459A-A5B8-A96D5D952D42}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Intro", "Intro\Intro.csproj", "{937D4D99-A6FE-459A-A5B8-A96D5D952D42}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NullableReferenceTypes", "Miscellaneous\NullableReferenceTypes\NullableReferenceTypes.csproj", "{0F8779BE-F32A-42A9-B2D7-1974A1D9DD09}"
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NullableReferenceTypes", "Miscellaneous\NullableReferenceTypes\NullableReferenceTypes.csproj", "{0F8779BE-F32A-42A9-B2D7-1974A1D9DD09}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommandLine", "Miscellaneous\CommandLine\CommandLine.csproj", "{EE7AF867-1BC6-4C80-8856-B4DDB975E546}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Schemas", "Schemas", "{0BFEC418-1A37-4960-8488-EA8AFB916EB9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Migrations", "Schemas\Migrations\Migrations.csproj", "{D381F3EE-FEA4-4777-B9CA-7EE7E4C3289E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -233,28 +239,10 @@ Global
{CE9050E2-48AE-4CC4-8CCB-E19EE3102C0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CE9050E2-48AE-4CC4-8CCB-E19EE3102C0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CE9050E2-48AE-4CC4-8CCB-E19EE3102C0A}.Release|Any CPU.Build.0 = Release|Any CPU
{70E581C3-38BB-46CC-9063-ADF9F2B76570}.Release|ARM.ActiveCfg = Release|Any CPU
{70E581C3-38BB-46CC-9063-ADF9F2B76570}.Release|ARM.Build.0 = Release|Any CPU
{70E581C3-38BB-46CC-9063-ADF9F2B76570}.Release|x64.ActiveCfg = Release|Any CPU
{70E581C3-38BB-46CC-9063-ADF9F2B76570}.Release|x64.Build.0 = Release|Any CPU
{70E581C3-38BB-46CC-9063-ADF9F2B76570}.Release|x86.ActiveCfg = Release|Any CPU
{70E581C3-38BB-46CC-9063-ADF9F2B76570}.Release|x86.Build.0 = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|ARM.ActiveCfg = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|ARM.Build.0 = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|x64.ActiveCfg = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|x64.Build.0 = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|x86.ActiveCfg = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Debug|x86.Build.0 = Debug|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|Any CPU.Build.0 = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|ARM.ActiveCfg = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|ARM.Build.0 = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|x64.ActiveCfg = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|x64.Build.0 = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|x86.ActiveCfg = Release|Any CPU
{6A67BD7F-86AA-4F18-ACAF-0420482189AE}.Release|x86.Build.0 = Release|Any CPU
{077C2862-467F-4DE0-8412-0F0670C36593}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{077C2862-467F-4DE0-8412-0F0670C36593}.Debug|Any CPU.Build.0 = Debug|Any CPU
{077C2862-467F-4DE0-8412-0F0670C36593}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand All @@ -267,6 +255,14 @@ Global
{0F8779BE-F32A-42A9-B2D7-1974A1D9DD09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F8779BE-F32A-42A9-B2D7-1974A1D9DD09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F8779BE-F32A-42A9-B2D7-1974A1D9DD09}.Release|Any CPU.Build.0 = Release|Any CPU
{EE7AF867-1BC6-4C80-8856-B4DDB975E546}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EE7AF867-1BC6-4C80-8856-B4DDB975E546}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EE7AF867-1BC6-4C80-8856-B4DDB975E546}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EE7AF867-1BC6-4C80-8856-B4DDB975E546}.Release|Any CPU.Build.0 = Release|Any CPU
{D381F3EE-FEA4-4777-B9CA-7EE7E4C3289E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D381F3EE-FEA4-4777-B9CA-7EE7E4C3289E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D381F3EE-FEA4-4777-B9CA-7EE7E4C3289E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D381F3EE-FEA4-4777-B9CA-7EE7E4C3289E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -304,6 +300,8 @@ Global
{CE9050E2-48AE-4CC4-8CCB-E19EE3102C0A} = {1AD64707-0BE0-48B0-A803-916FF96DCB4F}
{6A67BD7F-86AA-4F18-ACAF-0420482189AE} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{0F8779BE-F32A-42A9-B2D7-1974A1D9DD09} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{EE7AF867-1BC6-4C80-8856-B4DDB975E546} = {85AFD7F1-6943-40FE-B8EC-AA9DBB42CCA6}
{D381F3EE-FEA4-4777-B9CA-7EE7E4C3289E} = {0BFEC418-1A37-4960-8488-EA8AFB916EB9}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {20C98D35-54EF-46A6-8F3B-1855C1AE4F70}
Expand Down
5 changes: 3 additions & 2 deletions samples/core/Schemas/Migrations/MigrationTableNameContext.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;

namespace Migrations
{
public class MigrationTableNameContext : DbContext
{
readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample";

#region TableNameContext
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options.UseSqlServer(
connectionString,
_connectionString,
x => x.MigrationsHistoryTable("__MyMigrationsHistory", "mySchema"));
#endregion
}
Expand Down
11 changes: 11 additions & 0 deletions samples/core/Schemas/Migrations/Migrations.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.9" />
</ItemGroup>

</Project>
10 changes: 8 additions & 2 deletions samples/core/Schemas/Migrations/MyHistoryRepository.cs
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.EntityFrameworkCore.SqlServer.Migrations.Internal;

#pragma warning disable EF1001

namespace Migrations
{
public class MyHistoryRepositoryContext : DbContext
{
readonly string _connectionString = @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=Sample";

#region HistoryRepositoryContext
protected override void OnConfiguring(DbContextOptionsBuilder options)
=> options
.UseSqlServer(connectionString)
.UseSqlServer(_connectionString)
.ReplaceService<IHistoryRepository, MyHistoryRepository>();
#endregion
}
Expand Down

0 comments on commit 8aec4c9

Please sign in to comment.