FlexGrid
AntiForgery
Features
Sample
Description
This sample shows how you can use C1AntiForgeryTokenAttribute to prevent forgery of a request.
The sample uses Html.AntiForgeryToken() to generate a token per every request so then no one can forge a form post.
To Test, remove Html.AntiForgeryToken() in AntiForgency.cshtml, then update data on grid, server will return an 500 Internal Server Error.
Source
AntiForgeryController.cs
using C1.Web.Mvc; using MvcExplorer.Models; using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using C1.Web.Mvc.Serialization; namespace MvcExplorer.Controllers { public partial class FlexGridController : Controller { public ActionResult AntiForgery() { ViewBag.Countries = Sale.GetCountries(); ViewBag.Products = Sale.GetProducts(); return View(Source); } [C1AntiForgeryTokenAttribute] public ActionResult GridEditorsUpdateWithAntiForgery([C1JsonRequest]CollectionViewEditRequest<Sale> requestData) { return this.C1Json(CollectionViewHelper.Edit(requestData, sale => { string error = string.Empty; bool success = true; var fSale = Source.Find(item => item.ID == sale.ID); fSale.Country = sale.Country; fSale.Amount = sale.Amount; fSale.Start = sale.Start; fSale.End = sale.End; fSale.Product = sale.Product; fSale.Active = sale.Active; fSale.Amount2 = sale.Amount2; fSale.Color = sale.Color; return new CollectionViewItemResult<Sale> { Error = error, Success = success && ModelState.IsValid, Data = fSale }; }, () => Source)); } [C1AntiForgeryTokenAttribute] public ActionResult GridEditorsCreateWithAntiForgery([C1JsonRequest]CollectionViewEditRequest<Sale> requestData) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { string error = string.Empty; bool success = true; try { Source.Add(item); item.ID = Source.Max(u => u.ID) + 1; } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult<Sale> { Error = error, Success = success, Data = item }; }, () => Source)); } [C1AntiForgeryTokenAttribute] public ActionResult GridEditorsDeleteWithAntiForgery([C1JsonRequest]CollectionViewEditRequest<Sale> requestData) { return this.C1Json(CollectionViewHelper.Edit(requestData, item => { string error = string.Empty; bool success = true; try { var resultItem = Source.Find(u => u.ID == item.ID); Source.Remove(resultItem); } catch (Exception e) { error = e.Message; success = false; } return new CollectionViewItemResult<Sale> { Error = error, Success = success, Data = item }; }, () => Source)); } } }
AntiForgery.cshtml
@model IEnumerable<Sale> @{ List<string> countries = ViewBag.Countries; List<string> products = ViewBag.Products; } @section Scripts{ <script type="text/javascript"> c1.documentReady(function () { var grid = wijmo.Control.getControl('#customGridEditorsGrid'); grid.hostElement.addEventListener('keydown', function (e) { if (e.keyCode == 32) { e.preventDefault(); } }); }); // The following scripts added for customizing the updating for the Product column. // apply the customized updating for the Product column function cellEditEnding(grid, cellRangeEventArgs) { var col = cellRangeEventArgs.col; // when it is the editor of the "Product" column, // apply the updating manually. if (!cellRangeEventArgs.cancel && cellRangeEventArgs.panel.cellType == wijmo.grid.CellType.Cell && grid.columns[col].binding == 'Product') { updateCellValue(grid, cellRangeEventArgs); cellRangeEventArgs.cancel = true; } } function productEditorFocus(event) { var input = event.currentTarget; if (input) { wijmo.setSelectionRange(input, 0, input.value.length); } } function productEditorBlur(event) { var input = event.currentTarget; setTimeout(function () { if (wijmo.contains(document.activeElement, input) // ensure the input element is not removed from the page. || !document.body.contains(input)) { return; } var wrapper = input.parentNode, cellRange = getActiveEditorCellRange(input), grid = wijmo.Control.getControl('#customGridEditorsGrid'); updateCellValue(grid, cellRange); wrapper.parentNode.removeChild(wrapper); }); } // the id of the element would be [grid's id] + "_Cell_r" + row + "_c" + col + "_" function getActiveEditorCellRange(ele) { var id = ele.id, strId, row, col, index; if (id) { strId = id.substr('customGridEditorsGrid_Cell_r'.length); index = strId.indexOf('_c'); row = parseInt(strId.substring(0, index)); col = parseInt(strId.substr(index + 2)); return { row: row, col: col }; } } // update the Product cell's value with its editor. function updateCellValue(grid, cellRangeEventArgs) { var row, col, sel = grid.selection, cv = grid.collectionView; row = cellRangeEventArgs.row; col = cellRangeEventArgs.col; var input = getEditorControl(row, col); if (input == null) return; cv.editItem(cv.items[row]); grid.setCellData(row, col, input.value); cv.commitEdit(); cv.commitNew(); grid.select(sel); } function getEditorControl(row, col) { var elementId = 'customGridEditorsGrid_Cell_r' + row + '_c' + col; return document.getElementById(elementId); } function removeAnti() { $("input[name='__RequestVerificationToken']").remove(); } function restoreAnti() { location.reload(); } </script> } <script id="edtDate" type="text/template"> @(Html.C1().InputDate() .Id("dateEditor") .Format("d") .IsRequired(false) // add this for new row .CssStyle("width", "100%") // full with the cell .TemplateBind("Value", "Start") .ToTemplate() ) </script> <script id="edtTime" type="text/template"> @(Html.C1().InputTime() .Id("timeEditor") .Step(30) .Format("t") .IsRequired(false) // add this for new row .CssStyle("width", "100%") // full with the cell .TemplateBind("Value", "End").ToTemplate() ) </script> <script id="edtAmount" type="text/template"> @(Html.C1().InputNumber() .Id("amountEditor") .Format("c2") .IsRequired(false) // add this for new row .CssStyle("width", "100%") // full with the cell .Step(10) .TemplateBind("Value", "Amount").ToTemplate() ) </script> <script id="edtCountry" type="text/template"> @(Html.C1().ComboBox() .Id("countryEditor") .IsEditable(false) .Bind(countries) .CssStyle("width", "100%") // full with the cell .TemplateBind("Text", "Country").ToTemplate() ) </script> <script id="edtProduct" type="text/template"> <input type="text" id="{{uid}}" onfocus="productEditorFocus(event)" onblur="productEditorBlur(event)" style="width:100%;height:100%" value="{{Product}}" /> </script> <script id="edtColor" type="text/template"> @(Html.C1().InputColor() .Id("colorEditor") .CssStyle("width", "100%") // full with the cell .TemplateBind("Text", "Color").ToTemplate() ) </script> @Html.AntiForgeryToken() <!-- FlexGrid hosting the custom editors --> @(Html.C1().FlexGrid<Sale>() .Id("customGridEditorsGrid") .KeyActionTab(C1.Web.Mvc.Grid.KeyAction.Cycle) .AllowAddNew(true) .AllowDelete(true) .AutoGenerateColumns(false) .Columns(bl => { bl.Add(cb => cb.Binding("ID").Width("0.4*").IsReadOnly(true)); bl.Add(cb => cb.Binding("Start").Header("Date").Width("*").Format("d").CellTemplate(ctb => ctb.EditTemplateId("edtDate"))); bl.Add(cb => cb.Binding("End").Header("Time").Width("*").Format("t").CellTemplate(ctb => ctb.EditTemplateId("edtTime"))); bl.Add(cb => cb.Binding("Country").Width("1.5*").CellTemplate(ctb => ctb.EditTemplateId("edtCountry"))); bl.Add(cb => cb.Binding("Product").Width("1.5*").CellTemplate(ctb => ctb.EditTemplateId("edtProduct"))); bl.Add(cb => cb.Binding("Amount").Format("n2").Width("1.5*").CellTemplate(ctb => ctb.EditTemplateId("edtAmount"))); bl.Add(cb => cb.Binding("Amount2").Format("n2").Width("1.5*")); bl.Add(cb => cb.Binding("Color").Width("1.5*").CellTemplate(ctb => ctb.EditTemplateId("edtColor"))); bl.Add(cb => cb.Binding("Active").Width("1.5*")); }) .Bind(bl => bl.Update(Url.Action("GridEditorsUpdateWithAntiForgery")) .Create(Url.Action("GridEditorsCreateWithAntiForgery")) .Delete(Url.Action("GridEditorsDeleteWithAntiForgery")) .Bind(Model)) .CssStyle("height", "500px") .OnClientCellEditEnding("cellEditEnding") ) <div id="buttonsDiv"> <button class="btn" id="removeAnti" onclick="removeAnti();">@Html.Raw(Resources.FlexGrid.AntiForgency_Text3)</button> <button class="btn" id="restoreAnti" onclick="restoreAnti();">@Html.Raw(Resources.FlexGrid.AntiForgency_Text4)</button> </div> @section Description{ <p>@Html.Raw(Resources.FlexGrid.AntiForgency_Text0)</p> <p>@Html.Raw(Resources.FlexGrid.AntiForgency_Text1)</p> <p>@Html.Raw(Resources.FlexGrid.AntiForgency_Text2)</p> }
Documentation