locked
JsonSerializer.deserialize not outputting the correct data RRS feed

  • Question

  • User1374623307 posted

    Hello,

         This one has me confused as to how to deserialize the data correctly.  I am getting the correct data coming from the API, but cannot get the correct data after the derialization.  I am using System.Text.Json and not trying to install the Newtonsoft.Json.

    In my RazorPage I am calling a WebApi which is returning an ActionResult<Class>.  The deserialize will give me one correct result and a wrong result for the other.  So have the following:

    RazorPage:

    public async Task<IActionResult> OnPostAsync(string returnUrl = null)
            {
                if (ModelState.IsValid)
                {
                    var dataToSend = new LoginPostDataModel
                    {
                        Email = Input.Email,
                        Password = Input.Password,
                        RememberMe = Input.RememberMe,
                        ReturnUrl = returnUrl
                    };
    
                    var data = new StringContent(JsonSerializer.Serialize(dataToSend), Encoding.UTF8, "application/json");
                    Microsoft.AspNetCore.Identity.SignInResult signInResult = null;
    
                    using (HttpResponseMessage response = await _apiHelper.ApiClient.PostAsync("/api/Login", data))
                    {
                        if (response.IsSuccessStatusCode == false)
                        {
                            throw new Exception(response.ReasonPhrase);
                        }
                        else
                        {
                            var options = new JsonSerializerOptions { PropertyNameCaseInsensitive = true };
                            var resultString = await response.Content.ReadAsStringAsync();
                            var result = JsonSerializer.Deserialize<LoginPostResponseModel>(resultString, options);
                            ReturnUrl = result.ReturnUrl;  //Correct value
                            signInResult = result.SignInResult;  //Incorrect value
                        }
                    }
    
                    if (signInResult.Succeeded)
                    {
                        await _apiHelper.Authenticate(Input.Email);
    
                        _logger.LogInformation("User logged in.");
                        return LocalRedirect(returnUrl);
                    }
                    if (signInResult.RequiresTwoFactor)
                    {
                        return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, RememberMe = Input.RememberMe });
                    }
                    if (signInResult.IsLockedOut)
                    {
                        _logger.LogWarning("User account locked out.");
                        return RedirectToPage("./Lockout");
                    }
                    else
                    {
                        ModelState.AddModelError(string.Empty, "Invalid login attempt.");
                        return Page();
                    }
                }
    
                // If we got this far, something failed, redisplay form
                return Page();
            }

    LoginPostResponseModel:

    using Microsoft.AspNetCore.Identity;
    
    namespace IdentityApi.UILibrary.Models
    {
        public class LoginPostResponseModel
        {
            public SignInResult SignInResult { get; set; }
            public string ReturnUrl { get; set; }
        }
    }

    WebApi:

    [HttpPost]
            public async Task<ActionResult<LoginPostOutputModel>> PostAsync(LoginPostInputModel inputModel)
            {
                string returnUrl = inputModel.ReturnUrl ?? Url.Content("~/");
    
                var signInResult = await _signInManager.PasswordSignInAsync(inputModel.Email, inputModel.Password, inputModel.RememberMe, inputModel.LockoutOnFailure);
    
                var output = new LoginPostOutputModel
                {
                    ReturnUrl = returnUrl,
                    SignInResult = signInResult 
                };
    
                return output;  // This is returning the correct data
            }

    LoginOutputPostModel:

    using Microsoft.AspNetCore.Identity;
    
    namespace IdentityApi.WebApi.Models.IdentityModels
    {
        public class LoginPostOutputModel
        {
            public SignInResult SignInResult { get; set; }
            public string ReturnUrl { get; set; }
        }
    }

    output seen in Postman:

    {
        "signInResult": {
            "succeeded": true,
            "isLockedOut": false,
            "isNotAllowed": false,
            "requiresTwoFactor": false
        },
        "returnUrl": "/"
    }

    output of resultString:

    {"signInResult":{"succeeded":true,"isLockedOut":false,"isNotAllowed":false,"requiresTwoFactor":false},"returnUrl":"/"}

    output of JsonSerializer.Deserialize:

    result.ReturnUrl: "/"
    result.SignInResult: {Failed}
    result.SignInResult.IsLockedOut: false
    result.SignInResult.IsNotAllowed: false
    result.SignInResult.RequiresTwoFactor: false
    result.SignInResult.Succeeded: false
    Microsoft.AspNetCore.Identity.SignInResult.Failed.IsLockedOut: false
    Microsoft.AspNetCore.Identity.SignInResult.Failed.IsNotAllowed: false
    Microsoft.AspNetCore.Identity.SignInResult.Failed.RequiresTwoFactor: false
    Microsoft.AspNetCore.Identity.SignInResult.Failed.Succeeded: false
    Microsoft.AspNetCore.Identity.SignInResult.Success.IsLockedOut: false
    Microsoft.AspNetCore.Identity.SignInResult.Success.IsNotAllowed: false
    Microsoft.AspNetCore.Identity.SignInResult.Success.RequiresTwoFactor: false
    Microsoft.AspNetCore.Identity.SignInResult.Success.Succeeded: true

    I know that I should be getting a result.SignInResult.Succeeded = true, but it is giving me a false on the Deserialize.  Any thoughts as to why the Deserialize method is giving me the wrong data?

    Saturday, October 31, 2020 11:49 PM

Answers

  • User475983607 posted

    The serializer only populates public properties not protected properties like Succeeded.  See the SignInResult docs. 

    You'll have to create custom data to pass back and forth between Web API and Razor Pages.  You'll also need to move the sign in logic to Razor Pages because the authentication cookie is needed on the Razor Pages side not Web API.  

    Typically,  Web API authentication designs return a token to the caller on a successful login.  The token is used to access secured Web API resources.  Razor Pages  uses cookie authentication to access secure Razor Pages.  In other words your design does not use the framework as intended and why you are having troubles.

    • Marked as answer by Anonymous Thursday, October 7, 2021 12:00 AM
    Sunday, November 1, 2020 1:01 PM