ตรวจสอบให้แน่ใจว่าคอนโทรลเลอร์มีข้อผิดพลาดตัวสร้างสาธารณะแบบไม่มีพารามิเตอร์


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 Call:

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เป็นสิ่งที่ต้องมีคอนสตรัค paramertless DashboardDbContextไม่
Neil Smith

สวัสดี Smith.h.Neil แต่จะแสดงข้อผิดพลาดนั้นก็ต่อเมื่อมีการเพิ่มตัวสร้างเพิ่มเติมใน dbcontext ถ้าฉันลบสิ่งนั้นออกหรือแสดงความคิดเห็น (ตัวสร้างที่สอง) มันก็ใช้ได้
scarpacci

ฉันสามารถดูตัวสร้างสำหรับSiteController?
Neil Smith

และฉันเดาว่าคุณกำลังฉีดDbContextเข้าไปในที่เก็บ?
Neil Smith

@scarpacci คุณแน่ใจหรือไม่ว่าการเปลี่ยนแปลงเดียวที่คุณทำคือการลบตัวสร้างที่สองออกจาก DbContext เว้นแต่ว่าคุณจะข้ามการสร้างอินสแตนซ์ของคอนโทรลเลอร์โดยไม่มีตัวสร้าง DbContext ตัวที่สองก็ไม่สมเหตุสมผลที่ข้อผิดพลาดจะขึ้นอยู่กับตัวสร้างของ DbContext
Asad Saeeduddin

คำตอบ:


130

สิ่งที่เกิดขึ้นคือคุณถูกกัดโดยปัญหานี้ โดยทั่วไปสิ่งที่เกิดขึ้นคือคุณไม่ได้ลงทะเบียนคอนโทรลเลอร์อย่างชัดเจนในคอนเทนเนอร์ของคุณ Unity พยายามแก้ไขประเภทคอนกรีตที่ไม่ได้ลงทะเบียนให้คุณ แต่เนื่องจากไม่สามารถแก้ไขได้ (เกิดจากข้อผิดพลาดในการกำหนดค่าของคุณ) จึงส่งคืนค่าว่าง ถูกบังคับให้ส่งคืนค่าว่างเนื่องจาก Web API บังคับให้ทำเช่นนั้นเนื่องจากIDependencyResolverสัญญา เนื่องจาก Unity ส่งคืนค่า null Web API จะพยายามสร้างตัวควบคุมเอง แต่เนื่องจากไม่มีตัวสร้างเริ่มต้นจึงทำให้ข้อยกเว้น "ตรวจสอบให้แน่ใจว่าคอนโทรลเลอร์มีตัวสร้างสาธารณะแบบไม่มีพารามิเตอร์" ข้อความยกเว้นนี้ทำให้เข้าใจผิดและไม่ได้อธิบายสาเหตุที่แท้จริง

คุณจะเห็นข้อความแสดงข้อยกเว้นที่ชัดเจนกว่ามากหากคุณลงทะเบียนคอนโทรลเลอร์อย่างชัดเจนและนั่นคือเหตุผลที่คุณควรลงทะเบียนรูททุกประเภทอย่างชัดเจน

แต่แน่นอนข้อผิดพลาดในการกำหนดค่ามาจากการที่คุณเพิ่มตัวสร้างที่สองลงในDbContextไฟล์. Unity พยายามเลือกตัวสร้างที่มีอาร์กิวเมนต์มากที่สุดอยู่เสมอ แต่ก็ไม่รู้ว่าจะแก้ไขตัวสร้างนี้ได้อย่างไร

ดังนั้นสาเหตุที่แท้จริงคือคุณพยายามใช้ความสามารถในการเดินสายอัตโนมัติของ Unity เพื่อสร้างไฟล์DbContext. DbContextเป็นประเภทพิเศษที่ไม่ควรต่อสายอัตโนมัติ เป็นประเภทเฟรมเวิร์กดังนั้นคุณควรเลือกที่จะลงทะเบียนโดยใช้ตัวแทนจากโรงงาน :

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

โปรดทราบว่าเมื่อคุณสร้างโครงการของคุณใหม่คุณสามารถรีเซ็ตข้อมูลรับรองการเข้าสู่ระบบของคุณ ... ก่อนที่จะพยายามใช้วิธีนี้โปรด: สร้างโครงการของคุณใหม่ออกจากระบบด้วยตัวคุณเองจากนั้นกลับเข้ามาอีกครั้งจากนั้นรีเฟรชหน้าของคุณและสังเกตว่าปัญหายังคงมีอยู่หรือไม่
ymz

ขอบคุณ - dingleberries เหล่านี้ในทีมแบ็กเอนด์ของฉันทำลายกฎมากมายด้วยการกำหนดค่าเอกภาพ เริ่มสงสัยว่านั่นเป็นวิธีที่ทุกทีมใช้คอนเทนเนอร์ IOC หรือไม่
Dagrooms

@Dagrooms: นักพัฒนาหลายคนสนใจเรื่องนี้ แต่นี่ไม่ใช่ปัญหาที่มีอยู่ใน DI Containers ทั้งหมด ตัวอย่างเช่น Simple Injector จะตรวจสอบให้แน่ใจว่ามีการแจ้งข้อผิดพลาดที่แสดงออกในกรณีที่เกิดขึ้น เคล็ดลับดีๆอีกอย่าง: อย่าใช้แบบกำหนดเองIDependencyResolverแต่ใช้เฉพาะแบบกำหนดเองIControllerActivatorแทน
Steven

46

ในกรณีของฉันมันเป็นเพราะข้อยกเว้นภายในตัวสร้างของการพึ่งพาที่ฉีดของฉัน (ในตัวอย่างของคุณ - ภายในตัวสร้าง DashboardRepository) ข้อยกเว้นเกิดขึ้นที่ไหนสักแห่งในโครงสร้างพื้นฐาน MVC ฉันพบสิ่งนี้หลังจากเพิ่มบันทึกในสถานที่ที่เกี่ยวข้อง


7
นี่เป็นคำตอบที่สำคัญจริงๆ เป็นเรื่องง่ายมากที่จะตกหลุมพรางของการไล่ตามปัญหาการตั้งค่าด้วย Unity เมื่อมองเห็นMake sure that the controller has a parameterless public constructor.แต่ก็เป็นไปได้มากทีเดียวที่การพึ่งพาถูกตั้งค่า แต่ข้อยกเว้นที่อยู่ลึกลงไปในบาดาลได้หยุดการแก้ไข
Phil Cooper

2
นี้. ล้านเท่า! ฉันลืมเพิ่มแผนที่อ้างอิงในการกำหนดค่า Ninject ของฉัน
Travo

ข้อยกเว้นส่วนลึกของบาดาลของฉันคือคุณสมบัติของ 'สตริง' เมื่อมันควรจะเป็น '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

ผมมีปัญหาเหมือนกัน. ฉัน googled มันเป็นเวลาสองวัน ในที่สุดฉันก็สังเกตเห็นโดยบังเอิญว่าปัญหาคือตัวแก้ไขการเข้าถึงของตัวสร้างของคอนโทรลเลอร์ ฉันไม่ได้ใส่publicคีย์เวิร์ดไว้หลังคอนสตรัคเตอร์ของคอนโทรลเลอร์

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

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

ฉันเพิ่มประสบการณ์นี้เป็นคำตอบอื่นอาจมีคนอื่นทำผิดในลักษณะเดียวกัน


0

หากคุณมีอินเทอร์เฟซในคอนโทรลเลอร์ของคุณ

public myController(IXInterface Xinstance){}

คุณต้องลงทะเบียนในคอนเทนเนอร์ Dependency Injection

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

0

ฉันได้รับข้อผิดพลาดนี้เมื่อฉันกำหนดคุณสมบัติเป็นประเภทออบเจ็กต์เฉพาะโดยไม่ได้ตั้งใจแทนที่จะเป็นประเภทอินเทอร์เฟซที่ฉันกำหนดไว้ใน UnityContainer

ตัวอย่างเช่น:

การกำหนด UnityContainer:

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

SiteController (วิธีที่ไม่ถูกต้อง - ให้สังเกตประเภท repo):

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 โครงการ WebApi โดยใช้ Unity ถูกตั้งค่าเป็นเป้าหมาย. NET Framework 4.5 การเปลี่ยนไลบรารีคลาสเป็นเป้าหมาย 4.5 ช่วยแก้ปัญหาให้ฉันด้วย

ฉันค้นพบสิ่งนี้โดยแสดงความคิดเห็นเกี่ยวกับตัวสร้าง DI และเพิ่มตัวสร้างเริ่มต้น ฉันแสดงความคิดเห็นเกี่ยวกับวิธีการควบคุมและให้พวกเขาโยน NotImplementedException ฉันยืนยันว่าฉันสามารถเข้าถึงคอนโทรลเลอร์ได้และเมื่อเห็น NotImplementedException ของฉันบอกฉันว่ามันกำลังอินสแตนซ์คอนโทรลเลอร์ได้ดี ถัดไปในตัวสร้างเริ่มต้นฉันสร้างอินสแตนซ์ห่วงโซ่การพึ่งพาด้วยตนเองแทนที่จะใช้ Unity มันยังคงคอมไพล์อยู่ แต่เมื่อฉันรันข้อความแสดงข้อผิดพลาดกลับมา สิ่งนี้ยืนยันสำหรับฉันว่าฉันยังคงได้รับข้อผิดพลาดแม้ว่า Unity จะไม่อยู่ในภาพก็ตาม ในที่สุดฉันก็เริ่มต้นที่ด้านล่างของห่วงโซ่และพยายามหาทางแสดงความคิดเห็นทีละบรรทัดและทดสอบใหม่จนกว่าฉันจะไม่ได้รับข้อความแสดงข้อผิดพลาดอีกต่อไป สิ่งนี้ชี้ให้ฉันไปในทิศทางของชนชั้นที่กระทำผิดและจากที่นั่นฉันพบว่ามันถูกแยกออกเป็นกลุ่มเดียว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.