Configuring Magical Unicorn Mvc Error Toolkit - asp.net-mvc

I am trying to configure the Magical Unicorn Mvc Error Toolkit (v 2.1.2) on my MVC4 web site but I can't get it to work. Here's my code:
Web.config
<customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/Error/ServerError">
<error statusCode="404" redirect="~/Views/Error/NotFound.cshtml" />
</customErrors>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="404" subStatusCode="-1" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="404" path="~/Error/NotFound" responseMode="ExecuteURL" />
<error statusCode="500" path="~/Error/ServerError" responseMode="ExecuteURL" />
</httpErrors>
<system.webServer>
Error Controller
public class ErrorController : Controller
{
public ActionResult NotFound()
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
public ActionResult ServerError()
{
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return View();
}
}
[These were based on this https://stackoverflow.com/a/7499406/236860 post]
CustomerErrorHandler.cs (App_Start)
using Microsoft.Web.Infrastructure.DynamicModuleHelper;
using WorldDomination.Web.Mvc;
using CustomErrors.App_Start;
[assembly: WebActivator.PreApplicationStartMethod(typeof(CustomErrorHander), "PreStart")]
namespace CustomErrors.App_Start
{
public static class CustomErrorHander
{
public static void PreStart()
{
// Register the custom error handling module.
DynamicModuleUtility.RegisterModule(typeof (CustomErrorHandlingModule));
}
}
}
I am testing this application in Visual Studio 2012 using IIS Express. If I try to navigate to a non-existent page, or go to an action method that calls an exception I either get the default browser error page or a blank page.
I have also modified the above code as suggested at ASP.NET MVC Custom Error Pages with Magical Unicorn but this dis not seem to make any difference.
Can anyone point me in the right direction to get this working.

In the end, I could not get the Magical Unicorn Mvc Error Toolkit to work. The good news is that I don't think I had to! Since I am deploying the MVC application to an IIS 7.5 web server, I could use the later system.webServer.httpErrors section of my Web.config and a custom error controller.
Web.Config
<system.web>
<httpRuntime targetFramework="4.5" />
<compilation debug="false" targetFramework="4.5">
<customErrors mode="Off" /> <!-- IMPORTANT -->
...
</system.web>
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace">
<remove statusCode="403" />
<error statusCode="403" responseMode="ExecuteURL" path="/Error/AccessDenied" />
<remove statusCode="404" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<remove statusCode="500" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error/ApplicationError" />
</httpErrors>
...
</system.webServer>
Error Controller
public class ErrorController : Controller
{
public ActionResult AccessDenied()
{
Response.StatusCode = (int)HttpStatusCode.Forbidden;
Response.TrySkipIisCustomErrors = true;
if (Request.IsAjaxRequest())
{
// return Json friendly response here
}
return View();
}
public ActionResult NotFound()
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
Response.TrySkipIisCustomErrors = true;
if (Request.IsAjaxRequest())
{
// return Json friendly response here
}
return View();
}
public ActionResult ApplicationError()
{
Response.StatusCode = (int)HttpStatusCode.InternalServerError;
Response.TrySkipIisCustomErrors = true;
if (Request.IsAjaxRequest())
{
// return Json friendly response here
}
return View();
}
}
This all seems to work well with IIS Express and IIS 7.5.
Elmah logs the errors without any changes to the default error filters.
Fiddler also suggests that the correct HTTP Status codes are also being correctly maintained.

Related

Custom Error pages in MVC ASP NET for all errors

i want in my app to have custom error pages for 401, 404 etc error codes.
I try this but doesn't work?
In Web.config
<customErrors mode="Off" /> //Under system.web
<httpErrors errorMode="Custom" existingResponse="Replace" >//Under system.webServer
<clear />
<remove statusCode="401"/>
<error statusCode="401" responseMode="ExecuteURL" path="/Error/Unauthorized" />
<error statusCode="404" responseMode="ExecuteURL" path="/Error/NotFound" />
<error statusCode="500" responseMode="ExecuteURL" path="/Error" />
</httpErrors>
I have create also Error controller and Unauthorized views.
How can this work?
Example:
web.config:
in system.web add
<customErrors mode="RemoteOnly" defaultRedirect="~/error">//RemoteOnly means that on local network you will see real errors
<error statusCode="401" path="~/Error/Unauthorized" />
<error statusCode="404" path="~/Error/NotFound" />
<error statusCode="500" path="~/Error" />
</customErrors>
in system.webServer add
<httpErrors errorMode="Detailed" />
Controller:
your controller something like
public class ErrorController : Controller
{
public ViewResult Index()
{
return View("Error");
}
public ViewResult NotFound()
{
Response.StatusCode = 404;
return View("NotFound");
}
}
View:
and your view something like
#model System.Web.Mvc.HandleErrorInfo
#{
Layout = "_Layout.cshtml";
ViewBag.Title = "Error";
}
<div class="list-header clearfix">
<span>Error</span>
</div>
<div class="list-sfs-holder">
<div class="alert alert-error">
An unexpected error has occurred. Please contact the system administrator.
</div>
#if (Model != null && HttpContext.Current.IsDebuggingEnabled)
{
<div>
<p>
<b>Exception:</b> #Model.Exception.Message<br />
<b>Controller:</b> #Model.ControllerName<br />
<b>Action:</b> #Model.ActionName
</p>
</div>
}
</div>
Hopefully it's help for you.

WebAPI + SimpleMembership + WebSecurity - can never authenticate?

I'm trying to implement a single-page app. I carried over some of my working code from another project (MVC4) to implement authentication. Right now I see cookies being set, but WebSecurity / User.Identity do not seem to be working for some reason. After logging in, subsequent requests never validate as authenticated, either via WebSecurity.IsAuthenticated, or User.Identity.IsAuthenticated. Does anyone know why this is happening?
Controller code:
public class AccountController : ApiController {
private readonly UserService _userService;
public AccountController() {}
public AccountController(UserService userService) {
_userService = userService;
}
[AllowAnonymous]
[HttpGet]
[Route("api/authpayload")]
// This gets called when the app loads. Always, User.Identity.IsAuthenticated is false.
public HttpResponseMessage AuthPayload() {
var payload = new AuthPayloadDto();
try {
var userId = WebSecurity.GetUserId(User.Identity.Name);
if (User.Identity.IsAuthenticated && userId > 0) {
payload.Username = User.Identity.Name;
} else {
LogOut();
payload.IsAuthenticated = false;
}
return Request.CreateResponse(HttpStatusCode.OK, payload);
} catch (Exception e) {
return Request.CreateResponse(HttpStatusCode.InternalServerError, e);
}
}
[HttpPost]
[Route("api/login")]
[AllowAnonymous]
public HttpResponseMessage LogIn(LoginModel model) {
if (!ModelState.IsValid)
return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
try {
if (WebSecurity.IsAuthenticated)
return Request.CreateResponse(HttpStatusCode.Conflict, "already logged in.");
if (!WebSecurity.UserExists(model.Username))
return Request.CreateResponse(HttpStatusCode.Conflict, "User does not exist.");
if (WebSecurity.Login(model.Username, model.Password, persistCookie: model.RememberMe)) {
// This code always gets hit when I log in, no problems. I see a new cookie get sent down as well, using Chrome debugger.
var payload = new AuthPayloadDto();
return Request.CreateResponse(HttpStatusCode.OK, payload);
}
LogOut();
return Request.CreateResponse(HttpStatusCode.Forbidden, "Login Failed.");
} catch (Exception e) {
return Request.CreateResponse(HttpStatusCode.InternalServerError, e);
}
}
Web.config:
<system.web>
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<authentication mode="Forms">
<forms loginUrl="~/" timeout="2880" />
</authentication>
<roleManager enabled="true" defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="simple">
<providers>
<clear />
<add name="simple" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
<!--
If you are deploying to a cloud environment that has multiple web server instances,
you should change session state mode from "InProc" to "Custom". In addition,
change the connection string named "DefaultConnection" to connect to an instance
of SQL Server (including SQL Azure and SQL Compact) instead of to SQL Server Express.
-->
<sessionState mode="InProc" customProvider="DefaultSessionProvider">
<providers>
<add name="DefaultSessionProvider" type="System.Web.Providers.DefaultSessionStateProvider, System.Web.Providers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" connectionStringName="DefaultConnection" />
</providers>
</sessionState>
</system.web>
The cookie that gets sent after login is not expired, and it does get sent back on subsequent requests, but IsAuthenticated is always false. What am I doing wrong?
Update:
I updated my web.config to the following to get everything working:
<system.web>
<authentication mode="None" />
<compilation debug="true" targetFramework="4.5" />
<httpRuntime targetFramework="4.5" />
<roleManager enabled="true" defaultProvider="SimpleRoleProvider">
<providers>
<clear />
<add name="SimpleRoleProvider" type="WebMatrix.WebData.SimpleRoleProvider, WebMatrix.WebData" />
</providers>
</roleManager>
<membership defaultProvider="SimpleMembershipProvider">
<providers>
<clear />
<add name="SimpleMembershipProvider" type="WebMatrix.WebData.SimpleMembershipProvider, WebMatrix.WebData" />
</providers>
</membership>
</system.web>
But I'd like to leave this open in case anyone has an explanation of why this works; I'm pretty lost.
In my current mvc 4 project with mssql,
its a simple one i so I just wanted very simple memmbership provider
I disabled
InitializeSimpleMembershipAttribute
by
[Authorize]
//[InitializeSimpleMembership]
public partial class AccountController : Controller
and added this code to global.asax under Application_Start
WebSecurity.InitializeDatabaseConnection(
connectionStringName: "DefaultConnection",
userTableName: "UserProfile",
userIdColumn: "UserID",
userNameColumn: "UserName",
autoCreateTables: true);
in my sql database the application created some tables on of them was Roles and UserInRoles just added the roles I needed like Admin, customer, etc...
and I restrict the access to some Controllers or Actions by adding this code
[Authorize(Roles = "Admin")]
public class MessagesController : Controller

Securing ELMAH in ADFS Claims aware MVC 4 app using elmah.mvc.allowedRoles AppSettings

ELMAH for MVC support following appsettings configurations
elmah.mvc.allowedRoles
elmah.mvc.allowedUsers
to secure the elmah route path using roles/users. Apparently, it works fine for windows or forms authentications. But I couldn't make it working for the claim based authentication.
Does anyone have experience with this?
I do this in web config
<elmah>
<security allowRemoteAccess="true" />
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="elmah-sqlserver" applicationName="Eers.Web"/>
</elmah>
and further down
<location path="elmah">
<system.web>
<authorization>
<allow users="*"/>
</authorization>
</system.web>
</location>
<location path="elmah.axd" inheritInChildApplications="false">
<system.web>
<httpHandlers>
<add verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" />
</httpHandlers>
</system.web>
<system.webServer>
<handlers>
<add name="ELMAH" verb="POST,GET,HEAD" path="elmah.axd" type="Elmah.ErrorLogPageFactory, Elmah" preCondition="integratedMode" />
</handlers>
</system.webServer>
</location>
If you take note of the node it works just like any other security in MVC. It does not work with Claims though. for that You will have to write an Action filter
<authorization>
<allow users="*"/>
</authorization>
Here is my Actionfilter
public class ElmahRequestAuthorizationFilter : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.IsChildAction) return;
var controller = filterContext.RouteData.Values["controller"] as string;
if (controller != null && controller.ToLowerInvariant() != "elmah") return;
var authenticationComponent = GetAuthenticationInfo() // A method that will return us roles;
var goodRoles = new List<string> {
"TestRole",
"ThirdLevelSupport",
"Administrator"
};
var roles = authenticationComponent.Roles ?? new List<string>();
var thouShaltPass = roles.Intersect(goodRoles).Any();
if (!thouShaltPass)
{
throw new HttpException(404, "Not Found");
}
}
}

Display custom error page and show exception details

I have a custom Errors controller that looks like this:
public class ErrorsController : BaseController
{
public ActionResult RaiseError(string error = null)
{
string msg = error ?? "An error has been thrown (intentionally).";
throw new Exception(msg);
}
public ActionResult Error404()
{
Response.TrySkipIisCustomErrors = true;
Response.StatusCode = (int)HttpStatusCode.NotFound;
return View();
}
public ActionResult Error500()
{
Response.TrySkipIisCustomErrors = true;
var model = new Models.Errors.Error500()
{
ServerException = Server.GetLastError(),
HTTPStatusCode = Response.StatusCode
};
return View(model);
}
}
My Errors500.cshtml looks like this:
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Error500</title>
</head>
<body>
<div>
An internal error has occurred.
#if (Model != null && Model.ServerException != null && HttpContext.Current.IsDebuggingEnabled)
{
<div>
<p>
<b>Exception:</b> #Model.ServerException.Message<br />
</p>
<div style="overflow:scroll">
<pre>
#Model.ServerException.StackTrace
</pre>
</div>
</div>
}
</div>
</body>
</html>
and my web.config has my error handlers specified as such:
<system.webServer>
<httpErrors errorMode="Custom" existingResponse="Replace" >
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" subStatusCode="-1" responseMode="ExecuteURL" path="/Errors/Error404" />
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" subStatusCode="-1" responseMode="ExecuteURL" path="/Errors/Error500" />
</httpErrors>
The problem is: everytime I call /errors/raiseerror to test my 500 handling; I'm redirected to errors/error500 (fine). However, the exception data isn't rendered on the page because the Server.GetLastError() call returns null instead of the exception thrown by RaiseError().
What's the best way to handle a custom 500 error page where that custom page can render out the exception details as well?
The easiest way to go about this is:
Use MVC's built-in support to handle Exceptions. By default MVC uses HandleErrorAttribute that is registered in App_Start\FilterConfig.cs:
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
}
Now make sure you have a view called Error in Views\Shared folder. The view by default has model of type HandleErrorInfo with a property named Exception. You can show the Exception message and other details if you want like this:
Error.cshtml
#model HandleErrorInfo
#if(Model != null)
{
#Model.Exception.Message
}
You can customize the Error.cshtml page the way you want...

how to handle this in mvc 3 and iis 6 like stackoverflow?

how to handle 400 bad request like stackoverflow in mvc 3 , iis 6 ?
eg: www.stackoverflow.com/a<
return 404 not found page , instead of a YSOD page
updated: why this does not work ?
<httpErrors errorMode="Detailed">
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" subStatusCode="-1" path="/notfound" responseMode="ExecuteURL" />
<error statusCode="400" subStatusCode="-1" path="/Error" responseMode="ExecuteURL" />
</httpErrors>
Use customErrors tag of web.config:
<customErrors mode="On" defaultRedirect="UrlToRedirect" >
<error statusCode="400" redirect="UrlToRedirect"/>
</customErrors>
Eg.:
<customErrors mode="On" defaultRedirect="~/Error/Index">
<error statusCode="400" redirect="~/Error/Index"/>
</customErrors>
if UrlToRedirect = "~/Error/Index", Here, in this url, "Error" is the name of controller & "Index" is the name of Action method which returns Error View Page.
public class ErrorController : Controller
{
public ActionResult Index()
{
return View("Error");
}
}
In the "\Views\Shared Folder" of you application, you have "Error.cshtml" view page.

Resources