Hello Stackoverflow people,in my mvc project i have static class where i load static data then using it in controllers.
public class StaticData
{
public static List<ITEM_TYPES> _itemTypes ;
public static void LoadData()
{
try
{
using (pfservicereference.Service1Client ctx = new Service1Client())
{
_itemTypes = ctx.GetItemTypes();
}
}
catch (Exception ex)
{
throw new HttpException(500,ex.Message);
}
}
}
But how to redirect to Custom Error Page If i have HttpException Here?
I Have set customErrors mode="On" But it didnt helps.Is there any way to Redirect?
You can redirect to custom error page using following approaches,
Approach 1:
You can use try catch block inside action method and redirect to custom error page.
public ActionResult Index()
{
try
{
//Code logic here
}
catch (HttpException ex)
{
if (ex.ErrorCode == 500)
return RedirectToAction("error", "error");
}
return View();
}
Approach 2:
You can use exception filter for catching errors in application level, based on the error code we can redirect to custom error pages.
For this approach you can create separate exception filter class and mapped application level in global.asax or controller level.
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.Exception is HttpException)
{
HttpException exception = filterContext.Exception as HttpException;
if (exception.ErrorCode == 600)
filterContext.Result = new RedirectToRouteResult(new RouteValueDictionary
{
{ "action", "Error" },
{ "controller", "Error" }
});
filterContext.ExceptionHandled = true;
}
}
Related
I have a .NET appplication where there is a controller for receiving user requests, a service Service 1 which calls another service Service 2.
I have some code in the Service 2 where I query the database(DynamoDB) and get a 500 error in response when the user request values are incorrect. I want to handle this such that I catch this error/exception and send back the error message along with a 400 status code from the controller to the user. How should I modify the code to do this?
This is what I have tried. Currently, I'm just printing the error in Service 1 but I need to send it to the controller. Is sending the error message to the controller by throwing exceptions along the way the right way to do it?
The below code is similar to the actual code
Controller:
[HttpGet]
[Authorize(Policy = "Read-Entity")]
[Route("byParams/{param1}/{param2}")]
[Produces(typeof(DynamoResult<EntityResponse>))]
public async Task<IActionResult> ListByParams([FromQuery] DynamoQuery entityQuery)
{
try
{
return await HandleRequest(async () =>
{
return Ok((await _entityStore.ListByParams(entityQuery)));
});
}
catch (Exception e)
{
return BadRequest(e.Message);
}
}
Service 1:
public async Task<DynamoResult<EntityResponse>> ListByParams(DynamoQuery entityQuery)
{
results = new DynamoResult<Entity>();
try {
results = await GetPagedQueryResults(entityQuery);
}
catch (Exception e) {
Console.WriteLine(e);
}
return new DynamoResult<EntityResponse>
{
Data = results.Data.Select(_mapper.Map<EntityResponse>).ToList(),
};
}
Service 2:
private async Task<DynamoResult<TResponse>> GetPagedQueryResults(DynamoQuery query)
{
var results = new List<Document>();
try{
results = await search.GetNextSetAsync();
}
catch(Exception e){
throw new PaginationTokenException(e.Message);
}
return results;
}
[Serializable]
public class PaginationTokenException : Exception
{
public PaginationTokenException() { }
public PaginationTokenException(string message)
: base(message) {
throw new Exception(message);
}
public PaginationTokenException(string message, Exception inner)
: base(message, inner) { }
}
Assuming you want to hide implementation details from the controller (i.e. you don't want the controller to know/care that it's DynamoDB), I would create a custom exception and throw that from Service1.
Service1 would look something like this:
public async Task<DynamoResult<EntityResponse>> ListByParams(DynamoQuery entityQuery)
{
results = new DynamoResult<Entity>();
try {
results = await GetPagedQueryResults(entityQuery);
}
catch (Exception e) {
throw new MyCustomException('My error message', e);
}
return new DynamoResult<EntityResponse>
{
Data = results.Data.Select(_mapper.Map<EntityResponse>).ToList(),
};
}
In the controller you can then capture that exception explicitly:
[HttpGet]
[Authorize(Policy = "Read-Entity")]
[Route("byParams/{param1}/{param2}")]
[Produces(typeof(DynamoResult<EntityResponse>))]
public async Task<IActionResult> ListByParams([FromQuery] DynamoQuery entityQuery)
{
try
{
return await HandleRequest(async () =>
{
return Ok((await _entityStore.ListByParams(entityQuery)));
});
}
catch (MyCustomException e)
{
return BadRequest(e.Message);
}
}
Sorry if this is a duplicate question. However, I've tried looking for the answer and can't seem to find it.
Is there a way in ASP.NET to redirect to a page when a specific error occurs (in my case, when the request is too large). This needs to be just when the error occurs on a specific page, and not just on any page.
Thanks in advance!
As ADyson says in the comments, perhaps a try - catch block could be used for this situation.
try
{
// put the code that you want to try here
}
catch(Exception specificException)
{
return RedirectToAction(actionName, controllerName, routeValues);
}
Let me know if this helps.
Yes! there is as follows:
In the Global.asax file:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
HttpException httpException = exception as HttpException;
if (httpException != null)
{
if (httpException.GetHttpCode() == 404)
{
Server.ClearError();
Response.Redirect("~/Home/PageNotFound");
return;
}
}
//Ignore from here if don't want to store the error in database
HttpContextBase context = new HttpContextWrapper(HttpContext.Current);
RouteData routeData = RouteTable.Routes.GetRouteData(context);
string controllerName = null;
string actionName = null;
if (routeData != null)
{
controllerName = routeData.GetRequiredString("controller");
actionName = routeData.GetRequiredString("action");
}
ExceptionModel exceptionModel = new ExceptionModel()
{
ControllerName = controllerName ?? "Not in controller",
ActionOrMethodName = actionName ?? "Not in Action",
ExceptionMessage = exception.Message,
InnerExceptionMessage = exception.InnerException != null ? exception.InnerException.Message : "No Inner exception",
ExceptionTime = DateTime.Now
};
using (YourDbContext dbContext = new YourDbContext())
{
dbContext.Exceptions.Add(exceptionModel);
dbContext.SaveChanges();
}
// Ignore till here if you don't want to store the error on database
// clear error on server
Server.ClearError();
Response.Redirect("~/Home/Error");
}
Then in the controller:
public class HomeController : Controller
{
[AllowAnonymous]
public ActionResult Error()
{
return View();
}
[AllowAnonymous]
public ActionResult PageNotFound()
{
return View();
}
}
Here is everything you need to handle error in ASP.NET MVC Application.You can also customize according to your personal preference.
I have a global exception filter named LogErrorAttribute:
public class LogErrorAttribute : IExceptionFilter
{
private ILogUtils logUtils;
public void OnException(ExceptionContext filterContext)
{
if (this.logUtils == null)
{
this.logUtils = StructureMapConfig.Container.GetInstance<ILogUtils>();
}
this.logUtils.LogError(HttpContext.Current.User.Identity.GetUserId(), "Unknown error.", filterContext.Exception);
}
}
It's registered along with the standard HandleErrorAttribute filter:
filters.Add(new LogErrorAttribute());
filters.Add(new HandleErrorAttribute());
I'm registering those filters like this:
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
I also have an Application_Error fallback:
protected void Application_Error()
{
var exception = Server.GetLastError();
Server.ClearError();
var httpException = exception as HttpException;
//Logging goes here
var routeData = new RouteData();
routeData.Values["controller"] = "Error";
routeData.Values["action"] = "Index";
if (httpException != null)
{
if (httpException.GetHttpCode() == 404)
{
routeData.Values["action"] = "NotFound";
}
Response.StatusCode = httpException.GetHttpCode();
}
else
{
Response.StatusCode = 500;
}
// Avoid IIS7 getting involved
Response.TrySkipIisCustomErrors = true;
// Execute the error controller
if (exception != null)
{
this.errorLogger.Log(LogLevel.Error, "An unknown exception has occurred.", exception);
}
else if (httpException != null)
{
this.errorLogger.Log(LogLevel.Error, "An unknown HTTP exception has occurred.", httpException);
}
else
{
this.errorLogger.Log(LogLevel.Error, "An unknown error has occurred.");
}
}
Now, I have an API controller that grabs some data from the database and then uses AutoMapper to map the models to view models:
var viewModels = AutoMapper.Mapper.Map(users, new List<UserViewModel>());
Inside that AutoMapper configuration a custom resolver executes for one of the properties:
var appModuleAssignments = this.appModuleAssignmentManager.Get(userId);
var appModules = appModuleAssignments.Select(x => this.appModuleManager.Get(x.AppModuleId));
return AutoMapper.Mapper.Map(appModules, new List<AppModuleViewModel>());
At the moment I'm forcing the appModuleManager.Get statement to throw a regular exception:
throw new Exception("Testing global filter.");
This subsequently throws an exception in AutoMapper, both of which are unhandled, however neither the global filter or the Application_Error are picking up this exception.
What did I do wrong here?
A couple things I have done since posting:
Added the customErrors attribute to the Web.config to turn them on.
Removed the HandleErrorAttribute global filter because I realized it was setting the error to handled if it were even running. I would not expect it to be executing anyway because this error occurs outside the controller, but it would have likely bit me later.
The short answer is that you are adding a MVC Exception Filter rather than a Web API Exception Filter.
Your implementation checks for ExceptionContext rather than HttpActionExecutedContext
public override void OnException(HttpActionExecutedContext actionExecutedContext)
Since the framework will raises a Http Exception rather than a MVC Exception, your OnException override method is not triggered.
So, a more complete example:
public class CustomExceptionFilter : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext actionExecutedContext)
{
message = "Web API Error";
status = HttpStatusCode.InternalServerError;
actionExecutedContext.Response = new HttpResponseMessage()
{
Content = new StringContent(message, System.Text.Encoding.UTF8, "text/plain"),
StatusCode = status
};
base.OnException(actionExecutedContext);
}
}
Another important step is to register your Global Web API Exception Filter in WebApiConfig.cs, in the Register(HttpConfiguration config) method.
public static void Register(HttpConfiguration config)
{
...
config.Filters.Add(new CustomExceptionFilter());
}
Dave Alperovich answer will solve your issue by using HttpActionExecutedContext
public override void OnException(HttpActionExecutedContext context)
However as you are trying to capture all possible exceptions your application might generate then apart from exception filters one should use message handlers as well. A detailed explanation can be find here - http://www.asp.net/web-api/overview/error-handling/web-api-global-error-handling.
In summary, there are a number of cases that exception filters can’t handle. For example:
Exceptions thrown from controller constructors.
Exceptions thrown from message handlers.
Exceptions thrown during routing.
Exceptions thrown during response content serialization
So, If an unhandled error occurs from anywhere within the application, your Exception Handler will catch it and allow you to take specific action.
//Global exception handler that will be used to catch any error
public class MyExceptionHandler : ExceptionHandler
{
private class ErrorInformation
{
public string Message { get; set; }
public DateTime ErrorDate { get; set; }
}
public override void Handle(ExceptionHandlerContext context)
{
context.Result = new ResponseMessageResult(context.Request.CreateResponse(HttpStatusCode.InternalServerError,
new ErrorInformation { Message="An unexpected error occured. Please try again later.", ErrorDate=DateTime.UtcNow }));
}
}
I'm using Visual Studio 2010 and MVC 4 for my web application. This is my controller code:
public ActionResult MyController()
{
if (Request.IsAjaxRequest())
{
using (MyContainer context = new MyContainer())
{
try
{
var result = Some Query;
return PartialView("_MyView", result);
}
catch (Exception ex)
{
}
}
}
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Home", new { area = "User" });
}
else
{
return Redirect("/");
}
}
This method will be done successfully, But my ajax container not showing any things. In firebug this error raised:
NetworkError: 500 Internal Server Error + http://localhost....?X-Requested-With=XMLHttpRequest
Why does this error occur?
What do I do to solve this problem?
Thanks in advance!
The 500 Internal Server Error message might be seen in any number of ways because something was not processed fine on the server. In your case, as the commends, your MyContainer type does not implement IDisposable interface, so, you cannot use this type on the using(){ } block. When you use a type on a using block, this type have to implement IDIsposable because when it get over, the .Net Framework will remove the instance from the heap and the reference. I did some changes on your code without using block. Take a look:
public ActionResult ActionName()
{
if (Request.IsAjaxRequest())
{
try
{
MyContainer context = new MyContainer();
var result = Some Query;
return PartialView("_MyView", result);
}
catch (Exception ex)
{
// return some partial error that shows some message error
return PartialView("_Error");
}
}
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Index", "Home", new { area = "User" });
}
return Redirect("/");
}
Okay, so I am trying to get my controller to go to the Error.cshtml under the Shared folder on error. I've got the filter configured at startup:
Global.asax
protected void Application_Start()
{
...
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
...
}
FilterConfig.cs
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
HomeController.cs
[HandleError(View = "Error")] <---- I have the HandleError attribute
public class HomeController : Controller
{
IDbConnection _connection = new SqlConnection(ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString);
[Authorize]
public ActionResult Index()
{
// get the users current events
try
{
ViewBag.UserEvents = _connection.Query<MyEvents>("select ...)", new { });
}
catch (Exception ex)
{
throw new HttpException(500, ex.Message);
}
return View();
}
...
}
And so when the Index method is throwing an exception because I didn't open the connection, it just gives me the default ASP.NET exception page. What did I miss here?
Thanks!
Are you by any chance running this on your local machine? HandleError by default doesn't show errors on the local machine if you have customErrors set to Off or RemoteOnly. Set it to On.