XiHan.Framework 核心模块
XiHan.Framework.Core 是框架的核心模块,提供了基础设施和基本功能,是其他所有模块的基础。本文将详细介绍核心模块的主要功能和使用方法。
核心功能
依赖注入
XiHan.Framework 基于 .NET 内置的依赖注入系统,提供了更简便的注册方式和扩展功能:
csharp
// 在 Program.cs 中添加 XiHan 框架服务
builder.Services.AddXiHanFramework(options =>
{
options.ApplicationName = "MyApplication";
options.ConfigureServices = services =>
{
// 自定义服务配置
};
});
// 自动注册所有服务
builder.Services.AddXiHanServices(options =>
{
options.ScanAssemblies = new[] { typeof(Program).Assembly };
options.AutoRegisterServices = true;
});
服务生命周期
XiHan.Framework 支持以下几种服务生命周期,可以通过特性轻松标记:
- Transient(瞬时): 每次请求都会创建新的实例
- Scoped(作用域): 在同一个请求作用域内共享同一个实例
- Singleton(单例): 整个应用程序只有一个实例
csharp
// 使用特性标记服务生命周期
[TransientService]
public class MyTransientService : IMyService
{
// 实现...
}
[ScopedService]
public class MyScopedService : IMyService
{
// 实现...
}
[SingletonService]
public class MySingletonService : IMyService
{
// 实现...
}
// 服务可以实现多个接口
[ScopedService(
ServiceType = typeof(IMyService),
AdditionalInterfaces = new[] { typeof(IMyExtraService) })]
public class MyComplexService : IMyService, IMyExtraService
{
// 实现...
}
// 也可以通过优先级控制服务注册顺序
[ScopedService(ServiceLifetime.Scoped, Priority = 10)]
public class HighPriorityService : IMyService
{
// 优先级高的实现...
}
服务自动发现
XiHan.Framework 提供了服务自动发现功能,可以自动注册服务:
csharp
// 在 Program.cs 中自动注册所有服务
builder.Services.AddXiHanServices(options =>
{
// 配置要扫描的程序集
options.ScanAssemblies = new[] {
typeof(Program).Assembly,
typeof(MyDomainLayer).Assembly,
typeof(MyInfrastructureLayer).Assembly
};
// 启用自动注册
options.AutoRegisterServices = true;
// 自定义服务注册过滤器
options.ServiceRegistrationFilter = type =>
!type.Name.EndsWith("Legacy") &&
!type.Namespace.Contains("Deprecated");
});
配置管理
XiHan.Framework 提供了强类型的配置管理功能,支持多种配置源:
csharp
// 在 Program.cs 中注册配置
builder.Services.AddXiHanConfiguration();
// 绑定配置到强类型对象
builder.Services.Configure<AppSettings>(builder.Configuration.GetSection("AppSettings"));
// 注册配置为单例服务
builder.Services.ConfigureOptions<AppSettings>(builder.Configuration.GetSection("AppSettings"));
// 在服务中使用配置
public class MyService
{
private readonly AppSettings _settings;
public MyService(IOptions<AppSettings> options)
{
_settings = options.Value;
}
// 或通过 IOptionsSnapshot 获取动态更新的配置
public MyService(IOptionsSnapshot<AppSettings> options)
{
_settings = options.Value;
}
}
配置加密
对于敏感配置,XiHan.Framework 提供了配置加密功能:
csharp
// 使用加密配置
builder.Services.AddXiHanEncryptedConfiguration(options =>
{
options.EncryptionKey = builder.Configuration["EncryptionKey"];
options.EncryptionAlgorithm = EncryptionAlgorithm.AES;
options.EncryptedSections = new[] { "ConnectionStrings", "Authentication" };
});
// 在 appsettings.json 中使用加密值
{
"ConnectionStrings": {
"DefaultConnection": "encrypted:A4B8C15D..."
}
}
日志记录
XiHan.Framework 集成了 .NET 的日志系统,同时提供了更丰富的日志功能:
csharp
// 在 Program.cs 中配置日志
builder.Services.AddXiHanLogging(options =>
{
options.UseSerilog();
options.MinimumLevel = LogLevel.Information;
options.EnableEnrichers = true;
options.AddContextEnricher = true;
options.AddSourceContextEnricher = true;
});
// 配置 Serilog
builder.Host.UseSerilog((context, services, configuration) => configuration
.ReadFrom.Configuration(context.Configuration)
.ReadFrom.Services(services)
.Enrich.FromLogContext()
.WriteTo.Console()
.WriteTo.File("logs/app.log", rollingInterval: RollingInterval.Day));
// 在服务中使用日志
public class MyService
{
private readonly ILogger<MyService> _logger;
public MyService(ILogger<MyService> logger)
{
_logger = logger;
}
public void DoSomething()
{
_logger.LogInformation("开始执行操作...");
try
{
// 业务逻辑...
_logger.LogInformation("操作已完成");
}
catch (Exception ex)
{
// 使用结构化日志记录异常
_logger.LogError(ex, "执行操作时发生错误: {ErrorMessage}", ex.Message);
throw;
}
}
}
结构化日志
XiHan.Framework 支持结构化日志,便于日志分析和过滤:
csharp
// 使用结构化参数记录日志
_logger.LogInformation("用户 {UserId} 于 {LoginTime} 登录,IP地址: {IpAddress}",
userId, DateTime.Now, ipAddress);
// 使用日志作用域添加上下文信息
using (_logger.BeginScope(new Dictionary<string, object>
{
["RequestId"] = requestId,
["UserId"] = userId,
["CorrelationId"] = correlationId
}))
{
_logger.LogInformation("处理请求...");
// 请求处理逻辑...
_logger.LogInformation("请求处理完成");
}
异常处理
XiHan.Framework 提供了统一的异常处理机制:
csharp
// 在 Program.cs 中添加异常处理中间件
app.UseXiHanExceptionHandler(options =>
{
options.ShowDetails = app.Environment.IsDevelopment();
options.LogLevel = LogLevel.Error;
options.ResponseStatusCode = 500;
});
// 定义业务异常基类
public abstract class BusinessException : XiHanException
{
public BusinessException(string message, string errorCode = null)
: base(message)
{
ErrorCode = errorCode;
}
public string ErrorCode { get; }
}
// 定义具体的业务异常
public class UserNotFoundException : BusinessException
{
public UserNotFoundException(string userId)
: base($"用户 {userId} 不存在", "USER-404")
{
UserId = userId;
}
public string UserId { get; }
}
// 抛出业务异常
public async Task<User> GetUserAsync(string userId)
{
var user = await _userRepository.GetByIdAsync(userId);
if (user == null)
{
throw new UserNotFoundException(userId);
}
return user;
}
全局异常过滤器
对于 API 应用,可以使用全局异常过滤器:
csharp
// 在 Program.cs 中添加全局异常过滤器
builder.Services.AddControllers(options =>
{
options.Filters.Add<XiHanExceptionFilter>();
});
// 自定义异常过滤器
public class XiHanExceptionFilter : IExceptionFilter
{
private readonly ILogger<XiHanExceptionFilter> _logger;
private readonly IWebHostEnvironment _env;
public XiHanExceptionFilter(
ILogger<XiHanExceptionFilter> logger,
IWebHostEnvironment env)
{
_logger = logger;
_env = env;
}
public void OnException(ExceptionContext context)
{
_logger.LogError(context.Exception, "API请求处理过程中发生异常");
var result = new Result
{
Succeeded = false,
Message = context.Exception is BusinessException
? context.Exception.Message
: "处理请求时发生错误",
ErrorCode = context.Exception is BusinessException be
? be.ErrorCode
: "SYSTEM-ERROR"
};
// 添加详细错误信息(仅在开发环境)
if (_env.IsDevelopment() && !(context.Exception is BusinessException))
{
result.Errors = new Dictionary<string, string[]>
{
["ExceptionDetails"] = new[]
{
context.Exception.ToString()
}
};
}
context.Result = new ObjectResult(result)
{
StatusCode = context.Exception is BusinessException ? 400 : 500
};
context.ExceptionHandled = true;
}
}
结果类型
XiHan.Framework 提供了统一的结果类型,用于表示操作结果:
csharp
// 基础结果类型
public class Result
{
public bool Succeeded { get; set; }
public string Message { get; set; }
public string ErrorCode { get; set; }
public Dictionary<string, string[]> Errors { get; set; }
// 创建成功结果
public static Result Success(string message = null)
{
return new Result { Succeeded = true, Message = message };
}
// 创建失败结果
public static Result Failure(string message, string errorCode = null)
{
return new Result
{
Succeeded = false,
Message = message,
ErrorCode = errorCode
};
}
}
// 泛型结果类型
public class Result<T> : Result
{
public T Data { get; set; }
// 创建带数据的成功结果
public static Result<T> Success(T data, string message = null)
{
return new Result<T>
{
Succeeded = true,
Message = message,
Data = data
};
}
// 创建带数据类型的失败结果
public static Result<T> Failure(string message, string errorCode = null)
{
return new Result<T>
{
Succeeded = false,
Message = message,
ErrorCode = errorCode
};
}
}
// 在控制器中使用
[HttpGet("{id}")]
public async Task<ActionResult<Result<UserDto>>> GetUser(string id)
{
try
{
var user = await _userService.GetUserAsync(id);
return Result<UserDto>.Success(user);
}
catch (UserNotFoundException ex)
{
return Result<UserDto>.Failure(ex.Message, ex.ErrorCode);
}
}
// 或使用XiHanControllerBase提供的便捷方法
[HttpGet("{id}")]
public async Task<ActionResult<Result<UserDto>>> GetUser(string id)
{
try
{
var user = await _userService.GetUserAsync(id);
if (user == null)
{
return NotFound("用户不存在", "USER-404");
}
return Success(user);
}
catch (Exception ex)
{
return Error(ex.Message);
}
}
分页类型
XiHan.Framework 提供了统一的分页类型,用于表示分页数据:
csharp
// 分页参数
public class PageParameters
{
public int PageNumber { get; set; } = 1;
public int PageSize { get; set; } = 10;
public string SortField { get; set; }
public SortOrder SortOrder { get; set; } = SortOrder.Ascending;
public string SearchTerm { get; set; }
public Dictionary<string, string> Filters { get; set; }
}
// 分页结果
public class PagedResult<T>
{
public List<T> Items { get; set; }
public int TotalCount { get; set; }
public int PageNumber { get; set; }
public int PageSize { get; set; }
public int TotalPages => (int)Math.Ceiling(TotalCount / (double)PageSize);
public bool HasPrevious => PageNumber > 1;
public bool HasNext => PageNumber < TotalPages;
// 创建分页结果
public static PagedResult<T> Create(
List<T> items,
int totalCount,
int pageNumber,
int pageSize)
{
return new PagedResult<T>
{
Items = items,
TotalCount = totalCount,
PageNumber = pageNumber,
PageSize = pageSize
};
}
}
// 在服务中使用
public async Task<PagedResult<ProductDto>> GetPagedProductsAsync(PageParameters parameters)
{
// 创建查询
var query = _productRepository.GetAll();
// 应用过滤
if (!string.IsNullOrEmpty(parameters.SearchTerm))
{
query = query.Where(p => p.Name.Contains(parameters.SearchTerm) ||
p.Description.Contains(parameters.SearchTerm));
}
// 应用自定义过滤器
if (parameters.Filters != null)
{
if (parameters.Filters.TryGetValue("category", out var category))
{
query = query.Where(p => p.Category.Name == category);
}
if (parameters.Filters.TryGetValue("minPrice", out var minPriceStr) &&
decimal.TryParse(minPriceStr, out var minPrice))
{
query = query.Where(p => p.Price >= minPrice);
}
}
// 获取总数
var totalCount = await query.CountAsync();
// 应用排序
query = ApplySorting(query, parameters.SortField, parameters.SortOrder);
// 应用分页
var items = await query
.Skip((parameters.PageNumber - 1) * parameters.PageSize)
.Take(parameters.PageSize)
.Select(p => _mapper.Map<ProductDto>(p))
.ToListAsync();
// 返回分页结果
return PagedResult<ProductDto>.Create(
items,
totalCount,
parameters.PageNumber,
parameters.PageSize);
}
// 在API中使用
[HttpGet]
public async Task<ActionResult<Result<PagedResult<ProductDto>>>> GetProducts([FromQuery] PageParameters parameters)
{
var result = await _productService.GetPagedProductsAsync(parameters);
return Success(result);
}
高级功能
对象映射
XiHan.Framework 集成了 Mapster,提供了高性能的对象映射功能:
csharp
// 在 Program.cs 中添加对象映射
builder.Services.AddXiHanObjectMapping(options =>
{
options.UseMappingLibrary(MappingLibrary.Mapster);
options.ScanAssemblies = new[] { typeof(Program).Assembly };
});
// 定义映射配置
public class MappingProfile : IRegister
{
public void Register(TypeAdapterConfig config)
{
config.NewConfig<Product, ProductDto>()
.Map(dest => dest.CategoryName, src => src.Category.Name)
.Map(dest => dest.TotalSales, src => src.OrderItems.Sum(oi => oi.Quantity));
config.NewConfig<CreateProductDto, Product>()
.Map(dest => dest.CreatedDate, _ => DateTime.UtcNow)
.Ignore(dest => dest.Id);
}
}
// 在服务中使用对象映射
public class ProductService
{
private readonly IObjectMapper _mapper;
private readonly IRepository<Product> _productRepository;
public ProductService(
IObjectMapper mapper,
IRepository<Product> productRepository)
{
_mapper = mapper;
_productRepository = productRepository;
}
public async Task<ProductDto> GetProductAsync(int id)
{
var product = await _productRepository.GetByIdAsync(id);
return _mapper.Map<ProductDto>(product);
}
public async Task<Product> CreateProductAsync(CreateProductDto dto)
{
var product = _mapper.Map<Product>(dto);
return await _productRepository.InsertAsync(product);
}
}
数据验证
XiHan.Framework 集成了 FluentValidation,提供了强大的数据验证功能:
csharp
// 在 Program.cs 中添加验证
builder.Services.AddXiHanValidation(options =>
{
options.ScanAssemblies = new[] { typeof(Program).Assembly };
options.RegisterValidatorsAutomatically = true;
options.ValidateOnBuild = true;
});
// 定义验证规则
public class CreateProductValidator : AbstractValidator<CreateProductDto>
{
public CreateProductValidator(ICategoryRepository categoryRepository)
{
RuleFor(x => x.Name)
.NotEmpty().WithMessage("产品名称不能为空")
.MaximumLength(100).WithMessage("产品名称最多100个字符");
RuleFor(x => x.Price)
.GreaterThan(0).WithMessage("价格必须大于0");
RuleFor(x => x.Description)
.MaximumLength(500).WithMessage("描述最多500个字符");
RuleFor(x => x.CategoryId)
.MustAsync(async (categoryId, cancellation) =>
{
var categoryExists = await categoryRepository.ExistsAsync(c => c.Id == categoryId);
return categoryExists;
}).WithMessage("所选类别不存在");
}
}
// 在控制器中自动验证
[HttpPost]
public async Task<ActionResult<Result<ProductDto>>> CreateProduct(CreateProductDto dto)
{
// 无需手动验证,框架会自动处理验证并返回适当的错误响应
var product = await _productService.CreateProductAsync(dto);
return Success(_mapper.Map<ProductDto>(product));
}
事件总线
XiHan.Framework 提供了事件总线功能,支持发布/订阅模式:
csharp
// 在 Program.cs 中添加事件总线
builder.Services.AddXiHanEventBus(options =>
{
options.ScanAssemblies = new[] { typeof(Program).Assembly };
options.EnableRetry = true;
options.MaxRetryAttempts = 3;
options.RetryInterval = TimeSpan.FromSeconds(5);
});
// 定义事件
public class UserCreatedEvent : Event
{
public string UserId { get; set; }
public string Username { get; set; }
public string Email { get; set; }
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}
// 定义事件处理器
[EventHandler]
public class SendWelcomeEmailHandler : IEventHandler<UserCreatedEvent>
{
private readonly IEmailService _emailService;
private readonly ILogger<SendWelcomeEmailHandler> _logger;
public SendWelcomeEmailHandler(
IEmailService emailService,
ILogger<SendWelcomeEmailHandler> logger)
{
_emailService = emailService;
_logger = logger;
}
public async Task HandleAsync(UserCreatedEvent @event)
{
_logger.LogInformation("准备向用户 {@Username} 发送欢迎邮件", @event.Username);
try
{
await _emailService.SendEmailAsync(
to: @event.Email,
subject: "欢迎加入我们的平台",
body: $"你好 {@event.Username},感谢您注册我们的服务!"
);
_logger.LogInformation("已成功发送欢迎邮件");
}
catch (Exception ex)
{
_logger.LogError(ex, "发送欢迎邮件失败: {ErrorMessage}", ex.Message);
throw; // 重新抛出异常以触发重试机制
}
}
}
// 发布事件
public class UserService
{
private readonly IEventBus _eventBus;
private readonly IUserRepository _userRepository;
public UserService(
IEventBus eventBus,
IUserRepository userRepository)
{
_eventBus = eventBus;
_userRepository = userRepository;
}
public async Task<User> CreateUserAsync(CreateUserDto dto)
{
// 创建用户
var user = new User
{
Username = dto.Username,
Email = dto.Email,
// 其他属性...
};
// 保存用户
user = await _userRepository.InsertAsync(user);
// 发布事件
await _eventBus.PublishAsync(new UserCreatedEvent
{
UserId = user.Id,
Username = user.Username,
Email = user.Email
});
return user;
}
}
最佳实践
项目结构
推荐的项目结构如下:
MyXiHanApp/
├── src/
│ ├── MyXiHanApp.Domain/ # 领域模型、接口、服务
│ │ ├── Aggregates/ # 聚合根和领域实体
│ │ ├── Repositories/ # 仓储接口
│ │ ├── Services/ # 领域服务
│ │ └── Events/ # 领域事件
│ │
│ ├── MyXiHanApp.Application/ # 应用服务和DTO
│ │ ├── Services/ # 应用服务实现
│ │ ├── DTOs/ # 数据传输对象
│ │ ├── Mapping/ # 对象映射配置
│ │ └── Validators/ # 验证器
│ │
│ ├── MyXiHanApp.Infrastructure/ # 基础设施实现
│ │ ├── Data/ # 数据访问实现
│ │ │ ├── Context/ # 数据库上下文
│ │ │ ├── Repositories/ # 仓储实现
│ │ │ ├── Configurations/ # 实体配置
│ │ │ └── Migrations/ # 数据库迁移
│ │ │
│ │ ├── Services/ # 外部服务集成
│ │ └── Logging/ # 日志配置
│ │
│ └── MyXiHanApp.Web/ # Web API 和表示层
│ ├── Controllers/ # API控制器
│ ├── Middleware/ # 自定义中间件
│ ├── Filters/ # 过滤器
│ └── Startup/ # 启动配置
│
├── tests/
│ ├── MyXiHanApp.UnitTests/ # 单元测试
│ ├── MyXiHanApp.IntegrationTests/ # 集成测试
│ └── MyXiHanApp.FunctionalTests/ # 功能测试
│
└── tools/ # 实用工具和脚本
依赖倒置原则
遵循依赖倒置原则,让高层模块不依赖于低层模块:
csharp
// 定义接口在领域层
public interface IProductRepository
{
Task<Product> GetByIdAsync(int id);
Task<List<Product>> GetActiveProductsAsync();
Task<Product> AddAsync(Product product);
// 其他方法...
}
// 实现在基础设施层
public class ProductRepository : IProductRepository
{
private readonly ApplicationDbContext _context;
public ProductRepository(ApplicationDbContext context)
{
_context = context;
}
public async Task<Product> GetByIdAsync(int id)
{
return await _context.Products
.Include(p => p.Category)
.FirstOrDefaultAsync(p => p.Id == id);
}
public async Task<List<Product>> GetActiveProductsAsync()
{
return await _context.Products
.Where(p => p.IsActive && !p.IsDeleted)
.OrderByDescending(p => p.CreatedAt)
.ToListAsync();
}
public async Task<Product> AddAsync(Product product)
{
await _context.Products.AddAsync(product);
await _context.SaveChangesAsync();
return product;
}
// 其他方法实现...
}
// 在应用服务中使用仓储接口
public class ProductService
{
private readonly IProductRepository _productRepository;
private readonly IObjectMapper _mapper;
public ProductService(
IProductRepository productRepository,
IObjectMapper mapper)
{
_productRepository = productRepository;
_mapper = mapper;
}
public async Task<List<ProductDto>> GetActiveProductsAsync()
{
var products = await _productRepository.GetActiveProductsAsync();
return _mapper.Map<List<ProductDto>>(products);
}
// 其他方法...
}