简体   繁体   中英

C# MVC controller called twice

I am making a C# Razor MVC web app that is geared for Ipad. I am using JQuery mobile and Kendo UI. I have 2 input forms that use the Kendo grid that sit in a JQuery popup window.

My problem is that the Waste_Read controller is double firing and makes 2 kendo grids. This is unnoticeable in desktop apps but on the ipad 2 grids are visible.

Below is my _Layout.cshtml and Ham.cshtml (which is my view) code.

Thanks!

_Layout.cshtml

<!DOCTYPE html>
<html lang="en">
<head>
@{

if (Session["currentDate"] == null)
{
HttpContext.Current.Session["currentDate"] = DateTime.Today.ToString("yyyy-MM-dd");
}

if (Session["currentShift"] == null)
{
HttpContext.Current.Session["currentShift"] = 1;
}

if (Session["ReportType"] == null)
{
HttpContext.Current.Session["ReportType"] = "Daily";
}

}

<title>@ViewBag.Title</title>
<meta name="viewport" content="initial-scale = 1.0, maximum-scale = 1.0, user-scalable = no, width=device-width" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<link href="~/Resources/Triangle.ico" rel="shortcut icon" type="image/x-icon" />

@Styles.Render("~/Content/mobileCss", "~/Content/css")
@Scripts.Render("~/bundles/modernizr")
@Scripts.Render("~/bundles/jquery", "~/bundles/jquerymobile")

<link href="@Url.Content("~/Content/kendo/2013.1.319/kendo.common.min.css")" rel="stylesheet" type="text/css" />
<link href="@Url.Content("~/Content/kendo/2013.1.319/kendo.dataviz.min.css")" rel="stylesheet" type="text/css" />
<link href="@Url.Content("~/Content/kendo/2013.1.319/kendo.silver.min.css")" rel="stylesheet" type="text/css" />
<link href="@Url.Content("~/Content/kendo/2013.1.319/kendo.dataviz.silver.min.css")" rel="stylesheet" type="text/css" />

@*<script src="@Url.Content("~/Scripts/kendo/2013.1.319/jquery.min.js")"></script>*@
<script src="@Url.Content("~/Scripts/kendo/2013.1.319/kendo.all.min.js")"></script>
<script src="@Url.Content("~/Scripts/kendo/2013.1.319/kendo.aspnetmvc.min.js")"></script>
@*<script src="@Url.Content("~/Scripts/kendo.modernizr.custom.js")"></script>*@
<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>

<script type="text/javascript">


//prevents ipad vertical bounce scrolling
document.ontouchmove = function (event) {
event.preventDefault();
}

function UpdateDate() {
UpdateSessionDate();
UpdateSessionShift();
UpdateSessionReportType();

//$('#datepick').val('AT(Session["currentDate"])');

var DatePageType = '@(ViewBag.DatePageType)';

if (DatePageType == "Reporting") {

UpdateCharts();
}
if (DatePageType == "LiveView") {
UpdateViews($('#hoursaver').val());
UpdateLineViews($('#hoursaver').val());
UpdateOverallInfoBox($('#linesaver').val());
UpdateOverviewOfLabourChart()
}
if (DatePageType == "LabourEntry") {
// UpdateViews($('#hoursaver').val());
refreshLabourEntry();
}

}

function UpdateShift() {
UpdateSessionDate();
UpdateSessionShift();

//$('#datepick').val('AT(Session["currentDate"])');

var DatePageType = '@(ViewBag.DatePageType)';

if (DatePageType == "Reporting") {
UpdateCharts();
}
if (DatePageType == "LiveView") {
UpdateViews($('#hoursaver').val());
UpdateLineViews($('#hoursaver').val());
UpdateOverallInfoBox($('#linesaver').val());
}
if (DatePageType == "LabourEntry") {
refreshLabourEntry();

}
}

function pullfrompeviousLoad(objThis) {
var url = $(objThis).data('url') + '?hour=' + $(objThis).data('hour') + '&Shift=' + $(objThis).data('shift') + '&LineName=' + $(objThis).data('line');
window.location.href = url;
}

function menuLoad(objThis) {
var url = $(objThis).data('url');
window.location.href = url;
}

function buttonLoad(objThis) {
var url = $(objThis).data('url') + '?hour=' + $(objThis).data('time');
window.location.href = url;
}

function saveLoad(objThis) {

$('#labourform').submit();
var url = $(objThis).data('url') + '?hour=' + $(objThis).data('time');
window.location.href = url;
return false;
}

// update date session data
function UpdateSessionDate() {

$.post('/SetSession/SetVariable',
{
key: "currentDate",
value: kendo.toString($("#datepicker").data("kendoDatePicker").value(), "yyyy-MM-dd")
});

};

// update shift session data
function UpdateSessionShift() {

$.post('/SetSession/SetVariable',
{
key: "currentShift",
value: $('#shift').val()
});

};


// update report type session data
function UpdateSessionReportType() {

$.post('/SetSession/SetVariable',
{
key: "ReportType",
value: $('#ReportType').val()
});

};

function UpdateButtons(h) {
var arrayToModify = [];
var i = 0, j, k, buttonsToCreate, buttonContainer, newButton;
var buttonsToCreate = [];
var now = parseInt(h);

for (var j = (now - 7) ; j <= (now + 7) ; j++) {

if (j >= 0 && j <= 23) {
buttonsToCreate[i] = j;
i++;
}
}

buttonContainer = document.getElementById('ddShift');

for (k = 0; k < buttonsToCreate.length; k++) {

if (buttonsToCreate[k] == parseInt(h) + 1) {
newButton.style.cssText = 'background-color: red;';
}

newButton = document.createElement('input');
newButton.type = 'button';
newButton.value = buttonsToCreate[k];
newButton.id = buttonsToCreate[k];
newButton.onclick = function () {
arrayToModify[arrayToModify.length] = this.id;
$('#hoursaver').val(this.id);
UpdateViews(this.id);
UpdateLineViews(this.id);
};

buttonContainer.appendChild(newButton);
}
};

kendo.culture("en-US");

</script>

</head>

<body>

<div data-role="page" data-theme="b" id="index">

<div data-role="header" data-position="fixed">
<h1>@ViewBag.Title</h1>
<a href="#nav-panel" data-icon="bars" data-iconpos="notext" class="ui-btn-left">Menu</a>

@if (Request.IsAuthenticated)
{
@Html.ActionLink("My Account", "Index", "Account", routeValues: null, htmlAttributes: new { data_icon = "gear" })
}
else
{
@Html.ActionLink("Log in", "Login", "Account", routeValues: null, htmlAttributes: new { data_icon = "gear" })
}


<div class="datepickerbtn" style="width: 212.5px;">

@(Html.Kendo().DatePicker()
.Name("datepicker")
.Events(e =>
{
e.Change("UpdateDate");
})
.Format("yyyy-MM-dd")
.Value((String)Session["currentDate"])
)
</div>

<div class="shiftpickerbtn" id="btnshift">
<select id="shift" name="shift" onchange="UpdateShift()">
<option value="1">Shift 1</option>
<option value="2">Shift 2</option>
</select>
</div>


</div>
<div data-role="content">

@RenderBody()
</div>
<div data-role="footer" style="text-align: center" data-position="fixed">
@RenderSection("footer", false)
</div>
<div data-role="panel" data-position-fixed="true" data-theme="b" data-content-theme="d" id="nav-panel">
<ul data-role="listview" data-theme="a" class="nav-search">
<li data-icon="delete"><a href="#" data-rel="close">Close menu</a></li>
<li><a data-url="@Url.Action("Index", "Home")" onclick="menuLoad(this)">Home</a></li>
<li><a data-url="@Url.Action("Index", "LabourEntry")" onclick="menuLoad(this)">Labour Entry</a></li>
<li><a data-url="@Url.Action("Index", "LiveView")" onclick="menuLoad(this)">Live View</a></li>
<li><a data-url="@Url.Action("Index", "Report")" onclick="menuLoad(this)">Reporting</a></li>
<li><a data-url="@Url.Action("Loin", "ScheduleBuilder")" onclick="menuLoad(this)">Schedule Builder</a></li>
<li><a data-url="@Url.Action("About", "Home")" onclick="menuLoad(this)">About</a></li>
<li><a data-url="@Url.Action("Contact", "Home")" onclick="menuLoad(this)">Contact</a></li>
</ul>

</div>

</div>

@RenderSection("scripts", required: false)
</body>
</html>

Ham.cshtml

@model IEnumerable<OPS.Models.LabourSchedule>

@{
ViewBag.Title = "Ham";
Layout = "~/Views/Shared/_Layout.cshtml";
ViewBag.DatePageType = "LabourEntry";
}

<script>

$(document).ready(function () {

//set the value of the datepicker and Shift via session variables
$('#datepicker').val('@(Session["currentDate"])');
$('#shift').val('@(Session["currentShift"])');
$('#shift').selectmenu('refresh');

$('#lblWasteFormDate').html('@(Session["currentDate"])');

});

function Update_Data() {
return {
CurDate: kendo.toString($("#datepicker").data("kendoDatePicker").value(), "yyyy-MM-dd")
};
}

function Read_Data() {
return {
LineName: "Ham",
CurDate: kendo.toString($("#datepicker").data("kendoDatePicker").value(), "yyyy-MM-dd"),
ShiftName: @(Session["currentShift"]) + ""
};
}

function Read_DT_Data() {
return {
LineName: "Ham",
CurDate: kendo.toString($("#datepicker").data("kendoDatePicker").value(), "yyyy-MM-dd"),
ShiftName: $("#shift").val() + ""
};
}

</script>


@section footer
{
<div data-inline="true">

<div data-inline="true">
@if (ViewBag.curHour > 0)
{                                    
<a data-role="button" href="#" data-url="@Url.Action("Ham", "LabourEntry")" onclick="buttonLoad(this)"  data-icon="arrow-l" data-iconpos="notext" data-theme="c" data-inline="true" data-time="@ViewBag.prevHour"></a>                  
}
@for (var i = ViewBag.curHour - 7; i <= ViewBag.curHour + 7; i++)
{

if (ViewBag.curHour == i)
{                            
<a data-role="button" href="#" data-theme="b" data-inline="true">@i</a>                                
}
else if (@i >= 0 && @i <= 23)
{                             
<a data-role="button" href="#" data-url="@Url.Action("Ham", "LabourEntry")" onclick="buttonLoad(this)" data-theme="c" data-inline="true" data-time="@i">@i</a>                                          

}

}
@if (ViewBag.curHour < 23)
{                                                          
<a data-role="button" href="#" data-url="@Url.Action("Ham", "LabourEntry")" onclick="buttonLoad(this)"  data-icon="arrow-r" data-iconpos="notext" data-theme="c" data-inline="true" data-time="@ViewBag.nextHour">Arrow right</a>                    
}
<a href="#popupMenu" data-rel="popup" data-role="button" data-inline="true" data-transition="slideup" data-icon="grid" data-iconpos="notext" data-theme="b">Options</a>
</div>

</div>
<div data-role="popup" id="popupDownTime" class="ui-content" data-theme="d" data-overlay-theme="a" data-dismissible="false" style="width: 80%; position: relative; margin: 20px auto;">
<a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-btn-right">Close</a>

<div id="update-message"></div>
@using (Html.BeginForm(null, null, FormMethod.Post, new { id = "DTForm" }))
{

<input type="hidden" name="LineName" value="Ham" />
<table>
<tr>
<td colspan="3">
<label for="categories">Downtime Reason:</label>
@(Html.Kendo().DropDownList()
.Name("DTCatId")
.OptionLabel("Select downtime...")
.HtmlAttributes(new { style = "width:90%;" })
.DataTextField("Name")
.DataValueField("ID")
.DataSource(source =>
{
source.Read(read =>
{
read.Action("GetDowntimeCategories", "LabourEntry");
});
})
)
</td>
</tr>
<tr>
<td>
<label for="txt_DT_Duration">Duration (minutes):</label>
<input type="number" name="DT_Duration" pattern="[0-9]*" id="txt_DT_Duration" value="" />
</td>
<td>
<label for="txt_DT_People"># of People:</label>
<input type="number" name="DT_People" pattern="[0-9]*" id="txt_DT_People" value="" />
</td>
<td>
<label for="sl_Hrs_Type">Hours Type:</label>
<select name="Hrs_Type" id="sl_Hrs_Type" data-role="slider">
<option value="OT">OT</option>
<option value="REG" selected="selected">Reg</option>
</select>
</td>

</tr>
<tr>
<td colspan="3">
<label for="txt_DT_Desc">Description Detail:</label>
<textarea rows="12" name="DT_Desc" id="txt_DT_Desc"></textarea>
</td>
</tr>
<tr>
<td colspan="3">
<input type="submit" name="submit" value="Add Downtime" />
</td>

</tr>
<tr>
<td colspan="3">
@(Html.Kendo().Grid<OPS.Models.DownTime>()
.Name("DTGrid")
.Columns(columns =>
{
columns.Bound(p => p.ID).Hidden(true);
columns.Bound(p => p.DT_ID).Hidden(true);
columns.Bound(p => p.HR_TYPE).Hidden(true);
columns.Bound(p => p.LINE_ID).Hidden(true);
columns.Bound(p => p.SHIFT).Hidden(true);
columns.Bound(p => p.USER_ID).Hidden(true);
columns.Bound(p => p.DT_REASON).Title("Reason");
columns.Bound(p => p.DT_DETAIL).Title("Details");
columns.Bound(p => p.DURATION).Title("Duration (mins)");
columns.Bound(p => p.NUM_EFFECTED).Title("# of People");
})
.ToolBar(toolbar =>
{
toolbar.Save();
})
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Sortable()
.Scrollable()
.Resizable(resize => resize.Columns(true))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.ID);
})
.Batch(true)
.ServerOperation(false)
.Events(events => events.Error("error"))              
.Read(read => read.Action("DT_Read", "LabourEntry")
.Data("Read_DT_Data"))
.Update(update => update.Action("DT_Update", "LabourEntry"))
)
)
</td>
</tr>
</table>

}
</div>

<div data-role="popup" id="popupWaste" class="ui-content" data-theme="d" data-overlay-theme="a" data-dismissible="false" style="width: 90%; position: relative; margin: 20px auto;">
<a href="#" data-rel="back" data-role="button" data-theme="a" data-icon="delete" data-iconpos="notext" class="ui-btn-right">Close</a>

<div style="width: 100%;">

<h3>Date: <label id="lblWasteFormDate"></label>
</h3>


@(Html.Kendo().Grid<OPS.Models.LineProductWasteEntry>()
.Name("WasteGrid")
.Columns(columns =>
{

columns.Bound(p => p.Id).Hidden(true);
columns.Bound(p => p.BucketWeight).Hidden(true);
columns.Bound(p => p.LineCategoryId).Hidden(true);
columns.Bound(p => p.LineCategoryProduct).Hidden(true);
columns.Bound(p => p.LineProductId).Hidden(true);
columns.Bound(p => p.ShiftId).Hidden(true);
columns.Bound(p => p.SourceId).Hidden(true);
columns.Bound(p => p.UserId).Hidden(true);
columns.Bound(p => p.CategoryName);
columns.Bound(p => p.ProductName);
columns.Bound(p => p.Value);
columns.Bound(p => p.SourceName);
columns.Bound(p => p.Source);
columns.Bound(p => p.Weight);
columns.Bound(p => p.Weight2);
columns.Bound(p => p.Weight3);
})
.ToolBar(toolbar =>
{
toolbar.Save();
})
.Editable(editable => editable.Mode(GridEditMode.InCell))
.Sortable()
.Scrollable()
.Resizable(resize => resize.Columns(true))
.DataSource(dataSource => dataSource
.Ajax()
.Model(model =>
{
model.Id(p => p.Id);
model.Field(p => p.SourceName).Editable(false);
model.Field(p => p.CategoryName).Editable(false);
model.Field(p => p.ProductName).Editable(false);
model.Field(p => p.Value).Editable(false);
})
.Batch(true)
.ServerOperation(false)
.Events(events => events.Error("error"))        
.Read(read => read.Action("Waste_Read", "LabourEntry")
.Data("Read_Data"))
.Update(update => update.Action("Waste_Update", "LabourEntry")
.Data("Update_Data"))

)

)

</div>
</div>
<div data-role="popup" id="popupMenu" data-theme="a">
<ul data-role="listview" data-inset="true" style="min-width: 270px;" data-theme="a" class="nav-search">
<li><a href="#popupWaste" data-rel="popup" data-position-to="window" data-transition="pop">Add Waste</a></li>
<li><a href="#popupDownTime" data-rel="popup" data-position-to="window" data-transition="pop">Add Downtime</a></li>

</ul>
</div>

}

Only situation where I can think of a form posting twice is when you have a javascript function binded to the click of your submit button which then calls form.submit()

If that is anything like what you are currently doing then try doing e.preventDefault before calling the form.submit()

$('#mySubmitButton').click(function(e) {

         e.preventDefault(); //This prevent the submit button onclick from submitting by itself
         $('#myForm').submit(); //Manually call the form submit
});

$('#myForm').submit(function(e) {
      e.preventDefault(); //Prevent default here as well - this will allow you to do 
                          //your own posts without the defaults running (good for when you want to use ajax)
     // Simple ajax post using whatever action you put in your form 
     if ($(this).valid()) {
           $.ajax({
                url: this.action,
                type: this.method,
                data: $(this).serialize(),
                success: function (result) {
                })
           });
     }
});

This will ensure that your form will execute only once

In a much more complex setting I noticed my controller got hit more than once. When I remedied the following two things it no longer got a double hit:

  • IMG tags with src="#" (placeholders for lazy loading images from
    javascript) remove the hashtag ==> src=""

  • @Url.Content("~/some/static/path/some.css") remove the call to
    Url.Content ==> "/some/static/path/some.css" (of course that path
    needs to exist)

It is actually not very clear why @Url.Content() is hitting the controller again but thorough testing proved it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM