当我使用像Ninject这样的WebApi时,我试图围绕如何处理F#中的DI.
例如,在C#中,当我连接我的容器时,我只是告诉DI类型解析的内容,例如:
kernel.Bind().To ();
当控制器构造函数需要时,我的Api控制器将自动连接它.
太棒了,现在我可以整天为接口和类添加方法,无需再次触摸容器.
但是在F#中(除非我这样做完全错误)我创建了部分应用程序然后将它们传递给控制器,每次我添加一个方法我必须再次在容器中连接.也许这是正确的,我不确定,但似乎更多的接线.
为了澄清我的意思,让我们来看一个典型的REST Api.对于每个具有CRUD的实体 - 例如:
客户(创建,读取,更新,删除).
那么我是否必须将每个功能注入控制器?
所以在这个例子中,假设我有服务 - >域 - > repo模型:
let createCustomerFunc = createCustomerDomainFunc createCustomerRepoFunc let getAllCustomersFunc = getAllCustomerDomainFunc getAllCustomerRepoFunc let updateCustomerFunc cust = [...] let deleteCustomerFunc id = [...] let getSingleCustomerFunc id = [...]
现在在我的容器中,当我绑定它时,我会做类似的事情:
kernel.Bind().To () .WithConstructorArgument(createCustomerFunc, getAllCustomerFunc, etc...) |> ignore
现在如果我添加方法:GetActiveCustomers我将不得不修改上面的代码以传递新的部分应用程序?
感觉......错了 - 我只是错误地接近这个?
使用DI容器提供了一些优点,以及一些缺点.
主要优点是,如果您有一个庞大的代码库,您可以使用约定优于配置来连接所有依赖项.使用约定优于配置,您还可以获得代码必须更加一致的好处,因为它必须遵循约定.
但是有几个缺点.最直接的是你失去了编译器的快速反馈.您可以更轻松地对系统进行更改,并且在编译所有内容时,系统会在运行时失败.有些人希望你可以要求DI容器进行自我诊断,但你不能.
使用DI容器的另一个不那么明显的缺点是,如你所说,简单地向控制器等添加更多成员就太容易了.这实际上增加了耦合,或降低了内聚力,但DI提供的基于反射的自动化容器隐藏了这个问题.
由于我认为缺点超过了优点,我建议您使用Pure DI而不是DI Containers.
这适用于C#,Visual Basic .NET或Java中的面向对象编程,但同样适用于F#中的函数编程.
在未混合的Functional F#代码库中,我根本不会使用类或接口; 相反,我只会把功能组合在一起.
在使用ASP.NET Web API的混合代码库中,我尽可能快地跨越OOP和FP之间的桥梁.正如我在使用F# talk的测试驱动开发中解释的那样(在Pluralsight上可用的扩展材料),我将一个函数注入到Controller中,如下所示:
type ReservationsController(imp) = inherit ApiController() member this.Post(rendition : ReservationRendition) : IHttpActionResult = match imp rendition with | Failure(ValidationError msg) -> this.BadRequest msg :> _ | Failure CapacityExceeded -> this.StatusCode HttpStatusCode.Forbidden :> _ | Success () -> this.Ok () :> _
这是该控制器的整个代码库.所有行为都是通过实现的imp
.
在应用程序的启动代码中,imp
组成如下:
let imp = Validate.reservationValid >> Rop.bind (Capacity.check 10 SqlGateway.getReservedSeats) >> Rop.map SqlGateway.saveReservation
您可能会争辩说上面ReservationsController
只定义了一种Post
方法.如果Controller必须公开更多方法怎么办?
在这种情况下,为每个方法注入一个实现函数.在REST API中,任何Controller都应该只有2-3个方法,这实际上意味着2-3个依赖项.在我看来,这是一个完全可以接受的依赖项数量.
2-3方法最大的原因是在适当的RESTful设计中,资源往往遵循一些交互模式:
GET
POST
POST
, GET
PUT
, GET
DELETE
, GET
PUT
,DELETE
,GET
完整的组合(POST
,GET
,PUT
,DELETE
)是一个REST设计的味道,但所有的是一个完全不同的讨论.