如何从控制器中提取方法?

How to extract methods from controller?

我想将“我能做的”提取到服务中。我在控制器中有这个方法:

[AllowAnonymous]
        public async Task<IActionResult> ExternalLoginCallback(string returnUrl = null, string remoteError = null)
        {
            returnUrl = returnUrl ?? Url.Content("~/");

            LoginViewModel loginViewModel = new LoginViewModel
            {
                ReturnUrl = returnUrl,
                ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList()
            };

            if (remoteError != null)
            {
                ModelState.AddModelError(string.Empty, $"Error from external provider: {remoteError}");
                return View("Login", loginViewModel);
            }

            var info = await _signInManager.GetExternalLoginInfoAsync();
            if (info == null)
            {
                ModelState.AddModelError(string.Empty, "Error loading external login information.");
                return View("Login", loginViewModel);
            }

            var signInResult = await _signInManager.ExternalLoginSignInAsync(info.LoginProvider, info.ProviderKey, isPersistent: false, bypassTwoFactor: true);

            if (signInResult.Succeeded)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                var email = info.Principal.FindFirstValue(ClaimTypes.Email);

                if (email != null)
                {
                    var user = await _userManager.FindByEmailAsync(email);

                    if (user == null)
                    {
                        user = new ApplicationUser
                        {
                            UserName = info.Principal.FindFirstValue(ClaimTypes.Email),
                            Email = info.Principal.FindFirstValue(ClaimTypes.Email)
                        };

                        await _userManager.CreateAsync(user);
                    }
                    await _userManager.AddLoginAsync(user, info);
                    await _signInManager.SignInAsync(user, isPersistent: false);

                    return LocalRedirect(returnUrl);
                }

                ViewBag.ErrorTitle = $"Nie otrzymano informacji o adresie e-mail od dostawcy: {info.LoginProvider}";
                ViewBag.ErrorMessage = "Proszę skontaktować się z supportem fryzjer@aplikacjafryzjer.com";

                return View("Error");
            }
        }

某些属性仅适用于从 Controller 继承的 类,例如。模型状态或 Url。 我也可以提取代码的这些部分吗? service可以继承controller,那不就变成controller了吗?

-------------------------------------------- - - - - - - - - 编辑 - - - - - - - - - - - - - - - - - ----------------------------

好的,我尝试将我的方法与控制器分开。在我之前的代码控制器下面:

 public class AccountController : Controller
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;
        private readonly IEmailService _emailService;

        public AccountController(
            UserManager<ApplicationUser> userManager,
            SignInManager<ApplicationUser> signInManager,
            IEmailService emailService)
        {
            _userManager = userManager;
            _signInManager = signInManager;
            _emailService = emailService;
        }

        [HttpPost]
        public async Task<IActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                //register functionality
                var user = new ApplicationUser
                {
                    FirstName = model.FirstName,
                    LastName = model.LastName,
                    UserName = model.Email,
                    Email = model.Email,
                };

                var result = await _userManager.CreateAsync(user, model.Password);

                if (result.Succeeded)
                {
                    if (_signInManager.IsSignedIn(User) && User.IsInRole("Admin"))
                    {
                        return RedirectToAction("ListUsers", "Administrator");
                    }
                    //login user
                    await _signInManager.SignInAsync(user, isPersistent: false);

                    //generation of the email token
                    var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);

                    var link = Url.Action(nameof(VerifyEmail), "Home", new { userId = user.Id, code }, Request.Scheme, Request.Host.ToString());

                    await _emailService.SendAsync(user.Email, "Weryfikacja adresu e-mail", $"<a href=\"{link}\">Potwierdź e-mail</a>", true);

                    return RedirectToAction("EmailVerification");
                }
            }
            return View(model);
        }
}

现在我的控制器:

    public class AccountController : Controller
    {
        private readonly IUserManager _userManager;

        public AccountController(
            IUserManager userManager)
        {
            _userManager = userManager;
        }
        [HttpPost]
        public async Task<IActionResult> Register(RegisterViewModel model)
        {
            if (ModelState.IsValid)
            {
                (string action, string controller) = await _userManager.Register(model);
                return RedirectToAction(action, controller);
            }
            return View(model);
        }
}

我敢肯定,出了点问题。我不知道如何将此逻辑与控制器分开,但在其他论坛上我听说“你必须将你的逻辑与控制器分开!你的控制器必须简单 - 仅获取请求并发送响应,仅此而已!”。但是现在,当我开始重建我的项目时,我不确定这是否更复杂...

在我的服务中我return一个元组(???),因为我没有更好的主意...

        public async Task<(string, string)> Register(RegisterViewModel model)
        {
            //register functionality
            var user = new ApplicationUser
            {
                FirstName = model.FirstName,
                LastName = model.LastName,
                UserName = model.Email,
                Email = model.Email,
            };

            var result = await _userManager.CreateAsync(user, model.Password);

            if (result.Succeeded)
            {
                if (_signInManager.IsSignedIn(User) && User.IsInRole("Admin"))
                {
                    return ("ListUsers", "Administrator");
                }
                //login user
                await _signInManager.SignInAsync(user, isPersistent: false);

                //generation of the email token
                var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);

                var link = _urlHelper.Action(nameof(VerifyEmail), "Home", new { userId = user.Id, code });

                await _emailService.SendAsync(user.Email, "Weryfikacja adresu e-mail", $"<a href=\"{link}\">Potwierdź e-mail</a>", true);

                return ("EmailVerification", "Administrator");
            }

            return ("Register", "Administrator");
        }

据我所知,如果你想在其他不是从控制器继承的自定义服务中使用 Url。您可以注入 IActionContextAccessor 并使用 IUrlHelperFactory 来创建它。此外,如果您想使用其他基于 属性 或方法的控制器,您可以参考 asp.net core source codes 并找到它,然后您可以自己编写代码。

更多详情,您可以参考以下代码:

首先,您可以在 startup.cs ConfigureServices 方法中注入 IActionContextAccessor:

        services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();

然后您可以使用 DI 和工厂来创建 URLhelper,如下所示:

public class GetRoute : IGetRoute
{


    private IUrlHelper _urlHelper;

    private IActionContextAccessor _IActionContextAccessor;

    public IUrlHelper Url
    {
        get
        {
            if (_urlHelper == null)
            {
                 
                _urlHelper = _urlHelperFactory.GetUrlHelper(_IActionContextAccessor.ActionContext);
            }

            return _urlHelper;
        }
        set
        {
            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            _urlHelper = value;
        }
    }

    private readonly IUrlHelperFactory _urlHelperFactory ;

 
    public GetRoute(IActionDescriptorCollectionProvider actionDescriptorCollectionProvider, IUrlHelperFactory urlHelperFactory, IActionContextAccessor actionContextAccessor)
    {
        _IActionContextAccessor = actionContextAccessor;
        _urlHelperFactory = urlHelperFactory;
     }
    public string Getlink() {

       return Url.Link("default", "aaaa");
    }

}