Problem: How to display exception detail (InnerException?) in my DbError view in MVC3
The code below produces a null reference when trying to display the InnerException.
<p>#Model.Exception.GetType().Name<br />
#Model.Exception.InnerException.Message.ToString()<br /> <!-- null reference! -->
thrown in #Model.ControllerName #Model.ActionName</p>
In my global.asax
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute
{
ExceptionType = typeof(DbException),
// DbError.cshtml is a view in the Shared folder.
View = "DbError",
Order = 2
});
code originally from http://community.codesmithtools.com/CodeSmith_Community/b/tdupont/archive/2011/03/01/error-handling-and-customerrors-and-mvc3-oh-my.aspx
Not all exceptions have an inner one. Make sure that the provided exception actually has an InnerException. If it doesn't, simply print out the details of the provided exception instead (which you generally should do, the InnerException simply details the error mentioned in the root exception).
Related
public class DefaultCountValidationInterceptor implements ValidateInterceptor
{
#Override
public void onValidate(final Object object, final InterceptorContext interceptorContext) throws InterceptorException
{
if (object instanceof BaseStoreModel)
{
final BaseStoreModel baseStoreModel = (BaseStoreModel) object;
if (baseStoreModel.getCount() < 0 || baseStoreModel.getCount() > 100)
{
throw new InterceptorException("Count should be between 0 and 100");
}
}
}
}
Interceptor Configuration:
<bean id="defaultCountValidationInterceptor"
class="se.istone.hybris.maersk.core.interceptors.DefaultCountValidationInterceptor " />
<bean id="defaultCountValidationInterceptorMapping"
class="de.hybris.platform.servicelayer.interceptor.impl.InterceptorMapping">
<property name="interceptor"
ref="defaultCountValidationInterceptor" />
<property name="typeCode" value="BaseStore" />
</bean>
Validation error message is displaying correctly in Hybris5.4 HMC, but
its not workinig in Hybris 6.7(1905) Backoffice
You are always getting default message due OOTB code in ModelSavingExceptionTranslationHandler.toString().
public class ModelSavingExceptionTranslationHandler extends ModelExceptionTranslationHandler {
public static final String I18N_UNEXPECTED_UPDATE_ERROR = "unexpected.update.error";
public boolean canHandle(Throwable exception) {
return exception instanceof ModelSavingException
|| exception instanceof ObjectSavingException && exception.getCause() instanceof ModelSavingException;
}
public String toString(Throwable exception) {
return this.getLabelByKey("unexpected.update.error");
}
}
When you are throwing InterceptorException Hybris internally throws ModelSavingException with your InterceptorException as Cause.
Backoffice exception are handled by ExceptionTranslationService, which contain list of Handlers to handle different kinds of Exceptions. For ModelSavingException, ModelSavingExceptionTranslationHandler is used.
Since OOTB Handler is straight up displaying default message, you can either override this class or you can create your own Exception Translation Handler and add it in the handlers list.
Documentation -> https://help.sap.com/viewer/5c9ea0c629214e42b727bf08800d8dfa/1905/en-US/8bc9570b86691014a901c290d2c5f107.html
It could be an error copying your code and configuration, but your InterceptorMapping there are errors with the bean ref, it is on capital letter
"DefaultCountValidationInterceptor "
instead of
"defaultCountValidationInterceptor "
Apart from that, you should remove the blank spaces at the end of the bean ids and class attributes of beans declared.
I've been trying to reproduce your error on 1905 Hybris OOTB code, but I cannot reproduce it, I tried it with the AddressValidator (which implement ValidatorInteceptor as well), getting the message from the exception shown on the error alert on backoffice:
Link to Backoffice address validation error alert image
The problem could be if an exception different from InterceptorException is thrown, like a nullPointerException, are you sure of having the count attribute filled an being not null?
It could be obvius, but if any of the attributes on the baseStore is changed, and then saved, the validation interceptor will be runned. My advice is checking nulls before accessing the count attribute for not getting an error, like:
if (baseStoreModel.getCount() !=null && (baseStoreModel.getCount() < 0 || baseStoreModel.getCount() > 100))
Doing the condition on this way will avoid the null problem, because if you're having the count attribute set to null, the condition will exit as soon as the first condition is evaluated as false (baseStoreModel.getCount() != null).
Another way to avoid the null error is having a defaultValue on your *-items.xml definition, adding a:
<defaultvalue>Integer.valueOf(0)</defaultvalue>
#JagadeeshKumar, as #Zaheer Attar has said on his answer https://stackoverflow.com/a/62415830/3346298 (really good point), you could have your own ModelExceptionTranslation Handler. But I would check, before customising anything, what is the error, I mean, what is the exception recieved on the
de.hybris.platform.platformbackoffice.services.handlers.ModelSavingExceptionTranslationHandler
Use a debug point there to check the content of the exception, the cause and even finding out if your message from your validator is there.
Once you know the exception you could know the real reason of why the OOTB TranslationHandler is not working as expected.
Developing a new Handler could not solve the root reason of the error which could create adjacent problems in the next future.
I tried, it works. Beside you overrided or create new handlers, you also need to add configuration like "remove" original handlers
I have an exception handling in my application very similar to this solution:
http://www.devcurry.com/2012/06/aspnet-mvc-handling-exceptions-and-404.html
There is a nasty bug in my app where it is possible for the sql to deadlock with an other process. This happens rarely (1-2 requests fail daily because of this), but it still happens.
How can I automatically refresh the page on sql deadlock (and hide the error this way from the end user on get requests)?
Can I do it in the Application_Error function? Or in the overridden OnException in HandleErrorAttribute?
EDIT:
I mocked up some code in the BaseController I created:
protected override void OnException(ExceptionContext filterContext)
{
Exception ex = filterContext.Exception;
SqlException sex = ex as SqlException;
if (sex != null && sex.Number == 1205)
{
Log.Error("Transaction deadlocked with the following exception:");
Log.Exception(sex);
//I need to write the logic that refreshes the page here.
}
else
{
Log.Error("Application error with the following exception:");
Log.Exception(ex);
}
base.OnException(filterContext);
}
I need help on the refresh part.
I would deal with it by overriding the OnException() method of the controller. It would be best if you inherit all your controllers from a custom base one in which the override is done to maintain uniformity and DRYness of the solution.
just add bellow code, before base.OnException(filterContext);
// Stop any other exception handlers from running
filterContext.ExceptionHandled = true;
I'm working on a team-project and I am in the following situation:
I created my own Exception class, and I want all the thrown exceptions of type myException to be handled and automatically redirected to the Error view where I would nicely display the error, which is ok to do. This is what I added in my Web.config:
<customErrors mode="On" defaultRedirect="Error" />
The issue is I want all the rest of the exceptions to be thrown normally, seeing all the information about it, including the stack trace, the source file and the line error, which would be really good for the team-project.
I've tried the [HandleError(ExceptionType=typeof(myException)], but it is no use.
I also tried to override the OnException function of the controller and if the exception is not myException then i would throw it again, but i still get in the Error view.
protected override void OnException(System.Web.Mvc.ExceptionContext filterContext)
{
if (filterContext.Exception.GetType() != typeof(myException)) {
throw filterContext.Exception;
}
base.OnException(filterContext);
}
Any idea which could work?
Thanks.
You may get the result you want by leaving custom errors Off (so that for all the errors you get the stack trace displayed), and redirecting the exceptions you want to the controller/view you need (so that a friendly-looking page will be displayed).
You could define a base controller for all your controllers, and override its OnException method with something like below:
if (filterContext.Exception.GetType() == typeof(YourCustomException))
{
filterContext.ExceptionHandled = true;
filterContext.Result = RedirectToAction("ActionName", "ControllerName", new { customMessage = "You may want to pass a custom error message, or any other parameters here"});
}
else
{
base.OnException(filterContext);
}
I have custom error handling defined for my application and it all works wonderfully - when a resource cannot be found, the correct 'NotFound' view renders. When an unhanlded exception occurs, the 'ServerError' view renders.
The problem I am facing is that my application insists on trying to find a View called 'Error' but doesn't find it, as i don't have one and thus this exception gets thrown during my custom error handling routine:
"The view 'Error' or its master was not found or no view engine supports the searched locations. The following locations were searched: ... "
I have an Application_Error event handler which does the logging of all unhandled exceptions:
protected void Application_Error(Object sender, EventArgs e)
{
Exception lastEx = Server.GetLastError();
// Attempt to Log the error
try
{
Utils.Logger.Error(lastEx);
}
catch (Exception loggingEx)
{
// Try and write the original ex to the Trace
Utils.TryTrace(lastEx.Message);
// Try and write the logging exception to the Trace
Utils.TryTrace(loggingEx.Message);
}
}
I have customErrors turned 'On' in my web.config:
<customErrors mode="On" defaultRedirect="blah">
<error statusCode="404" redirect="dee"/>
<error statusCode="500" redirect="blah"/>
</customErrors>
And i have routes defined in my Global.asax.cs RegisterRoutes method which correspond to the Redirect defined in web.config above:
routes.MapRoute(
"Error - 404",
"dee",
new { controller = "Error", action = "NotFound" }
);
routes.MapRoute(
"ServerError", // When this route is matched we want minimal error info displayed
"blah",
new { controller = "Error", action = "ServerError" }
);
I have a BaseController which contains an OnActionExecuted routine:
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
Logger.Info(String.Format(Constants.LOG_ACTION_EXECUTED, filterContext.Controller.ToString(), filterContext.ActionDescriptor.ActionName));
// Log any exceptions
if (filterContext.Exception != null)
{
Stack<string> messages = new Stack<string>();
Exception current = filterContext.Exception;
messages.Push(current.Message);
while (current.InnerException != null)
{
messages.Push(current.InnerException.Message);
current = current.InnerException;
}
StringBuilder result = new StringBuilder();
while (messages.Count != 0)
{
result.Append(messages.Pop());
string nextline = messages.Count > 0 ? "OUTER EXCEPTION " + messages.Count + ": " : "";
result.Append(Environment.NewLine);
}
Logger.Error(result.ToString());
}
base.OnActionExecuted(filterContext);
}
Is there somewhere else that the Framework defines which view to render in the event of an unhandled exception?
Is my custom error handling routine missing a final step which would ensure that the Framework no longer expects to find the 'Error' view???
You need to remove the HandleErrorAttribute handler in Global.asax.cs file. This attribute sets the view as Error. Then MVC runtime will not handle the exception and exception will propagate to Asp.Net runtime where it will use the customErrors section to display the page.
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute()); // remove this line
}
I had already removed the line which added the filter automatically to all Controllers...as suggested by Eranga - so that wasn't what was causing the Framework to search for the 'Error' view.
The problem i was experiencing was being caused by some left over [HandleError] attribute tags sitting on top of one of my Controllers.
So it is interesting to note that: despite the fact that my controller had the [HandleError] attribute decorated at the top of its class definition, my custom error handling routine, as defined in the web.config, was still being called - and was correctly rendering the required Views...
The framework error handling (as defined by the HandleErrorAttribute) would fail, my Application_Error would catch the Exception and silently log it to the Database via my 'Logger' instance...then my custom error handling routine would complete successfully.
I've implemented an ActionFilterAttribute responsible for NHibernate transaction management. Transactions are committed in the OnResultedExecuted override, which occasionally will result in an exception being thrown.
I'm able to successfully intercept these exceptions in the controllers OnException override, however the page still redirects as if the transaction were successful.
What I'd like to be able to do is return the same view action that caused the error with the exceptions message added to the ModelState.
I've tried a number of different things, none of which seem to work.. here's my latest attempt:
[HttpPost]
[Transaction]
[HandleError]
public ActionResult Enroll(EnrollNewEmployeeCommand command)
{
if(command.IsValid())
{
try
{
_commandProcessor.Process(command);
}
catch(Exception exception)
{
ModelState.AddModelError("", exception.Message);
return View(command);
}
return this.RedirectToAction(x => x.Index()); // redirects to index even if an error occurs
}
return View(command);
}
protected override void OnException(ExceptionContext filterContext)
{
//dont interfere if the exception is already handled
if (filterContext.ExceptionHandled)
return;
ModelState.AddModelError("", filterContext.Exception.Message);
filterContext.ExceptionHandled = true;
// want to return original view with updated modelstate
filterContext.Result = new ViewResult
{
ViewName = filterContext.RequestContext.RouteData.Values["action"].ToString(),
ViewData = filterContext.Controller.ViewData
};
}
What I'd like to be able to do is return the same view action that caused the error with the exceptions message added to the ModelState
You can't. OnResultedExecuted happens too late. The view rendering has ended and you can no longer modify what will be sent to the client at this stage.
Your last chance if you want to still be able to modify the returned result to the client is OnResultExecuting. So you could commit your transactions there. Wouldn't be so penalizing I guess.
At the contrary, I would even commit transactions in the OnActionExecuted event, as at this stage all you've got should be a fully initialized view models passed to the view for rendering. That's where your transaction boundaries should end. The process of rendering of the views should be excluded from any transactions and DB stuff. It's just HTML (or something) rendering from a view model, plain and simple.