Sunday, March 22, 2020

Maintain Entity Framework Core DbContext in a Separate Project

Usually, when I have an application that has an API and a Database managed with EF, I really don't like to have the Application DbContext and all the Migrations inside the API project. It's actually very easy to split it out, this is a quick post on how we can maintain Entity Framework Core DbContext in a separate project. 

I have created a Solution WebApplication1 which has 2 projects, one is ASP.NET Core Web API and the other one just a .NET Core Class Library where I am maintaining Database specific things.

Solution
For WebApplication1.Data project, I have installed Microsoft.EntityFrameworkCore.SqlServer package and my WebApplication1.Data.csproj looks like this.
<Project Sdk="Microsoft.NET.Sdk">
 
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="3.1.2" />
  </ItemGroup>
 
</Project>
And I have a very simple ApplicationDbContext.
using Microsoft.EntityFrameworkCore;
 
namespace WebApplication1.Data
{
    public class Employee
    {
        public int Id { getset; }
        public string FirstName { getset; }
        public string LastName { getset; }
    }
 
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions options) : base(options)
        {
        }
 
        public DbSet<Employee> Employees { getset; }
    }
}
Then inside my WebApplication1.Api project, I have referenced WebApplication1.Data project and installed Microsoft.EntityFrameworkCore.Tools package there. This is very much required. This is my WebApplication1.Api.csproj looks like.
<Project Sdk="Microsoft.NET.Sdk.Web">
 
  <PropertyGroup>
    <TargetFramework>netcoreapp3.1</TargetFramework>
  </PropertyGroup>
 
  <ItemGroup>
    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.2" />
  </ItemGroup>
 
  <ItemGroup>
    <ProjectReference Include="..\WebApplication1.Data\WebApplication1.Data.csproj" />
  </ItemGroup>
 
</Project>
I have the Connection String inside appsettings.json and setup the ApplicationDbContext inside Startup.ConfigureServices method.
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
 
    services.AddDbContext<ApplicationDbContext>(options =>
    {
        options.UseSqlServer(Configuration.GetConnectionString("ApplicationDbContext"));
    });
}
So basically that's it. Using the Package Manager Console in Visual Studio, I can run Add-Migration command targetting WebApplication.Data project.
Package Manager Console
Or alternatively using dotnet ef global tool (you need to install the tool first). The parameters are self-explanatory.
 dotnet ef migrations add Initial --project .\WebApplication1.Data\WebApplication1.Data.csproj --startup-project .\WebApplication1.Api\WebApplication1.Api.csproj                                                
And it will add all the Migrations inside WebApplication.Data project which is what I wanted.
Migrations
To apply the migrations,  again using the Package Manager Console in Visual Studio, I can run Update-Database command targetting WebApplication.Data. Or using the CLI,
dotnet ef database update --project .\WebApplication1.Data\WebApplication1.Data.csproj --startup-project .\WebApplication1.Api\WebApplication1.Api.csproj
That was easy.

Happy Coding.

Regards,
Jaliya

Wednesday, March 18, 2020

dotnet ef Command Doesn't Work inside a Docker Container

I was facing this issue where I needed to run dotnet ef command inside a docker container and it's not recognizing the command.

Basically, my Dockerfile looked something like.
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
RUN dotnet tool install -g dotnet-ef --version 3.1.1 
RUN export PATH="$PATH:/root/.dotnet/tools"
RUN dotnet ef
I was installing dotnet-ef command, and I was setting the path. But still, I was getting this error,
Could not execute because the specified command or file was not found.
Possible reasons for this include:
  * You misspelled a built-in dotnet command.
  * You intended to execute a .NET Core program, but dotnet-ef does not exist.
  * You intended to run a global tool, but a dotnet-prefixed executable with this name could not be found on the PATH.
I have been trying different things for a couple of hours, finally, thanks to Petr Onderka with his brilliant answer managed to solve the issue. The reason is for it's to not work is the environment variables set by export don't survive across directives. What we need to do is to use the ENV directive instead.

And this worked.
FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
RUN dotnet tool install -g dotnet-ef --version 3.1.1 
ENV PATH $PATH:/root/.dotnet/tools
RUN dotnet ef --version
Thanks Petr Onderka again.

I hope this saves someone's time.

Happy Coding.

Regards,
Jaliya

Thursday, March 5, 2020

Visual C# Technical Guru - January 2020

Another month as a judge in Microsoft TechNet Guru Awards under Visual C# category. The TechNet Guru Awards celebrate the technical articles on Microsoft TechNet. 

Visual C# Technical Guru - January 2020
Happy Coding. 

Regards,
Jaliya