1

I am having a bug in one of the visual web parts. First of all, this is not my code and I am not an expert in javascript.

Secondly, this issue is only happening the first time after the pool has been recycled or the web application has been restarted, the rest of the times is working fine.

Explanation: the web part has a repeating section created using javascript, when the form is submitted, there are 2 events:

OnClick="btnAdvanceSubmit_Click" OnClientClick="SaveItems()"

SaveItems() is saving the repeating sections using clientContext.executeQueryAsync(onQuerySucceeded, onQueryFailed);

btnAdvanceSubmit_Click is starting a workflow and closing the form. if I include Thread.Sleep(3500) here the process finish properly and everything is saved fine. if I don't, the repeating section is not saved. This issue happens ONLY after an iisreset or similar operation.

Please, find my code below: javascript

  function SaveItems()
 { 
   var table = document.getElementById('tableAdvanceItems');
    var rowLength = table.rows.length;
    var formID = <%=expenseFormID%>;

    for (var i = 1; i < rowLength; i++) {

        var row = table.rows[i];
        var cellLength = row.cells.length;
        var id = row.cells[0].children[0].value;
        var exchangeRateSelect = row.cells[5].children[0];
        var advanceType = $(row.cells[1]).find("input[type='radio']:checked").val();
        var advanceBank = $(row.cells[2]).find("input[type='radio']:checked").val();
        var advanceAccount = row.cells[3].children[0].value;
        var amount = row.cells[4].children[0].value;
        var exchangeRate = exchangeRateSelect.options[exchangeRateSelect.selectedIndex].value;
        var currency = exchangeRateSelect.options[exchangeRateSelect.selectedIndex].text;
        var amountLC = row.cells[6].children[0].value;
        if (id) { 

            UpdateAdvanceItem(id, advanceType, advanceBank, advanceAccount, amount, exchangeRate, amountLC, formID, currency); }
        else { 

            InsertNewAdvanceItem(advanceType, advanceBank, advanceAccount, amount, exchangeRate, amountLC, formID, currency); }

    }

}





    function InsertNewAdvanceItem(advanceType, advanceBank, advanceAccount, amount, exchangeRate, amountLC, formID, currency) {
    var siteUrl = window.location.protocol + "//" + window.location.host + _spPageContextInfo.siteServerRelativeUrl;
    var clientContext = new SP.ClientContext(siteUrl);
    var list = clientContext.get_web()
        .get_lists()
        .getByTitle('Advance Items');
    this.listItem = list.addItem(itemCreateInfo);

    listItem.set_item('AGLAdvanceType', advanceType);
    listItem.set_item('AGLAdvanceTransferBank', advanceBank);
    if (advanceAccount) {listItem.set_item('AGLAdvanceTransferBankAccount', advanceAccount); }
    if (amount) {listItem.set_item('AGLAdvanceItemAmount', amount); }
    listItem.set_item('AGLExpenseItemExchangeRate', exchangeRate); 
    listItem.set_item('AGLAdvanceCurrency', currency);
    if (amountLC) {listItem.set_item('AGLAdvanceItemAmountLocalCur', amountLC); }

    listItem.set_item('AGLExpenseFormID', formID);

    var itemCreateInfo = new SP.ListItemCreationInformation();
    listItem.update();
    clientContext.load(listItem);
   clientContext.executeQueryAsync(onQuerySucceeded, onQueryFailed);

}

C#

          protected void btnSave_Click(object sender, EventArgs e){using (SPLongOperation longOperation =  new SPLongOperation(this.Page))  {   longOperation.LeadingHTML =  "Saving Data";
            longOperation.TrailingHTML = "Please wait while the data is being saved.";

                           //    Thread.Sleep(3500);
            longOperation.Begin();
            item = item ?? expensesList.AddItem();

            SaveData();
            longOperation.EndScript("window.frameElement.commitPopup();");
            StartWorkflow("Advance-Expense Form Reminder Workflow");
        }
        string close = @"<script type='text/javascript'>
                            window.returnValue = true;
                            window.close();
                            </script>";
        base.Response.Write(close);
    }                                          



function onQueryFailed(sender, args) {

    alert('Request failed. ' + args.get_message() + '\n' + args.get_stackTrace());
}


function onQuerySucceeded() {}

Is there any way to avoid this issue? if I include the commented line "Thread.sleep" will work, but I don't want the user to wait 3.5 seconds to submit a form.

I have tried do a SharePoint warm up using PowerShell, but still the same issue.

Thanks for your help.

Bets regards,

Eriel

3
  • 1
    I know you're not a JavaScript coder, but you really need to provide a lot more complete code to have any chance of getting help. clientContext.executeQueryAsync is committing all the stuff that was done to clientContext before that, but you didn't show any of that. And what do onQuerySucceeded and onQueryFailed do? In general, something is probably timing out because of the cold start (i.e. IIS reset), but that's about all I know at the moment.
    – Joe McShea
    Commented Apr 10, 2019 at 20:41
  • Add the code by editing your question, the format of comments makes any substantial code unusable.
    – Joe McShea
    Commented Apr 10, 2019 at 20:45
  • I have tried to do a warm up after the iisreset to see if the issue gets solved, but no luck yet.
    – Eriel
    Commented Apr 11, 2019 at 14:36

1 Answer 1

1

The problem you are having is because you are closing the window before the async operation has finished.

Closing the window in btnSave_Click while an async operation is potentially in progress is very dangerous in general, and that danger is being exposed by the cold start, but you could have intermittent problems with that code even without the cold start, and it would be a difficult bug to track down. i.e. it could fail say once every 10 or 20 or 50 times with no explanation, depending on the load on your server or sql server at the time, or a number of other factors.

You should move the window closing code:

string close = @"<script type='text/javascript'>
                    window.returnValue = true;
                    window.close();
                    </script>";
base.Response.Write(close);

into your onQuerySucceeded method. Something like:

function onQuerySucceeded() {
    string close = @"<script type='text/javascript'>
                    window.returnValue = true;
                    window.close();
                    </script>";
    base.Response.Write(close);
}

I say something like, because I don't know what base is, since the only place it is referenced is btnSave_Click, so I don't know if it's defined in onQuerySucceeded. If not, then you'll need to figure out how to make Response available to onQuerySucceeded, or close the window a different way.

By closing the window, you're aborting that async operation.

BTW, this is why the Tread.sleep for 3.5 seconds works, but that could fail intermittently too, you're just guessing at how long it will take and sometimes it may take longer. By moving the window close into the query succeeded callback, you're effectively sleeping for precisely as long as you need to and no more.

1
  • Thanks, I fixed the issue following you instructions. the save button was refreshing the page though (and the refresh was happening again before the operation was completed), so I had to disable the "submit" behavior from the button and include the "save" code in the client. Everything is working fine now. Thank you very much for your help!
    – Eriel
    Commented May 1, 2019 at 20:32

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.