@re-shell/cli
Version:
Full-stack development platform uniting microservices and microfrontends. Build complete applications with .NET (ASP.NET Core Web API, Minimal API), Java (Spring Boot, Quarkus, Micronaut, Vert.x), Rust (Actix-Web, Warp, Rocket, Axum), Python (FastAPI, Dja
1,532 lines (1,239 loc) • 86.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.aspnetAutoMapperTemplate = void 0;
exports.aspnetAutoMapperTemplate = {
id: 'aspnet-automapper',
name: 'aspnet-automapper',
displayName: 'ASP.NET Core with AutoMapper',
description: 'Enterprise .NET API with AutoMapper object-to-object mapping',
language: 'csharp',
framework: 'aspnet-automapper',
version: '1.0.0',
tags: ['aspnet', 'automapper', 'dto', 'mapping', 'enterprise'],
port: 5000,
dependencies: {},
features: ['authentication', 'database', 'validation', 'logging', 'testing'],
files: {
// Project file
'{{serviceName}}.csproj': `<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="8.0.0" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="8.0.0" />
<PackageReference Include="AutoMapper" Version="12.0.1" />
<PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="12.0.1" />
<PackageReference Include="AutoMapper.EF6" Version="2.1.1" />
<PackageReference Include="FluentValidation.AspNetCore" Version="11.3.0" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.0" />
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.0" />
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
</ItemGroup>
</Project>`,
// Program.cs
'Program.cs': `using {{serviceName}}.Data;
using {{serviceName}}.Services;
using {{serviceName}}.Models;
using {{serviceName}}.DTOs;
using {{serviceName}}.Profiles;
using {{serviceName}}.Validators;
using Microsoft.EntityFrameworkCore;
using AutoMapper;
using FluentValidation;
using Serilog;
using Microsoft.OpenApi.Models;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
var builder = WebApplication.CreateBuilder(args);
// Configure Serilog
Log.Logger = new LoggerConfiguration()
.ReadFrom.Configuration(builder.Configuration)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File("logs/log-.txt", rollingInterval: RollingInterval.Day)
.CreateLogger();
builder.Host.UseSerilog();
// Add services to the container
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
// Configure Entity Framework
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection")));
// Configure AutoMapper
builder.Services.AddAutoMapper(typeof(UserProfile), typeof(ProductProfile), typeof(OrderProfile));
// Configure FluentValidation
builder.Services.AddValidatorsFromAssemblyContaining<CreateUserDtoValidator>();
// Configure Swagger/OpenAPI
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "{{serviceName}} API",
Version = "v1",
Description = "Enterprise API with AutoMapper object-to-object mapping",
Contact = new OpenApiContact
{
Name = "{{serviceName}} Team",
Email = "team@{{serviceName}}.com"
}
});
// Include XML comments
var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
// Configure JWT authentication in Swagger
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
});
// Configure JWT Authentication
var jwtSettings = builder.Configuration.GetSection("JwtSettings");
var secretKey = jwtSettings["SecretKey"];
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = jwtSettings["Issuer"],
ValidAudience = jwtSettings["Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secretKey!))
};
});
// Register application services
builder.Services.AddScoped<IUserService, UserService>();
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddScoped<IAuthService, AuthService>();
var app = builder.Build();
// Configure the HTTP request pipeline
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
// Ensure database is created
using (var scope = app.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.EnsureCreated();
}
app.Run();`,
// Models/User.cs
'Models/User.cs': `using System.ComponentModel.DataAnnotations;
namespace {{serviceName}}.Models;
public class User
{
public int Id { get; set; }
[Required]
[StringLength(100)]
public string Name { get; set; } = string.Empty;
[Required]
[EmailAddress]
[StringLength(255)]
public string Email { get; set; } = string.Empty;
[Required]
public string PasswordHash { get; set; } = string.Empty;
[StringLength(20)]
public string? PhoneNumber { get; set; }
public DateTime DateOfBirth { get; set; }
[StringLength(500)]
public string? Address { get; set; }
[StringLength(100)]
public string? City { get; set; }
[StringLength(100)]
public string? Country { get; set; }
public bool IsActive { get; set; } = true;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedAt { get; set; }
// Navigation properties
public virtual ICollection<Order> Orders { get; set; } = new List<Order>();
}`,
// Models/Product.cs
'Models/Product.cs': `using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace {{serviceName}}.Models;
public class Product
{
public int Id { get; set; }
[Required]
[StringLength(200)]
public string Name { get; set; } = string.Empty;
[StringLength(1000)]
public string? Description { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
public decimal Price { get; set; }
[StringLength(100)]
public string? Category { get; set; }
[StringLength(50)]
public string? Brand { get; set; }
public int StockQuantity { get; set; }
[StringLength(500)]
public string? ImageUrl { get; set; }
public bool IsActive { get; set; } = true;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedAt { get; set; }
// Navigation properties
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
}`,
// Models/Order.cs
'Models/Order.cs': `using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace {{serviceName}}.Models;
public class Order
{
public int Id { get; set; }
[Required]
public int UserId { get; set; }
[Required]
[StringLength(50)]
public string OrderNumber { get; set; } = string.Empty;
[Required]
[Column(TypeName = "decimal(18,2)")]
public decimal TotalAmount { get; set; }
[Required]
[StringLength(50)]
public string Status { get; set; } = "Pending";
[StringLength(500)]
public string? ShippingAddress { get; set; }
[StringLength(500)]
public string? Notes { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
public DateTime? UpdatedAt { get; set; }
// Navigation properties
public virtual User User { get; set; } = null!;
public virtual ICollection<OrderItem> OrderItems { get; set; } = new List<OrderItem>();
}`,
// Models/OrderItem.cs
'Models/OrderItem.cs': `using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace {{serviceName}}.Models;
public class OrderItem
{
public int Id { get; set; }
[Required]
public int OrderId { get; set; }
[Required]
public int ProductId { get; set; }
[Required]
public int Quantity { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
public decimal UnitPrice { get; set; }
[Required]
[Column(TypeName = "decimal(18,2)")]
public decimal TotalPrice { get; set; }
// Navigation properties
public virtual Order Order { get; set; } = null!;
public virtual Product Product { get; set; } = null!;
}`,
// DTOs/UserDtos.cs
'DTOs/UserDtos.cs': `using System.ComponentModel.DataAnnotations;
namespace {{serviceName}}.DTOs;
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public string? PhoneNumber { get; set; }
public DateTime DateOfBirth { get; set; }
public string? Address { get; set; }
public string? City { get; set; }
public string? Country { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
}
public class CreateUserDto
{
[Required]
[StringLength(100)]
public string Name { get; set; } = string.Empty;
[Required]
[EmailAddress]
[StringLength(255)]
public string Email { get; set; } = string.Empty;
[Required]
[StringLength(100, MinimumLength = 6)]
public string Password { get; set; } = string.Empty;
[StringLength(20)]
public string? PhoneNumber { get; set; }
public DateTime DateOfBirth { get; set; }
[StringLength(500)]
public string? Address { get; set; }
[StringLength(100)]
public string? City { get; set; }
[StringLength(100)]
public string? Country { get; set; }
}
public class UpdateUserDto
{
[StringLength(100)]
public string? Name { get; set; }
[EmailAddress]
[StringLength(255)]
public string? Email { get; set; }
[StringLength(20)]
public string? PhoneNumber { get; set; }
public DateTime? DateOfBirth { get; set; }
[StringLength(500)]
public string? Address { get; set; }
[StringLength(100)]
public string? City { get; set; }
[StringLength(100)]
public string? Country { get; set; }
public bool? IsActive { get; set; }
}
public class UserSummaryDto
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
public bool IsActive { get; set; }
public int TotalOrders { get; set; }
public decimal TotalSpent { get; set; }
}`,
// DTOs/ProductDtos.cs
'DTOs/ProductDtos.cs': `using System.ComponentModel.DataAnnotations;
namespace {{serviceName}}.DTOs;
public class ProductDto
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string? Description { get; set; }
public decimal Price { get; set; }
public string? Category { get; set; }
public string? Brand { get; set; }
public int StockQuantity { get; set; }
public string? ImageUrl { get; set; }
public bool IsActive { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
}
public class CreateProductDto
{
[Required]
[StringLength(200)]
public string Name { get; set; } = string.Empty;
[StringLength(1000)]
public string? Description { get; set; }
[Required]
[Range(0.01, double.MaxValue)]
public decimal Price { get; set; }
[StringLength(100)]
public string? Category { get; set; }
[StringLength(50)]
public string? Brand { get; set; }
[Required]
[Range(0, int.MaxValue)]
public int StockQuantity { get; set; }
[StringLength(500)]
public string? ImageUrl { get; set; }
}
public class UpdateProductDto
{
[StringLength(200)]
public string? Name { get; set; }
[StringLength(1000)]
public string? Description { get; set; }
[Range(0.01, double.MaxValue)]
public decimal? Price { get; set; }
[StringLength(100)]
public string? Category { get; set; }
[StringLength(50)]
public string? Brand { get; set; }
[Range(0, int.MaxValue)]
public int? StockQuantity { get; set; }
[StringLength(500)]
public string? ImageUrl { get; set; }
public bool? IsActive { get; set; }
}
public class ProductSummaryDto
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
public string? Category { get; set; }
public int StockQuantity { get; set; }
public bool IsActive { get; set; }
}`,
// DTOs/OrderDtos.cs
'DTOs/OrderDtos.cs': `using System.ComponentModel.DataAnnotations;
namespace {{serviceName}}.DTOs;
public class OrderDto
{
public int Id { get; set; }
public int UserId { get; set; }
public string OrderNumber { get; set; } = string.Empty;
public decimal TotalAmount { get; set; }
public string Status { get; set; } = string.Empty;
public string? ShippingAddress { get; set; }
public string? Notes { get; set; }
public DateTime CreatedAt { get; set; }
public DateTime? UpdatedAt { get; set; }
// Navigation DTOs
public UserDto? User { get; set; }
public List<OrderItemDto> OrderItems { get; set; } = new();
}
public class CreateOrderDto
{
[Required]
public int UserId { get; set; }
[StringLength(500)]
public string? ShippingAddress { get; set; }
[StringLength(500)]
public string? Notes { get; set; }
[Required]
public List<CreateOrderItemDto> OrderItems { get; set; } = new();
}
public class UpdateOrderDto
{
[StringLength(50)]
public string? Status { get; set; }
[StringLength(500)]
public string? ShippingAddress { get; set; }
[StringLength(500)]
public string? Notes { get; set; }
}
public class OrderItemDto
{
public int Id { get; set; }
public int OrderId { get; set; }
public int ProductId { get; set; }
public int Quantity { get; set; }
public decimal UnitPrice { get; set; }
public decimal TotalPrice { get; set; }
// Navigation DTO
public ProductDto? Product { get; set; }
}
public class CreateOrderItemDto
{
[Required]
public int ProductId { get; set; }
[Required]
[Range(1, int.MaxValue)]
public int Quantity { get; set; }
}
public class OrderSummaryDto
{
public int Id { get; set; }
public string OrderNumber { get; set; } = string.Empty;
public decimal TotalAmount { get; set; }
public string Status { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; }
public int ItemCount { get; set; }
public string CustomerName { get; set; } = string.Empty;
}`,
// Profiles/UserProfile.cs
'Profiles/UserProfile.cs': `using AutoMapper;
using {{serviceName}}.Models;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Profiles;
/// <summary>
/// AutoMapper profile for User entity mappings
/// </summary>
public class UserProfile : Profile
{
public UserProfile()
{
// User -> UserDto (basic mapping)
CreateMap<User, UserDto>();
// CreateUserDto -> User (creation mapping)
CreateMap<CreateUserDto, User>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.PasswordHash, opt => opt.Ignore()) // Will be set separately
.ForMember(dest => dest.IsActive, opt => opt.MapFrom(src => true))
.ForMember(dest => dest.CreatedAt, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.UpdatedAt, opt => opt.Ignore())
.ForMember(dest => dest.Orders, opt => opt.Ignore());
// UpdateUserDto -> User (update mapping)
CreateMap<UpdateUserDto, User>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.PasswordHash, opt => opt.Ignore())
.ForMember(dest => dest.CreatedAt, opt => opt.Ignore())
.ForMember(dest => dest.UpdatedAt, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.Orders, opt => opt.Ignore())
.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
// User -> UserSummaryDto (summary mapping with calculated fields)
CreateMap<User, UserSummaryDto>()
.ForMember(dest => dest.TotalOrders, opt => opt.MapFrom(src => src.Orders.Count))
.ForMember(dest => dest.TotalSpent, opt => opt.MapFrom(src => src.Orders.Sum(o => o.TotalAmount)));
}
}`,
// Profiles/ProductProfile.cs
'Profiles/ProductProfile.cs': `using AutoMapper;
using {{serviceName}}.Models;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Profiles;
/// <summary>
/// AutoMapper profile for Product entity mappings
/// </summary>
public class ProductProfile : Profile
{
public ProductProfile()
{
// Product -> ProductDto (basic mapping)
CreateMap<Product, ProductDto>();
// CreateProductDto -> Product (creation mapping)
CreateMap<CreateProductDto, Product>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.IsActive, opt => opt.MapFrom(src => true))
.ForMember(dest => dest.CreatedAt, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.UpdatedAt, opt => opt.Ignore())
.ForMember(dest => dest.OrderItems, opt => opt.Ignore());
// UpdateProductDto -> Product (update mapping)
CreateMap<UpdateProductDto, Product>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.CreatedAt, opt => opt.Ignore())
.ForMember(dest => dest.UpdatedAt, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.OrderItems, opt => opt.Ignore())
.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
// Product -> ProductSummaryDto (summary mapping)
CreateMap<Product, ProductSummaryDto>();
}
}`,
// Profiles/OrderProfile.cs
'Profiles/OrderProfile.cs': `using AutoMapper;
using {{serviceName}}.Models;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Profiles;
/// <summary>
/// AutoMapper profile for Order entity mappings
/// </summary>
public class OrderProfile : Profile
{
public OrderProfile()
{
// Order -> OrderDto (basic mapping with navigation properties)
CreateMap<Order, OrderDto>();
// CreateOrderDto -> Order (creation mapping)
CreateMap<CreateOrderDto, Order>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.OrderNumber, opt => opt.MapFrom(src => GenerateOrderNumber()))
.ForMember(dest => dest.TotalAmount, opt => opt.Ignore()) // Will be calculated
.ForMember(dest => dest.Status, opt => opt.MapFrom(src => "Pending"))
.ForMember(dest => dest.CreatedAt, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.UpdatedAt, opt => opt.Ignore())
.ForMember(dest => dest.User, opt => opt.Ignore())
.ForMember(dest => dest.OrderItems, opt => opt.Ignore()); // Will be mapped separately
// UpdateOrderDto -> Order (update mapping)
CreateMap<UpdateOrderDto, Order>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.UserId, opt => opt.Ignore())
.ForMember(dest => dest.OrderNumber, opt => opt.Ignore())
.ForMember(dest => dest.TotalAmount, opt => opt.Ignore())
.ForMember(dest => dest.CreatedAt, opt => opt.Ignore())
.ForMember(dest => dest.UpdatedAt, opt => opt.MapFrom(src => DateTime.UtcNow))
.ForMember(dest => dest.User, opt => opt.Ignore())
.ForMember(dest => dest.OrderItems, opt => opt.Ignore())
.ForAllMembers(opts => opts.Condition((src, dest, srcMember) => srcMember != null));
// OrderItem -> OrderItemDto (basic mapping)
CreateMap<OrderItem, OrderItemDto>();
// CreateOrderItemDto -> OrderItem (creation mapping)
CreateMap<CreateOrderItemDto, OrderItem>()
.ForMember(dest => dest.Id, opt => opt.Ignore())
.ForMember(dest => dest.OrderId, opt => opt.Ignore())
.ForMember(dest => dest.UnitPrice, opt => opt.Ignore()) // Will be set from product
.ForMember(dest => dest.TotalPrice, opt => opt.Ignore()) // Will be calculated
.ForMember(dest => dest.Order, opt => opt.Ignore())
.ForMember(dest => dest.Product, opt => opt.Ignore());
// Order -> OrderSummaryDto (summary mapping with calculated fields)
CreateMap<Order, OrderSummaryDto>()
.ForMember(dest => dest.ItemCount, opt => opt.MapFrom(src => src.OrderItems.Sum(oi => oi.Quantity)))
.ForMember(dest => dest.CustomerName, opt => opt.MapFrom(src => src.User.Name));
}
/// <summary>
/// Generates a unique order number
/// </summary>
private static string GenerateOrderNumber()
{
return $"ORD-{DateTime.UtcNow:yyyyMMdd}-{Guid.NewGuid().ToString()[..8].ToUpper()}";
}
}`,
// Validators/CreateUserDtoValidator.cs
'Validators/CreateUserDtoValidator.cs': `using FluentValidation;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Validators;
public class CreateUserDtoValidator : AbstractValidator<CreateUserDto>
{
public CreateUserDtoValidator()
{
RuleFor(x => x.Name)
.NotEmpty()
.Length(2, 100)
.WithMessage("Name must be between 2 and 100 characters");
RuleFor(x => x.Email)
.NotEmpty()
.EmailAddress()
.MaximumLength(255)
.WithMessage("Valid email address is required");
RuleFor(x => x.Password)
.NotEmpty()
.MinimumLength(6)
.MaximumLength(100)
.Matches(@"^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)")
.WithMessage("Password must contain at least one lowercase letter, one uppercase letter, and one digit");
RuleFor(x => x.PhoneNumber)
.MaximumLength(20)
.When(x => !string.IsNullOrEmpty(x.PhoneNumber));
RuleFor(x => x.DateOfBirth)
.LessThan(DateTime.Now.AddYears(-13))
.WithMessage("User must be at least 13 years old");
RuleFor(x => x.Address)
.MaximumLength(500)
.When(x => !string.IsNullOrEmpty(x.Address));
RuleFor(x => x.City)
.MaximumLength(100)
.When(x => !string.IsNullOrEmpty(x.City));
RuleFor(x => x.Country)
.MaximumLength(100)
.When(x => !string.IsNullOrEmpty(x.Country));
}
}`,
// Validators/CreateProductDtoValidator.cs
'Validators/CreateProductDtoValidator.cs': `using FluentValidation;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Validators;
public class CreateProductDtoValidator : AbstractValidator<CreateProductDto>
{
public CreateProductDtoValidator()
{
RuleFor(x => x.Name)
.NotEmpty()
.Length(2, 200)
.WithMessage("Product name must be between 2 and 200 characters");
RuleFor(x => x.Description)
.MaximumLength(1000)
.When(x => !string.IsNullOrEmpty(x.Description));
RuleFor(x => x.Price)
.GreaterThan(0)
.WithMessage("Price must be greater than 0");
RuleFor(x => x.Category)
.MaximumLength(100)
.When(x => !string.IsNullOrEmpty(x.Category));
RuleFor(x => x.Brand)
.MaximumLength(50)
.When(x => !string.IsNullOrEmpty(x.Brand));
RuleFor(x => x.StockQuantity)
.GreaterThanOrEqualTo(0)
.WithMessage("Stock quantity cannot be negative");
RuleFor(x => x.ImageUrl)
.MaximumLength(500)
.Must(BeAValidUrl)
.WithMessage("ImageUrl must be a valid URL")
.When(x => !string.IsNullOrEmpty(x.ImageUrl));
}
private static bool BeAValidUrl(string? url)
{
if (string.IsNullOrEmpty(url))
return true;
return Uri.TryCreate(url, UriKind.Absolute, out var result)
&& (result.Scheme == Uri.UriSchemeHttp || result.Scheme == Uri.UriSchemeHttps);
}
}`,
// Validators/CreateOrderDtoValidator.cs
'Validators/CreateOrderDtoValidator.cs': `using FluentValidation;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Validators;
public class CreateOrderDtoValidator : AbstractValidator<CreateOrderDto>
{
public CreateOrderDtoValidator()
{
RuleFor(x => x.UserId)
.GreaterThan(0)
.WithMessage("Valid User ID is required");
RuleFor(x => x.ShippingAddress)
.MaximumLength(500)
.When(x => !string.IsNullOrEmpty(x.ShippingAddress));
RuleFor(x => x.Notes)
.MaximumLength(500)
.When(x => !string.IsNullOrEmpty(x.Notes));
RuleFor(x => x.OrderItems)
.NotEmpty()
.WithMessage("Order must contain at least one item");
RuleForEach(x => x.OrderItems)
.SetValidator(new CreateOrderItemDtoValidator());
}
}
public class CreateOrderItemDtoValidator : AbstractValidator<CreateOrderItemDto>
{
public CreateOrderItemDtoValidator()
{
RuleFor(x => x.ProductId)
.GreaterThan(0)
.WithMessage("Valid Product ID is required");
RuleFor(x => x.Quantity)
.GreaterThan(0)
.WithMessage("Quantity must be greater than 0");
}
}`,
// Data/ApplicationDbContext.cs
'Data/ApplicationDbContext.cs': `using Microsoft.EntityFrameworkCore;
using {{serviceName}}.Models;
namespace {{serviceName}}.Data;
public class ApplicationDbContext : DbContext
{
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
{
}
public DbSet<User> Users { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderItem> OrderItems { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
// User configuration
modelBuilder.Entity<User>(entity =>
{
entity.HasKey(e => e.Id);
entity.HasIndex(e => e.Email).IsUnique();
entity.Property(e => e.Name).IsRequired().HasMaxLength(100);
entity.Property(e => e.Email).IsRequired().HasMaxLength(255);
entity.Property(e => e.PasswordHash).IsRequired();
});
// Product configuration
modelBuilder.Entity<Product>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.Name).IsRequired().HasMaxLength(200);
entity.Property(e => e.Price).HasColumnType("decimal(18,2)");
});
// Order configuration
modelBuilder.Entity<Order>(entity =>
{
entity.HasKey(e => e.Id);
entity.HasIndex(e => e.OrderNumber).IsUnique();
entity.Property(e => e.OrderNumber).IsRequired().HasMaxLength(50);
entity.Property(e => e.TotalAmount).HasColumnType("decimal(18,2)");
entity.Property(e => e.Status).IsRequired().HasMaxLength(50);
entity.HasOne(e => e.User)
.WithMany(u => u.Orders)
.HasForeignKey(e => e.UserId)
.OnDelete(DeleteBehavior.Restrict);
});
// OrderItem configuration
modelBuilder.Entity<OrderItem>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.UnitPrice).HasColumnType("decimal(18,2)");
entity.Property(e => e.TotalPrice).HasColumnType("decimal(18,2)");
entity.HasOne(e => e.Order)
.WithMany(o => o.OrderItems)
.HasForeignKey(e => e.OrderId)
.OnDelete(DeleteBehavior.Cascade);
entity.HasOne(e => e.Product)
.WithMany(p => p.OrderItems)
.HasForeignKey(e => e.ProductId)
.OnDelete(DeleteBehavior.Restrict);
});
// Seed data
SeedData(modelBuilder);
}
private static void SeedData(ModelBuilder modelBuilder)
{
// Seed Products
modelBuilder.Entity<Product>().HasData(
new Product
{
Id = 1,
Name = "Laptop Pro 15",
Description = "High-performance laptop for professionals",
Price = 1299.99m,
Category = "Electronics",
Brand = "TechCorp",
StockQuantity = 50,
ImageUrl = "https://example.com/laptop.jpg",
IsActive = true,
CreatedAt = DateTime.UtcNow
},
new Product
{
Id = 2,
Name = "Wireless Mouse",
Description = "Ergonomic wireless mouse with precision tracking",
Price = 49.99m,
Category = "Electronics",
Brand = "TechCorp",
StockQuantity = 200,
ImageUrl = "https://example.com/mouse.jpg",
IsActive = true,
CreatedAt = DateTime.UtcNow
},
new Product
{
Id = 3,
Name = "Office Chair",
Description = "Comfortable ergonomic office chair",
Price = 299.99m,
Category = "Furniture",
Brand = "ComfortPlus",
StockQuantity = 30,
ImageUrl = "https://example.com/chair.jpg",
IsActive = true,
CreatedAt = DateTime.UtcNow
}
);
}
}`,
// Services/IUserService.cs
'Services/IUserService.cs': `using {{serviceName}}.DTOs;
namespace {{serviceName}}.Services;
public interface IUserService
{
Task<UserDto?> GetByIdAsync(int id);
Task<UserDto?> GetByEmailAsync(string email);
Task<IEnumerable<UserDto>> GetAllAsync();
Task<IEnumerable<UserSummaryDto>> GetSummariesAsync();
Task<UserDto> CreateAsync(CreateUserDto createUserDto);
Task<UserDto?> UpdateAsync(int id, UpdateUserDto updateUserDto);
Task<bool> DeleteAsync(int id);
Task<bool> ExistsAsync(int id);
Task<bool> EmailExistsAsync(string email);
}`,
// Services/UserService.cs
'Services/UserService.cs': `using Microsoft.EntityFrameworkCore;
using AutoMapper;
using {{serviceName}}.Data;
using {{serviceName}}.Models;
using {{serviceName}}.DTOs;
using BCrypt.Net;
namespace {{serviceName}}.Services;
public class UserService : IUserService
{
private readonly ApplicationDbContext _context;
private readonly IMapper _mapper;
private readonly ILogger<UserService> _logger;
public UserService(ApplicationDbContext context, IMapper mapper, ILogger<UserService> logger)
{
_context = context;
_mapper = mapper;
_logger = logger;
}
public async Task<UserDto?> GetByIdAsync(int id)
{
_logger.LogInformation("Getting user by ID: {UserId}", id);
var user = await _context.Users
.AsNoTracking()
.FirstOrDefaultAsync(u => u.Id == id);
return user != null ? _mapper.Map<UserDto>(user) : null;
}
public async Task<UserDto?> GetByEmailAsync(string email)
{
_logger.LogInformation("Getting user by email: {Email}", email);
var user = await _context.Users
.AsNoTracking()
.FirstOrDefaultAsync(u => u.Email == email);
return user != null ? _mapper.Map<UserDto>(user) : null;
}
public async Task<IEnumerable<UserDto>> GetAllAsync()
{
_logger.LogInformation("Getting all users");
var users = await _context.Users
.AsNoTracking()
.OrderBy(u => u.Name)
.ToListAsync();
return _mapper.Map<IEnumerable<UserDto>>(users);
}
public async Task<IEnumerable<UserSummaryDto>> GetSummariesAsync()
{
_logger.LogInformation("Getting user summaries");
var users = await _context.Users
.Include(u => u.Orders)
.AsNoTracking()
.OrderBy(u => u.Name)
.ToListAsync();
return _mapper.Map<IEnumerable<UserSummaryDto>>(users);
}
public async Task<UserDto> CreateAsync(CreateUserDto createUserDto)
{
_logger.LogInformation("Creating new user with email: {Email}", createUserDto.Email);
// Check if email already exists
if (await EmailExistsAsync(createUserDto.Email))
{
throw new InvalidOperationException($"User with email {createUserDto.Email} already exists");
}
var user = _mapper.Map<User>(createUserDto);
user.PasswordHash = BCrypt.Net.BCrypt.HashPassword(createUserDto.Password);
_context.Users.Add(user);
await _context.SaveChangesAsync();
_logger.LogInformation("User created successfully with ID: {UserId}", user.Id);
return _mapper.Map<UserDto>(user);
}
public async Task<UserDto?> UpdateAsync(int id, UpdateUserDto updateUserDto)
{
_logger.LogInformation("Updating user with ID: {UserId}", id);
var user = await _context.Users.FindAsync(id);
if (user == null)
{
_logger.LogWarning("User not found with ID: {UserId}", id);
return null;
}
// Check if email is being updated and already exists
if (!string.IsNullOrEmpty(updateUserDto.Email) &&
updateUserDto.Email != user.Email &&
await EmailExistsAsync(updateUserDto.Email))
{
throw new InvalidOperationException($"User with email {updateUserDto.Email} already exists");
}
_mapper.Map(updateUserDto, user);
user.UpdatedAt = DateTime.UtcNow;
await _context.SaveChangesAsync();
_logger.LogInformation("User updated successfully with ID: {UserId}", id);
return _mapper.Map<UserDto>(user);
}
public async Task<bool> DeleteAsync(int id)
{
_logger.LogInformation("Deleting user with ID: {UserId}", id);
var user = await _context.Users.FindAsync(id);
if (user == null)
{
_logger.LogWarning("User not found with ID: {UserId}", id);
return false;
}
_context.Users.Remove(user);
await _context.SaveChangesAsync();
_logger.LogInformation("User deleted successfully with ID: {UserId}", id);
return true;
}
public async Task<bool> ExistsAsync(int id)
{
return await _context.Users.AnyAsync(u => u.Id == id);
}
public async Task<bool> EmailExistsAsync(string email)
{
return await _context.Users.AnyAsync(u => u.Email == email);
}
}`,
// Services/IProductService.cs
'Services/IProductService.cs': `using {{serviceName}}.DTOs;
namespace {{serviceName}}.Services;
public interface IProductService
{
Task<ProductDto?> GetByIdAsync(int id);
Task<IEnumerable<ProductDto>> GetAllAsync();
Task<IEnumerable<ProductSummaryDto>> GetSummariesAsync();
Task<IEnumerable<ProductDto>> GetByCategoryAsync(string category);
Task<ProductDto> CreateAsync(CreateProductDto createProductDto);
Task<ProductDto?> UpdateAsync(int id, UpdateProductDto updateProductDto);
Task<bool> DeleteAsync(int id);
Task<bool> ExistsAsync(int id);
}`,
// Services/ProductService.cs
'Services/ProductService.cs': `using Microsoft.EntityFrameworkCore;
using AutoMapper;
using {{serviceName}}.Data;
using {{serviceName}}.Models;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Services;
public class ProductService : IProductService
{
private readonly ApplicationDbContext _context;
private readonly IMapper _mapper;
private readonly ILogger<ProductService> _logger;
public ProductService(ApplicationDbContext context, IMapper mapper, ILogger<ProductService> logger)
{
_context = context;
_mapper = mapper;
_logger = logger;
}
public async Task<ProductDto?> GetByIdAsync(int id)
{
_logger.LogInformation("Getting product by ID: {ProductId}", id);
var product = await _context.Products
.AsNoTracking()
.FirstOrDefaultAsync(p => p.Id == id);
return product != null ? _mapper.Map<ProductDto>(product) : null;
}
public async Task<IEnumerable<ProductDto>> GetAllAsync()
{
_logger.LogInformation("Getting all products");
var products = await _context.Products
.AsNoTracking()
.OrderBy(p => p.Name)
.ToListAsync();
return _mapper.Map<IEnumerable<ProductDto>>(products);
}
public async Task<IEnumerable<ProductSummaryDto>> GetSummariesAsync()
{
_logger.LogInformation("Getting product summaries");
var products = await _context.Products
.AsNoTracking()
.OrderBy(p => p.Name)
.ToListAsync();
return _mapper.Map<IEnumerable<ProductSummaryDto>>(products);
}
public async Task<IEnumerable<ProductDto>> GetByCategoryAsync(string category)
{
_logger.LogInformation("Getting products by category: {Category}", category);
var products = await _context.Products
.AsNoTracking()
.Where(p => p.Category == category)
.OrderBy(p => p.Name)
.ToListAsync();
return _mapper.Map<IEnumerable<ProductDto>>(products);
}
public async Task<ProductDto> CreateAsync(CreateProductDto createProductDto)
{
_logger.LogInformation("Creating new product: {ProductName}", createProductDto.Name);
var product = _mapper.Map<Product>(createProductDto);
_context.Products.Add(product);
await _context.SaveChangesAsync();
_logger.LogInformation("Product created successfully with ID: {ProductId}", product.Id);
return _mapper.Map<ProductDto>(product);
}
public async Task<ProductDto?> UpdateAsync(int id, UpdateProductDto updateProductDto)
{
_logger.LogInformation("Updating product with ID: {ProductId}", id);
var product = await _context.Products.FindAsync(id);
if (product == null)
{
_logger.LogWarning("Product not found with ID: {ProductId}", id);
return null;
}
_mapper.Map(updateProductDto, product);
product.UpdatedAt = DateTime.UtcNow;
await _context.SaveChangesAsync();
_logger.LogInformation("Product updated successfully with ID: {ProductId}", id);
return _mapper.Map<ProductDto>(product);
}
public async Task<bool> DeleteAsync(int id)
{
_logger.LogInformation("Deleting product with ID: {ProductId}", id);
var product = await _context.Products.FindAsync(id);
if (product == null)
{
_logger.LogWarning("Product not found with ID: {ProductId}", id);
return false;
}
_context.Products.Remove(product);
await _context.SaveChangesAsync();
_logger.LogInformation("Product deleted successfully with ID: {ProductId}", id);
return true;
}
public async Task<bool> ExistsAsync(int id)
{
return await _context.Products.AnyAsync(p => p.Id == id);
}
}`,
// Services/IOrderService.cs
'Services/IOrderService.cs': `using {{serviceName}}.DTOs;
namespace {{serviceName}}.Services;
public interface IOrderService
{
Task<OrderDto?> GetByIdAsync(int id);
Task<IEnumerable<OrderDto>> GetAllAsync();
Task<IEnumerable<OrderSummaryDto>> GetSummariesAsync();
Task<IEnumerable<OrderDto>> GetByUserIdAsync(int userId);
Task<OrderDto> CreateAsync(CreateOrderDto createOrderDto);
Task<OrderDto?> UpdateAsync(int id, UpdateOrderDto updateOrderDto);
Task<bool> DeleteAsync(int id);
Task<bool> ExistsAsync(int id);
}`,
// Services/OrderService.cs
'Services/OrderService.cs': `using Microsoft.EntityFrameworkCore;
using AutoMapper;
using {{serviceName}}.Data;
using {{serviceName}}.Models;
using {{serviceName}}.DTOs;
namespace {{serviceName}}.Services;
public class OrderService : IOrderService
{
private readonly ApplicationDbContext _context;
private readonly IMapper _mapper;
private readonly ILogger<OrderService> _logger;
public OrderService(ApplicationDbContext context, IMapper mapper, ILogger<OrderService> logger)
{
_context = context;
_mapper = mapper;
_logger = logger;
}
public async Task<OrderDto?> GetByIdAsync(int id)
{
_logger.LogInformation("Getting order by ID: {OrderId}", id);
var order = await _context.Orders
.Include(o => o.User)
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.Product)
.AsNoTracking()
.FirstOrDefaultAsync(o => o.Id == id);
return order != null ? _mapper.Map<OrderDto>(order) : null;
}
public async Task<IEnumerable<OrderDto>> GetAllAsync()
{
_logger.LogInformation("Getting all orders");
var orders = await _context.Orders
.Include(o => o.User)
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.Product)
.AsNoTracking()
.OrderByDescending(o => o.CreatedAt)
.ToListAsync();
return _mapper.Map<IEnumerable<OrderDto>>(orders);
}
public async Task<IEnumerable<OrderSummaryDto>> GetSummariesAsync()
{
_logger.LogInformation("Getting order summaries");
var orders = await _context.Orders
.Include(o => o.User)
.Include(o => o.OrderItems)
.AsNoTracking()
.OrderByDescending(o => o.CreatedAt)
.ToListAsync();
return _mapper.Map<IEnumerable<OrderSummaryDto>>(orders);
}
public async Task<IEnumerable<OrderDto>> GetByUserIdAsync(int userId)
{
_logger.LogInformation("Getting orders by user ID: {UserId}", userId);
var orders = await _context.Orders
.Include(o => o.User)
.Include(o => o.OrderItems)
.ThenInclude(oi => oi.Product)
.AsNoTracking()
.Where(o => o.UserId == userId)
.OrderByDescending(o => o.CreatedAt)
.ToListAsync();
return _mapper.Map<IEnumerable<OrderDto>>(orders);
}
public async Task<OrderDto> CreateAsync(CreateOrderDto createOrderDto)
{
_logger.LogInformation("Creating new order for user ID: {UserId}", createOrderDto.UserId);
using var transaction = await _context.Database.BeginTransactionAsync();
try
{
// Validate user exists
var userExists = await _context.Users.AnyAsync(u => u.Id == createOrderDto.UserId);
if (!userExists)
{
throw new InvalidOperationException($"User with ID {createOrderDto.UserId} does not exist");
}
// Create the order
var order = _mapper.Map<Order>(createOrderDto);
_context.Orders.Add(order);
await _context.SaveChangesAsync();
// Create order items
decimal totalAmount = 0;
foreach (var createOrderItemDto in createOrderDto.OrderItems)
{
var product = await _context.Products.FindAsync(createOrderItemDto.ProductId);
if (product == null)
{
throw new InvalidOperationException($"Product with ID {createOrderItemDto.ProductId} does not exist");
}
if (product.StockQuantity < createOrderItemDto.Quantity)
{
throw new InvalidOperationException($"Insufficient stock for product {product.Name}. Available: {product.StockQuantity}, Requested: {createOrderItemDto.Quantity}");
}
var orderItem = _mapper.Map<OrderItem>(createOrderItemDto);
orderItem.OrderId = order.Id;
orderItem.UnitPrice = product.Price;
orderItem.TotalPrice = product.Price * createOrderItemDto.Quantity;
_context.OrderItems.Add(orderItem);
// Update product stock
product.StockQuantity -= createOrderItemDto.Quantity;
product.UpdatedAt = DateTime.UtcNow;
totalAmount += orderItem.TotalPrice;
}
// Update order total
order.TotalAmount = totalAmount;
await _context.SaveChangesAsync();
await transaction.CommitAsync();
_logger.LogInformation("Order created successfully with ID: {OrderId}", order.Id);
// Return the complete order with related data
return await GetByIdAsync(order.Id) ?? throw new InvalidOperationException("Failed to retrieve created order");
}
catch
{
await transaction.RollbackAsync();
throw;
}
}
public async Task<OrderDto?> UpdateAsync(int id, UpdateOrderDto updateOrderDto)
{
_logger.LogInformation("Updating order with ID: {OrderId}", id);
var order = await _context.Orders.FindAsync(id);
if (order == null)
{
_logger.LogWarning("Order not found with ID: {OrderId}", id);
return null;
}
_mapper.Map(updateOrderDto, order);
order.UpdatedAt = DateTime.UtcNow;
await _context.SaveChangesAsync();
_logger.LogInformation("Order updated successfully with ID: {OrderId}", id);
return await GetByIdAsync(id);
}
public async Task<bool> DeleteAsync(int id)
{
_logger.LogInformation("Deleting order with ID: {OrderId}", id);
var order = await _context.Orders.FindAsync(id);
if (order == null)
{
_logger.LogWarning("Order not found with ID: {OrderId}", id);
return false;
}
_context.Orders.Remove(order);
await _context.SaveChangesAsync();
_logger.LogInformation("Order deleted successfully with ID: {OrderId}", id);
return true;
}
public async Task<bool> ExistsAsync(int id)
{
return await _context.Orders.AnyAsync(o => o.Id == id);
}
}`,
// Services/IAuthService.cs
'Services/IAuthService.cs': `namespace {{serviceName}}.Services;
public interface IAuthService
{
Task<string> AuthenticateAsync(string email, string password);
Task<bool> ValidateTokenAsync(string token);
}`,
// Services/AuthService.cs
'Services/AuthService.cs': `using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.S