I am trying to find a way to pass error messages back to my view from my controller.
public ActionResult Index()
{
ViewBag.splittingFileMessage = "Splitting File...";
ViewBag.startBatchMessage = "Start Batch Processing : ";
return View();
}
[HttpPost]
public ActionResult Index(HttpPostedFileBase file)
{
var numberRecordsPerFile = int.Parse(ConfigurationManager.AppSettings["NumberRecordsPerFile"]);
var inputFileFolder = ConfigurationManager.AppSettings["InputFileFolder"];
var batchSplitterClient = new SplitterServiceClient();
var batchSplitterResponse =
batchSplitterClient.SplitFile(new BatchSplitterRequest
{
FilePath = inputFileFolder,
NumberOfRecordsPerFile = numberRecordsPerFile
});
var numberOfMessages = batchSplitterResponse.NumberOfMessages;
if (batchSplitterResponse.Result.ResultCode == 200)
{
return RedirectToAction("Progress");
}
else
{
ViewBag.error = "test error";
return RedirectToAction("Index");
}
}
So you can see in my Httppost method I am trying to set an error message i.e. ViewBag.error if it occurs in my WCF call.
But in my view on initial load ofcourse this hasn't been set.
I my view I have
<div class="errors">
<%: ViewBag.error %>
</div>
But on initial page load the error comes up on ViewBag.error
The call is ambiguous between the following methods or properties: 'System.IO.TextWriter.Write(string, params object[])' and 'System.IO.TextWriter.Write(char[])'
[HandleError(View = "Error")]
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
int u = Convert.ToInt32("");// Error line
return View();
}
}
HandleError Attribute at Action Method Level
[HandleError(View = "Error")]
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
int u = Convert.ToInt32("");// Error line
return View();
}
Defining HandleError Attribute at Global Level
We can also apply the HandleError Attribute at the global level by registering it in the Global.asax in Application_Start event.
Example
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute(), 2); //by default added
filters.Add(new HandleErrorAttribute
{
View = "Error"
}, 1);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
RegisterGlobalFilters(GlobalFilters.Filters);
RegisterRoutes(RouteTable.Routes);
}
Error Page
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Error";
}
<h2>
Sorry, an error occurred while processing your request.
<br />
Error :
</h2>
<p>
#Model.Exception
</p>
Enabling Custom Error Handling
To enable custom error handling in the application by the HandleError attribute, we must add a CustomErrors element within the system.web section of web config.
Output
Catch Specific Type of Error
The ExceptionType property can help us to catch a specific type of error. For example, if we want to catch only an ApplicationException type of exception then we can define the ExceptionType.
[HandleError(ExceptionType = typeof(ApplicationException), View = "Error")]
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
int u = Convert.ToInt32(""); // Error line
return View();
}
User HandleErrorAttribute and Error Page or Elmah for Validation errors add to Modelstate and Use Error Page to look for Validation errors and display
If it answered your question, tick right mark on left side , to make it answered
Try casting it as a string
<div class="errors">
<%: (string)ViewBag.error %>
</div>
or ViewBag.error.ToString()
Related
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'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.
ASP.NET MVC3 view displays validation error if get request is invoked. How to show validation error only if post request is used like in MVC2 ?
View:
<%= Html.ValidationSummary(false, "Error") %>
Controller:
namespace Store.Controllers
{
public class CheckoutController : MyApp.Controllers.ControllerBase
{
[HttpGet]
public ActionResult Address()
{
return View(new AddressViewModel());
}
[HttpPost, ValidateAntiForgeryToken]
public ActionResult Address(AddressViewModel model, string name) {
if (!ModelState.IsValid)
return View(model);
return RedirectToAction("Payment");
}
}
}
I'm developing an ASP.NET MVC 3 project and I want to implement my custom error handling logic. I'm trying to this by extending HandleErrorAttribute like this :
public class ErrorHandlingAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (!filterContext.ExceptionHandled)
{
filterContext.Result = new JsonResult {
Data = new { success = false, error = filterContext.Exception.ToString() },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
filterContext.ExceptionHandled = true;
}
}
}
What I need is, after some AJAX calls, to show some error message (by rendering a partial view) on a modal popup dialog. So, in the OnException method, I set the ExceptionContext's result as a JsonResult (I'm not rendering the partialview to string right now, I'll do that later)
My controller action is like below (I have decorated it with my custom filter):
[HttpPost]
[ErrorHandling]
public JsonResult Create(StopEditViewModel viewModel)
{
Stop stop = Mapper.Map<StopViewModel, Stop>(viewModel.Stop);
if (ModelState.IsValid)
{
Stop addedStop = _testFacade.AddStop(stop);
return Json(new { success = true, tableContainer = _tableName }, JsonRequestBehavior.DenyGet);
}
return Json(new { success = false }, JsonRequestBehavior.DenyGet);
}
After doing some research, I found that I need to remove filters.Add(new HandleErrorAttribute()); line from the RegisterGlobalFilters method in Global.asax. I did that too.
My web.config file has <customErrors mode="On" /> tag.
But when I call the Create POST action, if an exception occurs, the custom filter method is not invoked. The application crashes. Am I missing something?
Thanks.
you can catch Exception OnFailure method in ajax option
In View
#using (Ajax.BeginForm("SomeAction", new AjaxOptions { OnFailure = "handleAjaxError" }))
{
}
function handleAjaxError(ajaxContext) {
alert("Request failed, status code ");
}
when you call action using Ajax it return within method.
I'm fairly new to ASP.NET MVC and am not sure how best to handle the following situation.
A method in my controller needs to load some data based on an ID argument. Under normal circumstances, this ID argument will be set to a valid ID of an entity within my database. I construct some data and place it in ViewBag, which the view uses to render the page.
However, I would like some basic error handling just in case the ID argument is not valid. Although I could write a bunch of error handling code in the view, it would be much simpler not to display the view if there is a major misuse or malfunction of the site.
Is there a way the controller could simply return a "Item not found" string or something like that, and display that rather than the normal view? Or perhaps someone can suggest a better idea?
if (itemId == null)
{
return Content("Item not found");
}
Or if you want to return an HTTP 404 instead:
throw new HttpException(404, "Item Not Found");
In case fetching model from database (as described in Darin's answer) is somehow complicated and cannot be made generic, this is how I deal with resources not found.
Implement your base controller
public abstract class MyBaseController : Controller
{
[NonAction]
protected virtual void EnsureResourceFound(object resource)
{
if (resource == null)
{
HttpStatusCode statusCode = HttpStatusCode.NotFound;
throw new HttpException((int)statusCode, statusCode.ToString());
}
}
}
And in derived controllers - use that method
[HttpGet]
public virtual ActionResult Edit(int id)
{
SomeModel model = null;
EnsureResourceFound(model = _someModelService.Get(id));
return View(question);
}
And what will you do with resulting http exception, return custom view, log the error, depends on configured HandleErrorAttribute.
You can do it by simply throwing exception from the Controller.
You need to write following code and need to add ErrorController and it's respective view.
Global.asax
Exception exception = Server.GetLastError();
Response.Clear();
HttpException httpException = exception as HttpException;
//Add controller name
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
//we will add controller's action name
routeData.Values.Add("action", "Index");
// Pass exception details to the target error View.
routeData.Values.Add("error", exception.Message);
// Clear the error on server.
Server.ClearError();
// Call target Controller and pass the routeData.
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
//and throw the exception from the Controller ny simply writing
throw new Exception()
ErrorController:
public class ErrorController : BaseController
{
#region Function Declaration
/// <summary>
/// Shows application error
/// </summary>
/// <param name="error">error description</param>
public ActionResult Index(string error)
{
ViewBag.Description = Resources.ErrorMessage.GeneralError;
if (string.IsNullOrEmpty(error))
{
ViewBag.DetailError = error;
}
else
{
ViewBag.DetailError = string.Empty;
}
return View("ErrorIndex");
}
#endregion
}
Another Approach :
If you want to write a view for a particular error than you have to write followig code. You have to just add DivByZero view.
[HandleError(View = "DivByZero", ExceptionType = typeof(System.DivideByZeroException))]
public ActionResult About()
{
List<Alok> alokList = new List<Alok>();
var al = from aa in alokList.Distinct()
select aa;
ViewData["Errorname"] = "Divide By Zero Exception";
ViewBag.ErrorName = "Divide By Zero Exception";
//throw new DivideByZeroException();
return View();
}
DivByZero View :
#model System.Web.Mvc.HandleErrorInfo
#{
ViewBag.Title = "Error";
Layout = "~/Views/Shared/_Layout.cshtml";
}
#*<h2>
#ViewData["Errorname"].ToString()
#ViewBag.ErrorName</h2>*#
<p>
Controller : #Model.ControllerName
</p>
<p>
Action : #Model.ActionName
</p>
<p>
Error Message : #Model.Exception
</p>
public ActionResult Foo(int id)
{
MyModel model = ...
if (model == null)
{
return HttpNotFound();
}
return View(model);
}
And since writing this same code over and over again in your actions could quickly become boring a better solution is to write a custom model binder which will fetch the model from the database and if not found will simply throw a new HttpException and set the status code to 404. Then your controller action will simply look like this:
public ActionResult Foo(MyModel model)
{
return View(model);
}
and the model binder itself:
public class MyModelBinder : IModelBinder
{
public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
{
var id = bindingContext.ValueProvider.GetValue("id");
if (id == null)
{
throw new HttpException(404, "Not found");
}
MyModel model = FetchTheModel(id.AttemptedValue);
if (model == null)
{
throw new HttpException(404, "Not found");
}
return model;
}
private MyModel FetchTheModel(string id)
{
throw new NotImplementedException();
}
}
This model binder could obviously be made more generic.