it-swarm.com.de

Stellen Sie sicher, dass der Controller einen fehlerfreien öffentlichen Konstruktorfehler hat

Ich habe dieses Tutorial befolgt, das gut funktioniert hat, bis ich meine DbContext geändert habe, um einen zusätzlichen Konstruktor zu erhalten. Ich habe jetzt Probleme mit der Lösung und bin mir nicht sicher, wie ich das beheben kann. Gibt es eine einfache Möglichkeit, den parameterlosen Konstruktor zu packen, oder nähere ich mich falsch? 

DbContext mit zwei Konstruktoren:

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

Repository:

DashboardDbContext _context;

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

UnityResolver code:

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

Fehler beim WebApi-Aufruf:

System.InvalidOperationException: Beim Erstellen eines Controllers vom Typ 'SiteController' ist ein Fehler aufgetreten. Stellen Sie sicher, dass der Controller über einen öffentlichen Parameter ohne Parameter verfügt.

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: Typ "Dashboard.Web.Controllers.SiteController" hat keinen Standardkonstruktor.

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)

Das Tutorial war großartig und hat für mich gut funktioniert, bis ich den zweiten Konstruktor hinzugefügt habe.

86
scarpacci

Was passiert ist, dass Sie von diesem Problem gebissen werden. Grundsätzlich ist es passiert, dass Sie Ihre Controller nicht explizit in Ihrem Container registriert haben. Unity versucht, nicht registrierte konkrete Typen für Sie aufzulösen. Da es jedoch nicht aufgelöst werden kann (durch einen Fehler in Ihrer Konfiguration verursacht), gibt es Null zurück. Es wird gezwungen, NULL zurückzugeben, da das Web-API dies aufgrund des IDependencyResolver-Vertrags dazu zwingt. Da Unity den Wert null zurückgibt, versucht das Web-API, den Controller selbst zu erstellen. Da es jedoch keinen Standardkonstruktor gibt, wird die Ausnahme "Vergewissern Sie sich, dass der Controller über einen öffentlichen Parameter ohne Parameter verfügt" ausgelöst. Diese Ausnahmemeldung ist irreführend und erklärt nicht die wahre Ursache.

Sie hätten eine deutlichere Ausnahmemeldung erhalten, wenn Sie Ihre Controller explizit registrieren. Aus diesem Grund sollten Sie immer alle Stammtypen explizit registrieren.

Aber der Konfigurationsfehler kommt natürlich dadurch zustande, dass Sie den zweiten Konstruktor zu Ihrem DbContext hinzufügen. Unity versucht immer, den Konstruktor mit den meisten Argumenten auszuwählen, weiß jedoch nicht, wie dieser bestimmte Konstruktor aufgelöst werden soll.

Die eigentliche Ursache ist also, dass Sie versuchen, die automatischen Verdrahtungsfunktionen von Unity zu verwenden, um DbContext zu erstellen. DbContext ist ein spezieller Typ, der nicht automatisch verkabelt werden sollte. Es handelt sich um einen Rahmentyp, und Sie sollten daher auf die Registrierung mit einem Werksdelegierten zurückgreifen :

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

In meinem Fall war es wegen einer Ausnahme im Konstruktor meiner injizierten Abhängigkeit (in Ihrem Beispiel - im DashboardRepository-Konstruktor). Die Ausnahme wurde irgendwo in der MVC-Infrastruktur erfasst. Ich habe dies gefunden, nachdem ich an relevanten Stellen Protokolle hinzugefügt habe.

36
Illidan

Ich hatte das gleiche Problem und ich habe es gelöst, indem ich Änderungen in der Datei UnityConfig.cs vorgenommen habe. Um das Abhängigkeitsproblem in der Datei UnityConfig.cs zu beheben, müssen Sie Folgendes hinzufügen:

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

Manchmal, weil Sie Ihre Schnittstelle in ContainerBootstraper.cs auflösen, ist es sehr schwierig, den Fehler abzufangen. In meinem Fall gab es einen Fehler beim Auflösen der Implementierung der Schnittstelle, die ich in den API-Controller injiziert habe. Ich konnte den Fehler nicht finden, da ich die Schnittstelle in meinem BootstraperContainer folgendermaßen aufgelöst habe: container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
Dann habe ich die folgende Zeile in meinen bootstrap container: container.RegisterType<MyController>(); eingefügt. Als ich das Projekt kompilierte, beschwerte sich der Compiler und blieb in der obigen Zeile stehen und zeigte der Fehler.

4
Amir978

Ich hatte das gleiche Problem. Ich habe es zwei Tage lang gegoogelt. Schließlich bemerkte ich versehentlich, dass das Problem der Zugriffsmodifizierer des Konstruktors des Controllers war. Ich legte das Schlüsselwort public nicht hinter den Konstruktor des Controllers.

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

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

Ich füge diese Erfahrung als weitere Antwort hinzu, vielleicht hat jemand anderer einen ähnlichen Fehler gemacht.

1
Bobs

Ich habe diesen Fehler erhalten, als ich versehentlich eine Eigenschaft als einen bestimmten Objekttyp definiert habe, anstelle des in UnityContainer definierten Schnittstellentyps.

Zum Beispiel:

UnityContainer definieren:

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

SiteController (der falsche Weg - Repo-Typ beachten):

private readonly DashboardRepository _repo;

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

SiteController (der richtige Weg):

private readonly IDashboardRepository _repo;

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

Wenn Sie eine Schnittstelle in Ihrem Controller haben

public myController(IXInterface Xinstance){}

Sie müssen sie beim Dependency Injection-Container registrieren.

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

Wenn Sie nityConfig.cs verwenden, um die Zuordnungen Ihres Typs wie folgt zu speichern.

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

Sie müssen den **webApiConfig.cs** über Container informieren

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