确保控制器具有无参数的公共构造函数错误

时间:2014-06-17 00:41:22

标签: c# asp.net-mvc asp.net-web-api unity-container

我已经遵循了这个非常有用的tutorial,直到我修改了DbContext以获得额外的构造函数。我现在遇到了解决方案的问题,不知道如何解决这个问题。是否有一种简单的方法可以强制它抓住无参数构造函数,或者我接近这个错误?

DbContext有两个构造函数:

public class DashboardDbContext : DbContext
{
    public DashboardDbContext() : base("DefaultConnection") { }

    public DashboardDbContext(DbConnection dbConnection, bool owns)
        : base(dbConnection, owns) { }
}

SiteController构造函数:

private readonly IDashboardRepository _repo;

public SiteController(IDashboardRepository repo)
{
    _repo = repo;
}

存储库:

DashboardDbContext _context;

public DashboardRepository(DashboardDbContext context)
{
    _context = context;
}

UnityResolver代码:

public class UnityResolver : IDependencyResolver
{
    private readonly IUnityContainer _container;

    public UnityResolver(IUnityContainer container)
    {
        _container = container;
    }

    public object GetService(Type serviceType)
    {
        try
        {
            return _container.Resolve(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return null;
        }
    }

    public IEnumerable<object> GetServices(Type serviceType)
    {
        try
        {
            return _container.ResolveAll(serviceType);
        }
        catch (ResolutionFailedException)
        {
            return new List<object>();
        }
    }

    public IDependencyScope BeginScope()
    {
        var child = _container.CreateChildContainer();
        return new UnityResolver(child);
    }

    public void Dispose()
    {
        _container.Dispose();
    }
}

WebApiConfig:

var container = new UnityContainer();
container.RegisterType<IDashboardRepository, DashboardRepository>(new HierarchicalLifetimeManager());
config.DependencyResolver = new UnityResolver(container);

WebApi呼叫错误:

  

System.InvalidOperationException:尝试创建类型为&#39; SiteController&#39;的控制器时发生错误。确保控制器具有无参数的公共构造函数。

at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType) 
at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request) 
at System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken) 
at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__0.MoveNext()
  

InnerException:System.ArgumentException:Type&#39; Dashboard.Web.Controllers.SiteController&#39;没有默认构造函数。

at System.Linq.Expressions.Expression.New(Type type) 
at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType) 
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator) 
at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)

该教程非常棒,并且在我添加第二个构造函数之前一直很好用。

10 个答案:

答案 0 :(得分:112)

发生的事情是你被this problem咬了。基本上,发生的事情是您没有在容器中明确注册控制器。 Unity尝试为您解决未注册的具体类型,但由于它无法解决它(由配置中的错误引起),因此它返回null。它被强制返回null,因为Web API强制它由于IDependencyResolver契约而这样做。由于Unity返回null,Web API将尝试创建控制器本身,但由于它没有默认构造函数,因此它将抛出&#34;确保控制器具有无参数的公共构造函数&#34;例外。此异常消息具有误导性,并不能解释真正的原因。

如果您明确注册了控制器,您会看到更清晰的异常消息,这就是为什么您应该始终明确注册所有根类型的原因。

但是,当然,配置错误来自于将第二个构造函数添加到DbContext。 Unity总是试图选择具有最多参数的构造函数,但它不知道如何解析这个特定的构造函数。

因此,真正的原因是您正在尝试使用Unity的自动布线功能来创建DbContextDbContext是一种特殊类型,不应自动连接。它是一种框架类型,你应该therefore fallback to registering it using a factory delegate

container.Register<DashboardDbContext>(
    new InjectionFactory(c => new DashboardDbContext())); 

答案 1 :(得分:38)

就我而言,这是因为我注入的依赖项的构造函数内部存在异常(在您的示例中 - 在DashboardRepository构造函数中)。这个例外是在MVC基础设施内部捕获的。我在相关地点添加了日志后发现了这一点。

答案 2 :(得分:5)

我遇到了同样的问题,我通过在UnityConfig.cs文件中进行更改来解决这个问题为了解决UnityConfig.cs文件中的依赖性问题,您必须添加:

public static void RegisterComponents()    
{
    var container = new UnityContainer();
    container.RegisterType<ITestService, TestService>();
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}

答案 3 :(得分:4)

有时因为你在ContainerBootstraper.cs中解析你的接口,所以很难捕获错误。在我的情况下,解决我注入到api控制器的接口的实现时出错。我找不到错误,因为我已经解决了bootstraperContainer中的接口,如下所示:   container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
然后我在我的引导容器中添加以下行:container.RegisterType<MyController>(); 因此,当我编译项目时,编译器抱怨并停在上面一行并显示错误。

答案 4 :(得分:1)

我遇到了同样的问题。我用Google搜索了两天。最后我不小心注意到问题是Controller的构造函数的访问修饰符。 我没有将public关键字放在Controller的构造函数后面。

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

        public MyController(IMyClass myClass)
        {
            _myClass = myClass;
        }
    }

我将此经验添加为另一个答案,也许其他人犯了类似的错误。

答案 5 :(得分:0)

如果您的控制器中有接口

public myController(IXInterface Xinstance){}

您必须将它们注册到Dependency Injection容器中。

container.Bind<IXInterface>().To<XClass>().InRequestScope();

答案 6 :(得分:0)

当我不小心将属性定义为特定的对象类型而不是我在UnityContainer中定义的接口类型时,出现了此错误。

例如:

定义UnityContainer:

var container = new UnityContainer();
container.RegisterInstance(typeof(IDashboardRepository), DashboardRepository);
config.DependencyResolver = new UnityResolver(container);

SiteController(错误的方式-通知回购类型):

private readonly DashboardRepository _repo;

public SiteController(DashboardRepository repo)
{
    _repo = repo;
}

SiteController(正确的方法):

private readonly IDashboardRepository _repo;

public SiteController(IDashboardRepository repo)
{
    _repo = repo;
}

答案 7 :(得分:0)

如果您正在使用 UnityConfig.cs 来抵抗您的类型的映射,如下所示。

public static void RegisterTypes(IUnityContainer container)
    {
     container.RegisterType<IProductRepository, ProductRepository>();
    }

您必须让**webApiConfig.cs**知道有关容器的信息

config.DependencyResolver = new Unity.AspNet.WebApi.UnityDependencyResolver(UnityConfig.Container);

答案 8 :(得分:0)

就我而言,Unity变成了一个红色鲱鱼。我的问题是针对不同版本.NET的不同项目的结果。正确设置了Unity,并且所有内容均已在容器中正确注册。一切都编译良好。但是类型位于类库中,并且该类库设置为以.NET Framework 4.0为目标。使用Unity的WebApi项目设置为以.NET Framework 4.5为目标。将类库更改为也以4.5为目标可以解决此问题。

我通过注释掉DI构造函数并添加默认构造函数发现了这一点。我注释掉了控制器方法,并让它们抛出NotImplementedException。我确认可以到达控制器,并且看到NotImplementedException告诉我正在实例化控制器。接下来,在默认构造函数中,我手动实例化了依赖关系链,而不是依赖于Unity。它仍然可以编译,但是当我运行它时,错误消息又回来了。这为我确认,即使Unity不在画面中,我仍然会收到错误消息。最终,我从链的最底部开始,然后向上移动,一次注释掉一行,然后重新测试,直到不再收到错误消息。这将我引向了令人反感的类的方向,从那里我发现它被隔离为一个单一的程序集。

答案 9 :(得分:0)

真的,真的希望这个答案能帮助其他人避免浪费一天半的时间; Ninject、MVC 设计模式、Global.asax、Web Common 文件等

就我而言,错误本身完全具有误导性。

我的整个应用程序运行正常,除了当我调用一个特定的控制器让我们调用 TestController 时。

测试控制器正在使用 Ninject 注入一个接口让我们像这样调用 ITest -

public class TestController : ApiController
{
    private readonly ITest _test;

    public TestController (ITest test)
    {
        _test= test;
    }

我向 TestController 中的一个方法发出了一个简单的 GET 请求,并且遇到了这个线程问题的上述错误。

我最终将其归结为仅在将 ITest 作为参数注入时才会发生的错误(因为我测试了不同的接口并且它运行良好!)

这让我检查了 Test 类并意识到我已经将自身的一个实例注入其中!像这样 -

public class Test: ITest
{
    private readonly ITest_test;

    public Nodes(ITest test)
    {
        _test = test;
    }

因此导致整个调用作为未处理的异常而失败并返回一个完全没有帮助我的完全奇怪的错误!