UNPKG

@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
"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