我正在探索.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

10-06 14:46