Custom Error Pages with ASP.NET MVC 5 and Elmah - asp.net-mvc-5

I am trying make work custom error page in asp mvc 5 but for some strange reason at moment to test my page, from elmah i am loging two errors ( the real error what i am testing and a error related with error page not found:
The view 'Error' or its master was not found or no view engine supports the searched locations. The following locations were searched:
~/Views/HotTowel/Error.aspx
~/Views/HotTowel/Error.ascx
~/Views/Shared/Error.aspx
~/Views/Shared/Error.ascx
~/Views/HotTowel/Error.cshtml
~/Views/HotTowel/Error.vbhtml
~/Views/Shared/Error.cshtml
~/Views/Shared/Error.vbhtml
I was looking into this url http://doingthedishes.com/2011/09/10/custom-errors-mvc-3-elmah.html, where the author had the same issue but with asp.net mvc 3. After read it, I tried remove the call to HandleErrorAttribute:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
//filters.Add(new HandleErrorAttribute());
}
}
But the issue is still there: i can see my custom page but asp.net mvc is throwing two exceptions.
Any help?
the solution is rewrite a class derived from HandleErrorAttribute ?
like this post: keep getting The view "Error" not found when using Elmah and asp.net mvc 4 ?

You can do the following from ELMAH.MVC 2.0.2 is out:
Set disableHandleErrorFilter to true:
<add key="elmah.mvc.disableHandleErrorFilter" value="true" />
Remove filters.Add(new HandleErrorAttribute()); from FilterConfig class:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
// filters.Add(new HandleErrorAttribute()); // <-- comment out
}
}

Here's a possible solution for you. I typically override the OnException method in a base controller class. filterContext.HttpContext.IsCustomErrorEnabled checks <customErrors> in the web.config. The showVerboseErrors variable is derived from a setting in the web.config.
protected override void OnException(ExceptionContext filterContext)
{
if (filterContext.HttpContext.IsCustomErrorEnabled)
{
//trigger elmah
Elmah.ErrorSignal.FromCurrentContext().Raise(filterContext.Exception);
//get the last elmah error
var errorList = new List<ErrorLogEntry>();
Elmah.ErrorLog.GetDefault(filterContext.HttpContext.ApplicationInstance.Context).GetErrors(0, 1, errorList);
var error = errorList.LastOrDefault();
//return the custom error page
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/Error.cshtml",
ViewData = new ViewDataDictionary() {
{ "ErrorDetails", showVerboseErrors && error != null ? filterContext.Exception.Message : null },
{ "ErrorId", error != null ? error.Id : null }
}
};
//stop further error processing
filterContext.ExceptionHandled = true;
}
else
{
base.OnException(filterContext);
}
}

Related

How to customize default error pages in azure web app for linux?

I have hosted .NET core 3.1.1 LTS app in Azure web app for linux? How do I customize default error pages like
1. 502
2 Error pages when app service is stopped.
3 Error page when app is being published from Visual studio , VS code / FTP
I find a docs about creating Application Gateway custom error pages,maybe it's good for you. custom error pages
How to create custom error page in code.
We also can handle it by code.Here is my suggest.
Errors like 500, we can handle it by filter,
public class ErrorPageFilter : ActionFilterAttribute
{
public override void OnResultExecuted(ResultExecutedContext context)
{
if (context.HttpContext.Response.StatusCode == 500)
{
context.HttpContext.Response.Redirect("error/500");
}
base.OnResultExecuted(context);
}
}
[ErrorPageFilter]
public abstract class PageController
{}
For .netcore mvc project, it also comes with pipeline processing for error pages when it is created.
In startup.cs,
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//dev env show error page
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
//prod env show custom page
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
}
//In HomeController has this function,
//You just replace cshtml file by you want
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
Errors like 404, we can,
In startup.cs file find configure function,then add below code,
app.UseStatusCodePagesWithReExecute("/error/{0}");
Then add error Controller,
public class ErrorController : Controller
{
/// <summary>
/// In content in {0} is error code
/// </summary>
/// <returns></returns>
[Route("/error/{0}")]
public IActionResult Page()
{
//Jump to 404 error page
if (Response.StatusCode == 404)
{
return View("/views/error/notfound.cshtml");
}
return View();
}
}
Pay attention, if use ErroeController( handle 404 error), pls don't use
app.UseExceptionHandler("/Home/Error"),
you just need handle error in Controller.

SwaggerRequestExample attribute does not work in ASP.NET MVC 5 (.NET Framework 4.5.2)

I am toying with Swashbuckle.Examples package (3.10.0) in an ASP.NET MVC project. However, I cannot make request examples appear within the UI.
Configuration (SwaggerConfig.cs)
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
.EnableSwagger(c => {
c.SingleApiVersion("v1", "TestApp.Web");
c.IncludeXmlComments(string.Format(#"{0}\bin\TestApp.Web.xml", System.AppDomain.CurrentDomain.BaseDirectory));
c.OperationFilter<ExamplesOperationFilter>();
c.OperationFilter<DescriptionOperationFilter>();
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter>();
})
.EnableSwaggerUi(c => { });
}
Request example classes
public class EchoRequestExample : IExamplesProvider
{
public object GetExamples()
{
return new EchoInput { Value = 7 } ;
}
}
public class EchoInput
{
public int Value { get; set; }
}
Action
[HttpGet]
[Route("Echo")]
[CustomApiAuthorize]
[SwaggerRequestExample(typeof(EchoInput), typeof(EchoRequestExample))]
[ResponseType(typeof(EchoServiceModel))]
public HttpResponseMessage Echo([FromUri] EchoInput model)
{
var ret = new EchoServiceModel
{
Username = RequestContext.Principal.Identity.Name,
Value = value
};
return Request.CreateResponse(HttpStatusCode.OK, ret);
}
Swagger UI shows xml comments and output metadata (model and an example containing default values), but shows no request example. I attached to process and EchoRequestExample.GetExamples is not hit.
Question: How to make SwaggerRequestExample attribute work in ASP.NET MVC 5?
Note: Windows identity is used for authorization.
I received an answer from library owner here:
Swagger request examples can only set on [HttpPost] actions
It is not clear if this is a design choice or just a limitation, as I find [HttpGet] examples also relevant.
I know the feeling, lot's of overhead just for an example, I struggle with this for a while, so I created my own fork of swashbuckle, and after unsuccessful attempts to merge my ideas I ended up detaching and renaming my project and pushed to nuget, here it is: Swagger-Net
An example like that will be:
[SwaggerExample("id", "123456")]
public IHttpActionResult GetById(int id)
{
Here the full code for that: Swagger_Test/Controllers/IHttpActionResultController.cs#L26
Wondering how that looks like on the Swagger-UI, here it is:
http://swagger-net-test.azurewebsites.net/swagger/ui/index?filter=IHttpActionResult#/IHttpActionResult/IHttpActionResult_GetById

Impossible to show Custom Error page with Nancy on OWIN

I have a website using Nancy which is hosted using OWIN.
In my Startup.cs file I define the PassThroughOptions as follows:
public void Configuration(IAppBuilder app)
{
app.UseNancy(o => {
o.PassThroughWhenStatusCodesAre(
HttpStatusCode.NotFound,
HttpStatusCode.InternalServerError
);
o.Bootstrapper = new Bootstrapper();
});
app.UseStageMarker(PipelineStage.MapHandler);
}
I need to pass-through the NotFound requests, so that things like my bundled .less files or miniprofiler-results or static files in the root of my site (robots.txt or sitemap.xml) work.
I also have a custom StatusCodeHandler for the 404 code, which also checks a custom header to distinguish between static files (or .less bundles/miniprofiler) and actual stuff that is not found in my modules' methods.
public void Handle(HttpStatusCode statusCode, NancyContext context)
{
Log.Warn("Not found: " + context.Request.Url);
base.Handle(statusCode, context, "Errors/NotFound");
}
This handler then should actually show the error page.
protected void Handle(HttpStatusCode statusCode, NancyContext context, string view)
{
var response = new Negotiator(context)
.WithModel(GetErrorModel(context))
.WithStatusCode(statusCode)
.WithView(view);
context.Response = responseNegotiator.NegotiateResponse(response, context);
}
But the error page is never shown. The request is processed three times and eventually the default IIS error page is shown (using errorMode="Custom" for httpErrors) or simply a white page (using existingResponse="PassThrough" for httpErrors).
Is there any way to display something so simple as a custom error page when hosting a Nancy website on OWIN?
What you've got there looks good, it looks like you've be using the Hosting Nancy with Owin docs.
Here's what works for me:
The Startup.cs (required for Owin): (We've both coded the configuration function differently, you're just using the extension helper while I'm not. Same result. This is in my App.Web project.)
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.UseNancy(options =>
{
options.Bootstrapper = new BootStrapper();
options.PerformPassThrough = context => context.Response.StatusCode == HttpStatusCode.NotFound;
});
app.UseStageMarker(PipelineStage.MapHandler);
}
}
404 handler: (As per the docs, doesn't matter where this is in the project, by implementing IStatusCodeHandler it'll be automatically picked up by Nancy This is in my App.WebApi project with other module classes.)
public class StatusCode404Handler : IStatusCodeHandler
{
public bool HandlesStatusCode(HttpStatusCode statusCode, NancyContext context)
{
return statusCode == HttpStatusCode.NotFound;
}
public void Handle(HttpStatusCode statusCode, NancyContext context)
{
var response = new GenericFileResponse("statuspages/404.html", "text/html")
{
StatusCode = statusCode
};
context.Response = response;
}
}
The 'statuspages' folder in my App.Web project:
Check this SO post for a comparison of using GenericFileReponse or ViewRenderer (How to display my 404 page in Nancy?).

Web Api on Azure shows no error detail using 'return InternalServerError(ex)'

My Web Api when run locally (in Release mode) will return any errors in this format:
{
"Message": "An error has occurred.",
"ExceptionMessage": "No text specified",
"ExceptionType": "System.Exception",
"StackTrace": null
}
But after deployment/publish to an Azure VM, only this remains:
{
"Message": "An error has occurred."
}
API code:
try
{
var msg = ...
new MessageService().SaveMessage(msg)); // <-- does some checks; may throw.
return Ok();
}
catch (Exception ex)
{
return InternalServerError(ex);
}
I'd like it to be more detailed on Azure, like the local result.
Can this be achieved, and if so, how?
I already (temporarily) removed <compilation xdt:Transform="RemoveAttributes(debug)" /> from the <system.web> part of Web.Release.config, and then re-deployed, but that made no difference.
Or am I using the wrong approach/pattern?
Obviously technical details should be limited, but right now we get no details at all.
You could try adding the following to your Global.asax:
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
Note: I wouldn't recommend that you keep this setting on in a production environment.
If instead you use
GlobalConfiguration.Configuration.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Default;
then you can use the system.webServer error switch e.g.
<system.webServer>
<httpErrors errorMode="Detailed" existingResponse="PassThrough">
</httpErrors>
</system.webServer>
Note the existingResponse attribute to preserve the error message.
I had the same problem, the post is three years old, things have changed a little. If you setup a new Azure Mobile App with Visual Studio 2017 there is no longer a Global.asax.cs. I searched for hours, where to put this IncludeErrorDetailPolicy. It won't work without that setting.
You do it in your Startup.MobileApp.cs:
public partial class Startup
{
public static void ConfigureMobileApp(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
new MobileAppConfiguration()
.UseDefaultConfiguration()
.ApplyTo(config);
Don't forget, in your Web.config you also need to set:
<system.webServer>
<httpErrors errorMode="Detailed" existingResponse="PassThrough">
</httpErrors>
</system.webServer>
Don't use that for production environment!
For Web API 2, you can implement a custom IExceptionLogger that utilizes Azure Application Insights. Something like this:
using Microsoft.ApplicationInsights;
using System.Web.Http.ExceptionHandling;
namespace Your.Namespace.Here
{
public class TelemetryExceptionLogger : ExceptionLogger
{
private readonly TelemetryClient telemetryClient;
public TelemetryExceptionLogger(TelemetryClient telemetryClient)
{
this.telemetryClient = telemetryClient;
}
public override void Log(ExceptionLoggerContext context)
{
if (context != null && context.Exception != null)
{
telemetryClient.TrackException(context.Exception);
}
base.Log(context);
}
}
}
Then you need to register it with Web API:
using Microsoft.ApplicationInsights;
using System.Web.Http;
using System.Web.Http.ExceptionHandling;
using Your.Namespace.Here;
namespace Some.Other.Namespace.Or.The.Same
{
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// --- Normal Web API configuration here ---
config.Services.Add(typeof(IExceptionLogger), new TelemetryExceptionLogger(new TelemetryClient()));
}
}
}
For this to work, you will need to have set up Application Insight in Azure and for your VS project, but that is a story for another time :)
For more information, see Application Insights: Exception Telemetry
I have a scenario with the same error, and the problem was a copy&paste in the route header attribute of a method. I have the same route for two methods
[Route("test/Method1")]
public IHttpActionResult Method1(){...}
[Route("test/Method1")]
public IHttpActionResult Method2(){...}
Check the new methods and Routes added.

Authenticate Attribute for MVC: ExecuteServiceStackFiltersAttribute: SessionFeature not present in time to set AuthSession?

I'm trying to create a simple Credentials Auth using OrmLiteAuthRepository(Postgres) and Memcached as caching layer on Mono 3.2.x / Ubuntu 12.04 in an MVC Application - I am using ServiceStack libraries version 4.0x
I am using a custom session object, adapted from ServiceStack's SocialBootstrap example
What works perfectly:
Getting the session inside a controller action, such as:
var currentSession = base.SessionAs<MyCustomUserSession>();
However, I don't want to check / validate the session and what may or may not be inside it in the action code, I would like to use an attribute, and this leads me to:
What does not work: Using the Authenticate attribute above the action name:
My problem (null AuthSession) shows up when trying to utilize the [Authenticate] attribute on an MVC action.
[Authenticate]
public ActionResult Index()
{
return View();
}
I have managed to narrow it down to the fact that ExecuteServiceStackFiltersAttribute executes this code, but it appears the AuthSession has not yet been made available by the SessionFeature - so the AuthSession will always be null at this point:
var authAttrs = GetActionAndControllerAttributes<AuthenticateAttribute>(filterContext);
if (authAttrs.Count > 0 && ( ssController.AuthSession==null || !ssController.AuthSession.IsAuthenticated))
{
filterContext.Result = ssController.AuthenticationErrorResult;
return;
}
If, for example I override the AuthenticationErrorResult and try to throw an exception if I manually initialize the session from the SessionFeature, it will throw the "there is life in the session" exception (of course, when I logged in with a valid user):
public override ActionResult AuthenticationErrorResult
{
get
{
if (AuthSession == null)
{
// the Authenticate filter is triggered by ExecuteServiceStackFilters attribute
// which seems to always have AuthSession null
var session = SessionFeature.GetOrCreateSession<MyCustomUserSession>(AuthService.Cache);
if (session == null || (session != null && session.IsAuthenticated == false))
{
throw new Exception("Hmmm...dead as a dodo");
}
else
{
throw new Exception("there is life in the session:" + session.UserName);
}
}
var returnUrl = HttpContext.Request.Url.PathAndQuery;
return new RedirectResult(LoginRedirectUrl.Fmt(HttpUtility.UrlEncode(returnUrl)));
}
}
Aside from creating my custom attributes / filters, is there a solution I should try (properties to set) with the incumbent ServiceStack codebase? If I'm missing something, please let me know.
My regards for a great project in any case.
My problem (null AuthSession) shows up when trying to utilize the [Authenticate] attribute on an MVC action.
Are you getting an Exception or are you just getting redirected to the 'Login' page? If you are not getting an Exception and just be redirected because you're not authenticated, the below may work. Also, are you implementing your own Custom Authentication Provider? If so, could you post a sample of it?
I don't think you have it in your code samples but I think your MVC Controller code is probably something like...
public class SomeController : ServiceStackController
{
[Authenticate]
public ActionResult Index()
{
return View();
}
}
Can you try adding your custom MyCustomUserSession to the Type of the ServiceStackController making it...
public class SomeController : ServiceStackController<MyCustomUserSession>
{
[Authenticate]
public ActionResult Index()
{
return View();
}
}

Resources