1

Я работаю над своим первым API, используя MVC. Я получил это работает ранее, создавая API и объявления/создания своих данных в контроллере, например, так:У контроллера веб-интерфейса API нет конструктора по умолчанию. Проблема с преобразователем зависимостей Ninject

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

Я не считаю, что это было необходимо, но вот сценарий, который я использовал для совершения вызова, хотя для более раннего тестирования я просто перешел к соответствующему 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> 

Имея это в виду, призыв к «апи/значения/2» будет возвращать данные для ID = 2 я могу получить это не работает без проблем. Конечно, я также стараюсь изменить переменную url, которую я использую при попытке вызвать API, о котором я расскажу ниже.

Далее я хотел перейти к использованию отдельного API, позвонив из моей ранее существующей базы данных в стиле базы данных.

Я использую шаблон репозитория и инъекцию зависимостей, так что здесь код для моего репозитория (названный «repo.cs»), контроллер API (названный «OrdersAPI» контроллер), а также подать мой ninjectWebcommon.cs

Repo.cs (класс хранилище)

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 = новый NinjectDependencyResolver (ядро);»
т.е. - линия, которая рекомендуется добавить в ссылке, которую я включил в качестве комментария в моем коде, я получаю сообщение об ошибке в этом http://postimg.org/image/qr2g66yaj/

изображения И когда я включаю что линия, ошибка, что я дал это: http://postimg.org/image/9wmfcxhq5/

+0

Можете ли вы разместить точное сообщение об ошибке/исключение, которое вы получаете? –

+2

Кроме того, вы регистрируете класс 'northwndEntities', но не' NorthwindRepository'? Я предполагаю, что резольвер возвращается к поиску конструктора без параметров, потому что он не может найти регистрацию, соответствующую текущему конструктору? –

+0

Должно быть, это был ошибка NorthwindRepository, которая была ошибкой кодирования. К сожалению, это еще не решило мою проблему. – OisinFoley

ответ

0

DI контейнер нужно знать все зависимости для создания экземпляра класса Ваш класс требует INorthwindRepository (как указано только constructore класса контроллера - public OrdersAPIController(INorthwindRepository _db)), но нет. реализация этого интерфейса регистрируется в контейнере.

+0

Простите за глупость, но вы имеете в виду в моем файле Ninject, есть что-то вроде этого? 'private static void RegisterServices (ядро IKernel) { kernel.Bind (). To (); } ' – OisinFoley

+0

@OFoley - выглядит разумно. Я не очень хорошо знаком с Ninject, чтобы подтвердить синтаксис. –

1

Вы должны связать свой репозиторий и свой интерфейс на методе RegisterServices:

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

Кроме того, вы должны проверить конфигурацию проекта. Вы можете указать download a Simple Ninject demo, который я создал из своей учетной записи Github, и сравнить ее с вашим проектом.

+0

Я неправильно пытался связать «северные ветви» вместо «INorthwindRepository». К сожалению, внесение изменений не устраняет проблему. Единственные различия в моем файле с вашими связаны с тем, что вы используете обычный контроллер в отличие от контроллера API. – OisinFoley

1

Оказывается, мне нужно добавить следующий код в верхней части моего 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'."} 

Кто-то может найти это полезным в будущем.

По крайней мере, я почти там :)

+1

Привяжите атрибут '[HttpGet]' к 'SpecificOrder()' action. –

+0

У меня все работает, оказалось, что я пытался запросить идентификатор, которого не было в моей базе данных. (Иды начинаются со 10000). [Httpget] был тем, с кем я тоже возился. Спасибо за помощь – OisinFoley

+0

Нужно добавить это в global.asax для возврата json, а не xml GlobalConfiguration.Configure (WebApiConfig.Register); var config = GlobalConfiguration.Configuration; config.Formatters.Remove (config.Formatters.XmlFormatter); – OisinFoley

Смежные вопросы