我使用Drum提供了一个通用类`UriMaker:
public class UriMaker<TController>
{
// I need use this one
public UriMaker(UriMakerContext context, HttpRequestMessage request) { }
public UriMaker(Func<MethodInfo, RouteEntry> mapper, UrlHelper urlHelper) { }
}
像这样使用:
public class UserController : ApiController
{
public UserController(UriMaker<UserController> urlMaker) {}
}
我曾经在Unity注册过它:
container.RegisterType(typeof(UriMaker<>),
new InjectionConstructor(typeof(UriMakerContext), typeof(HttpRequestMessage)));
但现在正在迁移到Simple Injector。我已经有了这个:
UriMakerContext uriMaker = config.MapHttpAttributeRoutesAndUseUriMaker();
container.RegisterSingle(uriMakerContext);
那么现在如何注册UriMaker<>
呢?
答案 0 :(得分:2)
尽管可以配置Simple Injector以允许将UriMaker<TController>
直接注入您的控制器,但我强烈建议您出于多种原因。
首先,您应该尽量减少应用程序对外部库的依赖性。这可以通过定义特定于应用程序的抽象(符合ISP)来轻松完成。
其次,直接注入UriMaker
会使您极难测试,因为UriMaker
被拉入您的测试代码,而它假设一个活动的HTTP请求并假设Web API路由系统是配置正确。这些都是您不希望您的测试代码依赖的内容。
最后,它使verifying the object graph变得更难,因为UriMaker依赖于HttpRequestMessage
,这是一个运行时值。通常,不应将运行时值注入服务的构造函数中。您应该使用组件(包含应用程序行为的东西)构建对象图,并在构建后通过对象图发送运行时数据。
相反,我建议采用以下抽象:
public interface IUrlProvider
{
Uri UriFor<TController>(Expression<Action<TController>> action);
}
现在您的控制器可以依赖于此IUrlProvider
,而不是依赖于外部库:
public class UserController : ApiController
{
private readonly IUrlProvider urlProvider;
public UserController(IUrlProvider urlProvider)
{
this.urlProvider = urlProvider;
}
public string Get()
{
this.urlProvider.UriFor<HomeController>(c => c.SomeFancyAction());
}
}
在幕后,您当然仍需要致电Drum
,为此您需要为IUrlProvider
定义代理实施:
public class DrumUrlProvider : IUrlProvider
{
private readonly UriMakerContext context;
private readonly Func<HttpRequestMessage> messageProvider;
public DrumUrlProvider(UriMakerContext context,
Func<HttpRequestMessage> messageProvider)
{
this.context = context;
this.messageProvider= messageProvider;
}
public Uri UriFor<TController>(Expression<Action<TController>> action)
{
HttpRequestMessage message = this.messageProvider.Invoke();
var maker = new UriMaker<TController>(this.context, message);
return maker.UriFor(action);
}
}
此实现可以通过以下方式注册为singleton:
container.EnableHttpRequestMessageTracking(config);
UriMakerContext uriMakerContext =
config.MapHttpAttributeRoutesAndUseUriMaker();
IUrlProvider drumProvider = new DrumUrlProvider(uriMakerContext,
() => container.GetCurrentHttpRequestMessage());
container.RegisterSingle<IUrlProvider>(drumProvider);
此示例使用Simple Injector Web API integration package允许使用HttpRequestMessage
和EnableHttpRequestMessageTracking
扩展方法检索当前请求GetCurrentHttpRequestMessage
,如here所述。