【问题标题】:Post new record into AspNetUsers from another controller (Web api)从另一个控制器 (Web api) 将新记录发布到 AspNetUsers
【发布时间】:2019-08-26 08:22:03
【问题描述】:

我想使用 webApi 将新用户发布到 AspNetUsers 这是我正在尝试做的事情: [HttpPost]

        public async Task<IHttpActionResult> POST([FromBody]ICollection<ApplicationUser> employees)
        {

        employees.First().PasswordHash = HashPassword(employees.First().PasswordHash);

        if (!ModelState.IsValid)
            {

                return BadRequest(ModelState);
            }


        foreach (var item in employees)
        {
            db.Users.Add(item);
        }
        try
        {
            await db.SaveChangesAsync();
        }
        catch (System.Data.Entity.Validation.DbEntityValidationException dbEx)
        {
            Exception raise = dbEx;
            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    string message = string.Format("{0}:{1}",
                        validationErrors.Entry.Entity.ToString(),
                        validationError.ErrorMessage);
                    // raise a new exception nesting
                    // the current instance as InnerException
                    raise = new InvalidOperationException(message, raise);
                }
            }
            throw raise;
        }
        var manager = new UserManager<ApplicationUser, int>
        (new CustomUserStore(new ApplicationDbContext()));

        var roleManager = new RoleManager<CustomRole, int>
            (new CustomRoleStore(new ApplicationDbContext()));
        manager.AddToRoles(employees.First().Id, "User");

        return CreatedAtRoute("DefaultApi", new { id = employees.First().Id  }, employees);
    }
    public static string HashPassword(string password)
    {
        if (password == null)
        {
            throw new ArgumentNullException("password");
        }


        byte[] salt;
        byte[] subkey;
        using (var deriveBytes = new Rfc2898DeriveBytes(password, SaltSize, PBKDF2IterCount))
        {
            salt = deriveBytes.Salt;
            subkey = deriveBytes.GetBytes(PBKDF2SubkeyLength);
        }

        var outputBytes = new byte[1 + SaltSize + PBKDF2SubkeyLength];
        Buffer.BlockCopy(salt, 0, outputBytes, 1, SaltSize);
        Buffer.BlockCopy(subkey, 0, outputBytes, 1 + SaltSize, PBKDF2SubkeyLength);
        return Convert.ToBase64String(outputBytes);
    }

我尝试使用 Postman 对其进行测试,结果如下:

****[ArgumentNullException]:值不能为空。 参数名称:值 在 System.Security.Claims.Claim..ctor(字符串类型,字符串值,字符串 valueType,字符串颁发者,字符串 originalIssuer,ClaimsIdentity 主题,字符串 propertyKey,字符串 propertyValue) 在 System.Security.Claims.Claim..ctor(字符串类型,字符串值) 在 Microsoft.AspNet.Identity.ClaimsIdentityFactory2.<CreateAsync>d__19.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter1.GetResult() 在 C:\DataInGrid\DataInGrid\Models\IdentityModels.cs:line 18 中的 DataInGrid.Models.ApplicationUser.d__0.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter1.GetResult() at DataInGrid.Providers.ApplicationOAuthProvider.<GrantResourceOwnerCredentials>d__2.MoveNext() in C:\DataInGrid\DataInGrid\Providers\ApplicationOAuthProvider.cs:line 42 --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler.<InvokeTokenEndpointResourceOwnerPasswordCredentialsGrantAsync>d__3f.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler.<InvokeTokenEndpointAsync>d__22.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler.<InvokeAsync>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Security.Infrastructure.AuthenticationMiddleware1.d__0.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 Microsoft.Owin.Security.Infrastructure.AuthenticationMiddleware1.<Invoke>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Security.Infrastructure.AuthenticationMiddleware1.d__0.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 Microsoft.AspNet.Identity.Owin.IdentityFactoryMiddleware2.<Invoke>d__5.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNet.Identity.Owin.IdentityFactoryMiddleware2.d__5.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContextStage.d__5.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(任务任务) 在 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(任务任务) 在 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.d__2.MoveNext() --- 从先前抛出异常的位置结束堆栈跟踪 --- 在 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.StageAsyncResult.End(IAsyncResult ar) 在 Microsoft.Owin.Host.SystemWeb.IntegratedPipeline.IntegratedPipelineContext.EndFinalWork(IAsyncResult ar) 在 System.Web.HttpApplication.AsyncEventExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() 在 System.Web.HttpApplication.ExecuteStepImpl(IExecutionStep 步骤) 在 System.Web.HttpApplication.ExecuteStep(IExecutionStep 步骤,Boolean& completedSynchronously) -->****

【问题讨论】:

    标签: asp.net asp.net-web-api asp.net-core


    【解决方案1】:

    您的代码一团糟。我不确定你在做什么。首先,UserManagerRoleManager 是服务。你永远不会更新它们;相反,你将它们注入你的类:

    [ApiController]
    public UserApiController : ControllerBase
    {
        private readonly UserManager<ApplicationUser> _userManager;
    
        public UserApiController(UserManager<ApplicationUser> userManager)
        {
            _userManager = userManager;
        }
    
        ...
    }
    

    然后,要创建一个新用户,您应该使用:

    await _userManager.CreateAsync(user, password);
    

    这将为您处理密码散列,以及其他必要的任务,例如规范化用户名、电子邮件地址等。

    接下来,您不应将帖子绑定到ApplicationUser。那是你的实体,它不适合像创建用户请求这样的东西。也就是说,它没有Password 属性来保存用户所需的密码,预先散列。相反,您应该创建一个仅包含您希望能够提交的属性的视图模型/DTO 类。这可能只是一个电子邮件地址和一个密码。

    然后,将发布的数据映射到 ApplicationUser 实体的实例:

    var user = new ApplicationUser
    {
        Email = model.Email
        // etc.
    };
    

    然后:

    await _userManager.CreateAsync(user, model.Password);
    

    由于您要发布要创建的用户列表,您只需对其进行迭代并对每个用户执行相同的操作。

    【讨论】:

    • 谢谢,我已经用过这样的东西了。我想要做的是将数据从网格(作为 Json 结果)发送到 Post 函数并将其存储在 AspNetUsers 中!
    • 然后呢? 如何发送数据无关紧要;持久化方法保持不变。
    • 这由 CreateAsync 解决。它处理密码散列,并且每次都会这样做。您的问题可能归结于不共享数据保护密钥存储,这对于不同的应用程序以相同的方式加密事物是必要的。
    • 我不太了解这个概念!现在我愿意 :) 非常感谢您
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-03-01
    • 1970-01-01
    • 2015-05-03
    • 2014-11-26
    • 1970-01-01
    • 2014-06-06
    相关资源
    最近更新 更多