I'm trying to render from controller either PartialView or View depending on condition coming from outside. Web-site fails on posting data with StackOverflowException.
Controller code:
public ActionResult Login(bool partial = false)
{
if (partial)
{
ViewBag.Partial = true;
return PartialView();
}
return View();
}
[HttpPost]
public ActionResult Login(UserViewModel userViewModel)
{
if (!ModelState.IsValid)
return View(userViewModel);
// some authrorization staff
}
Login.cshtml:
#using SK.DDP.ImageGallery.Helpers
#model SK.DDP.ViewModels.UserViewModel
#{
ViewBag.Title = "Login";
if (ViewBag.Partial != null)
{
Layout = string.Empty;
}
}
#*Some form staff*#
AuthorizationInfo.cshtml:
#{
Layout = string.Empty;
}
#{ Html.RenderAction("Login", "Authorization"); }
Template:
#*Some dif for form requested by menu*#
#{ Html.RenderAction("AuthorizationInfo", "Authorization"); }
I have a web-site with login page and login popup window appearing when user clicks on menu, so i wanted to reuse the same action of controller and code and app is continuing to fail with stackoverflow exception.
Thanks.
Seems its a bug in a Razor engine.
I workarounded it.
AuthorizationInfo.cshtml
#{ Html.RenderAction("LoginPartial"); }
AuthorizationController.cs
public ActionResult Login()
{
return View();
}
public ActionResult LoginPartial()
{
ViewBag.Partial = true;
return PartialView("Login");
}
Now Post of forms does not generate overflows with templates applied recursively.
Related
Can anyone tell me why I created Cate controllers after adding razor view mvc, the Index file of Categories was inserted with the _Layout interface above?
When i put RenderBody() at the top the _Layout is inserted at the end ?
here is img code of Index(Categories), _Layouu
#model IEnumerable<WebApplication1.Models.Category>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Categories</h1>
public IActionResult Index()
{
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
}
}
enter image description here
enter image description here
enter image description here
I'm using tempdata to give user a "success message" before redirection however at the moment it just redirect without giving the message. Maybe I have it at wrong place, I tried moving it to different parts of the code but it still didn't work.
Index View
#{
ViewBag.Title = "Home Page";
}
#if (TempData["notice"] != null)
{
<p>#TempData["notice"]</p>
}
<div>
<img src="~/Content/Images/TWO_Logo.jpg" alt="Logo" />
</div>
<div class="jumbotron">
<h1></h1>
<p class="lead">
</div>
Home Controller
namespace com.twcl.it.isms.Controllers
{
[Authorize(Roles = "Administrator, Issue, Transaction_Edit, Print")]
public class HomeController : Controller
{
public ActionResult Index()
{
TempData["notice"] = "Your item(s) successfully requested";
ViewBag.SuccessMessage = TempData["SuccesMeassge"];
return View();
}
public ActionResult About()
{
ViewBag.Message = "Your application description page.";
return View();
}
public ActionResult Contact()
{
ViewBag.Message = "Your contact page.";
return View();
}
public ActionResult Logoff()
{
HttpContext.Session.Abandon();
Response.Redirect("http://192.168.5.127");
//Response.StatusCode = 401;
//Response.End();
//////throw new HttpException(401, "Please close your browser to complete Log Off");
return View("Index");
}
In Index Action method just add TempData.Keep("notice"); which will keep tempdata available for next hop.
public ActionResult Index()
{
TempData.Keep("notice");
ViewBag.SuccessMessage = TempData["SuccesMeassge"];
return View();
}
On View to display alert message
#if (TempData.ContainsKey("notice"))
{
<script type="text/javascript">
alert(#TempData["notice"]);
</script>
}
Details about keep and peek.
when-to-use-keep-vs-peek-in-asp-net-mvc
If you are returning a RedirectResponse from your action method, it will send a 302 response back to the browser with the location header set to the url you want to redirect to and the browser makes a new GET request to that url. You will not be able to show an alert before the new GET request.
What you can do is, show the alert message in page rendered by the redirect.
[HttpPost]
public ActionResult Save(SomeViewmodel model)
{
TempData["Msg"] = "Some message";
return RedirectToAction("Index");
}
Now in the view returned by Index action, you can directly access TempData. No need to read and pass it via ViewBag again in Index action.
<script>
var msg = '#TempData["Msg"]';
if (msg.length) {
alert(msg);
}
</script>
I am using custom Login for my application. I want to insert last login date and time in database and show last login date and time when user login into application.
Controller Code:
public class HomeController : Controller
{
MyDatabaseEntities db = new MyDatabaseEntities();
//
// GET: /Home/
public ActionResult Index()
{
if(Session["LoggedUserID"]!= null)
{
return View();
}
else
{
return RedirectToAction("Login");
}
}
public ActionResult Login()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(Login l)
{
if (ModelState.IsValid)
{
using(MyDatabaseEntities db = new MyDatabaseEntities())
{
this.UpdateLoginLastUpdateStatus();
var v = db.Logins.Where(a => a.UserName.Equals(l.UserName) && a.Password.Equals(l.Password)).FirstOrDefault();
if (v!= null)
{
Session["LoggedUserID"] = v.UserID.ToString();
Session["LoggeduserName"] = v.UserName.ToString();
Session["LastLogin"] = v.LastWebLogin.ToString();
return RedirectToAction("Index");
}
}
}
if(!ModelState.IsValid)
{
ModelState.AddModelError("","Username or Password is incorrect!!");
}
return View(l);
}
public void UpdateLoginLastUpdateStatus()
{
Login l = new Login();
l.LastWebLogin = DateTime.Now.ToString();
db.SaveChanges();
}
[HttpGet]
public ActionResult LogOff()
{
Session.Abandon();
return RedirectToAction("Login", "Home");
}
}
}
Index View
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#if (Convert.ToString(Session["LoggedUserID"]) != "")
{
<section>
<p class="toplink">#Html.ActionLink("Logout", "LogOff", "Home")</p>
</section>
}
Last Logged on: #Session["LastLogin"]
You have been logged in.
I am able to Log In and Log Out but this Last Logged In Time is not working.
The problem is this line is trying to update the login LastWebLogin before you've even retrieved it:
this.UpdateLoginLastUpdateStatus();
You need to call this AFTER you've assigned the Login to the variable v. Additionally, the method is creating a NEW Login class, not using an existing one. For that to work you'd have to pass a parameter v to the method. You don't even need that method really - unless you call it from multiple places and you want to avoid repeated code - it just needs to be a simple as:
var v = db.Logins.Where(a => a.UserName.Equals(l.UserName) && a.Password.Equals(l.Password)).FirstOrDefault();
if (v!= null)
{
// get previous login
var prevLogin = v.LastWebLogin;
// update with current login
v.LastWebLogin = DateTime.Now.ToString();
db.SaveChanges();
Session["LoggedUserID"] = v.UserID.ToString();
... etc
I have a form which is a partial view in layout page. I need after success to render another partial view in the first one place.
However the partial view is rendered inside the first partial view. (for example if user fill the form in Mydomain/index the new partial view should display in the same url. And now it is displayed in /controller/create).
[ChildActionOnly]
public ActionResult Create()
{
ViewBag.SubjectId = new SelectList(db.subjects, "SubjectId", "Subjectname");
return PartialView();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "InfoId,FirstName,SureName,PhoneNumber,Address,Email,EnterdDate,IsActive,Tipol,SubjectId")] Info info)
{
info.EnterdDate = DateTime.Now;
info.IsActive = false;
if (ModelState.IsValid)
{
db.infos.Add(info);
db.SaveChanges();
TempData["thanks"] = info.FullName;
return PartialView("_bla");
}
ViewBag.SubjectId = new SelectList(db.subjects, "SubjectId", "Subjectname", info.SubjectId);
return View(info);
}
public PartialViewResult _bla()
{
var thanks = TempData["thanks"];
return PartialView();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "InfoId,FirstName,SureName,PhoneNumber,Address,Email,EnterdDate,IsActive,Tipol,SubjectId")] Info info)
{
info.EnterdDate = DateTime.Now;
info.IsActive = false;
if (ModelState.IsValid)
{
db.infos.Add(info);
db.SaveChanges();
TempData["thanks"] = info.FullName;
return RedirectToAction("Create");
}
ViewBag.SubjectId = new SelectList(db.subjects, "SubjectId", "Subjectname", info.SubjectId);
return View(info);
}
View Create:
#if (TempData["thanks"] != null)
{
<div class="alert alert-success">
#TempData["thanks"]
</div>
}
// your form
I am trying to learn MVC 3 & Razor and I'm stuck here for 3 hours now. This is what I have
MVC project created using the default template with Account registration and all that good stuff from the template. What I'm trying to do is have both registration page and login page in the index of the HomeController so I created a partial view for both Register (_RegisterPartial) and LogOn (_LogOnPartial). When I go to the index page, I see the registration and login forms which is good but when I try to login or register it goes into an infinite loop.
My HomeController looks like this;
// **************************************
// Registration
// **************************************
public ActionResult DoRegister()
{
return PartialView("_Register");
}
[HttpPost]
public ActionResult DoRegister(RegisterModel model)
{
if (ModelState.IsValid)
{
// Attempt to register the user
MembershipCreateStatus createStatus = MembershipService.CreateUser(model.UserName, model.Password, model.Email, model.UserProfile);
if (createStatus == MembershipCreateStatus.Success)
{
FormsService.SignIn(model.UserName, false); // createPersistentCookie
return View("Success");
}
else
{
ModelState.AddModelError("", AccountValidation.ErrorCodeToString(createStatus));
}
}
// If we got this far, something failed, redisplay form
ViewBag.PasswordLength = MembershipService.MinPasswordLength;
return View(model);
}
// **************************************
// Login
// **************************************
public ActionResult DoLogin()
{
return PartialView("_Login");
}
[HttpPost]
public ActionResult DoLogin(LogOnModel model, string returnUrl)
{
if (ModelState.IsValid)
{
if (MembershipService.ValidateUser(model.UserName, model.Password))
{
// logged in
FormsService.SignIn(model.UserName, model.RememberMe);
if (Url.IsLocalUrl(returnUrl))
{
Redirect(returnUrl);
}
else
{
View("Success");
}
}
else
{
// Not logged in
ModelState.AddModelError("", "The user name or password provided is incorrect.");
}
}
// If we got this far, something failed, redisplay form
return View("Success");
}
and my cshtml looks like this;
#{
ViewBag.Title = "Home Page";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#if (Request.IsAuthenticated)
{
#Html.ActionLink("Log Off", "LogOff", "Account")
}
else
{
Html.RenderAction("DoLogin");
Html.RenderAction("DoRegister");
}
Regards,
Ryan
Do you read exception messages?
A public action method 'Register' was not found on controller 'AudioRage.Controllers.HomeController'
Now look at the code of HomeController you've posted. Do you see a Register action on it? I don't.
So add one:
public ActionResult Register()
{
...
}
In your HomeController you have an action called Register but action is only accessible through POST verbs as it is decorated with the [HttpPost] attribute:
[HttpPost]
[ActionName("Register")]
public ActionResult Index(RegisterModel model)
so you cannot invoke it with a GET verb on /Home/Register.
I can't exactly replicate your situation but I would say that you partial forms are not posting correctly. Have a look a rendered html of the page and check where the forms are being posted to. My guess is that they are being posted to the Index action. Coupled with the redirect, I think that is where the infinite loop is coming from.
My guess is the html rendered for both forms are similar and posting to the same action i.e. <form action="/" method="post">, since they are being rendered by the HomeController's Index action.
Change the partial forms (_Login.cshtml and _Register.cshtml) and explicitly state which action/controller combination to post to (more on Html.BeginForm from MSDN)
#using (Html.BeginForm("DoLogin","Home")) {/*snipped*/} //in _Login.cshtml
#using (Html.BeginForm("DoRegister","Home")) {/*snipped*/} //in _Register.cshtml
Also I would change the Html.RenderAction calls to
Html.RenderPartial("_Login");
Html.RenderPartial("_Register");