Do I need to wrap my code with try...catch statements if I use ELMAH?
I have the following code:
namespace ElmahTestApp.Controllers
{
public class HomeController : Controller
{
//
// GET: /Home/
public ActionResult Index()
{
try
{
DateTime date = DateTime.Parse("asdasdasd");
}
catch (Exception ex)
{
}
return View();
}
}
}
The view shows up (as expected) however the exception does not get logged. Any suggestions? THanks in advance!
If you want your code to handle exceptions gracefully (eg, fallback to something else), you still need catch blocks.
Look at ErrorSignal. In your case, you'd do something like
catch (Exception ex)
{
Elmah.ErrorSignal.FromCurrentContext().Raise(ex);
}
Related
I am using micronaut with sqlite db in my appliation and service class method looks like this:-
private void loadListIntoDb(Stream<EmpDto> lines) {
try {
empRepository.deleteAll();
lines.forEach(empRepository::saveEmpList);
} catch (Exception ex) {
throw new RuntimeException("error while loading file into db", ex);
}
}
What I want is if saveEmpList get failed, all the deleted data by deleteAll method should also get reverted back.
I have tried like this to test but it didn't rolled back the deleted items:
#Transactional
private void loadListIntoDb(Stream<EmpDto> lines) {
try {
empRepository.deleteAll();
throw new Exception("test exception");
} catch (Exception ex) {
throw new RuntimeException("error while loading file into db", ex);
}
}
Is there anything that I am missing.
Regards,
Finally resolved it. We can't make a private method transactional in Micronaut. We need to make the method as public.
I am working on spring rest api and I would like to sure everything is working fine. I would like to log abnormal behaviors database connection error among others, I'm working with couchbase database and I'm getting in the endpoint response for example for this kind of exception: CouchbaseQueryExecutionException the next message: Unable to execute query due to the following n1ql errors: \n{\"msg\":\"No index available on keyspace kids_club that matches your query. Use CREATE INDEX or CREATE PRIMARY INDEX to create an index, or check that your expected index is online.\",\"code\":4000} and a very long trace.
For this i found a solution on internet that is extend ResponseEntityExceptionHandler and override handleExceptionInternal method like this:
#ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler {
private static String DEFAULT_VALIDATION_ERROR_CODE = "KC-0020";
#ExceptionHandler(MiddlewareException.class)
protected ResponseEntity<ResponseBody> handleKidsClubException(MiddlewareException ex) {
return buildErrorResponse(HttpStatus.valueOf(ex.getHttpStatus()), ex.toError());
}
#ExceptionHandler(ServiceUnavailableException.class)
protected ResponseEntity<ResponseBody> handleServiceUnavailable(ServiceUnavailableException ex) {
return buildErrorResponse(INTERNAL_SERVER_ERROR, ex);
}
#ExceptionHandler(NoSuchElementException.class)
protected ResponseEntity<ResponseBody> handleNoFoundElement(NoSuchElementException ex) {
return buildErrorResponse(NOT_FOUND, ex);
}
#ExceptionHandler(CouchbaseQueryExecutionException.class)
protected ResponseEntity<ResponseBody> handleCouchbaseQueryException(ConstraintViolationException ex) {
return buildErrorResponse(BAD_REQUEST, ex);
}
}
But I'm not able to catch any kind of Internal Server Error in this way.
It seems like spring is handle and building the final message to the user.
Any ideas to resolve this?
Thanks.
#ExceptionHandler(NullPointerException.class)
public final ResponseEntity<Object> handleNullPointerException(NullPointerException ex, WebRequest request) {
LOGGER.info("Entering into the handleAllException method");
System.out.println("Exception is : " + ex.getClass());
ResponseData error = new ResponseData();
error.setRespCode(HttpStatus.NOT_FOUND.toString());
error.setRespMessage(ex.getLocalizedMessage());
error.setTimestamp(LocalDateTime.now());
return new ResponseEntity(error, HttpStatus.INTERNAL_SERVER_ERROR);
}
please try this way below to check whether you are able to catch exception or not.. From the sysout you will get the exact exception. Then you can use that exception to catch any particular exception from that business logic..
I was looking for a way to redirect to an error page in a method that has no mapping / direct request, but is called from a method with one.
Example:
// Calling method
#GetMapping("/")
public String listUploadedFiles() {
doSomething(); // redirect if error must happen in side this method!
return "uploadForm";
}
// Method where redirection should happen
public void doSomething()
{
try {
// try some code here
} catch(Exception e) {
// call a method which redirects to an error page
}
}
The method above is called from a method which has a mapping, I want to redirect to an error directly in the method where the exception occurs. Is this possible with spring boot?
You can use #ExceptionHandler like in
#GetMapping("/")
public String listUploadedFiles() {
doSomething(); // redirect if error must happen in side this method!
return "uploadForm";
}
public void doSomething() {
try {
// try some code here
} catch(Exception e) {
throw new YourException();
}
}
#ExceptionHandler(YourException.class)
public String handleYourException(YourException e) {
return "errorPage";
}
Is there any way of overriding the error message logged by Elmah without duplicating it?
I have a custom exception class:
public class BusinessException : Exception
{
// detailed error message used for logging / debugging
public string InternalErrorMessage { get; set; }
public BusinessException(string message, string internalMessage)
:base(message)
{
InternalErrorMessage = internalMessage;
}
}
From the code, i throw an exception like this:
string detailedErrorMessage = string.Format("User {0} does not have permissions to access CreateProduct resource", User.Identity.Name);
throw new BusinessException("Permission denied", detailedErrorMessage);
When Elmah logs the error, it only logs Permission denied message. However, i need to log the InternalErrorMessage property of the exception instead.
I've tried to create a custom HandleErrorAttribute to do this, but this duplicates the exceptions logged:
public class ErrorHandleAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext.ExceptionHandled == true)
return;
Exception exception = filterContext.Exception;
BusinessException businessException = exception as BusinessException;
if (businessException != null)
{
ErrorSignal.FromCurrentContext().Raise(new Exception(businessException.InternalErrorMessage, exception));
}
}
}
I think your issue might be here:
if (businessException != null) {
ErrorSignal.FromCurrentContext().Raise(
new Exception(businessException.InternalErrorMessage, exception));
}
When you create a new exception rather than something like this:
if (businessException != null) {
ErrorSignal.FromCurrentContext().Raise(businessException));
}
I have this done the code for one of my sites and can see if I can recreate your issue later today (assuming this does not work). I think this is the SO post that helped me implement: How to get ELMAH to work with ASP.NET MVC [HandleError] attribute?
Edit:
Re-reading your question and the other answer I realize I was trying to solve your attempted correction and not the actual problem. Have you tried something like this solution which is only a slight deviation from your current attempt:
public override void OnException(ExceptionContext filterContext) {
if (filterContext.ExceptionHandled == true) {
return;
}
Exception exception = filterContext.Exception;
BusinessException businessException = exception as BusinessException;
if (businessException != null) {
var customEx = new Exception(
businessException.InternalErrorMessage, new BusinessException());
ErrorSignal.FromCurrentContext().Raise(customEx);
return;
}
}
Check that the InternalErrormessage is returning what you expect, and I expect that forcing a return here will prevent the exception from being logged twice. Otherwise it is essentially what you had done.
I suspect you'll need to create your own errorlog implementation to log anything other than the standard properties. This shouldn't be too difficult.
Using the SqlErrorLog as an example, you only need to override the log method & put in your own logic to modify what the Error class contains before calling the base implementation.
Using what #Matthew has also said will stop you logging the exception twice.
All the source code is here
I am going to be using Session["firmaid"] quite alot in my application. This value is set when someone logs in to my system.
If something happens, and this value is lost from the Session, i would like to somehow have a global method that will get it, if it throws a NullReferenceException.
How can i do this?
Currently, my solution is to try and catch every time i use Session["firmaid"], then execute the method that will put firmaid in the Session, if it throws an Exception.
Is there an easier way to do this?
Instead of try/catching everytime you could wrap the access to the session in a strongly typed class and then access the session through this wrapper.
Or even write an extension method:
public static class SessionExtensions
{
public static string GetFirmaId(this HttpSessionStateBase session)
{
var firmaid = session["firmaid"] as string;
if (string.IsNullOrEmpty(firmaid))
{
// TODO: call some method, take respective actions
}
return firmaid;
}
}
and then in your code instead of:
try
{
var firmaid = Session["firmaid"];
// TODO: do something with the result
}
catch (Exception ex)
{
// TODO: call some method, take respective actions
}
use:
var firmaid = Session.GetFirmaId();
// TODO: do something with the result
Why not simply write a static wrapper around this? Much more robust and more DRY:
public static int GetFirmaid() {
if (HttpContext.Current.Session["firmaid"] == null) {
//do something to fall back
}
return HttpContext.Current.Session["firmaid"]
}
You obviously would have to put this in a Class you can easily access and then call it through:
Class.GetFirmaid()
You can create an action filter which will ensure that Session["firmaid"] has a value:
public class SetFirmaIdAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
try
{
var firmaId = Session["firmaid"];
}
catch (Exception ex)
{
// pass filterContext if you need access to Request, Session etc.
Session["firmaid"] = SetFirmaId(filterContext);
}
}
private int SetFirmaId(ActionExecutingContext filterContext)
{
// TODO: implement some logic
}
}
OnActionExecuting will be called before action executes so you will already have Session["firmaid"] set when the action gets executed.
Once you implement this attribute you can put it on an action, controller or set it as global.