I work in an environment where applications are typically already stood up and so I have never had to setup the "guts" of a C# web application. However, wanting to learn this, I decided to create a .NET 6 Web API project, a .NET 6 Class Library project, and a .NET 4.8.1 Database project.
My Web API project only has the controllers using the MVC pattern. My Class Library project is my "domain" layer where I have my models, services (aka domains), and database queries. My Database project allows me to manage my database schema and any migrations.
In my class library I have setup my DbContext as well as a query, service, and model for an "Example" entity (which only has id and name fields) that look like this:
// DbContext
using MyApplication.Domain.Models;
using Microsoft.EntityFrameworkCore;
namespace MyApplication.Domain
{
public class MyApplicationDbContext : DbContext
{
public DbSet<ExampleModel> Examples { get; set; }
MyApplicationDbContext(DbContextOptions<MyApplicationDbContext> options) : base(options) { }
}
}
// Query
using MyApplication.Domain.Models;
namespace MyApplication.Domain.Queries
{
public class ExampleQuery
{
private readonly MyApplicationDbContext _context;
public ExampleQuery(MyApplicationDbContext context)
{
_context = context;
}
public IEnumerable<ExampleModel> Query(Dictionary<string, dynamic>? filter = null)
{
filter ??= new Dictionary<string, dynamic>();
var records = _context.Examples.AsQueryable();
if (filter.ContainsKey("ExampleId"))
{
Guid exampleId = filter["ExampleId"];
records = records.Where(record => record.ExampleId == exampleId);
}
return records;
}
}
}
// Service
using MyApplication.Domain.Exceptions;
using MyApplication.Domain.Models;
using MyApplication.Domain.Queries;
namespace MyApplication.Domain.Services
{
public class ExampleService
{
private readonly ExampleQuery _exampleQuery;
public ExampleService(ExampleQuery exampleQuery)
{
_exampleQuery = exampleQuery;
}
public IEnumerable<ExampleModel> GetAll()
{
return _exampleQuery.Query();
}
public ExampleModel Get(Guid id)
{
var records = _exampleQuery.Query(new Dictionary<string, dynamic>
{
{ "ExampleId", id }
});
if (!records.Any())
{
throw new NotFound404("There aren't any records by that id");
}
if (records.Count() > 1)
{
throw new Conflict409("There are multiple records with that id");
}
return records.Single();
}
}
}
// Model
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MyApplication.Domain.Models
{
public class ExampleModel
{
[Key]
[Required]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid ExampleId { get; set; }
[Required]
[MaxLength(64)]
public string? ExampleName { get; set; }
}
}
Then in my Web API project, I setup the dependency injection using the following in my Program.cs (using top level statements):
builder.Services.AddDbContext<MyApplicationDbContext>(dbContextOptions => dbContextOptions.UseSqlServer(builder.Configuration.GetValue<string>("ConnectionStrings:MyApplication")));
builder.Services.AddSingleton<ExampleQuery>();
builder.Services.AddSingleton<ExampleService>();
The issue is that my Web API project fails to run because ExampleQuery injects the MyApplicationDbContext with the error:
A suitable constructor for type
‘MyApplication.Domain.MyApplicationDbContext’ could not be located.
Ensure the type is concrete and services are registered for all
parameters of a public constructor.
Again, I’m not very familiar with setting up projects from scratch so I’m not certain how to resolve this dependency issue.
>Solution :
Your MyApplicationDbContext has private constructor, make it public
public class MyApplicationDbContext : DbContext
{
public DbSet<ExampleModel> Examples { get; set; }
public MyApplicationDbContext(DbContextOptions<MyApplicationDbContext> options) : base(options) { }
}