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


105

我遵循了本教程,该教程效果很好,直到我修改了我的教程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:尝试创建“ SiteController”类型的控制器时发生错误。确保控制器具有无参数的公共构造函数。

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:类型'Dashboard.Web.Controllers.SiteController'没有默认的构造函数。

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)

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


2
错误告诉您SiteController必须具有无参数构造函数,而不是DashboardDbContext
尼尔·史密斯

嗨,Smith.h.Neil,但是只有将其他构造函数添加到dbcontext时,它才会引发该错误。如果我删除它或将其注释掉(第二个构造函数),它将正常工作。
scarpacci 2014年

我可以看到构造函数SiteController吗?
尼尔·史密斯

我猜您是在将注入DbContext到存储库中吗?
尼尔·史密斯

@scarpacci您确定要做的唯一更改就是从DbContext中删除了第二个构造函数?除非通过不具有第二个DbContext构造函数以某种方式绕过控制器的实例化,否则错误依赖于DbContext的构造函数将是没有意义的。
Asad Saeeduddin 2014年

Answers:


130

发生的事情是您被这个问题咬了。基本上,发生的事情是您没有在容器中显式注册控制器。Unity尝试为您解析未注册的具体类型,但是由于无法解析(由于配置错误导致),因此它返回null。由于IDependencyResolver合同规定,Web API强制其返回null,因此它被迫返回null 。由于Unity返回null,因此Web API将尝试创建控制器本身,但是由于它没有默认构造函数,因此它将引发“确保控制器具有无参数公共构造函数”异常。此异常消息具有误导性,没有解释真正的原因。

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

但是,当然,配置错误是由于您在中添加了第二个构造函数而引起的DbContext。Unity总是尝试选择参数最多的构造函数,但是它不知道如何解析这个特定的构造函数。

因此,真正的原因是您试图使用Unity的自动装配功能来创建DbContextDbContext是不应该自动接线的特殊类型。这是一种框架类型,因此您应该回退到使用工厂委托进行注册

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

请注意,当您重建项目时,您可以重设登录凭据...在尝试应用此解决方案之前,请:重建项目,注销自己,然后再次登录,然后再进行-刷新页面并观察问题是否仍然存在
ymz

谢谢-我后端团队的这些dingleberries通过统一配置违反了很多规则。开始怀疑这是否是每个团队使用IOC容器的方式。
Dagrooms

@Dagrooms:许多开发人员对此颇为不满,但这不是所有DI容器中都存在的问题。例如,简单注入器将始终确保在出现此类错误时提示表达错误。另一个好提示:不要使用自定义,IDependencyResolver而只能使用自定义IControllerActivator
史蒂文

46

就我而言,这是由于我注入的依赖项的构造函数内部发生异常(在您的示例中-DashboardRepository构造函数内部)。MVC基础结构内部某处捕获到异常。我在相关位置添加日志后发现了这一点。


7
这是一个非常重要的答案。看到时很容易陷入Unity追逐设置问题的陷阱,Make sure that the controller has a parameterless public constructor.但是很有可能已经建立了依赖关系,但肠子深处的异常阻止了它的解决。
Phil Cooper

2
这个。一百万次!我忘记将依赖项映射添加到我的Ninject配置中。
特拉沃

我在肠子异常的最深处是应该是“ DateTime?”的属性类型“字符串”。如果我没有看到这个答案,就不会寻找那个。非常感谢。
Jazzy

更像LousyErrorMessageException()
Simon_Weaver

您将日志放置在哪些相关位置?我从调试器运行但没有异常,即使我检查了所有CLR异常也是如此。我必须添加手动构造函数解析,然后才得到错误。它告诉我添加诊断程序以获取可用的错误,该错误最终使我可以使用某些东西
Arjan

6

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

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

4

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


4

我有同样的问题。我用谷歌搜索了两天。最后,我意外地发现问题是Controller构造函数的访问修饰符。我没有将public关键字放在Controller的构造函数后面。

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

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

我将此经验作为另一个答案,也许有人犯了类似的错误。


0

如果您的控制器中有接口

public myController(IXInterface Xinstance){}

您必须将它们注册到依赖注入容器。

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

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;
}

0

如果您使用UnityConfig.cs抵制类型的映射,如下所示。

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

你必须让**webApiConfig.cs**容器知道

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

0

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

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

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.