Living life by the motto, "You didn't get this far by giving up." It hasn't failed her yet.
Dependency injection and service layers—how are you supposed to make them, much less use them? Let's find out!
In a previous article, I discussed loosely couple code and why you should be implementing it in your projects. I included a snippet of code showcasing a small service layer and using it via dependency injection in a Razor page, but I didn’t elaborate at the time regarding the process of how to create a service layer. Let’s rectify that.
The following instructions are for creating a service layer in an ASP.NET Core MVC application and are based on using Visual Studio as an IDE. If you are using a different language or a different IDE, your mileage may vary. For the sake of organization, I recommend creating a new folder nested under your project called ‘Services’ and an additional folder nested within that folder called ‘Interfaces.’ This isn’t necessary, but proper organization is always good practice in my opinion!
Once that’s done, you’ll want to right click ‘Services (or wherever you’ve elected to store services), then choose Add > Class. A pop-up window will appear, in which you want to choose Class and name your service appropriately. I recommend descriptive naming; for example, I needed a service for handling project data in my issue tracker application, so I made a service named ProjectService.cs, so I would know at a glance what that service is for.
Once that’s done, you’ll need to create an interface (we’ll discuss what that is more thoroughly in a minute) for your service. To do that, right click your ‘Interfaces’ folder (again, adjust if needed), Add > Class, and choose Interface this time. When naming, the convention is to begin the file name with a capital ‘I’; I further recommend descriptive naming again (so, with regards to my previous ProjectService.cs example, I named the corresponding interface IProjectService.cs).
As you can see, I use quite a few services in my applications!
Two more things to do. First, you’ll want to hop into your service and implement the interface. If you are unfamiliar with the concept, it is a form of inheritenc. You can copy what I’ve done here and adjust for your file names:
public class ProjectService : IProjectService
And last but most certainly not least, you’ll need to change your Program.cs file, which if you are unfamiliar, is often located at the bottom of your project files. Go into Program.cs and add the following code, again making adjustments to reflect your file names:
builder.Services.AddScoped<IProjectService, ProjectService>();
And that’s it for setup! Not too bad, right? Now, before dive into how to actually use the service we’ve just set up, let’s address the lingering question from before: What is an interface? When using dependency injection, one does not inject the service itself but rather the interface. That interface is essentially a list of promises, methods your service will perform. For example, my IProjectService.cs includes these two:
public Task<bool> AddProjectAsync(Project? project);
public Task<bool> UpdateProjectAsync(Project? project);
No code; just promises of code. Your service, meanwhile, implements those promises. My ProjectService.cs implements the above promises like this:
public async Task<bool> AddProjectAsync(Project? project)
{
if (project == null) return false;
try
{
_context.Add(project);
await _context.SaveChangesAsync();
return true;
}
catch (Exception)
{
return false;
}
}
public async Task<bool> UpdateProjectAsync(Project? project)
{
if (project == null) return false;
try
{
_context.Update(project);
await _context.SaveChangesAsync();
return true;
}
catch (Exception)
{
return false;
}
}
You’ll determine what methods you need your service to perform, write promises for them in your interface, and implement those promises in your service. You can always add or adjust these promises and implementations later, so don’t feel like you need to do it all at once. And don’t forget, you’ll need to inject your ApplicationDbContext to access your database (if you’re unsure how, see below).
Service layers provide rock solid foundations for our applications
Once written, you’ll still need to inject your service into your code to use it. Dependency injection in a Razor page is as simple as putting this at the top of the page:
@inject IProjectService _ProjectService
And using a promised method like so:
@_ProjectService.AddProject([projectName])
It’s only a little more complicated to use dependency injection in a controller (and if you were unsure how to inject your ApplicationDbContext before, this is how you do it!):
public class ProjectsController : BaseController
{
private readonly IProjectService _projectService;
public ProjectsController(IProjectService projectService)
{
_projectService = projectService;
}
[CONTROLLER ACTIONS GO HERE]
}
In both of the above examples, you’ll notice there’s a naming convention of using an underscore ( _ ) for the service. Once the service is injected you can access any of the promised methods by using dot notation (e.g., _ProjectService.AddProject(project)
).
There are lots of reasons to use a service layer through dependency injection! One of my favorites is avoiding the need for ViewModels (any information you need outside of your model can be accessed through the service layer). Like I mentioned in my previous article, using a service layer for commonly reused methods means you’re keeping your code loosely coupled and can more easily make adjustments to those methods without the risk of forgetting to make the changes everywhere it’s used.
So now that you know how to create a service, what are you waiting for? Start using them in your projects, and you won’t regret it!
0 Comments