I'm trying to inject a dependency into a web api controller using Unity.
I followed
http://www.asp.net/mvc/overview/older-versions/hands-on-labs/aspnet-mvc-4-dependency-injection
closely, however I still get error while instantiating constructor, there there's no parameterless constructor.
Controller:
public class ContactsController : ApiController
{
IContactsRepository repository;
public ContactsController(IContactsRepository repository)
{
this.repository = repository;
}
public List<ContactDTO> GetAllContacts()
{
return repository.GetAllContacts().ToList();
}
}
Repository interface and class:
public interface IContactsRepository
{
IEnumerable<ContactDTO> GetAllContacts();
}
Class:
public class ContactsRepository : IContactsRepository
{
public IEnumerable<ContactDTO> GetAllContacts()
{
using (var db = new ContactDatabaseEntities())
{
foreach (var contact in db.Contacts)
{
yield return contact.Convert();
}
}
}
}
I added the line:
Bootstrapper.Initialise();
to Global.asax file, and in Bootstrapper.cs I added:
container.RegisterType<IContactsRepository, ContactsRepository>();
However when i try to access contacts through the url I get the error:
An error occurred when trying to create a controller of type
'ContactsController'. Make sure that the controller has a
parameterless public constructor.
Am I missing something?
I see you are using ApiController - for WebAPI dependency injection is implemented in different way. You are referring to a standard MVC way of resolving dependencies, which won't work for WebAPI.
You need to install Unity.WebAPI package to get it working NuGet
Related
I am designing a NuGet package that will be consumed by my application. Due to the project's already implemented architecture, I need to provide a way to instantiate objects using dependency injection both for MVC and Web API outside my controller scope.
Currently I have a class that works in MVC projects, by instantiating objects using the DependencyResolver
public abstract class MyBaseClass<T> where T : class
{
public static T Instance
{
get
{
return DependencyResolver.Current.GetService<T>();
}
}
}
However, when consuming this same class from a WebAPI project, the DependencyResolver is not present, so Im not able to retrieve any object.
I have tried to access the dependency resolver via the HttpContext but have been unsuccessfull. Do you have any way I can access it through a NuGet package?
Thanks!
If it's possible, I'd suggest avoid the service locator pattern and inject the dependency through the constructor instead:
public abstract class MyBaseClass<T> where T : class
{
public MyBaseClass(T instance)
{
Instance = instance;
}
public T Instance { get; }
}
This will allow you to use your package through any "main" entry point (e.g. MVC or WebAPI) that you choose. At that point, it would be the responsibility of the consumer to provide the necessary dependency resolution strategy.
Here's an example of how a consumer (in this case a WebAPI service) of the package would implement the above code:
public class MyWebApiClass : MyBaseClass<MyDependency>
{
public MyWebApiClass(MyDependency resolvedDependency) : base(resolvedDependency) { }
}
public class MyDependency
{
public string Foo { get; set; }
public MyDependency()
{
Foo = "Bar";
}
}
Then the consuming service would also register those dependencies:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddTransient<MyDependency>();
services.AddTransient<MyWebApiClass>();
}
... and inject as needed, allowing the framework to resolve the dependencies (IoC at work):
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
private readonly MyWebApiClass _myWebApiClass;
public ValuesController(MyWebApiClass myWebApiClass)
{
_myWebApiClass = myWebApiClass;
}
// GET api/values
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { _myWebApiClass.Instance.Foo };
}
}
Making a call to the GET endpoint above, we can see our instance being resolved in MyBaseClass:
My Startup is like this :
public void ConfigureServices(IServiceCollection services)
{
// code here
Bootstraper.Setup(services);
}
And my Bootstraper class is like this :
public static partial class Bootstraper
{
// code here
public static IServiceCollection CurrentServiceCollection { get;set;}
public static IServiceProvider CurrentServiceProvider
{
get { return CurrentServiceCollection.BuildServiceProvider(); }
}
public static void Setup(IServiceCollection serviceCollection)
{
// code here
SetupLog();
InitializeCulture();
InitializeDbContexts();
RegisterDataModelRepositories();
}
and this is content of my RegisterDataModelRepositories():
CurrentServiceCollection.AddTransient<IDefAccidentGroupRepository>(p => new DefAccidentGroupRepository(ApplicationMainContextId));
CurrentServiceCollection.AddTransient<IDefGenderRepository>(p => new DefGenderRepository(ApplicationMainContextId));
in short : I just want to be able to use Service Locator in my methods without resolving dependency in class constructor ... is there any way around it ....
Dependency injection can also be done on a by action basis.
Referece Dependency injection into controllers: Action Injection with FromServices
Sometimes you don't need a service for more than one action within your controller. In this case, it may make sense to inject the service as a parameter to the action method. This is done by marking the parameter with the attribute [FromServices]
public IActionResult SomeAction([FromServices] IReportService reports) {
//...use the report service for this action only
return View();
}
Just make sure that the required services are registered with the service collection.
services.AddTransient<IDefAccidentGroupRepository>(p => new DefAccidentGroupRepository(ApplicationMainContextId));
services.AddTransient<IDefGenderRepository>(p => new DefGenderRepository(ApplicationMainContextId));
services.AddTransient<IReportService, ReportService>().
well , thanks for your help ...
There is a easier and better way for it , I just need to add another Service that use these repository and then resolve that service in my controller and let Asp.net Core 2.0 DI to solve the problem for me ...
public interface IActionService
{
IRepositoryA repA {get;set;}
IRepositoryB repB { get;set;}
DoTaskX();
DoTaskY();
}
then in my ActionService :
public class ActionService : IActionService
{
public IRepositoryA repA {get;set;}
public IRepositoryB repB { get;set;}
public ActionService (IRepositoryA rep_a , IRepositoryB rep_b ) {
repA = rep_a;
repB = rep_b;
}
DoTaskX(){
// do task using repository A and B
}
}
then I register IActionService in Startup.cs and resolve itin my ActionController and life become easier and code become cleaner ...
the solution was easy but I had to change my mindset to solve the problem ...
We have a project where we need to use DI and ASP Core.
I'm very new to this and have a question.
I have a controller named HomeController like this:
public class HomeController : BaseController {
private IOrderService _orderService;
public HomeController(IOrderService orderService) {
_orderService = orderService;
}
public IActionResult Index() {
var orders = _orderService.GetMyOrders();
return View(orders);
}
}
The code looks like this:
public class OrderService : BaseService, IOrderService {
public OrderService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public List<Orders> GetMyOrders() {
var orders = // do my code here which works fine!;
// here i need some code do check orders for delivery so
DeliveryService deliveryService = new DeliveryService(_dataContextService);
// update my orders and return these orders
return orders;
}
}
public class DeliveryService : BaseService, IDeliveryService {
public DeliveryService(IDataContextService dataContextService) {
_dataContextService = dataContextService;
}
public void MyMethod() {
}
}
public class BaseService {
protected IDataContextService _dataContextService;
}
Almost all my services have a constructor like the OrderService and DeliveryService. My question is, do I have to pass the _dataContextService every time, or is there a solution within the dependency pattern?
You should keep it the way you have it and asp.net core IoC will inject it for you, but make sure it is injected per request, this will help to insantiate only one context for each request and dispose it after the request is served.
You can register the context and services in the ConfigureServices method inside the Startup class as below
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
// Add application services.
services.AddTransient<HomeController>();
services.AddTransient<IOrderService , OrderService >();
services.AddTransient<IDeliveryService, DeliveryService>();
services.AddScoped<IDataContextService , YourDataContextService >();
}
The AddScoped method will create only one instance of the object for each HTTP request
If I understand correctly what you are asking, you are looking for an IoC container. .NET Core has built in support for dependency injection. Basically, you just indicate which implementation should be provided when an interface is requested. Then the container will instantiate the types for you. See for example https://learn.microsoft.com/en-us/aspnet/core/mvc/controllers/dependency-injection.
Hope that helps
I'm trying my hand at dependency injection for my RPG written in c# and some javascript.
I'm trying to inject a service into my controller but keep getting this error:
Error activating IdownloadService No matching bindings are available, and the type is not self-bindable.
In debug mode, it fails on this line with the above error in my CharacterController class:
public IdownloadService downloadService{ get; }
Here is the relevant code:
characterDownloadService.cs
namespace OrionRPG.Character.Downloads
{
public interface IdownloadService
{
Uri CharacterDownloadUri(int charId);
}
public class characterDownloadService : IdownloadService
{
public characterDownloadService()
{}
public const String CharacterServerUrl = "http://myUrl/Characters/";
public Uri CharacterDownloadUri(int charId)
{
var characterName = Character.Name(charId);
return new Uri(CharacterServerUrl + characterName);
}
}
}
CharacterController.cs
namespace OrionRPG.Api.Downloads
{
public class CharacterController
{
public IdownloadService downloadService{ get; }
//inject the service
public CharacterController(IdownloadService downloadService)
{
DownloadService = downloadService;
}
[Route("api/characters/download/{charId}")]
public IHttpActionResult GetCharacterDownload(int charId)
{
return Redirect(DownloadService.CharacterDownloadUri(charId));
}
}
}
Generally speaking, services need to be registered to a container before injection. Different dependency injection framework might have slightly different syntax, the principles are the same.
For example, if you are using Microsoft.Extensions.DependencyInjection, you will need to Register the service: In Startup.cs (ASP.NET Core), you will see a method named ConfigureServices, and you will need to register your service like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(); // Some code by template
...
// This line registers the IdownloadService; when injection happens, the service provider knows to create an implementation of characterDownloadService for requested IdownloadService.
services.AddTransient<IdownloadService, characterDownloadService>();
}
For more details, check this out.
1) As I understand you are trying to use ASP.NET WebApi and it is strange that CharacterController doesn't inherit ApiController
2) You need to use Dependency Injection container which will contains all mapping between interfaces and it's implementation. I would recommend to use Autofac as it is perfectly integrated with ASP.NET MVC and WebAPI. Here is a link with docs
I have a single ASP.NET 5.0 (vnext) project where I am implementing both a Web Api and an Mvc front end. I want my Mvc controller to call the Web Api controller, which is working just fine. I built the api based on the example at http://www.asp.net/vnext/overview/aspnet-vnext/create-a-web-api-with-mvc-6, and it is working great. The Mvc front end can call the WebApi controller successfully, but the ITodoRepository doesn't get provided by the dependency injection framework when I instantiate it from the Mvc controller.
public class Startup
{
public void Configure(IApplicationBuilder app, ILoggerFactory logFactory)
{
...
app.UseServices(services =>
{
services.AddSingleton<ITodoRepository, TodoRepository>();
});
...
[Route("api/[controller]")]
public class TodoController : Controller
{
/* The ITodoRepository gets created and injected, but only when the class is activated by Mvc */
TodoController(ITodoRepository repository)
{
_repository = repository;
}
[HttpGet]
public IEnumerable<TodoItem> Get()
{
return _repository.AllItems;
}
...
public class HomeController : Controller
{
public IActionResult Index()
{
var tc = new TodoController(/* have to create my own ITodoRepository here */);
return View(tc.Get());
}
...
I was able to add an ITodoRepository to the HomeController with the [Activate] attribute, and then pass that to the constructor for the TodoController, but that doesn't pass the smell test to me. Home Controller shouldn't have to have or even know about those.
Is there another way to create the TodoController instance that will invoke the DI logic and provide the dependencies?
If you're concerned about code smell, the main concern should be about having one controller calling another controller.
Controllers are meant to be called in two scenarios:
By the system (i.e. MVC)
By your unit tests
Instead, I recommend having both controllers call a business logic component that itself might use dependency injection to acquire its dependencies, and that each controller perhaps use dependency injection to acquire the business logic dependency as well.
public class HomeController : Controller {
public HomeController(IMyAppBusinessLogic bll) { ... }
}
public class WebApiController : Controller {
public WebApiController(IMyAppBusinessLogic bll) { ... }
}
public class MyAppBusinessLogic : IMyAppBusinessLogic {
public MyAppBusinessLogic(ITodoRepository repository) { ... }
}
Any middleware registered using app.UseServices are available only within the scope of a web request. There is no web request context when you are trying to instantiate the webapi controller directly from your MVC app and therefore the dependencies will not be resolved.
It's normal to create an execution context manually for the purposes of unit testing. Not sure which DI framework are you using but I do something like the following in my project (OWIN not vNext) which is using SimpleInjector
public static void UseInjector(this IAppBuilder app, Container container)
{
// Create an OWIN middleware to create an execution context scope
app.Use(async (context, next) =>
{
using (var scope = container.BeginExecutionContextScope())
{
await next.Invoke();
}
});
}