din*_*tom 12 c# asp.net-mvc dependency-injection asp.net-core-2.0
如果我在我的Asp.Net Core 2.0 Web应用程序中创建一个BaseController,其中包含一些常见的依赖关系,它们仍然是实际控制器中必需的.
例如,默认MVC 6 Web应用程序中的标准Account和Manage控制器.
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ILogger _logger;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<AccountController> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_logger = logger;
}
//rest of code removed
}
public class ManageController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ILogger _logger;
private readonly UrlEncoder _urlEncoder;
private const string AuthenicatorUriFormat = "otpauth://totp/{0}:{1}?secret={2}&issuer={0}&digits=6";
public ManageController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<ManageController> logger,
UrlEncoder urlEncoder)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_logger = logger;
_urlEncoder = urlEncoder;
}
// rest of code removed
}
Run Code Online (Sandbox Code Playgroud)
在我构建的自定义Web应用程序模板中,我将Account Controller重构为三个不同的控制器,RegisterController(处理用户注册的所有内容),LoginController(处理登录和注销),余额为第三个.我将Manage Controller拆分为两个,一个是ManagePasswordController(与密码相关的所有内容)和一个UserManageController(其他所有内容).
每个DI要求都有很多共性,我想把它们放在BaseController中.看起来像这样?
public abstract class BaseController : Controller
{
private readonly IConfiguration _config;
private readonly IEmailSender _emailSender;
private readonly ILogger _logger;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly UserManager<ApplicationUser> _userManager;
protected BaseController(IConfiguration iconfiguration,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<ManageController> logger)
{
_config = iconfiguration;
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_logger = logger;
}
//rest of code removed
}
Run Code Online (Sandbox Code Playgroud)
但似乎没有完成任何事情?因为在我看来,我仍然需要注入一切.我不能正确(我是DI的新手,所以显然没有任何线索)但是BaseController应该允许我在BaseController和RegisterController之间执行NO DI.我错了吗?我如何完成我想要做的事情?
public class RegisterController : BaseController
{
private const string ConfirmedRegistration = "User created a new account with password.";
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IEmailSender _emailSender;
private readonly ILogger _logger;
private readonly IConfiguration _config;
public RegisterController(
IConfiguration config,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<AccountController> logger) : base(config, userManager, signInManager, emailSender, logger)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_logger = logger;
_config = config;
}
//rest of code removed
}
Run Code Online (Sandbox Code Playgroud)
更新
根据Rufo爵士的建议
public abstract class BaseController : Controller
{
protected UserManager<ApplicationUser> UserManager { get; }
protected SignInManager<ApplicationUser> SignInManager { get; }
protected IConfiguration Config { get; }
protected IEmailSender EmailSender { get; }
protected ILogger AppLogger { get; }
protected BaseController(IConfiguration iconfiguration,
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ILogger<ManageController> logger)
{
AppLogger = logger;
EmailSender = emailSender;
Config = iconfiguration;
SignInManager = signInManager;
UserManager = userManager;
}
}
Run Code Online (Sandbox Code Playgroud)
和继承控制器
public class TestBaseController : BaseController
{
public TestBaseController() : base()
{
}
}
Run Code Online (Sandbox Code Playgroud)
这不起作用.Resharper告诉我,我必须在TestBaseController构造函数中将参数添加到基础构造函数调用中.
BaseController也应该继承自.Net Core 2.0中的Controller或ControllerBase吗?
Fra*_*hes 15
Microsoft.AspNetCore.MVC.Controller类附带扩展方法
HttpContext.RequestServices.GetService<T>
只要HttpContext在管道中可用,就可以使用它(例如,如果从控制器的构造函数调用HttpContext属性将为Null)
试试这种模式
注意:确保使用Microsoft.Extensions.DependencyInjection包含此指令 ;
基础控制器
public abstract class BaseController<T> : Controller where T: BaseController<T>
{
private ILogger<T> _logger;
protected ILogger<T> Logger => _logger ?? (_logger = HttpContext.RequestServices.GetService<ILogger<T>>());
Run Code Online (Sandbox Code Playgroud)
儿童控制器
[Route("api/authors")]
public class AuthorsController : BaseController<AuthorsController>
{
public AuthorsController(IAuthorRepository authorRepository)
{
_authorRepository = authorRepository;
}
[HttpGet("LogMessage")]
public IActionResult LogMessage(string message)
{
Logger.LogInformation(message);
return Ok($"The following message has been logged: '{message}'");
}
Run Code Online (Sandbox Code Playgroud)
不用说,请记住在Startup.cs - > ConfingureServices方法中注册您的服务
有使用非常少的很好的理由BaseController
在MVC.此方案中的基本控制器仅添加更多代码进行维护,没有任何实际好处.
对于真正的跨领域问题,在MVC中处理它们的最常见方式是使用全局过滤器,尽管在MVC核心中有一些值得考虑的新选项.
但是,您的问题看起来不像是违反单一责任原则的跨领域问题.也就是说,拥有超过3个注入的依赖项是一个代码气味,你的控制器做得太多了.最实际的解决方案是重构服务.
在这种情况下,我认为你有你需要明确的至少1个隐含的服务-即,UserManager
并SignInManager
应包到其自己的服务.从那里,您可以将其他3个依赖项注入该服务(当然,取决于它们的使用方式).所以,你可能会把这个减少到AccountController
和ManageController
.
一些迹象表明控制器做得太多了:
在这些情况下,值得一看,您是否可以将该逻辑转移到自己的服务中,将任何共享逻辑转移到该服务的依赖关系中等等.
归档时间: |
|
查看次数: |
9881 次 |
最近记录: |