0

I have an ASP.NET Core MVC project and I am trying to send a model and some other parameter from JavaScript to a controller action. First I fill the model from view fields whose names match the model properties.

var model = {};  //global variable
function updateModel()
{
    for(const element of document.querySelectorAll("input.account-property-input"))
    {
        if(element instanceof HTMLInputElement && typeof element.name === "string" && element.name.trim().length > 0)
        {
            model[element.name] = element.value;
        }
    }
    let checkbox = document.querySelector("input#enable-two-factor-checkbox");
    if(checkbox instanceof HTMLInputElement)
    {
        model[checkbox.name] = checkbox.checked;
    }
    if(checkbox.checked)
    {
        radio = document.querySelector("input#two-factor-by-phone-radio");
        model.TwoFactorMethod = radio.checked ? "TwoFactorByPhoneNumber" : "TwoFactorByEmail";
    }
}

Data sending:

model = updateModel();
const urlAction = window.location.origin + "/UserAccount/ConfirmContact";
const jqXHR = $.ajax({
    method: "POST",
    url: urlAction,
    data: { model: model, contactType: contactType },
    contentType: "application/json; charset=utf-8"
});
await jqXHR?.then(
    async function(data, textStatus, jqxhr)
    {
        alert(`request to ${urlAction} is successed`);
    },
    function(jqxhr, textStatus, errorThrown)
    {
        alert(`request to ${urlAction} is failed; status: ${textStatus}; error: ${errorThrown}`);
    });

My model:

public enum ContactType : int
{
    EMail = 0,
    PhoneNumber
}
public class AccountViewModel : ModelBase
{
    public string? UserId { get; set; }
    public string? UserName { get; set; }
    public string Password { get; set; }
    public string PasswordConfirmation { get; set; }
    public bool TwoFactorEnabled { get; set; }
    public TwoFactorMethod TwoFactorMethod { get; set; }
    public string? Email { get; set; }
    public string? PhoneNumber { get; set; }
    public ContactConfirmationState EmailConfirmationState { get; set; }
    public ContactConfirmationState PhoneConfirmationState { get; set; }
    public string Name { get; set; }
    public string? EsiaLogin { get; set; }
    public string? EsiaPassword { get; set; }
    public string EsiaPasswordConfirmation { get; set; }
    public AccountViewModel()
    {
    }
}

On the controller side:

[HttpPost]
public async Task<IActionResult> ConfirmContact(AccountViewModel model, ContactType contactType)
{
    if(model != null)
    {
        if(contactType == ContactType.PhoneNumber)
        {
            if(await PhoneConfirmationService.SendVerificationCode(model))
            {
                model.PhoneConfirmationState = ContactConfirmationState.AwaitingConfirmation;
            }
        }
        else
        {
            if(await EmailConfirmationService.SendVerificationCode(HttpContext, model))
            {
                model.EmailConfirmationState = ContactConfirmationState.AwaitingConfirmation;
            }
        }
    }
    return View("Register", model ?? new AccountViewModel());
}

But the action parameters are not initialized from the request, but with a default value.
How to send the data correctly?
My project repo

12
  • Where do you define your model JS variable? Commented Jul 10 at 20:00
  • Can you show the structure of the data being sent? Commented Jul 10 at 20:00
  • 1
    var model = updateModel();: updateModel() doesn't return anything, so of course model is null. Commented Jul 10 at 20:44
  • 1
    @StanislavPanferov: "Function updeteModel() set global variable model." - Perhaps, but that doesn't matter because model = updateModel() overwrites whatever was in that variable. Because updateModel() doesn't return anything. When you observe the AJAX request in your browser's debugging tools, what data is sent in that request? When you observe the model variable in your debugger at the $.ajax({ operation, what does that variable contain? Don't assume. Debug and observe. Commented Jul 11 at 11:18
  • 1
    @StanislavPanferov: Please see Something in my web site or project doesn't work. Can I just paste a link to it? Relevant code needs to be included in the question to produce a minimal reproducible example which demonstrates the problem, as well as information about the problem itself and what debugging you have done. To learn more about this community and how we can help you, please start with the tour and read How to Ask and its linked resources. Commented Jul 11 at 11:48

1 Answer 1

0

It looks like your approach isn’t correct. Since your view already has HTML elements with the same names as the model properties, Razor Pages’ model binder will automatically map those values to the view model. Because of this, you don’t need to use updateModel. I recommend removing your custom $.ajax call and instead using jquery-ajax-unobtrusive, which will make your code cleaner, more maintainable, and aligned with the Razor Pages binding conventions.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.