Since ITodoItemService
is in the Services
namespace, you’ll also need to add a using
statement at the top:
using AspNetCoreTodo.Services;
The first line of the class declares a private variable to hold a reference to the ITodoItemService
. This variable lets you use the service from the Index
action method later (you’ll see how in a minute).
The public TodoController(ITodoItemService todoItemService)
line defines a constructor for the class. The constructor is a special method that is called when you want to create a new instance of a class (the TodoController
class, in this case). By adding an ITodoItemService
parameter to the constructor, you’ve declared that in order to create the TodoController
, you’ll need to provide an object that matches the ITodoItemService
interface.
Now you can finally use the ITodoItemService
(via the private variable you declared) in your action method to get to-do items from the service layer:
The Task
pattern is common when your code calls out to a database or an API service, because it won’t be able to return a real result until the database (or network) responds. If you’ve used promises or callbacks in JavaScript or other languages, Task
is the same idea: the promise that there will be a result - sometime in the future.
If you’ve had to deal with “callback hell” in older JavaScript code, you’re in luck. Dealing with asynchronous code in .NET is much easier thanks to the magic of the
await
keyword!await
lets your code pause on an async operation, and then pick up where it left off when the underlying database or network request finishes. In the meantime, your application isn’t blocked, because it can process other requests as needed. This pattern is simple but takes a little getting used to, so don’t worry if this doesn’t make sense right away. Just keep following along!
The only catch is that you need to update the Index
method signature to return a Task<IActionResult>
instead of just IActionResult
, and mark it as async
:
public async Task<IActionResult> Index()
var todoItems = await _todoItemService.GetIncompleteItemsAsync();
// Pass the view to a model and render
You’re almost there! You’ve made the depend on the ITodoItemService
interface, but you haven’t yet told ASP.NET Core that you want the FakeTodoItemService
to be the actual service that’s used under the hood. It might seem obvious right now since you only have one class that implements ITodoItemService
, but later you’ll have multiple classes that implement the same interface, so being explicit is necessary.
Declaring (or “wiring up”) which concrete class to use for each interface is done in the ConfigureServices
method of the Startup
class. Right now, it looks something like this:
The job of the ConfigureServices
method is adding things to the service container, or the collection of services that ASP.NET Core knows about. The services.AddMvc
line adds the services that the internal ASP.NET Core systems need (as an experiment, try commenting out this line). Any other services you want to use in your application must be added to the service container here in ConfigureServices
.
Add the following line anywhere inside the ConfigureServices
method:
services.AddSingleton<ITodoItemService, FakeTodoItemService>();
This line tells ASP.NET Core to use the FakeTodoItemService
whenever the ITodoItemService
interface is requested in a constructor (or anywhere else).
AddSingleton
adds your service to the service container as a singleton. This means that only one copy of the FakeTodoItemService
is created, and it’s reused whenever the service is requested. Later, when you write a different service class that talks to a database, you’ll use a different approach (called scoped) instead. I’ll explain why in the Use a database chapter.
That’s it! When a request comes in and is routed to the TodoController
, ASP.NET Core will look at the available services and automatically supply the FakeTodoItemService
when the controller asks for an ITodoItemService
. Because the services the controller depends on are “injected” from the service container, this pattern is called dependency injection.