C# - 身份框架和整数 UserId - 等待 SignInAsync 问题

标签 c# asp.net asp.net-mvc asynchronous asp.net-identity

我正在开发一个 MVC5 演示应用程序,并试图与其中的 Dapper 一起使用身份框架。

我已经实现了一个包含许多层的 n 层混合架构,包括由 Dapper 处理的 DAL(使用存储库模式)。我正在使用标准 Microsoft.AspNet.Identity正确引用了 Owin 和 Core 程序集以进行身份​​验证 - 我继续阅读,因此不建议自己滚动!

我跑题了,我遇到的问题是我的身份实现中的以下方法...

PasswordSignInAsync()

例如,在我的 AccountContoller.cs 中我有以下内容:

 // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);

        int userId = Int32.Parse(User.Identity.GetUserId());

        switch (result)
        {
            case SignInStatus.Success:
                ViewBag.UserId = userId;
                return RedirectToAction("Index",  new RouteValueDictionary(new { controller = "User", action = "Index", id = userId }));
                //return RedirectToLocal(returnUrl);
            case SignInStatus.LockedOut:
                return View("Lockout");
            case SignInStatus.RequiresVerification:
                return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
            case SignInStatus.Failure:
                return View(model);
            default:
                ModelState.AddModelError("", "Invalid login attempt.");
                return View(model);
        }
    }

基本上,该方法让用户登录,如果 SignInStatus.Success然后重定向到我的 UserController.cs索引法。 Index 方法接受一个整数 id - 也就是经过身份验证的用户的 UserId 变量。

我的 Index(int id)路由到/Users/{id} 或例如/Users/5

然而,提交表单后发生的事情是:

Server Error in '/' Application.

Value cannot be null. Parameter name: String Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.ArgumentNullException: Value cannot be null. Parameter name: String

Source Error:

Line 77: var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false); Line 78: Line 79:
int userId = Int32.Parse(User.Identity.GetUserId()); Line 80:
Line 81: switch (result)

Source File: c:[ProjectName is omitted]\Controllers\AccountController.cs Line: 79

Stack Trace:

[ArgumentNullException: Value cannot be null. Parameter name: String] System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal) +12099581
System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info) +120
System.Int32.Parse(String s) +24 [ProjectName is omitted for security].Controllers. d__4.MoveNext() in [ProjectName is omitted]\Controllers\AccountController.cs:79 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +99
System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +58 System.Runtime.CompilerServices.TaskAwaiter.GetResult() +26 System.Threading.Tasks.TaskHelpersExtensions.ThrowIfFaulted(Task task) +61 System.Web.Mvc.Async.TaskAsyncActionDescriptor.EndExecute(IAsyncResult asyncResult) +114
System.Web.Mvc.Async.<>c__DisplayClass37.b__36(IAsyncResult asyncResult) +66
System.Web.Mvc.Async.WrappedAsyncResult1.CallEndDelegate(IAsyncResult asyncResult) +47<br/> System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +136
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethod(IAsyncResult asyncResult) +49
System.Web.Mvc.Async.AsyncInvocationWithFilters.b__3d() +117 System.Web.Mvc.Async.<>c__DisplayClass46.b__3f() +323 System.Web.Mvc.Async.<>c__DisplayClass33.b__32(IAsyncResult asyncResult) +44
System.Web.Mvc.Async.WrappedAsyncResult1.CallEndDelegate(IAsyncResult asyncResult) +47<br/> System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +136
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +102
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeActionMethodWithFilters(IAsyncResult asyncResult) +50
System.Web.Mvc.Async.<>c__DisplayClass2b.b__1c() +72 System.Web.Mvc.Async.<>c__DisplayClass21.b__1e(IAsyncResult asyncResult) +185
System.Web.Mvc.Async.WrappedAsyncResult1.CallEndDelegate(IAsyncResult asyncResult) +42<br/> System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +133
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncControllerActionInvoker.EndInvokeAction(IAsyncResult asyncResult) +40
System.Web.Mvc.Controller.b__1d(IAsyncResult asyncResult, ExecuteCoreState innerState) +34
System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +70<br/> System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +133
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +37
System.Web.Mvc.Controller.EndExecuteCore(IAsyncResult asyncResult) +44 System.Web.Mvc.Controller.b__15(IAsyncResult asyncResult, Controller controller) +39
System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +62<br/> System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +133
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +37 System.Web.Mvc.Controller.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.Controller.System.Web.Mvc.Async.IAsyncController.EndExecute(IAsyncResult asyncResult) +39
System.Web.Mvc.MvcHandler.b__5(IAsyncResult asyncResult, ProcessRequestState innerState) +39
System.Web.Mvc.Async.WrappedAsyncVoid1.CallEndDelegate(IAsyncResult asyncResult) +70<br/> System.Web.Mvc.Async.WrappedAsyncResultBase1.End() +133
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +56
System.Web.Mvc.Async.AsyncResultWrapper.End(IAsyncResult asyncResult, Object tag) +37
System.Web.Mvc.MvcHandler.EndProcessRequest(IAsyncResult asyncResult) +40 System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest(IAsyncResult result) +38
System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute() +9723757 System.Web.HttpApplication.ExecuteStep(IExecutionStep step, Boolean& completedSynchronously) +155

我不想在 UserController 中执行索引操作接受可为 null 的参数(即 int?id),尽管使 int 可为 null 可以修复它(通过加载空白索引页)——但重点是 Profile 属于用户并且不能是通用的...

    // UserController.cs  /User/Index/5
    // GET: User's Profile page by calling DAL ProfileRepository.cs!
    public ActionResult Index(int id)
    {
        Profile profile = _profileRepository.ProfileGet(id);
        return View(profile);
    }

奇怪的是,如果我重新加载登录页面并重新提交登录表单,它会设法为 userId 变量分配一个整数值并路由到他们的个人资料!

我不知道这是否与 await SignInAsync 方法有关,但这肯定会停止线程执行直到方法调用完成?

或者可能与将字符串解析为 int 相关: int userId = Int32.Parse(User.Identity.GetUserId());

但是如果SignInAsync已经成功完成应该有一个User.Identity调用GetUserId()在右边?

因此很奇怪,出现错误转储后按 Ctrl + F5 会导致加载正确的配置文件页面 - 这意味着正确分配了整数值。

呸!我正处于考虑废弃 Identity 框架的地步——这对我来说已经足够艰难了,我将它与可怕的 EF 分离并使用我自己的数据库架构!

如果你们还需要看我的资源,请告诉我

祝一切顺利

:-)

或者应该是 o.O !

最佳答案

您的代码有问题。 First Identity 的默认用户 ID 值为 GUID,因此您无法解析为 int。继续使用字符串数据类型或将默认数据类型更改为 int。其次,您在调用 SignInManager.PasswordSignInAsync() 方法后使用 User.Identity.GetUserId()。不要工作。最后必须向服务器发送一个新请求,以便您可以检查登录的用户信息。这就是为什么您的代码在刷新后可以正常工作的原因。第三,您的索引操作存在安全问题,每个人都可以通过在浏览器中直接输入正确的 URL 来访问您的用户数据。因此你可以这样写:

public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
    var result = await SignInManager.PasswordSignInAsync(model.UserName, 
        model.Password, model.RememberMe, shouldLockout: false);

    switch (result)
    {
        case SignInStatus.Success:
            ViewBag.UserId = userId;
            return RedirectToAction("Index","User");
        case SignInStatus.LockedOut:
            return View("Lockout");
        case SignInStatus.RequiresVerification:
            return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
        case SignInStatus.Failure:
            return View(model);
        default:
            ModelState.AddModelError("", "Invalid login attempt.");
            return View(model);
    }
}

public ActionResult Index()
{
    string userID=User.Identity.GetUserId();
    // use userID in your way
}

但如果您想在调用 SignInManager.PasswordSignInAsync() 之前获取用户 ID 而无需重定向,请考虑使用用户管理器获取用户 ID:

var result = await SignInManager.PasswordSignInAsync(model.UserName, 
        model.Password, model.RememberMe, shouldLockout: false);

var userId =UserManager.FindByName(model.UserName).Id;
// instead of 
// int userId = Int32.Parse(User.Identity.GetUserId());

关于C# - 身份框架和整数 UserId - 等待 SignInAsync 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32038438/

相关文章:

c# - 防止点击按钮时页面刷新

c# - 帮助 C# HttpWebRequest URI 丢失其编码

c# - 存储过程根据过滤器查看所有记录不接受空值

asp.net listview Container.DataItemIndex

c# - MVC 删除删除不相关的数据

c# - ASP.NET MVC 中的递归

c# - @Html.Editor用于百分比显示和保存

c# - UDP数据传输比TCP慢

jquery 1.6.2 ajax 请求 aspx 方法总是返回 parsererror

c# - 无法在 Docker 上运行 asp.net mvc 6