什么return in web api asp net core

What return in web api asp net core

我不确定在 LoginAsync 方法中我应该 return 什么。有时我对 return 有错误,但有时验证成功。我目前正在使用动态,但听说这是不好的做法。我应该用什么? 它是 AccountService 服务中的 LoginAsync:

public async Task<dynamic> LoginAsync(User user)
{
    var existingUser_byEmail = await FindUserByEmailAsync(user.Email);

    if (existingUser_byEmail == default)
        return new Error
        {
            StatusCode = 400,
            ErrorMessages = { { "email", "Nie odnaleziono użytkownika z podanym adresem e-mail" } }
        };

    if (BCrypt.Net.BCrypt.EnhancedVerify(user.Password, existingUser_byEmail.Password))
        return new AuthSuccessful { StatusCode = 200, Token = _jwtService.GenerateToken(existingUser_byEmail) };
    else
        return new Error { StatusCode = 401, ErrorMessages = { { "password", "Błędne hasło" } } };
}

它是 AccountController 中的登录方法:

[HttpPost("login")]
public async Task<IActionResult> LogIn([FromBody] User user)
{
    var response = await _accountService.LoginAsync(user);
    return StatusCode(response.StatusCode, response);
}

谢谢大家的回答,祝你有美好的一天! :D

您有多种选择。

1。 Interface/baseclass

似乎您 return 的所有内容都具有相似的结构 – StatusCode 属性,以及在给定状态代码的上下文中有意义的其他一些附加属性。

所以最明显的可能是为这些创建一个基础 class 或一个接口,如下所示:

    public interface IOperationResult
    {
        int StatusCode { get; init; }
        object Response { get; }
    }

    public class Error : IOperationResult
    {
        public int StatusCode { get; init; }
        public string[,] ErrorMessages { get; init; }
        public object Response => ErrorMessages;
    }

    public class AuthSuccessful : IOperationResult
    {
        public int StatusCode { get; init; }
        public string Token { get; init; }
        public object Response => Token;
    }

这是一个定义明确的结构,可以说支持更复杂的业务逻辑,当您可能需要检查 return 值的确切类型并以类型安全的方式访问它们的属性时。

2。值元组

最近我经常使用的另一个选项是 returning 一个值元组,其中一个成员包含 success/failure,另一个成员包含结果;像下面这样。在这种情况下看起来很糟糕,因为错误消息的格式没有定义。但是,如果您为此使用了 class 或结构,那就没问题了。

public async Task<(int statusCode, object response)> LoginAsync(User user)
{
    var existingUser_byEmail = await FindUserByEmailAsync(user.Email);

    if (existingUser_byEmail == default)
        return (statusCode: 400, response: new[] { new[] { "email", "Nie odnaleziono użytkownika z podanym adresem e-mail" } });
    if (BCrypt.Net.BCrypt.EnhancedVerify(user.Password, existingUser_byEmail.Password))
        return (statusCode: 200, response: _jwtService.GenerateToken(existingUser_byEmail));
    else
        return (statusCode: 401, response: new[] { new[] { "password", "Błędne hasło" } });
}

// Then you can do a tuple deconstruction assignment:
[HttpPost("login")]
public async Task<IActionResult> LogIn([FromBody] User user)
{
    var (statusCode, response) = await _accountService.LoginAsync(user);
    return StatusCode(statusCode, response);
}

3。在服务外做HTTP代码和错误信息选择

更传统的做法是 return 来自身份验证服务的不同标志,然后将其映射到靠近控制器(或控制器内部)某处的 HTTP 代码。通过这种方式,您可以避免将服务与 HTTP 问题耦合,这可以说不应该是他们的责任。

例如很多内置身份服务使用 Microsoft.AspNetCore.Identity.SignInResult class.

在下面的实现中,我将 LoginAsync 方法更改为 return 在密码无效和电子邮件无效的情况下均失败。这实际上是一种更好的做法,因为如果您告诉尝试登录的人某个电子邮件地址有或没有帐户,您就是在泄露用户信息

public async Task<(SignInResult result, string token)> LoginAsync(User user)
{
    var existingUser_byEmail = await FindUserByEmailAsync(user.Email);
    if (existingUser_byEmail == default)
        return (SignInResult.Failed, null);
    if (BCrypt.Net.BCrypt.EnhancedVerify(user.Password, existingUser_byEmail.Password))
        return (SignInResult.Success, _jwtService.GenerateToken(existingUser_byEmail));
    else
        return (SignInResult.Failed, null);
}

[HttpPost("login")]
public async Task<IActionResult> LogIn([FromBody] User user)
{
    var (result, token) = await _accountService.LoginAsync(user);

    if (result.Succeeded)
        return Ok(token);

    // Handle lock-out and 'login not allowed' situation too, if necessary.
    return Unauthorized("Invalid password or email.");
}