Upewnij się, że kontroler ma parametrless public constructor error

Podążałem za tym tutorialem, który działał świetnie, dopóki nie zmodyfikowałem mojego DbContext, aby mieć dodatkowy konstruktor. Mam teraz problemy z rezolucją i nie wiem, co zrobić, aby to naprawić. Czy jest łatwy sposób, aby zmusić go do złapania konstruktora bez parametru, czy podchodzę do tego niepoprawnie?

DbContext z dwoma konstruktorami:

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

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

SiteController konstruktor:

private readonly IDashboardRepository _repo;

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

Repozytorium:

DashboardDbContext _context;

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

UnityResolver kod:

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

Błąd wywołania WebApi:

System.InvalidOperationException: wystąpił błąd podczas próby utworzenia kontrolera typu "SiteController". Upewnij się, że kontroler ma bez parametru publiczny konstruktor.

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 ' Dashboard.Www.Kontrolery.SiteController ' nie posiada domyślnego konstruktora.

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)

Tutorial był świetnie i działa mi dobrze aż do momentu dodania drugiego konstruktora.

Author: Steven, 2014-06-17

5 answers

Dzieje się tak, że jesteś ugryziony przez ten problem . Zasadniczo stało się tak, że nie zarejestrowałeś kontrolerów bezpośrednio w kontenerze. Unity próbuje rozwiązać niezarejestrowane konkretne typy dla ciebie, ale ponieważ nie może go rozwiązać (spowodowane błędem w konfiguracji), zwraca null. Jest on zmuszony do zwracania null, ponieważ Web API zmusza go do tego ze względu na kontrakt IDependencyResolver. Ponieważ Unity zwraca null, Web API spróbuje stworzyć sam kontroler, ale ponieważ nie ma domyślnego konstruktora, rzuci on wyjątek "upewnij się, że kontroler ma parametrless public constructor". Ten Komunikat o wyjątku jest mylący i nie wyjaśnia prawdziwej przyczyny.

Zobaczyłbyś o wiele jaśniejszy komunikat o wyjątkach, gdybyś zarejestrował swoje Kontrolery jawnie i dlatego zawsze powinieneś jawnie zarejestrować wszystkie typy rootów.

Ale oczywiście błąd konfiguracji wynika z dodania drugiego konstruktora do Twój DbContext. Unity zawsze próbuje wybrać konstruktor z największą liczbą argumentów, ale nie ma pojęcia, jak rozwiązać ten konkretny konstruktor.

Więc prawdziwą przyczyną jest to, że próbujesz wykorzystać możliwości automatycznego okablowania Unity do stworzenia DbContext. DbContext jest specjalnym typem, który nie powinien być automatycznie podłączony. Jest to typ frameworka i powinieneś , dlatego możesz go zarejestrować za pomocą delegata fabrycznego :

container.Register<DashboardDbContext>(
    new InjectionFactory(c => new DashboardDbContext())); 
 103
Author: Steven,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-08-11 11:30:36

W moim przypadku było to spowodowane wyjątkiem wewnątrz konstruktora mojej iniekcyjnej zależności (w twoim przykładzie - wewnątrz konstruktora DashboardRepository). Wyjątek został złapany gdzieś wewnątrz infrastruktury MVC. Znalazłem to po dodaniu logów w odpowiednich miejscach.

 35
Author: Illidan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-25 03:56:49

Miałem ten sam problem i rozwiązałem go, wprowadzając zmiany w UnityConfig.plik cs w celu rozwiązania problemu zależności w UnityConfig.plik cs musisz dodać:

public static void RegisterComponents()    
{
    var container = new UnityContainer();
    container.RegisterType<ITestService, TestService>();
    DependencyResolver.SetResolver(new UnityDependencyResolver(container));
}
 5
Author: user1407955,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-26 19:31:55

Czasami, ponieważ rozwiązujesz swój interfejs w ContainerBootstraper.cs bardzo trudno złapać błąd. W moim przypadku wystąpił błąd w rozwiązaniu implementacji interfejsu, który wstrzyknąłem do kontrolera api. Nie mogłem znaleźć błędu, ponieważ rozwiązałem interfejs w moim bootstraperContainer w następujący sposób: container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
następnie dodałem następujący wiersz w moim kontenerze bootstrap: container.RegisterType<MyController>(); więc kiedy kompiluję projekt , kompilator narzekał i zatrzymał się w powyżej linia i pokazał błąd.

 4
Author: Amir978,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-03 04:59:13

Miałem ten sam problem. Wygooglowałem to przez dwa dni. W końcu przypadkowo zauważyłem, że problemem był modyfikator dostępu konstruktora kontrolera. Nie umieściłem public słowa kluczowego za konstruktorem kontrolera.

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

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

Dodaję to doświadczenie jako kolejną odpowiedź może ktoś inny popełnił podobny błąd.

 0
Author: Bobs,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-05-05 10:34:23