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

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

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

Ответ 1

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

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

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

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

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

Ответ 2

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

Ответ 3

У меня была такая же проблема, и я разрешил ее, внося изменения в файл 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());
то я добавляю следующую строку в мой контейнер для начальной загрузки: container.RegisterType<MyController>(); поэтому, когда я компилирую проект, компилятор жаловался и останавливался в приведенной выше строке и показывал ошибку.

Ответ 5

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

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

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

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

Ответ 6

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

public myController(IXInterface Xinstance){}

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

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

Ответ 7

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

Ответ 8

Если вы используете UnityConfig.cs для сохранения соответствия типов, как показано ниже.

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

Вы должны сообщить **webApiConfig.cs** о контейнере

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

Ответ 9

В моем случае Unity оказалась красной селедкой. Моя проблема была результатом различных проектов, нацеленных на разные версии .NET. Unity была настроена правильно и все было правильно зарегистрировано в контейнере. Все скомпилировано нормально. Но тип был в библиотеке классов, и библиотека классов была настроена на целевую платформу .NET Framework 4.0. Проект WebApi, использующий Unity, был настроен на .NET Framework 4.5. Изменение библиотеки классов на 4.5 также решило эту проблему.

Я обнаружил это, закомментировав конструктор DI и добавив конструктор по умолчанию. Я закомментировал методы контроллера и заставил их генерировать исключение NotImplementedException. Я подтвердил, что могу связаться с контроллером, и, увидев мое исключение NotImplementedException, сказал, что это нормально работает с контроллером. Затем в конструкторе по умолчанию я вручную создал цепочку зависимостей вместо того, чтобы полагаться на Unity. Это все еще скомпилировано, но когда я запустил его, сообщение об ошибке вернулось. Это подтвердило для меня, что я все еще получил ошибку, даже когда Unity был вне поля зрения. Наконец, я начал с конца цепочки и продолжил свой путь, комментируя по одной строке за раз и повторяя тестирование, пока я больше не получаю сообщение об ошибке. Это указало мне на направление класса-нарушителя, и оттуда я понял, что он был изолирован для одной сборки.