European ASP.NET MVC 4 and MVC 5 Hosting

BLOG about ASP.NET MVC 3, ASP.NET MVC 4, and ASP.NET MVC 5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET MVC 3 Hosting :: Error handling in ASP.NET MVC3

clock November 23, 2011 07:42 by author Scott

In ASP.NET MVC (versions 1 to 3) we have the [HandleError] attribute, that will allow us to handle errors in a very easy way.

Just by decorating an action (or controller if we want to extend HandleError behaviour to all actions on that controller) with the HandleError attribute and enabling “CustomErrors” in web.config, we get a nice redirection to a friendly view in case an unhandled error raises.

Internally, we could have a look at the implementation of OnException method inside HandleError using Reflector to see how it works:



As we can see, the unhandled exception will be handled if it hasn't been already marked as "handled" and if custom error handling is enabled .

Web.config customErrors section

The CustomErrors section allow us to define automatic error handling behaviour. If it doesn't exists, it must be created inside system.web section. as shown here:




Posible values for mode are "Off | On | RemoteOnly". This will allow us to easy define behaviour for development and production scenarios :

·         On: custom error handling enabled

·         Off: custom error handling disabled. If an error is raised, we will see the yellow screen of death of ASP.NET

·         RemoteOnly: if we launch the application in the local server (targeting http://localhost ), we won't see custom errors. If we access the application from other machine, we will see custom erros. This option is used by developers to debug applications. If there is an error, you can always (among other things) RD to your server and launch the application in a local browser so you see the exception in a first seat.

Behaviour:

·         If we use the HandleError attribute and CustomErrors is enabled, when an unhandled error raises, the MVC runtimewill look for a “Errors.aspx” view in the context of the HttpRequest being processed (current view folder associated to controller or shared view folder), and will render it. In this case the "defaultredirect" and "redirect" CustomErrors attributes are ignored

·         If we don't use the HandleError attribute and CustomErrors is enabled , we will get an HTTP redirection to the url defined on the "redirect" and "defaultredirect" attributes, within the CustomErrors section in web.config (in our case, /Error/General

Important: ASP.NET MVC3, registers the HandleError attribute globally (for all controllers) !! (see image). Take that into account so you don't think your MVC3 controlleris not using the HandleError attribute (by default it is). In previous versions of  ASP.NET MVC, where we didn't have global filters, the HandleError attribute had to be defined manually for each action or controller.



Also important: If you have enabled CustomErrors=On , also added the [HandleError ] and still get a yellow screen of death please make sure the Error.aspx has no errors (check master page and the errors.aspx code) , it may have an error (this is pretty common scenario and difficult to debug).You can check if this is happening simple by temporaly removing all Error.aspx code and replacing by a text (más información).

To avoid showing ASP.NET yellow screen of death if your Error.aspx has errors, use "redirect" CustomErrros attribute to show a static  html page.



Controller OnException

Alternatively to HandleError, we can also override the OnException  method of a controller (or all of them if we use a base controller class).

An example of exception handling, logging and redirection to friendly message would be:



Note: the OnException event is executed independly of the use of HandleError in the controler.

Using Elmah to intercept, log and notify of unhandled errors

Elmah is a fantastic library that help us to intercept, register (in the desired format: database, text file, xml, etc) and optionally deliverunhandled errors ocurred in our application, so we keep everything in control at all times. It also provieds a web interface so you can access the error records remotely, and a RSS feed so you can subscribe with your favorite RSS reader.



With NuGet , a library package manager, available with ASP.NET MVC3, install Elmah is a pretty straightforward process. First step is launching NuGet:



Then, we search for "Elmah":



and proceed to install it. NuGet will handle for us the necessary steps required to install and configure it (in previous versions of ASP.NET MVC we had to do it manuall). NuGet does for us:

·         downloads the last version from the oficial repository

·         adds the assembly reference to our project

·         modifies the web.config to add the proper configuration parameters

In our case, Elmah needs some parameters and configuration sections (httpModules,httpHandlers, etc)  in order to work del web.config :



If we want Elmah to record errors or events in XML files inside a certain directory , we have to indicate it::



And that's it.. When an unhandled error is raised, Elmah will be able to intercept it and record it, and also send an email to the administrator. 

Registering with Elmah custom events and errors

Elmah offers an API so we can record or own events or exceptions . We can use that funcionality to log exceptions that we have already handled with our code. Example:



Elmah and HandleError


Elmah works perfectly with unhandled exceptions (yellow screen of death), but won't be able to intercept exceptions that are being handled by the [HandleError] attribute.

To fix this, we need to create a custom HandleError attribute and add a custom behaviour to the new attribute.



More details and source code here: 
http://stackoverflow.com/questions/766610/how-to-get-elmah-to-work-with-asp-net-mvc-handleerror-attribute 

Filtering unwanted events in Elmah

If Elmah is logging too many stuff, (ex: 404 errors looking for favicon.ico), I have the posibility of applying custom filters to those unwanted events .

First, we must add the Elmah ErrorFilter module to web.config:



Once registered, we implement the following events on Global.asax.cs, defining the filtering rules I want to apply:



Final notes

In my particular experience, I found the best practice to use the custom HandleError as shown in the last part of this article (having the HandleError applied globaly) with CustomErrors enabled, helped by Elmah to handle, register and send unhandled exceptions . When necessary, I use the Elmah signal capabilities for those handled exceptions I want to log.



European ASP.NET MVC 3 Hosting :: RenderBody, RenderPage and RenderSection in ASP.NET MVC 3

clock November 11, 2011 05:27 by author Scott

Everybody knows Razor is the new view engine ASP.NET Web Pages, so I thought I’d write about some Razor syntax you may not be aware of. The three methods I’ll be focusing on today are RenderBody, RenderPage and RenderSection. You’ll need to understand how each of these work if you want to get know the Razor syntax intimately. This code also works in WebMatrix if you're using it.

Before moving on, you need to download ASP.NET MVC 3.
Click here to download and install them using the Microsoft Web Platform Installer.

Open studio 2010 and create a new ASP.NET MVC 3 Web Application (Razor) project. Now it's time to start coding! I’ll begin with the RenderBody method.

RenderBody

The RenderBody method resides in the master page, or in Razor this is commonly referred to as the Layout page. There can only be one RenderBody method per Layout page. If you’re from Web Forms world, the easiest way to think of RenderBody is it’s like the
ContentPlaceHolder server control. The RenderBody method indicates where view templates that are based on this master layout file should “fill in” the body content.



RenderPage

Layout pages can also contain content that can be filled by other pages on disk. This is achieved by using the RenderPage method. This method takes either one or two parameters. The first is the physical location of the file, the second is an optional array of objects that can be passed into the page. Add a new cshtml file to the Shared folder and call it _Header.cshtml. I've prefixed this file with an underscore because I don't want this file to be called outside of RenderPage. By default, ASP.NET will not serve pages beginning with an underscore. Here's the code I'm adding to the _Header.cshtml page.


<h1>Header Here</h1>

And to use this in the layout, it's as easy as this.



RenderSection


Layout pages also have the concept of sections. A layout page can only contain one RenderBody method, but can have multiple sections. To create a section you use the RenderSection method. The difference between RenderSection and RenderPage is RenderPage reads the content from a file, whereas RenderSection runs code blocks you define in your content pages. The following code illustrates how to render a footer section.



RenderSection expects one parameter and that is the name of the section. If you don’t provide that, an exception will be thrown. Views can add data to sections by using the following code.



If you ran the website now it’ll run without error. If on the other hand you don’t include the section footer in the view, you’ll get an error.



That’s because by default, sections are mandatory. To make sections optional, just add the second parameter, which is a Boolean value.



Now things will run just fine.

These three methods you will use time and time again when you're using the Razor view engine. This code works both for ASP.NET MVC 3 and also WebMatrix. Have fun!



European ASP.NET MVC 3 Hosting :: How to Integrate ASP.NET MVC 3 with ASP.NET 4 Web Forms Application

clock November 8, 2011 06:59 by author Scott

The easiest way to add ASP.NET MVC 3 to an upgraded ASP.NET 2.0 WebForms application:

- Run the Upgrade Wizard (open the  Visual Studio2008 Web Application in Visual Studio 2010)
- Create a default ASP.NET MVC application for reference (you'll throw it away later)
- Use a differencing tool like
Beyond Compare to integrate the new web.config entries from the ASP.NET MVC sections into the upgraded ASP.NET WebForms application

Upgrading an ASP.NET 2.0 WebForms Application



Now, open this application in Visual Studio 2010. You'll get the Conversion/Upgrade Wizard



Then click Next until Finish. You will get prompt to upgrade the 2.0 application to .NET Framework 4. Click Yes.



Here's the same WebForms application, now upgraded in Visual Studio 2010. It still runs and it's still WebForms. Or, more accurately, it continues to  be ASP.NET.



I'm going to take a new default ASP.NET MVC 3 application and Beyond Compare and compare the upgraded app with the default app.



I'll copy over these folders and files:

- Content
- Controllers
- Models
- Scripts
- Views
- Global.asax, Global.asax.cs

Now, here's the before and after references from the upgraded application. You’ll see the old one on image_6 and the new one on the image_7.



Here's the references I added.

1. Microsoft.CSharp - (as this was a C# app)

2. System.Web.Mvc  - From \Program Files (x86)\Microsoft ASP.NET\ASP.NET MVC 3\Assemblies

3. System.Web.WebPages and System.Web.Razor - From \Program Files (x86)\Microsoft ASP.NET\ASP.NET Web Pages\v1.0\Assemblies

4. System.ComponentModel.DataAnnotations

Next, add these sections to the Web.config. Again, it's easier to use a diff tool and you might have a little trial and error.

Thought: This might be a nice
NuGet package for someone to make...

Add these settings in appSettings:

<appSettings>
   <add key="ClientValidationEnabled" value="true"/>
   <add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>

Add these assembly elements under compilation:

<compilation debug="true" targetFramework="4.0">
  <assemblies>
    <add assembly="System.Web.Abstractions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
  </assemblies>
</compilation>

Add these namespaces in pages

<system.web>
  <pages>
     <namespaces>
       <add namespace="System.Web.Helpers" />
       <add namespace="System.Web.Mvc" />
       <add namespace="System.Web.Mvc.Ajax" />
       <add namespace="System.Web.Mvc.Html" />
       <add namespace="System.Web.Routing" />
       <add namespace="System.Web.WebPages"/>
     </namespaces>
   </pages>
</system.web>

If you're running IIS7 at some point, which I'm sure you will, add these:

<system.webServer>
  <validation validateIntegratedModeConfiguration="false"/>
  <modules runAllManagedModulesForAllRequests="true"/>
</system.webServer>


And finally add this assembly binding redirect, just in case you've got ASP.NET MVC 1 or 2 assemblies in your Global Assembly Cache (GAC).

<configuration>
 <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
        <bindingRedirect oldVersion="1.0.0.0-2.0.0.0" newVersion="3.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>


Also, make sure you merge in the Global.asax.cs so that your Routes are registered at application startup.

public class SomeHybrid: System.Web.HttpApplication
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new HandleErrorAttribute());
    }

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);
    }
}

Now, at this point I can visit both pages. The WebForms page is a file on disk, so ASP.NET routing passes requests directly on to this page when I /default.aspx. The ASP.NET Routing engine is engaged so I can also hit /Home/Index.


If I want to get fancy, I can add a PageRoute so I have pretty URLs when visit my WebForms pages as well. Just add a route in the Global.asax like this. Make sure that simple routes like these come first, as the default ASP.NET MVC route is very "greedy" and would gobble up a simple URL like /calculator

routes.MapPageRoute("WebFormThing", "Calculator", "~/Default.aspx");

Now I can visit /Calculator and the request is routed to /Default.aspx. And of course, my ASP.NET MVC 3 Razor pages like /Home/Index work also.



Finally, just to make the point, here's the Default.aspx from the WebForms part of my new app next to the source for a Razor page



Enjoy it.



About HostForLIFE.eu

HostForLIFE.eu is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2016 Hosting, ASP.NET Core 2.2.1 Hosting, ASP.NET MVC 6 Hosting and SQL 2017 Hosting.


Tag cloud

Sign in