1

I have a UserController and a BaseController with some functions and dependencies injected as below. The BaseController is shared between multiple controllers. But All the controllers do not need all the injected dependencies from the BaseController. Controller1 Needs dependencies D1 and D2 but Controller2 requires only D1 from BaseController. How can I achieve this?

In the below code, UserController does not require the injected webHostEnvironment from the base but I need to inject it as it present in BaseController else Visual Studio throws compiler error of missing dependency. Please let me know if additional details are required to resolve the issue.

UserController

using MyApp.Data;
using MyApp.Models;
using MyApp.Models.ViewModels;
using MyApp.Utilities;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.UI.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace MyApp.Controllers
{
    [Authorize]
    public class UserController : BaseController
    {
        private readonly ApplicationDbContext db;
        private readonly ILogger<UserController> logger;
        private readonly RoleManager<IdentityRole> roleManager;
        private readonly IEmailSender emailSender;

        public UserController(  ApplicationDbContext db,
                                ILogger<UserController> logger,
                                UserManager<ApplicationUser> userManager,
                                RoleManager<IdentityRole> roleManager,
                                IEmailSender emailSender,
                                IWebHostEnvironment webHostEnvironment) : base (userManager, webHostEnvironment)
        {
            this.db = db;
            this.logger = logger;
            this.roleManager = roleManager;
            this.emailSender = emailSender;
        }

        [HttpGet]
        public IActionResult Index()
        {
            var userList = userManager.Users;
            return View(userList);
        }

        [HttpGet]
        public async Task<IActionResult> Read(string? id)
        {
            var user = await userManager.FindByIdAsync(id);
            if (user == null)
            {
                return RecordNotFound();
            }
            UserViewModel model = new()
            {
                Id = user.Id,
                FirstName = user.FirstName,
                LastName = user.LastName,
                UserName = user.UserName,
                Email = user.Email,
                PhoneNumber = user.PhoneNumber,
            };
            return View(model);
        }
    //And Some more Action Methods for the controller
    }
}

BaseController

using MyApp.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;

namespace MyApp.Utilities
{
    [Authorize]
    public class BaseController : Controller
    {
        protected readonly UserManager<ApplicationUser> userManager;
        protected readonly IWebHostEnvironment webHostEnvironment;
        
        public BaseController(  UserManager<ApplicationUser> userManager,
                                IWebHostEnvironment webHostEnvironment)
        {
            this.userManager = userManager;
            this.webHostEnvironment = webHostEnvironment;
            
        }

        [HttpGet] [HttpPost]
        public IActionResult RecordNotFound()
        {
            TempData[HelperStatic.ErrorMessage] = HelperStatic.recordNotFoundMsg;
            return View("Index");
        }

        [HttpPost]
        public IActionResult SaveNew()
        {
            TempData[HelperStatic.SuccessMessage] = HelperStatic.recordSavedMsg;
            return RedirectToAction("Create");
        }
        
        //And Many other Reusable Methods for all controllers
    }
}
9
  • 2
    If your base controller needs some dependencies in case a base method is called, you have to inject all needed ones. If your derived class doesn't need those base functionality why do you derive from it? Or you should make multiple finer grained base classes to derive from the specific from for each case. Commented Dec 20, 2021 at 9:07
  • Can you post more detailed information about the compiler error? Based on your code, I create a Asp.net 5 application, after adding the using Microsoft.AspNetCore.Hosting; reference, the code works well on my side, check this screenshot (as we can see the code execute to the break point). Commented Dec 20, 2021 at 9:21
  • @ZhiLv Please find the error message screenshot here when I remove a dependency ibb.co/ThBFW99 Commented Dec 20, 2021 at 10:04
  • 1
    @ahp Is it an option to provide null as the dependency for the BaseController constructor? It is unclear if the dependency is optional or required. Commented Dec 22, 2021 at 13:15
  • 1
    @ahp You have to define for yourself if the dependency should be required or optional for the BaseController. In case it is optional, you can use null as the value. In case it is required, you have to use an actual instance of the dependency (or let it injected by some framework for you). Commented Dec 22, 2021 at 16:45

1 Answer 1

4

It would seem what you have here is too much going on in your base controller.

If you have actions within the base controller that are not applicable to all, then they are living in the wrong place.

For example (from what you've given), this action looks like it should maybe live e.g. on an error controller:

[HttpGet] [HttpPost]
public IActionResult RecordNotFound()
{
    TempData[HelperStatic.ErrorMessage] = HelperStatic.recordNotFoundMsg;
    return View("Index");
}

And you redirect to 'Error/RecordNotFound' rather than having this live within every inheriting controller.

You cannot have dependencies on your base constructor that are not also injected on sub classes. If this is causing you a problem, it's because there's too much going on in the base!

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.