我正在探索.NET WebAPI应用程序中DryIoc的使用,并且注意到初始化步骤有奇怪的行为.在一个简单的测试webapi应用程序中,我具有以下DryIoc注册类,该类在WebApi配置注册后立即被调用.
public class DryIocConfig
{
public static void Register(HttpConfiguration config)
{
var c = new Container().WithWebApi(config);
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
}
以及以下WebApi控制器:
public class ValuesController : ApiController
{
private readonly IWidgetService _widgetService;
public ValuesController(IWidgetService widgetService)
{
_widgetService = widgetService;
}
// GET api/values
public IEnumerable<Widget> Get()
{
return _widgetService.GetWidgets();
}
}
这似乎很好用,但是在我看来,尝试起来是一样的,但是写得更冗长,代码出错了.
public class DryIocConfig
{
public static void Register(HttpConfiguration config)
{
var c = new Container();
c.WithWebApi(config); // Now separate statement rather than chained.
c.Register<IWidgetService, WidgetService>(Reuse.Singleton);
c.Register<IWidgetRepository, WidgetRepository>(Reuse.Singleton);
}
}
我得到的异常如下(作为JSON):
{
"Message" : "An error has occurred.",
"ExceptionMessage" : "An error occurred when trying to create a controller of type 'ValuesController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType" : "System.InvalidOperationException",
"StackTrace" : " at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException" : {
"Message" : "An error has occurred.",
"ExceptionMessage" : "Type 'IOCContainerTest.DryLoc.Controllers.ValuesController' does not have a default constructor",
"ExceptionType" : "System.ArgumentException",
"StackTrace" : " at System.Linq.Expressions.Expression.New(Type type)\r\n at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
}
}
DryIoc有点奇怪,还是我从未遇到过的C#细微差别?
解决方法:
这是因为.WithWebApi()是每个source的扩展方法.
public static IContainer WithWebApi(this IContainer container, HttpConfiguration config,
IEnumerable<Assembly> controllerAssemblies = null, IScopeContext scopeContext = null,
Func<Type, bool> throwIfUnresolved = null)
{
container.ThrowIfNull();
if (container.ScopeContext == null)
container = container.With(scopeContext: scopeContext ?? new AsyncExecutionFlowScopeContext());
container.RegisterWebApiControllers(config, controllerAssemblies);
container.SetFilterProvider(config.Services);
InsertRegisterRequestMessageHandler(config);
config.DependencyResolver = new DryIocDependencyResolver(container, throwIfUnresolved);
return container;
}
在第一个语法示例中,您将创建一个Container的新实例,并将该新创建的实例传递给.WithWebApi().依次更新容器实例,最后将其返回给变量c.
在第二个语法示例中,您永远不会将扩展方法BACK的值返回到原始变量,也不会对其进行更新.您正在调用它,就好像它是一个void方法一样,在这种情况下不执行任何操作,因此是例外.
如果您改写了以下内容:
var c = new Container();
c = c.WithWebApi(config);
从本质上讲,它应该是第一种语法的更详细的示例,并且已经使用新功能正确地更新了c.