How do I show custom error in view from controller in MVC? - model-view-controller

Action Method in Controller:
public async Task<IActionResult> Signup(Login login)
{
if (login.Username != null || login.Password != null)
{
if (ModelState.IsValid)
{
if (!UserExists(login.Username,login.Password))
{
_context.Add(login);
await _context.SaveChangesAsync();
return RedirectToAction("LoginView");
}
else
{
ModelState.AddModelError("Name", "Invalid name");
//Trying this method but not sure how would it work on view.
return RedirectToAction("AddCustomError");
}
}
else
return View("Signup");//Custom Error here
}
return View("Signup");//Custom Error here
}
How would i display custom error in view?
Is there any other method to get similar custom error from controller to view?

Related

Ajax Error 500: A circular reference was detected

I'm trying to update my view with new information, so when it is sent to the controller for saving, the information gets passed.
The same method works fine when creating an object (Create-View) but throws an ajax error 500: A circular reference was detected while serializing an object of type 'System.Data.Entity.DynamicProxies.Gutscheine_', when editing an existing object (Edit-View).
Here's my ajax-call:
function onCloseButtonClick(s) {
$.ajax({
type: "POST",
url: "#Url.Action("UpdateGutscheinEdit")",
data: { sBild: document.getElementById(s).value, bIcon: true },
success: function (response) {
document.getElementById("sBild").value = response.sBild;
document.getElementById("bIcon").value = response.bIcon;
document.getElementById("fileToUpload").value = "";
popupIconAuswaehlen.Hide();
},
error: function (jqxhr, status, exception) {
alert(jqxhr.status); //throws 500
alert('Exception', exception);
}
})
}
And here's the method:
public ActionResult UpdateGutscheinEdit(string sBild, bool bIcon)
{
Gutscheine currentGutschein = Session["CurrentGutscheinEdit"] as Gutscheine;
if (!string.IsNullOrEmpty(sBild))
{
currentGutschein.sBild = sBild;
currentGutschein.bIcon = bIcon;
}
Session["CurrentGutscheinEdit"] = currentGutschein;
return Json(currentGutschein);
}
The Edit-(get)-method is a standard one:
public ActionResult Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Gutscheine gutscheine = db.Gutscheine.Find(id);
if (gutscheine == null)
{
return HttpNotFound();
}
if(Session["CurrentGutscheinEdit"] == null)
{
Session["CurrentGutscheinEdit"] = gutscheine;
}
return View(Session["CurrentGutscheinEdit"] as Gutscheine);
}
Circular reference gives some hint, but I'm pretty new to all this, so it doesn't help me much in figuring out the problem.
If you have any ideas how to fix this, please let me know. Any help is appreciated!
Adding db.Configuration.ProxyCreationEnabled = false; before getting the object from the database did the trick.
Finished code: (I also removed some stuff at the end which screwed something else up)
public ActionResult Edit(string id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
db.Configuration.ProxyCreationEnabled = false;
Gutscheine gutscheine = db.Gutscheine.Find(id);
if (gutscheine == null)
{
return HttpNotFound();
}
Session["CurrentGutscheinEdit"] = gutscheine;
return View(Session["CurrentGutscheinEdit"] as Gutscheine);
}
Big thanks to the commenter that provided the link!

Pass ViewModel to JSONresult in controller

My application was working but I was asked to change how message are displayed by using the JSONResponseFactory. But when I try that my ViewModel is empty going back to the JSonResult (which used to be ActionResult). I've been told I may have to serialize the form fields. Here are some present code excerpts:
cshtml:
function SubmitForm() {
$.ajaxSetup({ cache: false });
$.post('#Url.Action("StoreLevelPlanning", "StoreLevelPlanning")', { actionType: "Submit"})
.done(function (data) {
if (data.Success == true) {
CreateInformationMessage(data.Message, 'window.location.href = "#Url.Action("storemanagement", "AccountListing")";');
}
else {
CreateErrorMessage(data.Message);
}
});
}
Controller:
public JsonResult StoreLevelPlanning_Post(string actionType) // actionType is Save or Submit
{
// message to return to the view on success
string successMessage = "";
var model = new VM_StoreLevelPlanning();
TryUpdateModel(model);
try
{
if (ModelState.IsValid)
{
model.buttonPressed = actionType;
repo.UpdateCLPCategoryAndRemark(model);
//Render different message depending on ActionType
if (actionType == "Save")
{
successMessage = "Your plan was saved. You will now be directed to the Listing Screen";
}
else if (actionType == "Submit")
{
successMessage = "Your plan has been submitted. You will now be directed to the Listing Screen.";
}
else
{
//return RedirectToAction("storemanagement", "AccountListing");
// need to revisit to figure out if this can be removed
throw new Exception("Else case happened");
}
}
else
{
if (actionType == "Save")
{
// TODO : change this to throw an error so that the ErrorLog class is utilized
throw new Exception("Your plan was not saved. Please retry.");
}
else
{
// TODO : change this to throw an error so that the ErrorLog class is utilized
throw new Exception("Your plan was not submitted. Please retry.");
}
}
}
catch (Exception e)
{
return Json(JsonResponseFactory.ErrorResponse(e.Message));
}
return Json(JsonResponseFactory.SuccessResponse(successMessage));
}
I'm open to any suggestions since I'm new to MVC. The idea is to put out a successful save message and redirect the user to the Listing page. But he way I changed the code now the view model is empty. It does not use a form collection. The data is in a list in the view model.
Thank you in advance...

Recommended way to handle http errors inside my asp.net mvc 5 web application

i need a way to globally handle http errors inside my asp.net mvc web application. i did the following if the call to the action method is Ajax :-
$(document).ready(function () {
$(document).ajaxError(function (e, xhr, textStatus, errorThrown) {
if (xhr.status == 401)
window.location = "/Account/Login";
else if (xhr.status == 403 || xhr.status == 404)
alert(xhr.statusText, 'Error');
$(".loadingimage").hide();
});
where my action method looks as follow:-
[CheckUserPermissions(Action = "Edit", Model = "Skill")]
public async Task<ActionResult> DeleteKBLink(int? skillid,int? linktokbid)
{
if (skillid == null || linktokbid==null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var linktokb= await unitofwork.SkillRepository.FindLinkToKB(linktokbid.Value);
if (linktokb == null)
{
return new HttpStatusCodeResult(404, "The link has already been deleted.");
}
but i am not sure how i can handle the http errors in-case the request is not ajax ? currently i will be redirected to http not found page .. thnaks
This solution works well for me...
[1]: Remove all 'customErrors' & 'httpErrors' from Web.config
[2]: Check 'App_Start/FilterConfig.cs' looks like this:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
}
[3]: in 'Global.asax' add this method:
public void Application_Error(Object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
Server.ClearError();
var routeData = new RouteData();
routeData.Values.Add("controller", "ErrorPage");
routeData.Values.Add("action", "Error");
routeData.Values.Add("exception", exception);
if (exception.GetType() == typeof(HttpException))
{
routeData.Values.Add("statusCode", ((HttpException)exception).GetHttpCode());
}
else
{
routeData.Values.Add("statusCode", 500);
}
Response.TrySkipIisCustomErrors = true;
IController controller = new ErrorPageController();
controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
Response.End();
}
[4]: Add 'Controllers/ErrorPageController.cs'
public class ErrorPageController : Controller
{
public ActionResult Error(int statusCode, Exception exception)
{
Response.StatusCode = statusCode;
ViewBag.StatusCode = statusCode + " Error";
return View();
}
}
[5]: in 'Views/Shared/Error.cshtml'
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = (!String.IsNullOrEmpty(ViewBag.StatusCode)) ? ViewBag.StatusCode : "500 Error";
}
<h1 class="error">#(!String.IsNullOrEmpty(ViewBag.StatusCode) ? ViewBag.StatusCode : "500 Error"):</h1>
//#Model.ActionName
//#Model.ContollerName
//#Model.Exception.Message
//#Model.Exception.StackTrace

ASP.NET MVC Ajax Error returning view instead of ajax

I'm making an ASP.NET MVC call to a method via AJAX and the error throws an exception. I'd like the message of the exception to be passed back to the client, and I'd prefer not to have to catch the exception. Something like this:
[HttpPost]
public ActionResult AddUser(User user) {
if (UserIsValid(user)) {
return Json(new { resultText = "Success!" });
}
throw new Exception("The user was invalid. Please fill out the entire form.");
}
I'm seeing in my firebug response an HTML page
<!DOCTYPE html>
<html>
<head>
<title>"The user was invalid. Please fill out the entire form."</title>
.....
I'd like to not be forced to use a try catch block to do this. Is there a way to automatically get the jQuery $(document).ajaxError(function () {} to read in this exception message? Is this bad practice? Can I override the controller OnException? Or do I have to try/catch and return JSON?
Something like this would be nice:
$(document).ajaxError(function (data) {
alert(data.title);
});
You can do this with a custom filter:
$(document).ajaxError(function(event, jqxhr) {
console.log(jqxhr.responseText);
});
-
[HttpPost]
[CustomHandleErrorAttribute]
public JsonResult Foo(bool isTrue)
{
if (isTrue)
{
return Json(new { Foo = "Bar" });
}
throw new HttpException(404, "Oh noes...");
}
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
var exception = filterContext.Exception;
var statusCode = new HttpException(null, exception).GetHttpCode();
filterContext.Result = new JsonResult
{
JsonRequestBehavior = JsonRequestBehavior.AllowGet, //Not necessary for this example
Data = new
{
error = true,
message = filterContext.Exception.Message
}
};
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = statusCode;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
Somewhat inspired by this blogpost: http://www.prideparrot.com/blog/archive/2012/5/exception_handling_in_asp_net_mvc
Rather than handle an exception that was raised by the server, why not have a flag in the JSON response?
[HttpPost]
public ActionResult AddUser(User user) {
if (UserIsValid(user)) {
return Json(new { success = true, resultText = "Success!" });
}
return Json(new { success = false, resultText = "The user was invalid. Please fill out the entire form." });
}

How do I retain navigation elements after ModelState.IsValid fails?

I have the following pair of controller methods for Editing.
The initial call is no problem, and correctly displays the model and properties from two of the child/navigation objects (1:1 relationships).
When I try to save, if the model is valid there is no problem.
When it is Invalid though, I get a null reference in my view referencing any of the child/navigation properties - which were correctly there in the original view.
public ActionResult Edit(int id)
{
var reportcustomerlimit = db.ReportCustomerLimits.Single(r => r.Id == id);
return View(reportcustomerlimit);
}
[HttpPost]
public ActionResult Edit(ReportCustomerLimit reportcustomerlimit)
{
if (ModelState.IsValid)
{
db.ReportCustomerLimits.Attach(reportcustomerlimit);
reportcustomerlimit.ReportCustomer.Verified = false;
ReportGenerator.ClearAllReportsZip();
db.ObjectStateManager.ChangeObjectState(reportcustomerlimit, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index", new { id = reportcustomerlimit.CustomerNumber });
}
else
{
//What do I do here?
}
return View(reportcustomerlimit);
}
What am I missing?
(Note: The validation is normally done client side, and stops the form being submitted - but I've turned off javascript to test the server side validation works as well)
Try this code:
[HttpPost]
public ActionResult Edit(ReportCustomerLimit reportcustomerlimit)
{
if (ModelState.IsValid)
{
db.ReportCustomerLimits.Attach(reportcustomerlimit);
reportcustomerlimit.ReportCustomer.Verified = false;
ReportGenerator.ClearAllReportsZip();
db.ObjectStateManager.ChangeObjectState(reportcustomerlimit, EntityState.Modified);
db.SaveChanges();
return RedirectToAction("Index", new { id = reportcustomerlimit.CustomerNumber });
}
else
{
var reportcustomerlimit = db.ReportCustomerLimits.Single(r => r.Id == id);
return View(reportcustomerlimit);
}
}
Hope it helps.

Resources