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/
您需要在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'."}
将来有人可能会发现这很有用。
至少我快到了:)