I am deleting things like this:
[Transaction]
[AcceptVerbs(HttpVerbs.Post)]
public RedirectToRouteResult DeleteQualitativeGlobalFeatureValue(string Id)
{
try
{
BlaService.DeleteBla(Id);
}
catch (Exception e)
{
ModelState.AddModelError("Exception", e.Message);
}
return RedirectToAction("Bladibla", new { Id = FeatureId });
}
However, if something is ’illegally’ deleted (e.g. causing the violation of a referential constraint) I get a horrible exception which is not caught by my try catch block. I presume this has to do with the [Transaction] attribute. How can I avoid this to catch ANY exceptions in the controller method?
Thanks.
Best wishes,
Christian
This is because actual commit and database-side validation happens on transaction commit.
You can use your own, slightly modifed version of the Sharp attribute.
public class TransactionAttribute: ActionFilterAttribute
{
private TransactionAttributeHelper helper = new TransactionAttributeHelper();
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
helper.BeginTransaction();
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
try
{
// notice that I rollback both on exception and model error, this helps a lot
helper.FinishTransaction(filterContext.Exception == null &&
filterContext.Controller.ViewData.ModelState.IsValid);
}
catch (Exception ex)
{
// here add ModelError, return error, or redirect
}
}
}
TransactionAttributeHelper is placed to .Data assembly to avoid NHibernate reference in .Controllers.
public class TransactionAttributeHelper
{
public void BeginTransaction()
{
NHibernateSession.CurrentFor(GetEffectiveFactoryKey()).BeginTransaction();
}
public void FinishTransaction(bool commit)
{
string effectiveFactoryKey = GetEffectiveFactoryKey();
ITransaction currentTransaction =
NHibernateSession.CurrentFor(effectiveFactoryKey).Transaction;
if (currentTransaction.IsActive)
{
if (commit)
{
currentTransaction.Commit();
}
else
{
currentTransaction.Rollback();
}
}
}
private static string GetEffectiveFactoryKey()
{
return NHibernateSession.DefaultFactoryKey;
}
}
Alternatively, of course, you can do transations without the attribute using repository.DbContext.BeginTransaction/Commit/etc methods and catch/process errors manually. But the above approach saves from a lot of such manual work.
You should look into an attribute that implements the IExceptionFilter interface. For example the System.Web.Mvc.HandleErrorAttribute can display an alternate view for an exception and gives that view access to the exception. You can also create your own attributes that implement IExceptionFilter if you want to handle things differently or log the exception using log4net or Elmah.
Having an IExceptionFilter attribute on the method will catch the exception even if the exception occurs in the TransactionAttribute's code.
Related
I am trying to login to our Application. When I input the username and the password and click login. It throws an error in the API. Saying: Incorrect Syntax near the keywoard 'IF'.
Here is the image for full exception details.
Full Exception Details
I tried to debug the solution and it starts from here:
[HttpGet]
[ActionName("checkUser")]
public HttpResponseMessage IsUserActive(string userNames)
{
try
{
var isActive = _userService.IsUserActive(userNames);
return Helper.ComposeResponse(HttpStatusCode.OK, isActive);
}
catch (Exception e)
{
throw e;
}
}
After this, it will then be redirected to this method/function:
public bool IsUserActive(string username)
{
try
{
var result = RetrieveAll().Where(x => x.Username.Equals(username));
return result.Any();
}
catch (Exception e)
{
throw e;
}
}
After this function, it will then be redirected to below function.
Then it will throw the exception in this line of code specifically in
return GetDbSet<User>().Where(x => x.DeleteFlag == false).OrderByPropertyName("LastName", SortDirection.Ascending);
public IQueryable<User> RetrieveAll()
{
try
{
return GetDbSet<User>().Where(x => x.DeleteFlag == false).OrderByPropertyName("LastName", SortDirection.Ascending);
}
catch (Exception e)
{
throw e;
}
}
GetDbSet Contains this line of code.
protected virtual DbSet<TEntity> GetDbSet<TEntity>() where TEntity : class
{
return Context.Set<TEntity>();
}
OrderByPropertyName Contains this line of code.
public static IQueryable<T> OrderByPropertyName<T>(this IQueryable<T> query, string attribute, SortDirection direction)
{
return ApplyOrdering(query, attribute, direction, "OrderBy");
}
I don't know what's wrong or where is that "IF" coming from or where should I edit for me to go proceed in logging in the application. I really appreciate your help. Thanks in advance.
I have an Error-view which should be loaded if an Exception occurs. The Error view is located in:
Views/Shared/Error.cshtml (See attached picture).
In my Controller, my try-and catch looks like this:
public IActionResult Device(string id, bool like, int type)
{
try
{
//code
return View(viewModel);
}
catch (Exception exe)
{
return View("Error", exe);
}
}
This works and the correct Error View is displayed. However, I have a ViewComponent which should display the same Error-view.
I have tried the following:
1) Copy the Error-file and pasted it in the same folder as my ViewComponent (Right beneath the Default view). This does not give me an error, but the Default-view is the one being loaded.
2) I have returned the Error view from the shared-folder in the following way:
return View("../../../Shared/Error");
This as well does not give errors, but the Default view is the one being loaded.
Any ideas on how to solve this?
EDIT
So far I have created a new class
public class HandleExceptionAttribute : ExceptionFilterAttribute
{
public override void OnException(ExceptionContext context)
{
var result = new ViewResult { ViewName = "Error" };
var modelMetadata = new EmptyModelMetadataProvider();
result.ViewData = new ViewDataDictionary(
modelMetadata, context.ModelState);
result.ViewData.Add("HandleException",
context.Exception);
context.Result = result;
context.ExceptionHandled = true;
}
}
And in my Error View I added this:
#{
ViewData["Title"] = "Error";
Layout = "_LayoutCustomer";
Exception ex = ViewData["HandleException"] as Exception;
}
And lastly, I added [HandleException] on top of my Controller:
[HandleException]
public class CustomerController : Controller
{
//All the actions...
}
To simulate a new Exception, I use:
public IActionResult Device(string id, bool like, int type)
{
try
{
throw new Exception();
//code
return View(viewModel);
}
catch (Exception exe)
{
throw;
}
}
This seems to work in the Controller-actions. How can I simulate if it works within the ViewComponent? It gives me an error when I do the same try-catch method.
Step 1 : - Create a Custom ExpectionFilter Attribute
public class CustomExpectionFilter : IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/Error.cshtml"
};
}
}
Step 2 :- Register CustomExpectionFilter in FilterConfig
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new CustomExpectionFilter());
}
}
Step 3 :- Change on
public IActionResult Device(string id, bool like, int type)
{
try
{
//code
return View(viewModel);
}
catch (Exception)
{
throw;
}
}
Now when ever error occur in application it will be calling CustomExpection Filter and this filter will handle error and display Error page.
I've got ErrorController which customly handles my website errors.
It's pretty standard:
public class ErrorController : BaseController
{
public ActionResult Error404(Exception ex)
{
return View();
}
public ActionResult Error500(Exception ex)
{
return View();
}
}
However, in case if some rendering exception occurs inside of the View code (and this might occur, as the page has Master page (master layout) and different might happen), then I am not able to catch that rendering exception.
I can really see that exception with implementing ActionFilterAttribute.OnResultExecuted:
public override void OnResultExecuted(ResultExecutedContext filterContext)
{
if (filterContext.Exception != null)
{
// not sure what to do here
} else base.OnResultExecuted(filterContext);
}
but in that case MVC looks for ~/Shared/Error.cshtml (incl. this path) after that exception occurs, and I can't provide the Errors view rendering exception to the user -- the "Last chance exception".
Is there any way to handle that?
Here is a nice article on Exception handling in ASP.Net MVC that should help
Method 4:- Inheriting from “HandleErrorAttribute”
public class CustomHandleErrorAttribute: HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
Exception ex = filterContext.Exception;
filterContext.ExceptionHandled = true;
var model = new HandleErrorInfo(filterContext.Exception, "Controller", "Action");
filterContext.Result = new ViewResult()
{
ViewName = "Error",
ViewData = new ViewDataDictionary(model)
};
}
}
And you attach that to your base controller.
public JsonResult Menu() { // Exception }
I need application not to redirect user to the 404 page, but return special JSON result like { "result":1 }.
I wonder, is there any another solution, not try-catching.
You can implement your own FilterAttribute similar to the HandleErrorAttribute.
The HandleErrorAttribute normally does a redirect when an error occurs, but you could implement a similar attribute that returns a JsonResult. Something like the following will do:
public class CustomHandleErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
if (filterContext == null)
{
throw new ArgumentNullException("filterContext");
}
filterContext.Result = new JsonResult
{
Data = new { result = 1 },
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
filterContext.ExceptionHandled = true;
}
}
And then
[CustomHandleError]
public JsonResult Menu()
{
throw new Exception();
}
I would recommend that you download the MVC source code from CodePlex and inspect the current implementation of HandleErrorAttribute. It is a lot more subtle than my crude implementation above and you may want some of its functionality.
I need something that would work like this:
public ActionResult Ac()
{
try {
//stuff...
}
catch(MyException ex)
{
//handle
}
}
but without putting try catch in each action method
You want to annotate your classes with HandleErrorAttribute - http://msdn.microsoft.com/en-us/library/system.web.mvc.handleerrorattribute.aspx.
If the functionality of the built in handler above isn't sufficient then you can define your own class which implements IExceptionFilter - the OnException method takes an ExceptionContext object with Result and HttpContext properties you can use to control the outcome, something like:
public class MyHandleErrorAttribute : FilterAttribute, IExceptionFilter
{
public void OnException(ExceptionContext filterContext)
{
Exception e = filterContext.Exception;
// Do some logging etc. here
if (!filterContext.ExceptionHandled && filterContext.HttpContext.IsCustomErrorEnabled)
{
ViewResult lResult = ...
filterContext.Result = lResult;
filterContext.ExceptionHandled = true;
filterContext.HttpContext.Response.Clear();
filterContext.HttpContext.Response.StatusCode = 500;
filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
}
}
Use Exception Filters for exception handling.
How about
[HandleError(ExceptionType = typeof(MyException ), View = "MyErrView"))]
public ActionResult Ac()
{
//stuff
}
but with a custom HandleError Attribute that handles the type of exceptions you are targeting. This SO question should give you a good start.