Đảm bảo rằng bộ điều khiển có lỗi khởi tạo công khai không tham số


105

Tôi đã làm theo hướng dẫn này , nó đã hoạt động tốt, cho đến khi tôi sửa đổi DbContextđể có thêm một hàm tạo. Tôi hiện đang gặp sự cố với giải pháp và không biết phải làm gì để khắc phục sự cố này. Có cách nào dễ dàng để buộc nó lấy hàm tạo không tham số hoặc tôi đang tiếp cận điều này không chính xác?

DbContext với hai hàm tạo:

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

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

SiteController constructor:

private readonly IDashboardRepository _repo;

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

Kho:

DashboardDbContext _context;

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

UnityResolver mã:

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

Lỗi từ Cuộc gọi WebApi:

System.InvalidOperationException: Đã xảy ra lỗi khi cố gắng tạo bộ điều khiển loại 'SiteController'. Đảm bảo rằng bộ điều khiển có một hàm tạo công khai không tham số.

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: Nhập 'Dashboard.Web.Controllers.SiteController' không có hàm tạo mặc định.

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)

Hướng dẫn này rất tuyệt và đã hoạt động tốt cho tôi cho đến khi tôi thêm hàm tạo thứ hai.


2
Lỗi đang nói với bạn rằng đó SiteControllerlà thứ phải có một hàm tạo không paramertless, không phải vậy DashboardDbContext.
Neil Smith

Xin chào Smith.h.Neil, nhưng nó chỉ ném ra lỗi đó khi hàm tạo bổ sung được thêm vào dbcontext. Nếu tôi loại bỏ hoặc nhận xét nó ra (hàm tạo thứ hai) thì nó hoạt động tốt.
Scarpacci

Tôi có thể xem hàm tạo cho SiteController?
Neil Smith

Và tôi đoán bạn đang đưa nó DbContextvào kho lưu trữ?
Neil Smith

@scarpacci Bạn có chắc chắn thay đổi duy nhất bạn đang thực hiện là xóa hàm tạo thứ hai khỏi DbContext không? Trừ khi bạn bằng cách nào đó bỏ qua việc khởi tạo bộ điều khiển của mình bằng cách không có hàm tạo DbContext thứ hai, nếu không sẽ không có ý nghĩa gì nếu lỗi phụ thuộc vào các hàm tạo của DbContext.
Asad Saeeduddin

Câu trả lời:


130

Những gì đang xảy ra là bạn bị cắn bởi vấn đề này . Về cơ bản, điều đã xảy ra là bạn đã không đăng ký bộ điều khiển một cách rõ ràng trong vùng chứa của mình. Unity cố gắng giải quyết các loại cụ thể chưa được đăng ký cho bạn, nhưng vì nó không thể giải quyết nó (do lỗi trong cấu hình của bạn), nó trả về null. Nó buộc phải trả về null, vì Web API buộc nó phải làm như vậy do IDependencyResolverhợp đồng. Vì Unity trả về null, Web API sẽ cố gắng tạo chính bộ điều khiển, nhưng vì nó không có hàm tạo mặc định nên nó sẽ ném ra ngoại lệ "Đảm bảo rằng bộ điều khiển có một hàm tạo công khai không tham số". Thông báo ngoại lệ này gây hiểu lầm và không giải thích nguyên nhân thực sự.

Bạn sẽ thấy một thông báo ngoại lệ rõ ràng hơn nhiều nếu bạn đã đăng ký bộ điều khiển của mình một cách rõ ràng, và đó là lý do tại sao bạn nên đăng ký tất cả các loại gốc một cách rõ ràng.

Nhưng tất nhiên, lỗi cấu hình đến từ việc bạn thêm hàm tạo thứ hai vào của bạn DbContext. Unity luôn cố gắng chọn hàm tạo có nhiều đối số nhất, nhưng nó không biết cách giải quyết hàm tạo cụ thể này.

Vì vậy, nguyên nhân thực sự là bạn đang cố gắng sử dụng khả năng tự động nối dây của Unity để tạo DbContext. DbContextlà một loại đặc biệt không nên có dây tự động. Nó là một loại khung và do đó bạn nên dự phòng để đăng ký nó bằng cách sử dụng nhà máy ủy quyền :

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

XIN LƯU Ý khi bạn xây dựng lại dự án của mình, bạn có thể đặt lại thông tin đăng nhập của mình ... trước khi thử áp dụng giải pháp này, vui lòng: xây dựng lại dự án của bạn, tự đăng xuất, sau đó đăng nhập lại, chỉ sau đó - làm mới trang của bạn và quan sát xem sự cố vẫn tiếp diễn
ymz

Cảm ơn bạn - những quả dingleberries này trong nhóm phụ trợ của tôi đã phá vỡ rất nhiều quy tắc với cấu hình thống nhất. Bắt đầu tự hỏi liệu đó có phải là cách mọi đội sử dụng IOC container hay không.
Dagroom

@Dagroom: Nhiều nhà phát triển hơi lo lắng về điều này, nhưng đây không phải là vấn đề tồn tại trong tất cả DI Containers. Ví dụ, Simple Injector sẽ luôn đảm bảo rằng lỗi diễn đạt được nhắc trong trường hợp điều đó xảy ra. Một mẹo hay khác: Đừng sử dụng tùy chỉnh IDependencyResolvermà chỉ sử dụng tùy chỉnh IControllerActivatorthay thế.
Steven

46

Trong trường hợp của tôi, đó là do ngoại lệ bên trong phương thức khởi tạo của phụ thuộc được đưa vào của tôi (trong ví dụ của bạn - bên trong hàm tạo DashboardRepository). Ngoại lệ đã được bắt gặp ở đâu đó bên trong cơ sở hạ tầng MVC. Tôi tìm thấy điều này sau khi tôi thêm nhật ký vào những nơi có liên quan.


7
Đây là một câu trả lời thực sự quan trọng. Rất dễ rơi vào bẫy theo đuổi các vấn đề thiết lập với Unity khi nhìn thấy Make sure that the controller has a parameterless public constructor.nhưng hoàn toàn có thể sự phụ thuộc được thiết lập nhưng một ngoại lệ nằm sâu trong ruột đã khiến nó không được giải quyết.
Phil Cooper

2
Điều này. Một triệu lần! Tôi đã quên thêm bản đồ phụ thuộc vào cấu hình Ninject của mình.
Travo

Ngoại lệ sâu trong ruột của tôi là một loại thuộc tính 'chuỗi' khi nó đáng lẽ phải là 'DateTime?'. Sẽ không tìm kiếm điều đó nếu tôi không thấy câu trả lời này. Cảm ơn rất nhiều.
Jazzy

Giống như LousyErrorMessageException ()
Simon_Weaver

Bạn đã đặt nhật ký ở những nơi liên quan nào? Tôi đã chạy từ trình gỡ lỗi nhưng không có ngoại lệ, ngay cả khi tôi đã kiểm tra tất cả các ngoại lệ CLR. Tôi đã phải thêm giải quyết hàm tạo thủ công và chỉ sau đó tôi gặp lỗi. Nó nói với tôi để thêm chẩn đoán để có được một lỗi có thể sử dụng, mà cuối cùng đã cho tôi một cái gì đó để làm việc với
Arjan

6

Tôi gặp vấn đề tương tự và tôi đã giải quyết nó bằng cách thực hiện các thay đổi trong tệp UnityConfig.cs Để giải quyết vấn đề phụ thuộc trong tệp UnityConfig.cs, bạn phải thêm:

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

4

Đôi khi vì bạn đang giải quyết giao diện của mình trong ContainerBootstraper.cs nên rất khó để bắt lỗi. Trong trường hợp của tôi, đã xảy ra lỗi khi giải quyết việc triển khai giao diện mà tôi đã đưa vào bộ điều khiển api. Tôi không thể tìm thấy lỗi vì tôi đã giải quyết giao diện trong bootstraperContainer của mình như thế này: container.RegisterType<IInterfaceApi, MyInterfaceImplementaionHelper>(new ContainerControlledLifetimeManager());
sau đó tôi đã bổ sung dòng sau trong vùng chứa bootstrap của mình: container.RegisterType<MyController>(); vì vậy khi tôi biên dịch dự án, trình biên dịch đã phàn nàn và dừng ở dòng trên và hiển thị lỗi .


4

Tôi đã từng gặp vấn đề tương tự. Tôi đã tìm kiếm nó trong hai ngày. Cuối cùng, tôi vô tình nhận thấy rằng vấn đề là công cụ sửa đổi truy cập của phương thức khởi tạo của Bộ điều khiển. Tôi đã không đặt publictừ khóa đằng sau hàm tạo của Bộ điều khiển.

public class MyController : ApiController
    {
        private readonly IMyClass _myClass;

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

Tôi thêm kinh nghiệm này như một câu trả lời khác có thể ai đó đã mắc lỗi tương tự.


0

Nếu bạn có một giao diện trong bộ điều khiển của mình

public myController(IXInterface Xinstance){}

Bạn phải đăng ký chúng vào vùng chứa Dependency Injection.

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

0

Tôi đã gặp lỗi này khi vô tình xác định thuộc tính là một kiểu đối tượng cụ thể, thay vì kiểu giao diện mà tôi đã xác định trong UnityContainer.

Ví dụ:

Định nghĩa UnityContainer:

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

SiteController (sai cách - thông báo loại repo):

private readonly DashboardRepository _repo;

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

SiteController (đúng cách):

private readonly IDashboardRepository _repo;

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

0

Nếu bạn đang sử dụng UnityConfig.cs để chống lại các ánh xạ kiểu của bạn như bên dưới.

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

Bạn phải cho biết **webApiConfig.cs**về Container

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

0

Trong trường hợp của tôi, Unity hóa ra là một con cá trích đỏ. Sự cố của tôi là kết quả của các dự án khác nhau nhắm mục tiêu các phiên bản .NET khác nhau. Unity đã được thiết lập đúng và mọi thứ đã được đăng ký với vùng chứa một cách chính xác. Mọi thứ được biên dịch tốt. Nhưng kiểu nằm trong thư viện lớp và thư viện lớp được đặt thành mục tiêu .NET Framework 4.0. Dự án WebApi sử dụng Unity đã được đặt thành mục tiêu .NET Framework 4.5. Thay đổi thư viện lớp cũng nhắm mục tiêu 4,5 đã khắc phục sự cố cho tôi.

Tôi đã phát hiện ra điều này bằng cách bình luận về hàm tạo DI và thêm hàm tạo mặc định. Tôi đã nhận xét ra các phương thức bộ điều khiển và yêu cầu chúng ném NotImplementedException. Tôi xác nhận rằng tôi có thể tiếp cận bộ điều khiển và thấy NotImplementedException của tôi cho tôi biết rằng nó đang khởi tạo bộ điều khiển tốt. Tiếp theo, trong hàm tạo mặc định, tôi khởi tạo chuỗi phụ thuộc theo cách thủ công thay vì dựa vào Unity. Nó vẫn được biên dịch, nhưng khi tôi chạy nó, thông báo lỗi đã xuất hiện trở lại. Điều này xác nhận với tôi rằng tôi vẫn gặp lỗi ngay cả khi Unity không có trong hình. Cuối cùng, tôi bắt đầu ở cuối chuỗi và làm việc theo cách của mình, nhận xét từng dòng một và kiểm tra lại cho đến khi tôi không còn nhận được thông báo lỗi nữa. Điều này chỉ cho tôi về hướng của lớp vi phạm, và từ đó tôi phát hiện ra rằng nó bị cô lập thành một nhóm duy nhất.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.