Skip to content

Commit e72828a

Browse files
committed
feat: adds DI methods for easy injection
1 parent 605a6bf commit e72828a

18 files changed

Lines changed: 526 additions & 156 deletions

ProjectR.Sample/Controllers/ProductsController.cs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using ProjectR.Sample.Domain;
55
using ProjectR.Sample.Application.DTOs;
66
using ProjectR.Sample.Application.Mappers;
7+
using ProjectR.Services;
78

89
namespace ProjectR.Sample.Api.Controllers
910
{
@@ -14,9 +15,11 @@ public class ProductsController : ControllerBase
1415

1516
// In a real app, this would be a repository connected to a database.
1617
private static readonly List<Product> _products = new();
18+
private readonly IMapperResolver _mapperResolver;
1719

18-
public ProductsController()
20+
public ProductsController(IMapperResolver mapperResolver)
1921
{
22+
_mapperResolver = mapperResolver;
2023
}
2124

2225
[HttpGet("{id}")]
@@ -28,25 +31,21 @@ public ActionResult<ProductDto> GetById(Guid id)
2831
return NotFound();
2932
}
3033

31-
// --- USAGE OF ProjectAs ---
32-
// The mapper handles the complex projection, including the nested
33-
// Money object and the collection of Reviews.
34-
var productDto = product.ProjectAs<ProductDto, Product, ProductDtoMapper>();
34+
var mapper = _mapperResolver.GetMapper<Product, ProductDto>();
35+
var productDto = product.Project<ProductDto, Product, ProductDtoMapper>();
3536
return Ok(productDto);
3637
}
3738

3839
[HttpPost]
3940
public IActionResult CreateProduct([FromBody] CreateProductDto createDto)
4041
{
41-
// --- USAGE OF Build ---
42-
// The mapper uses its "zero-config" policy to find the `Product.Create`
43-
// factory method and constructs a valid domain entity.
44-
// Note: A custom policy would be needed if the DTO shape was very different.
45-
var newProduct = createDto.Build<CreateProductDto, Product, CreateProductMapper>();
42+
var newProduct = _mapperResolver
43+
.GetMapper<Product, CreateProductDto>()
44+
.Build(createDto);
4645

4746
_products.Add(newProduct);
4847

49-
return CreatedAtAction(nameof(GetById), new { id = newProduct.Id }, new ProductDtoMapper().ProjectAs(newProduct));
48+
return CreatedAtAction(nameof(GetById), new { id = newProduct.Id }, _mapperResolver.GetMapper<Product, ProductDto>().Project(newProduct));
5049
}
5150

5251
[HttpPut("{id}")]
@@ -58,11 +57,10 @@ public IActionResult UpdateProduct(Guid id, [FromBody] UpdateProductDto updateDt
5857
return NotFound();
5958
}
6059

61-
// --- USAGE OF ApplyTo ---
62-
// The mapper applies the changes from the DTO to the existing entity.
63-
// The default policy will map matching properties (`Name`) and ignore others (`Id`).
64-
new ProductDtoMapper().ApplyTo(new ProductDto { Name = updateDto.Name }, productToUpdate);
65-
// In a real app, you would call _repository.SaveChanges() here.
60+
_mapperResolver.GetMapper<Product, UpdateProductDto>().Apply(updateDto, productToUpdate);
61+
62+
_products.RemoveAll(p => p.Id == id);
63+
_products.Add(productToUpdate);
6664

6765
return NoContent();
6866
}

ProjectR.Sample/Controllers/WeatherForecastController.cs

Lines changed: 0 additions & 33 deletions
This file was deleted.

ProjectR.Sample/Domain/Domain.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public class Review
2828
public class Product
2929
{
3030
public Guid Id { get; private set; }
31-
public string Name { get; private set; }
31+
public string Name { get; set; }
3232
public Money Price { get; private set; }
3333
private readonly List<Review> _reviews = new();
3434
public IReadOnlyList<Review> Reviews => _reviews.ToList();
@@ -59,11 +59,11 @@ public static Product Create(string name, Money? price = null)
5959
/// <summary>
6060
/// A domain method to update the product's name.
6161
/// </summary>
62-
public void ChangeName(string newName)
62+
public void ChangeName(string name)
6363
{
64-
if (!string.IsNullOrWhiteSpace(newName))
64+
if (!string.IsNullOrWhiteSpace(name))
6565
{
66-
Name = newName;
66+
Name = name;
6767
}
6868
}
6969

ProjectR.Sample/Mappers/Mappers.cs

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,9 @@
44

55
namespace ProjectR.Sample.Application.Mappers
66
{
7-
///// <summary>
8-
///// A simple mapper for the Money value object.
9-
///// ProjectR handles this with its "zero-config" default policy.
10-
///// </summary>
11-
//public partial class MoneyMapper : Mapper<Money, MoneyDto> { }
7+
public partial class UpdateProductMapper : Mapper<Product, UpdateProductDto> {
128

13-
///// <summary>
14-
///// A simple mapper for the Review entity.
15-
///// Also handled by the "zero-config" default policy.
16-
///// </summary>
17-
//public partial class ReviewMapper : Mapper<Review, ReviewDto> { }
18-
19-
///// <summary>
20-
///// This mapper handles the standard projection from the Product entity to the ProductDto.
21-
///// It's "zero-config" because it relies on the MoneyMapper and ReviewMapper for its complex properties.
22-
///// </summary>
23-
//public partial class ProductMapper : Mapper<Product, ProductDto> { }
9+
}
2410

2511
/// <summary>
2612
/// A specialized mapper dedicated to creating a Product entity from a CreateProductDto.

ProjectR.Sample/Program.cs

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,51 @@
1+
using Microsoft.OpenApi.Models;
2+
using ProjectR.DI;
3+
using ProjectR.Sample.Application.DTOs;
4+
using System.Reflection;
5+
16
var builder = WebApplication.CreateBuilder(args);
27

38
// Add services to the container.
4-
59
builder.Services.AddControllers();
610

11+
// Aggiungi la scansione e registrazione dei mapper
12+
builder.Services.AddMappers(typeof(ProductDto).Assembly);
13+
14+
// *** 1. Configurazione avanzata di Swagger/OpenAPI ***
15+
builder.Services.AddEndpointsApiExplorer();
16+
builder.Services.AddSwaggerGen(options =>
17+
{
18+
// Aggiunge informazioni generali all'interfaccia di Swagger
19+
options.SwaggerDoc("v1", new OpenApiInfo
20+
{
21+
Version = "v1",
22+
Title = "ProjectR Sample API",
23+
Description = "An ASP.NET Core Web API for managing Products and Reviews."
24+
});
25+
26+
// Configura Swashbuckle per usare i commenti XML del codice sorgente
27+
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
28+
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
29+
});
30+
31+
732
var app = builder.Build();
833

34+
app.UseStaticFiles();
35+
936
// Configure the HTTP request pipeline.
37+
// *** 2. Abilita il middleware di Swagger solo in ambiente di sviluppo ***
38+
if (app.Environment.IsDevelopment())
39+
{
40+
app.UseSwagger();
41+
// Rende l'interfaccia di Swagger disponibile alla radice dell'applicazione (es. http://localhost:5033)
42+
app.UseSwaggerUI(options =>
43+
{
44+
options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
45+
options.RoutePrefix = string.Empty;
46+
});
47+
}
48+
1049

1150
app.UseHttpsRedirection();
1251

@@ -15,3 +54,4 @@
1554
app.MapControllers();
1655

1756
app.Run();
57+

ProjectR.Sample/ProjectR.Sample.csproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,19 @@
44
<TargetFramework>net9.0</TargetFramework>
55
<Nullable>enable</Nullable>
66
<ImplicitUsings>enable</ImplicitUsings>
7+
<GenerateDocumentationFile>true</GenerateDocumentationFile>
78
</PropertyGroup>
89

910
<ItemGroup>
10-
<ProjectReference Include="..\ProjectR\ProjectR.csproj"
11-
OutputItemType="Analyzer" />
11+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="9.0.4" />
12+
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="9.0.4" />
13+
</ItemGroup>
14+
15+
<ItemGroup>
16+
<ProjectReference Include="..\ProjectR\ProjectR.csproj">
17+
<OutputItemType>Analyzer</OutputItemType>
18+
<ReferenceOutputAssembly>true</ReferenceOutputAssembly>
19+
</ProjectReference>
1220
</ItemGroup>
1321

1422
</Project>

ProjectR.Sample/ProjectR.Sample.http

Lines changed: 0 additions & 6 deletions
This file was deleted.

ProjectR.Sample/Properties/launchSettings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"http": {
55
"commandName": "Project",
66
"dotnetRunMessages": true,
7-
"launchBrowser": false,
7+
"launchBrowser": true,
88
"applicationUrl": "http://localhost:5033",
99
"environmentVariables": {
1010
"ASPNETCORE_ENVIRONMENT": "Development"
@@ -13,7 +13,7 @@
1313
"https": {
1414
"commandName": "Project",
1515
"dotnetRunMessages": true,
16-
"launchBrowser": false,
16+
"launchBrowser": true,
1717
"applicationUrl": "https://localhost:7186;http://localhost:5033",
1818
"environmentVariables": {
1919
"ASPNETCORE_ENVIRONMENT": "Development"

ProjectR.Sample/WeatherForecast.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

ProjectR/Builders/CodeBuilder.cs

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,8 @@ private void BuildProjectAsMethod(INamedTypeSymbol mapperSymbol, MappingPlan pla
9494
{
9595
var sourceTypeName = plan.SourceType.ToDisplayString();
9696
var destTypeName = plan.DestinationType.ToDisplayString();
97-
BuildXmlDoc(mapperSymbol, "ProjectAs");
98-
Indent(); _sb.AppendLine($"public override {destTypeName} ProjectAs({sourceTypeName} source)");
97+
BuildXmlDoc(mapperSymbol, "Project");
98+
Indent(); _sb.AppendLine($"public override {destTypeName} Project({sourceTypeName} source)");
9999
Indent(); _sb.AppendLine("{");
100100
_indentationLevel++;
101101
GenerateNullCheck("source", destTypeName);
@@ -124,13 +124,14 @@ private void BuildApplyToMethod(INamedTypeSymbol mapperSymbol, MappingPlan plan)
124124
{
125125
var sourceTypeName = plan.SourceType.ToDisplayString();
126126
var destTypeName = plan.DestinationType.ToDisplayString();
127-
BuildXmlDoc(mapperSymbol, "ApplyTo");
128-
Indent(); _sb.AppendLine($"public override void ApplyTo({sourceTypeName} source, {destTypeName} destination)");
127+
BuildXmlDoc(mapperSymbol, "Apply");
128+
Indent(); _sb.AppendLine($"public override void Apply({sourceTypeName} source, {destTypeName} destination)");
129129
Indent(); _sb.AppendLine("{");
130130
_indentationLevel++;
131131
Indent(); _sb.AppendLine("if (source is null || destination is null) return;");
132132
_sb.AppendLine();
133133
GenerateMappingInstructions("source", "destination", plan, isApplyTo: true);
134+
Indent(); _sb.AppendLine("ApplyToRefiner(destination, source);");
134135
_indentationLevel--;
135136
Indent(); _sb.AppendLine("}");
136137
}
@@ -169,7 +170,9 @@ private void GenerateCreationBlock(string variableName, ITypeSymbol variableType
169170
_sb.AppendLine($"new {variableType.ToDisplayString()}()");
170171
break;
171172
}
172-
_sb.Append($", {sourceVarName});");
173+
Indent(); _sb.Append($", {sourceVarName});");
174+
_indentationLevel--;
175+
_sb.AppendLine();
173176

174177
}
175178

@@ -260,12 +263,12 @@ private string GetLambdaParameterName(LambdaExpressionSyntax lambda)
260263

261264
private string GetNestedMethodName(ITypeSymbol? sourceType, ITypeSymbol? destinationType, bool isApplyTo)
262265
{
263-
if (sourceType == null || destinationType == null) return "ProjectAs";
266+
if (sourceType == null || destinationType == null) return "Project";
264267
bool sourceIsDto = sourceType.Name.EndsWith("Dto"), destIsDto = destinationType.Name.EndsWith("Dto");
265-
if (isApplyTo) return "ApplyTo";
266-
if (!sourceIsDto && destIsDto) return "ProjectAs";
268+
if (isApplyTo) return "Apply";
269+
if (!sourceIsDto && destIsDto) return "Project";
267270
if (sourceIsDto && !destIsDto) return "Build";
268-
return "ProjectAs";
271+
return "Project";
269272
}
270273

271274
private ITypeSymbol? GetCollectionElementType(ITypeSymbol type)

0 commit comments

Comments
 (0)