Web API控制器没有默认构造函数.对象依赖解析器问题

本文关键字:依赖 问题 对象 构造函数 控制器 API 默认 Web | 更新日期: 2023-09-27 18:08:44

我正在使用MVC开发我的第一个API。我已经得到了它的工作以前通过创建一个API和声明/创建控制器内的数据,像这样:

public class ValuesController : ApiController
{
    private northwndEntities db = new northwndEntities();
    Product[] products = new Product[] 
    { 
        new Product { Id = 1, Name = "Tomato Soup", Category = "Groceries", Price = 1 }, 
        new Product { Id = 2, Name = "Yo-yo", Category = "Toys", Price = 3.75M }, 
        new Product { Id = 3, Name = "Hammer", Category = "Hardware", Price = 16.99M } 
    };
    public IEnumerable<Product> GetAllProducts()
    {
        return products;
    }
    public Product GetProduct(int id)
    {
        var product = products.FirstOrDefault((p) => p.Id == id);
        return (product);
    }
}

这是我快速创建的一个模型:Product.cs

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Category { get; set; }
    public decimal Price { get; set; }
}

我不认为这是必要的,但这里是我用来调用的脚本,即使在早期的测试中,我只是导航到适当的URL,而不是试图花哨。

 <script>
        //var apiurl = "api/values";
        var apiurl = "api/ordersapi";
        $(document).ready(function() {
            $.getJSON(apiurl).done(function(data) {
                $.each(data, function(key, item) {
                    $('<li>', { text: formatItem(item) }).appendTo($('#products'));
                });
            });
        });
        function formatItem(item) {
            return item.Name + ": $" + item.Price;
        }
        function find() {
            var pId = $('#prdId').val();
            $.getJSON(apiurl + '/' + pId)
                .done(function (data) {
                    $('#product').text(formatItem(data));
                })
                .fail( function(jqxHr, textStatus, err) {
                    $('#product').text("Error: "+err);
                });
        }
    </script>

考虑到这一点,调用"api/values/2"将返回ID = 2的数据我可以让它工作,没有问题。当然,我也要确保在尝试调用我即将在下面概述的API时改变我正在使用的url变量。

接下来,我想进一步使用一个单独的API,从我已经存在的(数据库优先的风格)数据库调用。

我正在使用存储库模式和依赖注入,所以这里是我的存储库(名为"repo.cs"),API控制器(名为"OrdersAPI"控制器)的代码,以及我的ninjectWebcommon.cs文件

Repo.cs (repository类)

public interface INorthwindRepository : IDisposable
{
    IQueryable<Order> GetOrders();
    Order GetOrderById(int id);
}
public class NorthwindRepository : INorthwindRepository
{
    private northwndEntities _ctx;
    public NorthwindRepository(northwndEntities ctx)
    {
        _ctx = ctx;
    }
    public IQueryable<Order> GetOrders()
    {        
        return _ctx.Orders.OrderBy(o => o.OrderID);
    }
    public Order GetOrderById(int id)
    {
        return _ctx.Orders.Find(id);
    }
    public void Dispose()
    {
        _ctx.Dispose();
    }
}

OrdersAPIController.cs

public class OrdersAPIController : ApiController
{
    private INorthwindRepository db;
    public OrdersAPIController(INorthwindRepository _db)
    {
        db = _db;
    }
    //api/ordersapi
    public IEnumerable<Order> Orders()
    {
        return db.GetOrders();
    }
//api/ordersapi/5
    public Order SpecificOrder(int id)
    {
        Order order = db.GetOrderById(id);
        return order;
    }
}

NinjectWebCommon.cs(*注意CreateKernel()方法中的注释)

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(RAD302PracticeAPI.App_Start.NinjectWebCommon), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethodAttribute(typeof(RAD302PracticeAPI.App_Start.NinjectWebCommon), "Stop")]
namespace RAD302PracticeAPI.App_Start
{
using System;
using System.Web;
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using Ninject;
using Ninject.Web.Common;
using RAD302PracticeAPI.Models;
using System.Web.Http;
using Ninject.Web.Mvc;
using System.Web.Mvc;
//using System.Web.Http;
//using Ninject.Web.Mvc;
public static class NinjectWebCommon 
{
    private static readonly Bootstrapper bootstrapper = new Bootstrapper();
    /// <summary>
    /// Starts the application
    /// </summary>
    public static void Start() 
    {
        DynamicModuleUtility.RegisterModule(typeof(OnePerRequestHttpModule));
        DynamicModuleUtility.RegisterModule(typeof(NinjectHttpModule));
        bootstrapper.Initialize(CreateKernel);
        //tried code from...
        //http://haacked.com/archive/2012/03/11/itrsquos-the-little-things-about-asp-net-mvc-4.aspx/
        //but it didnt work
        //GlobalConfiguration.Configuration.ServiceResolver.SetResolver(DependencyResolver.Current.ToServiceResolver());
    }
    /// <summary>
    /// Stops the application.
    /// </summary>
    public static void Stop()
    {
        bootstrapper.ShutDown();
    }
    /// <summary>
    /// Creates the kernel that will manage your application.
    /// </summary>
    /// <returns>The created kernel.</returns>
    private static IKernel CreateKernel()
    {

        var kernel = new StandardKernel();
        try
        {
            kernel.Bind<Func<IKernel>>().ToMethod(ctx => () => new Bootstrapper().Kernel);
            kernel.Bind<IHttpModule>().To<HttpApplicationInitializationHttpModule>();
            RegisterServices(kernel);
            //this line is giving me an error saying:
            //"Cannot implicitly convert type 'Ninject.Web.Mvc.NinjectDependencyResolver' to
            //'System.Web.Http.Dependencies.IDependencyResolver'. An explicit conversion exists (are you missing a cast?)
            //However from one or two places here it has been recommended as a possible solution to solve
            //the dependency issue
            //one place is here: http://stackoverflow.com/questions/17462175/mvc-4-web-api-controller-does-not-have-a-default-constructor
            GlobalConfiguration.Configuration.DependencyResolver = new NinjectDependencyResolver(kernel);
            return kernel;
        }
        catch
        {
            kernel.Dispose();
            throw;
        }
    }
    /// <summary>
    /// Load your modules or register your services here!
    /// </summary>
    /// <param name="kernel">The kernel.</param>
    private static void RegisterServices(IKernel kernel)
    {
        kernel.Bind<northwndEntities>().To<northwndEntities>();   
    }        
}
}

从我在我的ninject.cs页面的评论区张贴的链接,似乎问题是我需要为我的应用程序设置一个依赖解析器。我认为当你不使用API时,这是为你做的,但在这种情况下,你必须这样做。我愿意接受纠正。所以,我的直觉是,我需要创建一个依赖解析器类,但是我留下评论的那行不起作用,并且应该是我需要的解决方案,基于其他So页面。

感谢任何花时间提供建议的人。克服这个障碍会让我到达我想去的地方,至少现在是这样。我已经花了一些精力去研究问题所在。只是希望更有经验的人能发现一些微妙的东西。

*更新:当我取消注释

这一行时

" GlobalConfiguration.Configuration。DependencyResolver = new NinjectDependencyResolver(kernel);"
ie -在我的代码中作为注释包含的链接中建议添加的行,我在此图像中得到错误http://postimg.org/image/qr2g66yaj/

当我包含这一行时,我得到的错误是这样的:http://postimg.org/image/9wmfcxhq5/

Web API控制器没有默认构造函数.对象依赖解析器问题

您需要在RegisterServices方法上绑定存储库和接口:

kernel.Bind<INorthwindRepository>().To<NorthwindRepository>();

同样,你必须检查你的项目配置。你可以从我的Github帐户下载一个简单的Ninject演示,并将其与你的项目进行比较。

DI容器需要知道实例化类的所有依赖项。你的类需要INorthwindRepository(因为它只在控制器类的构造函数- public OrdersAPIController(INorthwindRepository _db)中指定),但是这个接口的实现没有在容器中注册。

我需要在我的NinjectWebCommon.cs文件的顶部添加以下代码

public class NinjectDependencyScope : IDependencyScope
{
    IResolutionRoot resolver;
    public NinjectDependencyScope(IResolutionRoot resolver)
    {
        this.resolver = resolver;
    }
    public object GetService(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");
        return resolver.TryGet(serviceType);
    }
    public System.Collections.Generic.IEnumerable<object> GetServices(Type serviceType)
    {
        if (resolver == null)
            throw new ObjectDisposedException("this", "This scope has been disposed");
        return resolver.GetAll(serviceType);
    }
    public void Dispose()
    {
        IDisposable disposable = resolver as IDisposable;
        if (disposable != null)
            disposable.Dispose();
        resolver = null;
    }
}
public class NinjectDependencyResolver : NinjectDependencyScope, System.Web.Http.Dependencies.IDependencyResolver
{
    IKernel kernel;
    public NinjectDependencyResolver(IKernel kernel)
        : base(kernel)
    {
        this.kernel = kernel;
    }
    public IDependencyScope BeginScope()
    {
        return new NinjectDependencyScope(kernel.BeginBlock());
    }
} 

这给我带来了一个新问题,当导航到"http://localhost:53895/api/OrdersAPI/2"时我在浏览器中得到一条消息说

{"Message":"The requested resource does not support http method 'GET'."}

将来有人可能会发现这很有用。

至少我快到了:)