dinnerplanner-deluxe / DinnerPlanner.API
bryanbalmer's picture
The backend should be in dotnet using domain driven design
1a90b46 verified
Raw
History Blame Contribute Delete
4.34 kB
```csharp
// DinnerPlanner.API (ASP.NET Core Web API)
// Domain Layer (DDD Core)
public class Recipe : Entity<Guid>
{
public string Name { get; private set; }
public string Description { get; private set; }
public string Instructions { get; private set; }
private readonly List<Ingredient> _ingredients = new();
public IReadOnlyCollection<Ingredient> Ingredients => _ingredients.AsReadOnly();
private readonly List<Tag> _tags = new();
public IReadOnlyCollection<Tag> Tags => _tags.AsReadOnly();
private Recipe() { } // For EF Core
public Recipe(string name, string description, string instructions)
{
Id = Guid.NewGuid();
Name = name;
Description = description;
Instructions = instructions;
}
public void AddIngredient(string name)
{
_ingredients.Add(new Ingredient(name));
}
public void AddTag(string name)
{
_tags.Add(new Tag(name));
}
}
public class Ingredient : ValueObject
{
public string Name { get; }
public Ingredient(string name)
{
Name = name;
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Name;
}
}
public class Tag : ValueObject
{
public string Name { get; }
public Tag(string name)
{
Name = name;
}
protected override IEnumerable<object> GetEqualityComponents()
{
yield return Name;
}
}
// Application Layer (MediatR Handlers)
public class GetRecipesQuery : IRequest<List<RecipeDto>> { }
public class GetRecipesQueryHandler : IRequestHandler<GetRecipesQuery, List<RecipeDto>>
{
private readonly IRecipeRepository _repository;
public GetRecipesQueryHandler(IRecipeRepository repository)
{
_repository = repository;
}
public async Task<List<RecipeDto>> Handle(GetRecipesQuery request, CancellationToken cancellationToken)
{
var recipes = await _repository.GetAllAsync();
return recipes.Select(r => new RecipeDto
{
Id = r.Id,
Name = r.Name,
Description = r.Description,
Ingredients = r.Ingredients.Select(i => i.Name).ToList(),
Instructions = r.Instructions,
Tags = r.Tags.Select(t => t.Name).ToList()
}).ToList();
}
}
// Infrastructure Layer (EF Core)
public class RecipeRepository : IRecipeRepository
{
private readonly DinnerPlannerDbContext _context;
public RecipeRepository(DinnerPlannerDbContext context)
{
_context = context;
}
public async Task AddAsync(Recipe recipe)
{
await _context.Recipes.AddAsync(recipe);
await _context.SaveChangesAsync();
}
public async Task<List<Recipe>> GetAllAsync()
{
return await _context.Recipes
.Include(r => r.Ingredients)
.Include(r => r.Tags)
.ToListAsync();
}
}
// API Layer (Controllers)
[ApiController]
[Route("api/[controller]")]
public class RecipesController : ControllerBase
{
private readonly IMediator _mediator;
public RecipesController(IMediator mediator)
{
_mediator = mediator;
}
[HttpGet]
public async Task<ActionResult<List<RecipeDto>>> Get()
{
var recipes = await _mediator.Send(new GetRecipesQuery());
return Ok(recipes);
}
[HttpPost]
public async Task<ActionResult<RecipeDto>> Create(CreateRecipeCommand command)
{
var recipe = await _mediator.Send(command);
return CreatedAtAction(nameof(Get), new { id = recipe.Id }, recipe);
}
}
// Startup Configuration
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<DinnerPlannerDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddScoped<IRecipeRepository, RecipeRepository>();
services.AddMediatR(typeof(GetRecipesQueryHandler));
services.AddControllers();
services.AddSwaggerGen();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseEndpoints(endpoints => endpoints.MapControllers());
app.UseSwagger();
app.UseSwaggerUI();
}
}
```