如何在F# ASP.NET Minimal API中使用键控服务注入属性?
纯F# + .NET 8 Minimal API 键控服务解决方案
1. 定义服务接口与实现
先创建键控服务的核心接口及具体实现类:
type IMessageService = abstract member GetMessage : unit -> string // SMS服务实现 type SmsMessageService() = interface IMessageService with member _.GetMessage() = "This is an SMS notification" // 邮件服务实现 type EmailMessageService() = interface IMessageService with member _.GetMessage() = "This is an Email notification"
2. 注册键控服务
在应用构建阶段完成带键服务的注册:
let builder = WebApplication.CreateBuilder(args) // 注册键控单例服务 builder.Services.AddKeyedSingleton<IMessageService, SmsMessageService>("sms") builder.Services.AddKeyedSingleton<IMessageService, EmailMessageService>("email") let app = builder.Build()
3. 定义端点(规避Lambda属性丢失问题)
F#的Lambda表达式会被包装为Func实例,导致参数上的FromKeyedServices属性无法被ASP.NET Core识别,因此需采用静态方法或实例方法定义端点逻辑:
方式一:模块内静态方法
module MessageEndpoints = static member GetMessage( [<FromKeyedServices(Key = "{key}")>] messageService: IMessageService, [<FromRoute>] key: string) = messageService.GetMessage() // 映射端点 app.MapGet("/message/{key}", MessageEndpoints.GetMessage)
方式二:类实例方法(适配复杂端点逻辑)
type MessageEndpointHandler() = member _.HandleMessage( [<FromKeyedServices(Key = "{key}")>] messageService: IMessageService) = messageService.GetMessage() // 注册处理器类 builder.Services.AddTransient<MessageEndpointHandler>() // 映射端点 app.MapGet("/message/{key}", (handler: MessageEndpointHandler) => handler.HandleMessage)
4. 验证效果
启动应用后,访问对应端点即可获取预期结果:
GET /message/sms返回This is an SMS notificationGET /message/email返回This is an Email notification
关键注意事项
- 禁止用Lambda表达式定义带
FromKeyedServices属性的端点参数,否则会因Func包装导致属性丢失,触发InvalidOperationException。 - 使用静态/实例方法时,参数上的
FromKeyedServices属性会被完整保留,ASP.NET Core可正常识别并注入对应键的服务。
内容的提问来源于stack exchange,提问作者Adam
相关产品推荐
相关产品推荐

