0

I'm working on an asp.net core application. There is a settings page that is initially empty. The user can then update the settings by selecting a json file. These settings are then confirmed and sent to the controller. The controller should return the same page but displaying the updated settings.

The file is being read and sent to the controller, it is then correctly being deserialized into a settings object and stored in the session.

I have tried using a GET for updating the settings but the query string is too long.

This is the form the user submits, it's part of a dialog that is shared between multiple different functions so is very generic.

<form method="post">
    <button type="submit" class="btn btn-primary" id="modalSubmitButton">Okay</button>
</form>

After the user chooses a file the content of it is retrieved and an event handler is set for the above button.

function OpenFile(event) {
    const input = event.target
    if ('files' in input && input.files.length > 0) {
        var file = (event.target.files)[0];
        var fileReader = new FileReader();
        fileReader.onload = (function (file) {
            return function (e) {
                var contents = e.target.result;

                document.getElementById("modalHeading").innerHTML = "Please confirm overwrite";
                document.getElementById("modalSubmitButton").addEventListener("click", function (e) {
                    LoadSettings(contents);
                });

                $("#dialog").modal('show');
            };
        })(file);
        fileReader.readAsText(file);
    }
}  

Adding this to the click event makes the controller only called once (but with null for the model)

e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();

return false;

The ajax call to call the controller when the button is clicked.

function LoadSettings(settings) {
    data = JSON.stringify(settings);

    $.ajax({
        type: "POST",
        data: data,
        url: "https://localhost:44365/Site/LoadSettings",
        contentType: "application/json; charset=utf-8"
    })
}

This is the function that is called, there are two different settings pages depending on the json.

[HttpPost]
public void LoadSettings([FromBody]SiteSettings config)
{
    HttpContext.Session.SetObject("config", config);

    if (config.Config.Count < 2)
    {
        return Settings();
    }

    return MultiSettings();
}

Which calls this (the controller function responsible for this page).

[HttpGet]
public IActionResult Settings()
{
    var config = HttpContext.Session.GetObject<SiteSettings>("config");
    Model = new SettingsViewModel();

    if (config != null)
    {
        Model.Config = config;
    }
    return View(Model);
}

That constructor takes the settings json and deserializes it.

public SiteSettings Config { get; set; }

public SettingsViewModel(string settingsConfig)
{
    try
    {
        Config = JsonConvert.DeserializeObject<SiteSettings>(settingsConfig);
    }
    catch (Exception ex)
    {
        Config = new SiteSettings();
    }            
}

I am getting a 415 error when calling this using Ajax. I am able to make a POST and send the settings via Postman and receive the page with the updated settings. Looking at it in Fiddler the function is called twice, the first with the json and the second without.

In Fiddler the first request has the 'Session was aborted by the client, Fiddler or the server' icon.

Zoosmell
  • 149
  • 1
  • 1
  • 13
  • Are you sure that you don't have an Exception in the `SettingsViewModel` constructor ? Additionally if you need to redirect to another controller action you should use `RedirectToAction` or equivalent methods and avoid calling an action method – Gwinn Oct 31 '19 at 12:29
  • There is an exception in the SettingsViewModel constructor, it's getting called twice, the first with the config string and the second with null. RedirectToAction doesn't seem to work with Ajax but I'll look at an alternative. – Zoosmell Oct 31 '19 at 14:31
  • Possible duplicate of [How to prevent buttons from submitting forms](https://stackoverflow.com/questions/932653/how-to-prevent-buttons-from-submitting-forms) – Justin Lessard Oct 31 '19 at 16:48
  • Why when you call `OpenFile(event)` do you continually add event handlers? I notice your `LoadSettings(settings)` call to ajax returns nowhere, perhaps add a `.fail(function(){});` as described https://api.jquery.com/jquery.ajax/ – Mark Schultheiss Oct 31 '19 at 17:18
  • You do not show where `OpenFile(event)` is called or that HTML, and frankly I find your code a bit confusing and less than optimal leaving us guessing quite a bit here. – Mark Schultheiss Oct 31 '19 at 17:27
  • If you state: "The controller should return the same page but displaying the updated settings." then why are you even using ajax? Why not just post the form and return that new page with the model for the view? – Mark Schultheiss Oct 31 '19 at 17:32
  • I'm voting to close this question as off-topic because there are simply too many gaps in the illustrated code to provide an effective answer. I strongly suspect that the ajax call runs but never returns and the for post happens but without any action? Your problem statement simply feels like you threw stuff out there without clearly understanding the problem area and where it lies. – Mark Schultheiss Oct 31 '19 at 17:34

0 Answers0