json-api-dotnet / JsonApiDotNetCore

A framework for building JSON:API compliant REST APIs using ASP.NET and Entity Framework Core.
https://www.jsonapi.net
MIT License
686 stars 159 forks source link

No DbContext was found in assembly. #1200

Closed ail-milan closed 2 years ago

ail-milan commented 2 years ago

DESCRIPTION

I have created a solution. which have 2 projects,

  1. Project A (WebAPI) - .NET 6.0
  2. Project B (Class Library c#) - .NET 6.0

Now what happed is my DbContext is in the Project B, all my DB related stuff is in the Project B All my controllers are in the Project A. Project A has a reference to Project B.

Project A Program.cs content ...

builder.Services.AddDbContext<DatabaseContext>();
// Json:API config
builder.Services.AddJsonApi<DatabaseContext>();

Project B DatabaseContext.cs content ...

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    string connectionString = _configuration.GetConnectionString("DBConnection");
    optionsBuilder.UseSqlServer(connectionString, b => b.MigrationsAssembly("Project A"));
}

Now try to create Migrations using below command...

dotnet-ef migrations add Init_DB

it will be giving me error ...

No DbContext was found in assembly
bkoelman commented 2 years ago

This sounds like an EF Core problem. JADNC just consumes the model to serve API requests, it has nothing to do with migrations. You'll probably get the same error when not using JADNC at all. Can you verify that?

ail-milan commented 2 years ago

If I remove the line

builder.Services.AddJsonApi<DatabaseContext>();

it will work perfectly ...

bkoelman commented 2 years ago

I'm quite surprised to hear that. I'm willing to help and find the root cause. For that I'm going to need to reproduce this, but my knowledge of how migrations work is superficial. It would help if you can provide a minimal repro project (zip or GitHub repro) with the exact steps to get to the error (for example, from which directory you're running the command). It would also help to include the versions used (OS, .NET, EF, etc)

ThomasBarnekow commented 2 years ago

Wouldn't you normally have to specify the project that contains the DbContext if is it not in the main (startup) one? EF Core migrations will not find it otherwise.

bkoelman commented 2 years ago

I've tried to set things up based on your description, but am unable to reproduce the problem.

You can find the project here: MigrationsDemo.zip. It contains a git repository, so you can review my changes or revert individual steps.

To start the PostgreSQL database in a docker container, run this script. When running the application, it returns the expected error that the database does not yet exist.

Details ```json { "links": { "self": "https://localhost:7233/people", "first": "https://localhost:7233/people" }, "errors": [ { "id": "a4bdd24f-aa2a-4bfe-91c0-1ca59841bdaf", "status": "500", "title": "An unhandled error occurred while processing this request.", "detail": "3D000: database \"MigrationsExample\" does not exist", "meta": { "stackTrace": [ "Npgsql.PostgresException (0x80004005): 3D000: database \"MigrationsExample\" does not exist", " at async IBackendMessage Npgsql.Internal.NpgsqlConnector.ReadMessage(DataRowLoadingMode dataRowLoadingMode)+ReadMessageLong(?)", " at async Task Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken)+OpenCore(?)", " at async Task Npgsql.Internal.NpgsqlConnector.Open(NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken)", " at async ValueTask Npgsql.ConnectorPool.OpenNewConnector(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken)", " at async ValueTask Npgsql.ConnectorPool.Get(NpgsqlConnection conn, NpgsqlTimeout timeout, bool async, CancellationToken cancellationToken)+RentAsync(?)", " at async void Npgsql.NpgsqlConnection.Open()+OpenAsync(?)", " at async Task Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenInternalAsync(bool errorsExpected, CancellationToken cancellationToken) x 2", " at async Task Microsoft.EntityFrameworkCore.Storage.RelationalConnection.OpenAsync(CancellationToken cancellationToken, bool errorsExpected)", " at async Task Microsoft.EntityFrameworkCore.Storage.RelationalCommand.ExecuteReaderAsync(RelationalCommandParameterObject parameterObject, CancellationToken cancellationToken)", " at async Task Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable+AsyncEnumerator.InitializeReaderAsync(AsyncEnumerator enumerator, CancellationToken cancellationToken)", " at async Task Npgsql.EntityFrameworkCore.PostgreSQL.Storage.Internal.NpgsqlExecutionStrategy.ExecuteAsync(TState state, Func> operation, Func>> verifySucceeded, CancellationToken cancellationToken)", " at async ValueTask Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable+AsyncEnumerator.MoveNextAsync()", " at async Task> Microsoft.EntityFrameworkCore.EntityFrameworkQueryableExtensions.ToListAsync(IQueryable source, CancellationToken cancellationToken) x 2", " at async Task> JsonApiDotNetCore.Repositories.EntityFrameworkCoreRepository.GetAsync(QueryLayer queryLayer, CancellationToken cancellationToken)", " at object CallSite.Target(Closure, CallSite, object)", " at TRet System.Dynamic.UpdateDelegates.UpdateAndExecute1(CallSite site, T0 arg0)", " at async Task> JsonApiDotNetCore.Repositories.ResourceRepositoryAccessor.GetAsync(QueryLayer queryLayer, CancellationToken cancellationToken) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/Repositories/ResourceRepositoryAccessor.cs:line 36", " at async Task> JsonApiDotNetCore.Services.JsonApiResourceService.GetAsync(CancellationToken cancellationToken)", " at async Task JsonApiDotNetCore.Controllers.BaseJsonApiController.GetAsync(CancellationToken cancellationToken)", " at async Task JsonApiDotNetCore.Controllers.JsonApiController.GetAsync(CancellationToken cancellationToken) in C:/projects/jsonapidotnetcore/src/JsonApiDotNetCore/Controllers/JsonApiController.cs:line 46", " at async ValueTask Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor+TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, object controller, object[] arguments)", " at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeActionMethodAsync()+Awaited(?)", " at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeNextActionFilterAsync()+Awaited(?)", " at void Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)", " at Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(ref State next, ref Scope scope, ref object state, ref bool isCompleted)", " at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.InvokeInnerFilterAsync()+Awaited(?)", " at async Task Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeNextExceptionFilterAsync()+Awaited(?)", " Exception data:", " Severity: FATAL", " SqlState: 3D000", " MessageText: database \"MigrationsExample\" does not exist", " File: postinit.c", " Line: 875", " Routine: InitPostgres" ] } } ] } ```

Then, I'm running the below commands:

PS D:\Bart\Source\Projects\MigrationsDemo\WebApi> dotnet tool restore
Tool 'dotnet-ef' (version '6.0.9') was restored. Available commands: dotnet-ef

Restore was successful.
PS D:\Bart\Source\Projects\MigrationsDemo\WebApi> dotnet dotnet-ef migrations add InitDB
Build started...
Build succeeded.
Done. To undo this action, use 'ef migrations remove'
PS D:\Bart\Source\Projects\MigrationsDemo\WebApi> dotnet dotnet-ef database update
Build started...
Build succeeded.
Applying migration '20221007210202_InitDB'.
Done.

And now the application starts normally (the table is empty, obviously):

{
  "links": {
    "self": "https://localhost:7233/people",
    "first": "https://localhost:7233/people"
  },
  "data": []
}

VERSIONS USED

ail-milan commented 2 years ago

I have just tried with your given sample code, and it will work perfectly!! Here I have created sample from your code, and it is working fine, DemoAPI Project

Closing this issue!! Thanks for guiding me.

bkoelman commented 2 years ago

Glad to hear this works for you. And thanks for sharing your project.