LightInject如何在控制台应用中调用控制器的HttpPost方法
实现方案
控制器上的[HttpPost]、[Route]等特性仅用于ASP.NET Core路由系统识别HTTP请求,本地直接调用类方法时这些特性不会产生任何限制,本质就是调用普通类的公开异步方法。你可以按两种方案实现:
方案1:直接调用控制器方法(快速实现)
首先修正你现有Bootstrapper代码的容器引用问题:你当前在静态RegisterServicesAsync方法中新建了ServiceContainer实例,和构造函数注入的容器没有关联,会导致依赖注入链路断裂。
修正后的代码如下:
public class MyBootstrapper { private readonly IServiceContainer _serviceContainer; public MyBootstrapper(IServiceContainer container) { _serviceContainer = container; // 注册依赖 container.RegisterConstructorDependency<ILog>((factory, info) => new InfoLogger(info.Member.DeclaringType)); container.Register<MyController>(); } public async Task RunAsync() { await RegisterServicesAsync(); } // 去掉static修饰符,复用类内的容器实例 protected async Task RegisterServicesAsync() { using (_serviceContainer.BeginScope()) { // 解析控制器实例 var myController = _serviceContainer.Resolve<MyController>(); // 如果你的Start方法中没有用到HttpContext相关属性(Request/Response/User等),可跳过下面这步 myController.ControllerContext = new ControllerContext { HttpContext = new DefaultHttpContext() }; // 直接调用Start方法,传入业务需要的Id参数 IActionResult result = await myController.Start("你的业务ID参数"); // 按需处理返回的IActionResult即可 } } }
控制台侧的Configure方法无需大幅改动,注意确保Bootstrapper初始化时传入的是全局容器实例即可。
方案2:抽离业务服务(推荐)
将业务逻辑写在控制器中不符合单一职责原则,如果你需要多端复用业务逻辑,建议把逻辑从控制器中抽离为独立服务层,控制器和Bootstrapper都依赖该服务调用逻辑:
- 定义并实现业务服务
// 服务接口 public interface IMyBusinessService { // 返回值替换为你实际的业务返回类型,不要使用IActionResult Task<string> StartAsync(string id); } // 服务实现 public class MyBusinessService : IMyBusinessService { private readonly ILog _logger; public MyBusinessService(ILog logger) { _logger = logger; } public async Task<string> StartAsync(string id) { // 将原MyController.Start方法中的业务逻辑迁移到此处 } }
- 改造控制器依赖服务
public class MyController : ControllerBase { private readonly IMyBusinessService _businessService; public MyController(IMyBusinessService businessService) { _businessService = businessService; } [Route("api/route/{Id}/Start")] [HttpPost] public async Task<IActionResult> Start(string Id) { var result = await _businessService.StartAsync(Id); return Ok(result); } }
- Bootstrapper中直接调用服务,无需处理控制器相关的HttpContext适配
public class MyBootstrapper { private readonly IServiceContainer _serviceContainer; public MyBootstrapper(IServiceContainer container) { _serviceContainer = container; // 注册依赖 container.RegisterConstructorDependency<ILog>((factory, info) => new InfoLogger(info.Member.DeclaringType)); container.Register<IMyBusinessService, MyBusinessService>(); } public async Task RunAsync() { await RegisterServicesAsync(); } protected async Task RegisterServicesAsync() { using (_serviceContainer.BeginScope()) { // 直接解析业务服务调用即可 var businessService = _serviceContainer.Resolve<IMyBusinessService>(); await businessService.StartAsync("你的业务ID参数"); } } }
注意事项
- 直接调用控制器方法时如果用到HttpContext相关属性,必须手动赋值
DefaultHttpContext,否则会触发空引用异常 - 尽量避免用
Wait()同步阻塞异步方法,有条件的话可以将控制台入口方法改为async Task类型,用await调用RunAsync避免死锁
内容的提问来源于stack exchange,提问作者imj
相关产品推荐
相关产品推荐

