My controller is throwing the error
The required anti-forgery form field "__RequestVerificationToken" is not present.
But This is exactly what I am doing
Logging in with test user
VIEW
#using (Html.BeginForm(new { ReturnUrl = ViewBag.ReturnUrl }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary()
<fieldset>
<legend>Log in Form</legend>
<ol>
<li>
#Html.LabelFor(m => m.UserName)
#Html.TextBoxFor(m => m.UserName)
</li>
<li>
#Html.LabelFor(m => m.Password)
#Html.PasswordFor(m => m.Password)
</li>
<li>
#Html.LabelFor(m => m.RememberMe)
#Html.CheckBoxFor(m => m.RememberMe)
</li>
CONTROLLER
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(LoginModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (Membership.ValidateUser(model.UserName, model.Password))
{
FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
return RedirectToCreateUserProfile(model, returnUrl);
}
else
{
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
once authenticated i am redirected to the home page
then i click on a menu option to show me user profile and i get the above error
LAYOUT VIEW (Showing more code the needed but want to make the JS is causing an issue)
<!DOCTYPE html>
<html>
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/kendo/2013.2.918/kendo.common.min.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/kendo/2013.2.918/kendo.dataviz.min.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/kendo/2013.2.918/kendo.metro.min.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/kendo/2013.2.918/kendo.dataviz.metro.min.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/kendo/2013.2.918/jquery.min.js")"></script>
<script src="#Url.Content("~/Scripts/kendo/2013.2.918/kendo.all.min.js")"></script>
<script src="#Url.Content("~/Scripts/kendo/2013.2.918/kendo.aspnetmvc.min.js")"></script>
<script src="#Url.Content("~/Scripts/kendo.modernizr.custom.js")"></script>
<script type="text/javascript">
var _gaq = _gaq || [];
var pluginUrl =
'//www.google-analytics.com/plugins/ga/inpage_linkid.js';
_gaq.push(['_require', 'inpage_linkid', pluginUrl]);
_gaq.push(['_setAccount', 'UA-44529127-1']);
_gaq.push(['_trackPageview']);
(function () {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();
</script>
</head>
<body>
<header>
<div class="content-wrapper">
<div class="float-left">
<p class="site-title">#Html.ActionLink("your logo here", "Index", "Home")</p>
</div>
<div class="float-right">
<section id="login">
#Html.Partial("_LoginPartial")
</section>
<nav>
<ul id="menu">
<li>#Html.ActionLink("Home", "Index", "Home")</li>
<li>#Html.ActionLink("About", "About", "Home")</li>
<li>#Html.ActionLink("Contact", "Contact", "Home")</li>
#if (User.IsInRole("Admin"))
{
<li>#Html.ActionLink("API", "Index", "Help", new { area = "" }, null)</li>
}
</ul>
</nav>
</div>
</div>
</header>
<div id="body">
#if (Request.IsAuthenticated)
{
<ul id="IndexHomeMenu">
#if (User.IsInRole("Admin"))
{
<li>
Administration#*#Html.ActionLink("Administration", "Contact", "Home")*#
<ul>
<li>#Html.ActionLink("Manage Roles", "Index", "AdminView")</li>
<li>#Html.ActionLink("Manage Users", "Contact", "Home")</li>
<li>#Html.ActionLink("Inactive Reasons", "Index", "InactiveReasonView")</li>
</ul>
</li>
}
<li>
My Information
<ul>
<li>#Html.ActionLink("Profile", "EditByName", "UserView", new { UserName = User.Identity.Name }, new { #class = "selected" })</li>
<li>#Html.ActionLink("Phone Numbers", "Active", "PhoneNumberView",new {userName= User.Identity.Name },null)</li>
<li>#Html.ActionLink("Address's", "Active", "AddressView",new {userName= User.Identity.Name },null)</li>
#if(!User.IsInRole("Clients")){
<li>#Html.ActionLink("Subscription", "Index", "AdminView")</li>}
</ul>
I am clicking on #Html.ActionLink("Profile", "EditByName", "UserView", new { UserName = User.Identity.Name }, new { #class = "selected" })
CONTROLLER
[ValidateAntiForgeryToken]
public ActionResult EditByName(string userName)//EditByName
{
if (User.Identity.IsAuthenticated)
{
UserModel usermodel = repository.Get(User.Identity.Name);// db.UserModels.Find(id);
if (usermodel == null)
{
return RedirectToAction("Create","UserView", User.Identity.Name);
}
return View(usermodel);
}
else { return RedirectToAction("Login", controllerName: "AccountView"); }
}
This is when the error occurs. and im not sure whats missing, I am creating the token and it is on all forms.
You are using the [ValidateAntiForgeryToken] on a GET action (The EditByName action), while it is meant to work on POST actions.
See this question on the [ValidateAntiForgeryToken] purpose and this article explaining how to prevent CSRF attacks using it.
Remove the [ValidateAntiForgeryToken] from the EditByName GET-action method.
Also, use the [Authorize] atrribute instead of if (User.Identity.IsAuthenticated).
And may any user edit any profile, as long as they know the username?
Related
I are trying to develop a shareable widget.
I am developing by using razor.view, razor.page and razor.component (project templates are Razor Class Library and ASP.NET Core 6 MVC).
_Imports.razor under RCL Project is as follows:
#using System.Net.Http
#using Microsoft.AspNetCore.Authorization
#using Microsoft.AspNetCore.Components.Authorization
#using Microsoft.AspNetCore.Components.Forms
#using Microsoft.AspNetCore.Components.Routing
#using Microsoft.AspNetCore.Components.Web
#using Microsoft.JSInterop
#using System.IO
#using CarRentalWidget.Models.DBEntities.Franchises
#using CarRentalWidget.Models.ViewModels.GooogleGeoCodes
AutoCompleteLocationsComponent.razor is as follows:
#using System.Net.Http
#using System.Net.Http.Json
#using System.Threading.Tasks
#inject HttpClient Http
#namespace CarRentalWidget.RCL.CarWidgetUI.Pages
<div>
<input
type="text"
id="TxtBxPickUpLoc"
class="postcode tf-form-control"
placeholder="Please Enter Postcode or Town"
value="#inputValue"
#onchange="DoChangeLocation"
autoComplete="off"
/>
#if(!string.IsNullOrWhiteSpace(inputValue))
{
<a className="location" href="#" id="branch-selector" onClick={onClearLocations}></a>
}
else if (string.IsNullOrWhiteSpace(inputValue))
{
<a className="location empty" href="#" id="branch-selector" onClick={onClearLocations}></a>
}
</div>
<div class="sautocomplete-content-container tk-search-drop-wrapper ac-drop-active">
<div class="sautocomplete-content tk-search-drop">
<div class="branch-info">
<ul id="LocationSuggestions" class="suggestions">
#if (locationData != null && locationData.Count() > 0)
{
#foreach (FranchiseWebInquiry suggestion in locationData!)
{
// Flag the active suggestion with a class
if (index == activeSuggestionIndex)
{
className = "suggestion-active";
}
<li class="#className" key="#index + #suggestion.FranchiseName" onClick="onClick(suggestion)">
<a pickupid="#suggestion.PickupId + #suggestion.FranchisesId" franchisesid="#suggestion.FranchisesId" subofficeid="#suggestion.SubOfficeId" href="#">
<span class="locName">#suggestion.FranchiseName</span>
<span class="locDetails">#getAddress(suggestion)
</span>
</a>
</li>
++index;
}
}
</ul>
</div>
</div>
</div>
#code {
private string inputValue = "";
private string className = "";
private int activeSuggestionIndex;
private int index = 0;
private FranchiseWebInquiry[]? locationData;
private bool getError;
private bool shouldRender;
protected override bool ShouldRender() => shouldRender;
private GoogleGeocode? currentMapItems;
private async Task<GoogleGeocode?> loadGoogleGeoCodeData(string postCodeOrTown)
{
currentMapItems = await Http.GetFromJsonAsync<GoogleGeocode?>
("https://maps.googleapis.com/maps/api/geocode/json?types=geocode&language=en&key=mykey&address=" + postCodeOrTown);
return currentMapItems;
}
private async Task getLocationsApi(string postCodeOrTown)
{
await loadGoogleGeoCodeData(postCodeOrTown);
Result? serviceResult = currentMapItems!.Results!.FirstOrDefault();
Location? locDetail = serviceResult != null && serviceResult.Geometry != null ? serviceResult.Geometry.Location:null;
double providedLattitude = locDetail != null ? locDetail.Lat : 0;
double providedLongitude = locDetail != null ? locDetail.Lng : 0;
locationData = await Http.GetFromJsonAsync<FranchiseWebInquiry[]?>
("https://localhost:7177/api/CarRental/allfranchises/?postCodeOrAddress=" + postCodeOrTown + "&lattitude=" + providedLattitude + "&longitude=" + providedLongitude);
}
private async void DoChangeLocation(ChangeEventArgs e)
{
inputValue = e.Value!.ToString();
if (inputValue!.Length >= 5)
{
await getLocationsApi(inputValue);
}
Console.WriteLine("It is definitely: " + inputValue);
}
private string getAddress(FranchiseWebInquiry suggestion)
{
//debugger;
string localAddress = "";
if (suggestion != null)
{
if (!string.IsNullOrWhiteSpace(suggestion.Address1))
{
localAddress = suggestion.Address1 + " , ";
}
if (!string.IsNullOrWhiteSpace(suggestion.Address2))
{
localAddress += suggestion.Address2 + " , ";
}
if (!string.IsNullOrWhiteSpace(suggestion.Address3))
{
localAddress += suggestion.Address3 + " , ";
}
if (!string.IsNullOrWhiteSpace(suggestion.Town))
{
localAddress += suggestion.Town + "- " + (!string.IsNullOrWhiteSpace(suggestion.PostCode) ? "(" + suggestion.PostCode + "), ":"");
}
if (!string.IsNullOrWhiteSpace(suggestion.PrimaryContact))
{
localAddress += suggestion.PrimaryContact;
}
}
return localAddress;
}
}
and Index.cshtml is as follows:
#page "/car-index"
#model CarRentalWidget.RCL.CarWidgetUI.Pages.IndexPageModel
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Car Rental Widget</title>
</head>
<body>
<div class="widget-wrapper">
<div class="main-heading">
<h1>
Test 1
</h1>
</div>
<div class="widget-slider">
<div class="row step-row">
<div class="col-12">
<div class="pickup-location tf-search-group">
<div class="label-location tf-search-label">pick up location</div>
<div id="PickUpLocationControlId" class="input-group-location tf-search-field">
<div class="card">
#(await Html.RenderComponentAsync<CarRentalWidget.RCL.CarWidgetUI.Pages.AutoCompleteLocationsComponent>
(RenderMode.ServerPrerendered/*,new { Data="I came from Index",style= "badge-danger" }*/))
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
Now I just added the reference in my ASP.NET Core 6 MVC project and open the browser and tried this url in the browser.
https://localhost:7177/car-index
Everything is working as expected. No issue till so far.
Now I am trying to consume this through a plain html (and Javascript/jQuery).
My client end application request is as follows:
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
$("button").click(function(){
$.ajax({url: "https://localhost:7177/car-index", success: function(result){
$("#CarWidget").html(result);
}});
});
});
</script>
</head>
<body>
<div id="CarWidget">
</div>
</body>
</html>
See I tried with above script, there is no error code even in Browser Network tab.
Why?
For detailed understanding, you can follow this link as well
https://learn.microsoft.com/answers/comments/872715/view.html
and these links
https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-6.0&tabs=visual-studio
https://learn.microsoft.com/en-us/aspnet/core/blazor/components/class-libraries?view=aspnetcore-6.0&tabs=visual-studio
my view statement shows error that " for each statement cannot operate on variables of type public definition for 'get enumerator' "
I defined all objects in model and view models. still i get this error. any solution for this?
MY VIEW:
#using Edi.ViewModel
#model viewmodel
#{
<link rel="stylesheet" type="text/css" href="~/Content/style.css" />
Layout = null;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link href="~/Content/Site.css" rel="stylesheet" />
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<link href="~/Content/bootstrap.css" rel="stylesheet" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
</head>
<body>
<form id="form1" name="zoo">
<div class="med">
<pre>
<fieldset id="field1">
<legend>Bill Date Range</legend>
<input type="checkbox">After <input type="date" /> <input type="checkbox">Before <input type="date" />
</fieldset>
<fieldset id="field2">
<legend>Options</legend>
<label>Facility</label> #Html.DropDownListFor(Model => Model.Facility, Model.Facility, "Select Facility", new { style = "width:200px; height :30px" })
<label>Ins Queue</label> #Html.DropDownListFor(Model => Model.InsQueue, Model.InsQueue, "Select InsQueue", new { style = "width:200px; height:30px" })
Claim type <select style="width: 100px; height:30px"><option value="ALL">All</option><option value="NEW">New</option><option value="RESUBMIT">Resubmit</option></select>
</fieldset>
<pre>
<label>No of Bills Selected </label><input type="text" size="1" /> <label> EDI send To </label> #Html.DropDownListFor(Model => Model.EdiSendTo, Model.EdiSendTo, "Select Edi", new { style = "width:200px; height :30px" }) <button type="button" onclick="">Select All</button> <button type="reset" onclick="">Refresh</button> <button type="button" onclick="">Clear All</button> <button type="button" onclick="">Edit Bill</button>
</pre>
<table id="myTable">
<tr class="hd">
<th>visit</th>
<th>billno</th>
<th>patient</th>
<th>providername</th>
<th>insname</th>
<th>payby</th>
<th>inscode</th>
<th>user</th>
<th>claimtype</th>
</tr>
-------------------#foreach (var items in Model)------------------------------
{
<tr onclick="javascript:showRow1(this);">
<td>#items.visit</td>
<td>#items.billno</td>
<td>#items.Patient</td>
<td>#items.ProviderName</td>
<td>#items.InsName</td>
<td>#items.PayBy</td>
<td>#items.InsCode</td>
<td>#items.User</td>
<td>#items.ClaimType</td>
</tr>
}
</table>
</div>
</form>
</body>
</html>
MY CONTROLLER:
namespace Edi.Controllers
{
public class HomeController :Controller
{
// GET: Home
public ActionResult Index()
{
mbill mt = new mbill();
billing db = new billing();
viewmodel vm = new viewmodel();
vm.Facility = db.Add1();
vm.EdiSendTo = db.Add2();
vm.InsQueue = db.Add3();
List<mbill> itemlist = new List<mbill>();
itemlist = db.Index();
return View("Index",vm);
}
}
}
MY MODEL:
public List<mbill> Index()
{
List<mbill> itemList = new List<mbill>();
connection();
SqlCommand cmd = new SqlCommand("procGetEDIBills", con);
cmd.CommandType = CommandType.StoredProcedure;
con.Open();
SqlDataAdapter sd = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
sd.Fill(dt);
mbill item = new mbill();
using (SqlDataReader sdr = cmd.ExecuteReader())
{
mbill io = new mbill();
while (sdr.Read())
{
io = new mbill();
io.visit = sdr["VisitDate"].ToString();
io.billno = sdr["Billno"].ToString();
io.Patient = sdr["PatientName"].ToString();
io.ProviderName = sdr["ProviderName"].ToString();
io.InsName = sdr["InsuranceName"].ToString();
io.PayBy = sdr["BillPayBy"].ToString();
io.InsCode = sdr["InsuranceId"].ToString();
io.User = sdr["QueueByUser"].ToString();
io.ClaimType = sdr["ClaimType"].ToString();
itemList.Add(io);
}
}
con.Close();
return itemList;
}
}
if i delete #using Edi.ViewModel, #model viewmodel, on view then foreach error disappears and dropdownlistfor shows does not contain definition for dropdownlistfor error.
After reading several posts regarding this issue, it is mostly related to including
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
and the proper order of including jquery first.
<script src="~/Scripts/jquery-1.12.4.js"></script>
I think I did properly, but OnBegin is not firing still.
_Layout.cshtml:
<head>
<meta charset="utf-8" />
<meta content='width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0' name='viewport' />
<title>Test</title>
#Scripts.Render("~/bundles/modernizr")
<script src="~/Scripts/jquery-1.12.4.js"></script>
<script src="~/Scripts/bootstrap.min.js"></script>
<script src="~/Scripts/respond.min.js"></script>
<script src="~/Scripts/jquery.dataTables.js"></script>
<script src="https://cdn.datatables.net/responsive/2.1.0/js/dataTables.responsive.min.js"></script>
<script src="https://cdn.datatables.net/buttons/1.2.2/js/dataTables.buttons.min.js"></script>
<script src="https://cdn.datatables.net/buttons/1.2.2/js/buttons.colVis.min.js"></script>
<script src="~/Scripts/light-bootstrap-dashboard.js"></script>
<script src="~/Scripts/bootstrap-notify.js"></script>
<script src="~/Scripts/jquery.unobtrusive-ajax.js"></script>
<script src="~/Scripts/jquery.validate.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js"></script>
#RenderSection("scripts", required: false)
</head>
So the order of process is:
School View:
#model Test.Models.School
<div class="editorRow">
#using (Html.BeginCollectionItem("schools"))
{
#Html.ActionLink("New Employee", "NewEmployee", "Test", new
{
#class = "btn btn-info btn-md",
data_toggle = "modal",
data_target = "#modal-container-employee"
})
</div>
<div id="modal-container-employee" class="modal fade" tableindex="-1" role="dialog">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
Controller:
public ActionResult NewEmployee()
{
var newEmployee = new Employee();
return View(newEmployee);
}
Employee view:
#model Test.Models.Employee
#{
Layout = null;
}
#using (Ajax.BeginForm("PostEmployee", "Employee", new AjaxOptions
{
HttpMethod = "post",
InsertionMode = InsertionMode.Replace,
OnBegin = "closeModal"
}))
{
#Html.AntiForgeryToken()
<div id="test" class="">
<div class="modal-title title">
<input type="submit" id="submit" value="Save" /><span id="closes">x</span>
</div>
#Html.EditorFor(model => model.FullName)
</div>
}
<script>
function closeModal() {
$('#modal-container').modal('hide');
}
</script>
controller:
[HttpPost]
public ActionResult PostEmployee(Employee model)
{
try
{
var newEmployee = new Employee
{
FullName = model.FullName
};
db.Employees.Add(newEmployee);
db.SaveChanges();
return Json(new { status = "success" }, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
return Json(new { status = "error", errorMessage = ex.Message }, JsonRequestBehavior.AllowGet);
}
}
As a result, "success" Json is returned, but ajax is not catching it, it directly goes to the other page where it shows JSON array {"status":"success"}.
Can anyone find the problem?
This is Index view:
<script type="text/jscript" language="javascript">
$(document).ready(function () {
$("#tabs").tabs();
});
</script>
<div class="demo">
<div id="tabs">
<ul>
<li>Overview</li>
<li><a href="/CarDetails/Specification?Id=" + '#ViewBag.versionId'>Specifications</a></li>
</ul>
<div>
</div>
<div>
</div>
</div>
</div>
public class CarDetailsController : Controller
{
public ActionResult Index(int? versionID)
{
ViewBag.versionId = versionID;
return View();
}
public ActionResult Specification(int Id)
{
return PartialView(CarDetails.GetCarModelVersionDetailsByConfigGrpId(Id));
}
}
Above controller is being called by
#Html.ActionLink(item.VersionName, "Index", "CarDetails", new { versionID = item.ModelVersionId },null)
I need querystring value of versionID within Specification action of CarDetailsControl.
But it becomes empty.
Please guide me.
Thanks,
#Paul
changing to
<li><a href="/CarDetails/Specification?versionID=#ViewBag.versionId" >Specifications</a></li>
has resolved my problem.
I'm having a problem getting a form to work without javascript being enabled.
This should be enough to go on, ask if you need to know anything else - I don't want to just put the whole solution up here!
~/Views/_ViewStart.cshtml:
#{ Layout = "~/Views/Shared/Layout.cshtml"; }
~/Views/Shared/Layout.cshtml:
#using System.Globalization; #{ CultureInfo culture = CultureInfo.GetCultureInfo(UICulture); }<!DOCTYPE html>
<html lang="#culture.Name" dir="#(culture.TextInfo.IsRightToLeft ? "rtl" : "ltr")">
<head>
<title>AppName :: #ViewBag.Title</title>
<link href="#Url.Content("~/favicon.ico")" rel="shortcut icon" type="image/x-icon" />
<link href="#Url.Content("~/apple-touch-icon.png")" rel="apple-touch-icon" />
<link href="#Url.Content("~/Content/css/site.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Content/js/jquery-1.6.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Content/js/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Content/js/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Content/js/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Content/js/app.js")" type="text/javascript"></script>
#RenderSection("SectionHead", false)
</head>
<body>
<div id="page-container">
<div id="nav">
<div id="nav-user">
#{ Html.RenderAction("LoginStatus", "Account"); }
#{ Html.RenderPartial("CultureSelector"); }
</div>
</div>
<div id="page-content">
<h2>#ViewBag.Title</h2>
#RenderBody()
</div>
</div>
</body>
</html>
~/Views/Account/Index.cshtml:
#model AccountFilterModel
#{
ViewBag.Title = "Account Home";
var loadingId = "loading" + new Random().Next();
Model.FilterFormId = "filter-account-form";
}
#using (Ajax.BeginForm("List", "Account", Model, new AjaxOptions { UpdateTargetId = "result-list", LoadingElementId = loadingId }, new { id = "filter-account-form" })) {
<!-- form controls and validation summary stuff -->
<input id="filter" type="submit" value="Filter" />
<span id="#loadingId" style="display: none">
<img src="#Url.Content("~/Content/images/ajax-loader.gif")" alt="Loading..." />
</span>
}
<div id="result-list">
#{ Html.RenderAction("List", Model); }
</div>
~/Views/Account/List.cshtml:
#model FilterResultModel
#helper SortLink(AccountSort sort, SortDirection dir) {
string display = (dir == SortDirection.Ascending ? "a" : "d"); // TODO: css here
if (Model.Filter.SortBy != null && ((AccountSortModel)Model.Filter.SortBy).Sort == sort && dir == Model.Filter.SortOrder) {
#:#display
} else {
FilterModel fm = new FilterModel(Model.Filter);
fm.SortBy = AccountSortModel.SortOption[sort];
fm.SortOrder = dir;
#display
}
}
#if (Model.Results.Count > 0) {
var first = Model.Results.First();
<table>
<caption>
#string.Format(LocalText.FilterStats, Model.FirstResultIndex + 1, Model.LastResultIndex + 1, Model.CurrentPageIndex + 1, Model.LastPageIndex + 1, Model.FilteredCount, Model.TotalCount)
</caption>
<thead>
<tr>
<th>
#Html.LabelFor(m => first.Username)
<span class="sort-ascending">
#SortLink(AccountSort.UsernameLower, SortDirection.Ascending)
</span>
<span class="sort-descending">
#SortLink(AccountSort.UsernameLower, SortDirection.Descending)
</span>
</th>
<!-- other table headers -->
</tr>
</thead>
<tbody>
#foreach (AccountModel account in Model.Results) {
<tr>
<td>#Html.EncodedReplace(account.Username, Model.Filter.Search, "<span class=\"filter-match\">{0}</span>")</td>
<!-- other columns -->
</tr>
}
</tbody>
</table>
Html.RenderPartial("ListPager", Model);
} else {
<p>No Results</p>
}
Relevant part of AccountController.cs:
public ActionResult Index(AccountSort? accountSort, FilterModel model = null) {
FilterModel fm = model ?? new FilterModel();
if (accountSort.HasValue) fm.SortBy = AccountSortModel.SortOption[accountSort.Value];
return View(fm);
}
public ActionResult List(AccountSort? accountSort, FilterModel model = null) {
FilterModel fm = model ?? new FilterModel();
if (accountSort.HasValue) fm.SortBy = AccountSortModel.SortOption[accountSort.Value];
return Request.IsAjaxRequest() ? (ActionResult)PartialView("List", Service.Get(fm)) : View("Index", model);
}
With javascript enabled, this works fine - the content of div#result-list is updated as expected.
If I don't do the Request.AjaxRequest() and just return the PartialView, then with javascript disabled I get a page with just the content of the results on it. If I have the code as above, then I get a StackOverflowException.
How do I get this to work?
Solution
Thanks to #xixonia, I discovered the problem - here is my solution:
public ActionResult List(AccountSort? accountSort, FilterModel model = null) {
FilterModel fm = model ?? new FilterModel();
if (accountSort.HasValue)
fm.SortBy = AccountSortModel.SortOption[accountSort.Value];
if (Request.HttpMethod == "GET")
return PartialView("List", Service.Get(fm));
if (Request.HttpMethod == "POST")
return Request.IsAjaxRequest() ? (ActionResult) PartialView("List", Service.Get(fm)) : RedirectToAction("Index", model);
return new HttpStatusCodeResult((int) HttpStatusCode.MethodNotAllowed);
}
You can use the following extension method to determine if the request is an ajax request
Request.IsAjaxRequest()
If it is, you can return a partial view, otherwise you can return a full view or redirect.
if(Request.IsAjaxRequest())
{
return PartialView("view", model);
}
else
{
return View(model);
}
edit: here's the problem:
The "List" is returning the "Index" view when the request is not an AJAX request:
public ActionResult List(AccountSort? accountSort, FilterModel model = null) {
FilterModel fm = model ?? new FilterModel();
if (accountSort.HasValue) fm.SortBy = AccountSortModel.SortOption[accountSort.Value];
return Request.IsAjaxRequest() ? (ActionResult)PartialView("List", Service.Get(fm)) : View("Index", model);
}
The "Index" view is rendering the "List" action:
#{ Html.RenderAction("List", Model); }
AKA: Recursion.
You need to engineer a way to display your list without drawing the index page, or make your index page draw a partial view with your list modal as a parameter.