I am having a silly problem trying to deserialize asp.net core model state errors to an object. My code is like this
For backend register method
[HttpPost("register-user")]
[ValidateModel]
public async Task<IActionResult> Index(RegisterDto registerDto)
{
try
{
Data.Models.User user = mapper.Map<RegisterDto, Data.Models.User>(registerDto);
user.LockoutEnd = DateTimeOffset.Now;
user.Warehouse = configuration["Config:Warehouse"];
user.SiteId = Convert.ToInt32(configuration["Config:SiteId"]);
IdentityResult result = await userManager.CreateAsync(user, registerDto.Password);
if (result.Succeeded)
{
AddLogInformation(logger, "User created a new account with password.");
string token = await userManager.GenerateEmailConfirmationTokenAsync(user);
token = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(token));
string confirmationUrl = Url.Action("Index", "EmailConfirmation",
new {userId = user.Id, code = token}, Request.Scheme);
emailSender.SendEmailAsync(registerDto.Email, "Confirm your email",
GetEmailConfirmationTemplate(registerDto.FirstName, registerDto.LastName,
confirmationUrl));
ApplicationRole retailPersonRole =
await roleManager.FindByNameAsync(RoleHelper.GetRetailUserRoleName());
if (retailPersonRole != null) await userManager.AddToRoleAsync(user, retailPersonRole.Name);
if (userManager.Options.SignIn.RequireConfirmedAccount)
{
AddLogInformation(logger, "Sent email confirmation email to user");
return Ok(SuccessResult(null));
}
//If confirm account is set to false
await signInManager.SignInAsync(user, false);
return Ok(SuccessResult(null));
}
// If we got this far, something failed, redisplay form
return Ok(FailedMessage(logger, "Cannot register user at this time. Please try again later."));
}
catch (Exception e)
{
return ServerErrorJsonResult(logger, "Error while trying to register user. Error message is: " + e.Message);
}
}
And I am catching the model state error in action filter and returning a response as below.
public class ValidateModelAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
var modelState = context.ModelState;
if (!modelState.IsValid)
context.Result = new BadRequestObjectResult(new JsonResult(new {modelError = true, Errors = modelState}));
}
}
Now in the front-end (xamarin), I have a model to where the error should be deserialised so that I can display a proper error to user.
My register model in the front end is like this
public class RegisterDto: BaseDto
{
public string FirstName { get; set; }
public string MiddleName { get; set; }
public string LastName { get; set; }
public string PhoneNumber { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public AddressDto BillingAddress { get; set; }
public RegisterDto Errors { get; set; }
}
My Address Dto is like this
public class AddressDto
{
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string PostCode { get; set; }
public string State { get; set; }
}
I am creating the post request in xamarin like this.
public async Task<TResult> PostAsync<TResult>(string uri, TResult data, string token = "", string header = "")
{
try
{
HttpClient httpClient = CreateHttpClient(token);
if (!string.IsNullOrEmpty(header))
{
AddHeaderParameter(httpClient, header);
}
var content = new StringContent(JsonConvert.SerializeObject(data));
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
HttpResponseMessage response = await httpClient.PostAsync(uri, content);
await HandleResponse(response);
string serialized = await response.Content.ReadAsStringAsync();
TResult result = await Task.Run(() =>
JsonConvert.DeserializeObject<TResult>(serialized, serializerSettings));
return result;
}
catch (Exception e)
{
return default;
}
}
And finally, in the view model, I am doing this
--
userToBeRegistered is an instance of RegisterDto
await something.PostAsync(UrlHelper.RegisterUrl, userToBeRegistered);
The serialized string output is like this
{
"errors":{
"Email":[
"Email is required"
],
"LastName":[
"Last name is required"
],
"Password":[
"Password is required"
],
"FirstName":[
"First name is required"
],
"PhoneNumber":[
"Phone number is required"
],
"BillingAddress.City":[
"Suburb is required"
],
"BillingAddress.State":[
"State is required"
],
"BillingAddress.Address1":[
"Street address is required"
],
"BillingAddress.PostCode":[
"Postcode is required"
]
},
"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title":"One or more validation errors occurred.",
"status":400,
"traceId":"|3c2d7d70-49a6eceecbeedab8."
}
My question is how can I deserialise it to an errors object. If I keep running the above code, then I get this error.
"Unexpected character encountered while parsing value: [. Path 'errors.Email', line 1, position 20."
Can anyone help me with this?
Try the below method.
Create ErrorInfor class:
class ErrorInfor
{
public MyError errors { get; set; }
public string type { get; set; }
public string title { get; set; }
public int status { get; set; }
public string traceId { get; set; }
public class MyError
{
public List<string> FirstName { get; set; }
public List<string> LastName { get; set; }
public List<string> PhoneNumber { get; set; }
public List<string> Email { get; set; }
public List<string> Password { get; set; }
[JsonProperty("BillingAddress.City")]
public List<string> Citiy { get; set; }
[JsonProperty("BillingAddress.State")]
public List<string> State { get; set; }
[JsonProperty("BillingAddress.Address1")]
public List<string> Address1 { get; set; }
[JsonProperty("BillingAddress.PostCode")]
public List<string> PostCode { get; set; }
}
}
then you could get the data from your above json string.
ErrorInfor errorInfor = JsonConvert.DeserializeObject<ErrorInfo>(json);