MVC3 HandleError doesn't show error page - c#

I've been following this guide for the HandleError attribute:
blogs.msdn.com
which I use like this (AccountController):
[HandleError(View="ErasErrorPage")]
public ActionResult Index()
{
ViewBag.admins = _accountMapper.GetAdmins(false);
ViewBag.members = _accountMapper.GetMembers(false);
ViewBag.Countries = _countryMapper.GetCountries();
return View();
}
This code throws an exception because _accountMapper.GetAdmins(false) fails because of a System.Data.EntityException.
I've put the ErasErrorPage view in my Shared folder and I've added <customErrors mode="On"/> but the ErasErrorPage does not show up. All I get when the error occurs is a yellow screen of death saying:
Obviously, setting the mode to "Off" or "RemoteOnly" doesn't solve the problem.
Anyone has an idea why this doesn't work?
EDIT
If I surf directly to http://localhost:3527/Account/Index, I do get the correct ErasErrorPage, but I don't want that. I want the website to automaticly redirect to that page when an exception is thrown somewhere. Is this possible?
EDIT2
I've put the [HandleError(View="ErasErrorPage")] attribute right before every single Public ActionResult methodName() { ... } method, and I still get the Yellow Screen of Death saying I need to change the mode to "Off" or "RemoteOnly"...

Make sure that the ErasErrorPage view doesn't itself throw an exception. Here are the steps I did and which worked fine for me:
Create a new ASP.NET MVC 3 Project using the default Visual Studio wizard
Add ~/Views/Shared/ErasErrorPage.cshtml with the following content:
#{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title>ErasErrorPage</title>
</head>
<body>
<div>
OOPS
</div>
</body>
</html>
Modify HomeContoller to look like this:
public class HomeController : Controller
{
[HandleError(View = "ErasErrorPage")]
public ActionResult Index()
{
throw new Exception("oops");
}
}
In web.config put:
<customErrors mode="On" />
Navigate to /Home/Index => the custom error page is displayed as expected

Since this doesn't work at all, I've found a very good alternative:
Custom error pages on asp.net MVC3
I also found out why it failed:
We were trying to connect to the database before we tried rendering views. The HandleError attribute won't even be triggered by that (I think). The method above does do that. It handles any exception, anywhere.

It does work, I have a BaseController with the attribute [HandleError(View = "Error")] and an Error view in Shared with a dynamic model (should be HandleErrorInfo) and at the Index action in the HomeController I am throwing an exception:
throw new Exception("Test exception");
The error view is then rendered and displays the correct information.
ErrorView:
<div class="errorMessage">
<h1 class="errorHeader">#Model.Exception.GetType().Name</h1>
<cite class="errorAction">thrown in #Model.ControllerName #Model.ActionName</cite>
<p class="errorMessage">thrown in #Model.Message</p>
</div>

Related

Routing error 404 only when deployed in UAT web server. Works locally. ASP.NET Core

I've completed testing my ASP.NET Core app locally, and it works fine. However I'm getting 404 errors for a trigger on my view after publishing to our UAT server and I cannot determine why. I'm possibly missing something obvious and would appreciate fresh eyes. Thank you.
I have tried amending the routing in StartUp and attempted mixed routing in my controller.
Relevant part of Configure method in startup.cs:
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=StartPage}/{id?}");
});
Relevant form in my StartPage view:
<form action="#Url.Action("StartSlsProcess", "Home")" method="post" enctype="multipart/form-data" id="trigger">
<div id="process-trigger">
#(Html.DevExtreme().Button()
.Text("Start SLS")
.Type(ButtonType.Success)
.UseSubmitBehavior(true)
)
</div>
</form>
Method in HomeController:
[HttpPost]
public ActionResult StartSlsProcess()
{
var empty = new string[0];
ConsoleApp.Program.StartProcessFromUI(empty);
return new EmptyResult();
}
I would expect when the button is pushed on the view that it triggers the StartProcessFromUI method on my console app, continues the separate process and refreshes the view, as it does locally.
Edit: what is further confusing the issue is that my other Action works fine, and is set up the same:
<form action="#Url.Action("Upload", "Home")" method="post" enctype="multipart/form-data" id="uploader">
<div id="fileuploader-container">
#(Html.DevExtreme().FileUploader().Name("file")
.ID("file-uploader")
.Accept("*")
.UploadMode(FileUploadMode.Instantly)
.UploadUrl(Url.Action("Upload", "Home"))
//.OnUploadError("fileUploader_onUploadError")
//.OnValueChanged("fileUploader_valueChanged")
)
</div>
</form>
HomeController method:
[HttpPost]
public ActionResult Upload()
{
try
{
var file = Request.Form.Files["file"];
var path = Path.Combine(_hostingEnvironment.WebRootPath, "uploads");
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
using(var fileStream = System.IO.File.Create(Path.Combine(path, file.FileName))) {
file.CopyTo(fileStream);
fileStream.Flush();
}
MoveFileFromServer(path, file);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
return new EmptyResult();
}
Additionally, the method on my ConsoleApp, StartProcessFromUI actually gets hit, it's just that the 404 Error is then returned in the foreground.
At least for the C# side, I can tell you it is not a programming issue. As a general rule the networking code does not care if the other end is on the same computer, the same switch, or the Voyager 2 Probe.
Making certain there is a path there is a Networking Problem, not a programming one. As your Title says, the error is a 404/Routing one. So it is definitely somewhere in the Networking. Maybe the Server is not set up to allow external (non-Localhost) Connections, or some similar security feature. Many default profiles are created with such settings for security reasons. It could also be a overagressive Firewall.
When in doubt, you can just verify it with a simple HTML file, that should be delivered as stored on the disk.

System.Web.HttpException when using [Authorize]

I am facing a very weird problem that I am unable to solve.
I have this button onclick of which I go to the controller action method where I need to use [Authorize], when I use [Authorize] I get the following error.
The following sections have been defined but have not been rendered for the layout page "~/Views/Shared/_Layout.cshtml": "Scripts".
System.Web.HttpException
However, when I don't use [Authorize] it works fine. Why does it behave like that? Any help would be highly appreciated.
[Authorize]
public async Task<ActionResult> Calendar(int id, string start, string end)
{
//code
}
On your ~/Views/Shared/_Layout.cshtml page you have likely a required section that has to be included on every view, it will be something like this:
#RenderSection("scripts")
You need to change it to this:
#RenderSection("scripts", required: false)
Which means the section will be optional on pages using your layout page.
Old but still relevant:
https://weblogs.asp.net/scottgu/asp-net-mvc-3-layouts-and-sections-with-razor

My PartialView is causing my application to breakdown everytime

I'm trying to load my partial view with some data from database, but I'm getting following issue when I run the application:
Child actions are not allowed to perform redirect actions.
I don't know why this is happening because I'm pretty new with MVC technology.
Here is my PartialViewResult method in a controller:
public PartialViewResult UnReadEmails()
{
if (User.Id != null)
{
List<Emails> resultList = EmailController.GetUnreadEmailsByUserId(User.Id);
return PartialView("~/Views/Emails/_UnReadEmails.cshtml", resultList);
}
return PartialView("Error, not found!");
}
And here is my partialview itself, it is called _UnReadEmails (as you can see I'm displaying here info about sender and email body), PartialView is retrieving list of Emails that I'm sending to from my Controller
#model IEnumerable<Emails>
foreach (var item in Model)
{
<li>
<a>
<span>
<span>#item.EmailSender</span>
<span class="email">
#item.Body;
</span>
</a>
</li>
}
After I tried to load my partial view on this way:
#Html.Action("UnreadEmails", "Message")
I started to receive following issue that I mentioned in my Title,
I already tried few things to solve this like changing #Html.Action("UnreadEmails", "Message") to #Url.Action("UnreadEmails", "Message") etc etc but that didn't solve my issue.
EDIT: It allways breaks on this line (on view) :
#Html.Action("UnreadEmails", "Message")
It never goes into code behind..
After Chris suggestion on another post I added [AllowAnonymous] on the top of the method:
[AllowAnonymous]
public PartialViewResult UnReadEmails()
{
if (User.Id != null)
{
List<Emails> resultList = EmailController.GetUnreadEmailsByUserId(User.Id);
return PartialView("~/Views/Emails/_UnReadEmails.cshtml", resultList);
}
return PartialView("Error, not found!");
}
EDIT EDIT EDIT:
Interesting fact is that whatever I wrote in my Controller's method and even if I comment all code, it will still break on a View, that means it will never came into a Controller's method. I put breakpoing there at the begining of the UnReadEmails method and it was never hitted, it allways breaks on a View!
EDIT AFTER MAURIZIO suggestion to change it to #Html.RenderPartial
Than I received following issue:
The partial view 'UnReadEmails' was not found or no view engine
supports the searched locations. The following locations were
searched: ~/Views/Dashboard/UnReadEmails.aspx
~/Views/Dashboard/UnReadEmails.ascx ~/Views/Shared/UnReadEmails.aspx
~/Views/Shared/UnReadEmails.ascx ~/Views/Dashboard/UnReadEmails.cshtml
~/Views/Dashboard/UnReadEmails.vbhtml
~/Views/Shared/UnReadEmails.cshtml ~/Views/Shared/UnReadEmails.vbhtml
EDIT:
Compiler Error Message: CS0120: An object reference is required for the non-static field, method, or property 'MessageController.UnReadEmails()'
I tried to make UnReadEmails() as static but than I received following error :
Error 1 An object reference is required for the non-static field,
method, or property 'System.Web.Mvc.Controller.PartialView(string,
object)' ...Controllers\Message\MessageController.cs
Since your partial view is not in the Shared folder you need to provide the full path
{#Html.RenderPartial("~/Views/Emails/_UnReadEmails.cshtml")}
Since that view needs the list of emails you need to add that as parameter
{#Html.RenderPartial("~/Views/Emails/_UnReadEmails.cshtml",EmailController.GetUnreadEmailsByUserId(User.Id))}
The best aproach would be to create a property in the Model (List<Emails> lstUnreadEmails) and load that list of emails in a method of the MessageController, so that the information is ready for the partial to be render with this instruction:
{#Html.RenderPartial("~/Views/Emails/_UnReadEmails.cshtml",Model.lstUnreadEmails)}
In case you dont have a "main model" you could store that in a ViewBag, calling this from a MessageController method
ViewBag.lstUnreadEmail‌s = E‌​mailController.Get‌‌​​Un‌​readEmailsByUserId(U‌​ser.Id);
And in the View use this
{#Html.RenderPartial("~/Views/Emails/_UnReadEmails.cshtml",ViewBag.lstUnreadEmail‌​s)}

Doesn't call newly created view in mvc 4 even view is exist

I have created a new view created button in older view. I can't open new view neither from Action nor from url.
Controller: HomeController
OlderView: Index (View/Home/Index.cshtml)
Action: Success
NewView: Success (View/Home/Success.cshtml)
Index.cshtml:
<input type="button" value="Download" onclick="location.href='#Url.Action("Success", "Home")'" />
HomeController:
[HttpPost]
public ActionResult Success()
{
//return View(); //this also doesn't work
return View("Success");
}
Success.cshtml:
#{
ViewBag.Title = "Success";
}
<h2>Your transaction has been completed successfully.</h2>
If I try directly from url: http://xxx.xxx.x.xx:xxxx/Home/Success, it throw following error
Description: HTTP 404. The resource you are looking for (or one of its dependencies) could have been removed, had its name changed, or is temporarily unavailable. Please review the following URL and make sure that it is spelled correctly.
Requested URL: /Home/Success
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.6.1069.1
Can anybody suggest me what I am missing here? Do I need to register the view anywhere?
You are calling a view means that request is get request but you write view as httpPost ...
So change action as HttpGet
or
call with button click or any other post actions...

Razor Virtual Path issue

The controller is:
public class HomeController : Controller
{
public ActionResult LogOn()
{
return View();
}
[HttpPost]
public ActionResult LogOn(string captcha)
{
if (captcha == HttpContext.Session["captcha"].ToString())
return Content("ok");
else
return Content("failed");
}
public CaptchaImageResult ShowCaptchaImage()
{
return new CaptchaImageResult();
}
}
The view is:
<%using (Html.BeginForm())
{ %>
<p><img src="/Home/ShowCaptchaImage" /></p>
<p>Please enter the string as shown above:</p>
<p><%= Html.TextBox("captcha")%></p>
<p><input type="submit" value="Submit" /></p>
<% } %>
Everything goes well, the captcha image is rendered (CaptchaImageResult writes a jpg in the response stream). But if i use the razor view engine there is no captcha image rendered.
How to fix it?
And one more thing: is it a good way to display captcha?
Later edit: <img src=#Href("../../Home/ShowCaptchaImage") /> works fine.
The problem wasn't because razor it was because in the first example i was using Visual Studio Development server and in the second one i was using IIS
<img src="/Home/ShowCaptchaImage" />
This causes the browser to request /Home/ShowCaptchaImage from the root of the HTTP origin (scheme+domain+port) on which you host the application. You need to map the URL to reflect things like any virtual folders in which the app is hosted. If I'm not wrong and this is the problem you are facing, take a look at ResolveUrl/ResolveClientUrl equivalents for Asp.Net Razor? (I haven't tested it, but it looks good).
Also, you could diagnose the problem easily using Firebug or an equivalent tool in another browser - take a look at the requests which are made and you will see what the browser actually requests.

Categories