Injecting Controller vs Injecting Service inside Razor view

Viewed 2477

What is the best practice in injecting dependencies inside Razor view?

We can use Controller as a service and inject that or inject Service

I don't know what is the cons and pros of these injecting ways.

  1. Controller:

in Startup.cs

 public void ConfigureServices(IServiceCollection services)
 {
     .
     .
     .
    services.AddControllersWithViews().AddControllersAsServices().AddRazorRuntimeCompilation();
 }

then inside home.cshtml

@inject CourseController _courseControler 
.
.
.
<select asp-for="CategoryID" class="form-control round">
   @foreach (var item in await _courseControler.GetAllCourceCategory()){
      <option value="@item.ID">@item.Description</option>
   } 
</select>
  1. Service:

in Startup.cs

 public void ConfigureServices(IServiceCollection services)
 {
     .
     .
     .
    services.AddTransient<ICourseService, CourseService>();
 }

then inside home.cshtml

@inject ICourseService _courseService
.
.
.
<select asp-for="CategoryID" class="form-control round">
   @foreach (var item in await _courseService.GetAllCourceCategory()){
      <option value="@item.ID">@item.Description</option>
   } 
</select>
1 Answers

I will explain this by assuming that the application is a .NET Core MVC app. (Indeed the same principles are also applicable to Razor Page application but there will be some difference when implementing it.).

In short, injecting controller or service in a view is not a good idea.


Using @inject

From the .NET Core documentation:

ASP.NET Core supports dependency injection into views. This can be useful for view-specific services.

So, View-specific is the key.

Injecting a Controller into a View

Again, from Microsoft's documentation:

MVC controllers are responsible for responding to requests made against an ASP.NET MVC website.

When you inject a controller into a view file, your controller is NOT doing what it supposed to do.

Injecting a Service into a View

If the service is UI-specific, you can do that. You can find an example from the official documentation.

If your service is not handling UI-specific stuff (e.g. getting data from your database), it should be injected at controller level (or, in the .cshtml.cs file when you are using Razor Pages).

Use a View Model

If ICourseService is a data-specific service, you should call _courseService.GetAllCourseCategory() in the controller action.

You may need a view model like this:

public class HomeViewModel
{
  public List<Course> Courses { get; set; }
}

In your controller action:

// inject ICourseService in the controller constructor
public Task<IActionResult> Home()
{
  var viewModel = new HomeViewModel
  {
    Courses = await _courseService.GetAllCourseCategory()
  };
  return View(viewModel);
}

In the view file:

@model HomeViewModel
<select asp-for="CategoryID" class="form-control round">
  @foreach (var item in Model.Courses) {
    <option value="@item.ID">@item.Description</option>
  } 
</select>

Now this is what a typical MVC application looks like.


Conclusion

You can inject a controller or a service in the view file but most of the time you shouldn't do so in a MVC application. This violates the purpose of the controller and the view. Similarly, injecting a non-UI specific service to the view also violates the purpose of a view.

Use a model to carry your data (retrieved from services). Use a controller for the flow. Use a view to render your model. That's how MVC works.

Related