it-swarm.com.ru

Убедитесь, что в контроллере есть ошибка открытого конструктора без параметров

Я следовал этому 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;
}

Repository:

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)

Учебное пособие было отличным и работало хорошо для меня, пока я не добавил второго конструктора.

86
scarpacci

То, что происходит, - то, что вы укушены эта проблема . По сути, произошло то, что вы не зарегистрировали свои контроллеры явно в своем контейнере. Unity пытается разрешить незарегистрированные конкретные типы для вас, но поскольку он не может разрешить его (вызванный ошибкой в ​​вашей конфигурации), он возвращает ноль. Он вынужден возвращать null, потому что Web API заставляет его делать это из-за контракта IDependencyResolver. Так как Unity возвращает null, Web API попытается создать сам контроллер, но, поскольку у него нет конструктора по умолчанию, он выдаст исключение «Убедитесь, что у контроллера есть открытый конструктор без параметров». Это сообщение об ошибке вводит в заблуждение и не объясняет истинную причину.

Вы бы увидели гораздо более четкое сообщение об исключении, если бы регистрировали свои контроллеры явно, и поэтому вам всегда следует регистрировать все корневые типы явно.

Но, конечно, ошибка конфигурации происходит из-за того, что вы добавляете второй конструктор к своей переменной DbContext. Unity всегда пытается выбрать конструктор с наибольшим количеством аргументов, но не знает, как разрешить этот конкретный конструктор.

Итак, настоящая причина в том, что вы пытаетесь использовать возможности автоматического подключения Unity для создания DbContext. DbContext - это специальный тип, который не должен быть автоматически подключен. Это тип фреймворка, и вы должны поэтому отступить от регистрации его с помощью делегата фабрики :

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

В моем случае это произошло из-за исключения внутри конструктора моей внедренной зависимости (в вашем примере - внутри конструктора DashboardRepository). Исключение было поймано где-то внутри инфраструктуры MVC. Я нашел это после того, как я добавил журналы в соответствующих местах.

36
Illidan

У меня была та же проблема, и я решил ее, внеся изменения в файл UnityConfig.cs. Чтобы устранить проблему зависимости в файле UnityConfig.cs, необходимо добавить:

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

Иногда, потому что вы разрешаете свой интерфейс в ContainerBootstraper.cs, очень трудно уловить ошибку. В моем случае произошла ошибка при разрешении реализации интерфейса, который я ввел в контроллер api. Я не смог найти ошибку, потому что я разрешил интерфейс в моем bootstraperContainer следующим образом: container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
Затем я добавил следующую строку в мой контейнер начальной загрузки: container.RegisterType<MyController>(); , поэтому, когда я компилировал проект, компилятор жаловался и останавливался в приведенной выше строке и отображал ошибку. 

4
Amir978

У меня такая же проблема. Я гуглил это два дня. Наконец я случайно заметил, что проблема заключалась в модификаторе доступа конструктора Контроллера .... Я не поместил ключевое слово public позади конструктора Контроллера.

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

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

Я добавляю этот опыт в качестве другого ответа, может быть, кто-то еще совершил аналогичную ошибку.

1
Bobs

Я получил эту ошибку, когда случайно определил свойство как определенный тип объекта вместо типа интерфейса, который я определил в 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
MasterPiece

Если у вас есть интерфейс в вашем контроллере

public myController(IXInterface Xinstance){}

Вы должны зарегистрировать их в контейнере Inpendency Injection.

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