System web mvc error

How to Make Custom Error Pages Work in ASP.NET MVC 5 In this article, we’ll take a look at how to manually customize an error page in ASP.NET and ASP.NET MVC 5. Read on for more! Join the DZone community and get the full member experience. We can manually customize an error page in […]

Содержание

  1. How to Make Custom Error Pages Work in ASP.NET MVC 5
  2. In this article, we’ll take a look at how to manually customize an error page in ASP.NET and ASP.NET MVC 5. Read on for more!
  3. Introduction
  4. MVC Description
  5. Need for Custom Error Page
  6. Steps to Be Followed
  7. Step 1
  8. Step 2
  9. Code Ref
  10. Code Description
  11. Step 3
  12. Code Ref
  13. Code Description
  14. Step 4
  15. Code Ref
  16. Code Description
  17. Step 5
  18. Code Ref
  19. Code Description
  20. Step 6
  21. Step 7
  22. Code Ref
  23. Step 8
  24. Code Ref
  25. Code Description
  26. Step 9
  27. Code Ref
  28. Output
  29. Code Ref
  30. Summary
  31. How to Make Custom Error Pages Work in ASP.NET MVC 5
  32. In this article, we’ll take a look at how to manually customize an error page in ASP.NET and ASP.NET MVC 5. Read on for more!
  33. Introduction
  34. MVC Description
  35. Need for Custom Error Page
  36. Steps to Be Followed
  37. Step 1
  38. Step 2
  39. Code Ref
  40. Code Description
  41. Step 3
  42. Code Ref
  43. Code Description
  44. Step 4
  45. Code Ref
  46. Code Description
  47. Step 5
  48. Code Ref
  49. Code Description
  50. Step 6
  51. Step 7
  52. Code Ref
  53. Step 8
  54. Code Ref
  55. Code Description
  56. Step 9
  57. Code Ref
  58. Output
  59. Code Ref
  60. Summary
  61. Common Issues
  62. Troubleshooting
  63. Kendo.Mvc.Examples upgraded to 4.6.2
  64. I Am Still Getting the Old Version
  65. The Icons Are Missing after the Upgrade
  66. JavaScript
  67. jQuery Is Unavailable or Undefined
  68. Widgets Are Unavailable or Undefined
  69. The System.Web.Mvc Versions Referenced in the Application and Used by Kendo.Mvc.dll Are Different
  70. Live Method Is Unavailable, Undefined or Unsupported
  71. DOM-Based Open Redirection Issue in kendo.aspnetmvc.min.js Is Reported
  72. Server Side
  73. Visual Studio Server IntelliSense Does Not Show MVC Helper Extension Methods
  74. Html.Kendo().SomeKendoWidgetFor() Does Not Update Bound Properties on Server
  75. Nesting MVC Wrappers Produces Server-Side Exceptions When Using WebForms View Engine
  76. Nesting MVC Wrappers Produces Server-Side Exceptions When Using Razor View Engine
  77. High Memory Consumption On Server
  78. Performance
  79. Menu Renders Too Slowly in Debug Mode
  80. Widgets
  81. Kendo UI MVC Wrappers Do Not Work Inside Client Templates
  82. Widget Value Is Not Bound to Model Property
  83. Widget Loading Icon Continues Spinning
  84. Widgets Do Not Work with Remote Binding and Throw No Errors
  85. Widgets Display Zero Values
  86. Only One Widget Instance Works on Page
  87. Loading Partial Views Containing Widgets Work Only the First Time
  88. MVC Wrappers Cause Double AJAX Postback in Debug Mode Using Ajax.Beginform()
  89. Theme Images Do Not Appear When Using CSS Bundling
  90. MVC Wrapper with Ajax Binding Shows Outdated Data
  91. Date Picker HtmlHelpers
  92. Display the DateTimeOffset Value in a Widget
  93. Client Validation Fails with Invalid Date
  94. Editor HtmlHelper
  95. Editor Shows HTML Tags after Validation

How to Make Custom Error Pages Work in ASP.NET MVC 5

In this article, we’ll take a look at how to manually customize an error page in ASP.NET and ASP.NET MVC 5. Read on for more!

Join the DZone community and get the full member experience.

We can manually customize an error page in ASP.NET and ASP.NET MVC 5.

Introduction

The MVC architectural pattern separates the user interface (UI) of an application into three main parts.

  1. The Model − A set of classes that describes the data you are working with as well as the business logic.
  2. The View − Defines how the application’s UI will be displayed. It is pure HTML, which decides how the UI is going to look.
  3. The Controller − A set of classes that handles communication from the user, overall application flow, and application-specific logic.

MVC Description

This is responsible for rendering the user interface, whether that be HTML or whether it actually be UI widgets on a desktop application. The view talks to a model, and that model contains all of the data that the view needs to display. Views generally don’t have much logic inside of them at all.

The controller that organizes is everything. When an HTTP request arrives for an MVC application, that request gets routed to a controller, and then it’s up to the controller to talk to either the database, the file system, or the model.

Need for Custom Error Page

We would just configure our custom error pages in one place and it would just work, no matter how/where the error was raised. In order to handle exceptions thrown by your action methods, you need to mark your method with the HandleError attribute. The HandleError attribute also allows you to use a custom page for this error.

Steps to Be Followed

Step 1

First, create an Application named “Error.”

Step 2

Now, create a controller class file named “HomeController.cs.”

Code Ref

Code Description

HandleError provides built-in exception filters. The HandleError attribute in ASP.NET MVC can be applied over the action method as well as the controller or at the global level.

At Home/Index or Home/Index1, the app will show error.cshtml as the view not found in index1 but in the web.config file. The error statusCode=»404″ means that the file is not found and it means the controller name or controller action method name is the issue.

[HandleError] //If I put in this attribute and run, it will go to the Customized By Default error page.

Step 3

Now, create a controller class file named “ErrorController.cs.”

Code Ref

Code Description

[HandleError] //If I put in this attribute and run, using Error/Index, it will go to Customized By Default Error page.

Step 4

Now, go to the Views folder, create a view named “NotFound.cshtml” in the Views/Error folder.

Code Ref

Code Description

This error file will be shown when the file is not found or the Controller Name/Controller Action Method Name is not there.

Step 5

Now, go to the Views folder, create a view named “Index.cshtml” in the Views/Home folder.

Code Ref

Code Description

This Index file will be shown when the file is found or the Controller Name/Controller Action Method Name is there.

Step 6

Visual Studio, by default, is creating two cshtml files, i.e. _Layout.cshtml and Error.cshtml inside the Shared folder.

  1. The _Layout.cshtml file is for creating any Master Page file in MVC.
  2. In this cshtml file, put your own layout for master page purposes, as we did it in ASP.NET earlier.
  3. The _Layout.cshtml fileis referred to in the _ViewStart.cshtml file.
  4. The _ViewStart.cshtml file contains the _Layout.cshtml to show the master page on every page by mentioning it in other cshtml files, like the Index.cshtml file.
  5. If you want to apply the Master page in MVC, only mention the cshtml page reference of ViewStart.cshtml in other child cshtml files instead of _Layout.cshtml.

Step 7

Now, put your own code in the Error.cshtml file by removing the existing code.

Code Ref

This file will be shown while processing your request or while the view of the corresponding controller and controller action method is there.

Step 8

Go to the Web.config file. Add some code for the ‘file not found’ exception.

Code Ref

Code Description

Similar to the code given above, you can create other exceptions related to the page (Controllers and Controller Action Methods).

Step 9

Go to the RouteConfig.cs file in the App_Start folder, add some code to set the start page.

Code Ref

Output

Available Home Controller and Controller Action Method and Index View name are given.

If you type in the below URL >>

Home Controller and Controller Action Method name are available there, but the Index1 View name is not there.

Your request or the view of the corresponding Controller and Controller Action Method are not there. So, you will get error page like this.

Home Controller and Controller Action Method are available but the View name is not there, i.e. Home1 and Index1.

So, for the page you are looking for, the file is not found or the Controller Name/Controller Action Method Name is not there.

In the URL given above, the path /Error/NotFound is configured in the Web.Config file.

The HTML Action Link Helper class acts like the ASP.NET Link button and it will redirect the user to the mentioned page or the proper Controller name and Action method name.

Code Ref

The output of the redirected page is mentioned in the Action Link.

Summary

Here, we’ve learned how to reconfigure an error page in the web.config file and show the error of the file not found on an exception page to the end user.

Happy coding and best of luck!

Opinions expressed by DZone contributors are their own.

Источник

How to Make Custom Error Pages Work in ASP.NET MVC 5

In this article, we’ll take a look at how to manually customize an error page in ASP.NET and ASP.NET MVC 5. Read on for more!

Join the DZone community and get the full member experience.

We can manually customize an error page in ASP.NET and ASP.NET MVC 5.

Introduction

The MVC architectural pattern separates the user interface (UI) of an application into three main parts.

  1. The Model − A set of classes that describes the data you are working with as well as the business logic.
  2. The View − Defines how the application’s UI will be displayed. It is pure HTML, which decides how the UI is going to look.
  3. The Controller − A set of classes that handles communication from the user, overall application flow, and application-specific logic.

MVC Description

This is responsible for rendering the user interface, whether that be HTML or whether it actually be UI widgets on a desktop application. The view talks to a model, and that model contains all of the data that the view needs to display. Views generally don’t have much logic inside of them at all.

The controller that organizes is everything. When an HTTP request arrives for an MVC application, that request gets routed to a controller, and then it’s up to the controller to talk to either the database, the file system, or the model.

Need for Custom Error Page

We would just configure our custom error pages in one place and it would just work, no matter how/where the error was raised. In order to handle exceptions thrown by your action methods, you need to mark your method with the HandleError attribute. The HandleError attribute also allows you to use a custom page for this error.

Steps to Be Followed

Step 1

First, create an Application named “Error.”

Step 2

Now, create a controller class file named “HomeController.cs.”

Code Ref

Code Description

HandleError provides built-in exception filters. The HandleError attribute in ASP.NET MVC can be applied over the action method as well as the controller or at the global level.

At Home/Index or Home/Index1, the app will show error.cshtml as the view not found in index1 but in the web.config file. The error statusCode=»404″ means that the file is not found and it means the controller name or controller action method name is the issue.

[HandleError] //If I put in this attribute and run, it will go to the Customized By Default error page.

Step 3

Now, create a controller class file named “ErrorController.cs.”

Code Ref

Code Description

[HandleError] //If I put in this attribute and run, using Error/Index, it will go to Customized By Default Error page.

Step 4

Now, go to the Views folder, create a view named “NotFound.cshtml” in the Views/Error folder.

Code Ref

Code Description

This error file will be shown when the file is not found or the Controller Name/Controller Action Method Name is not there.

Step 5

Now, go to the Views folder, create a view named “Index.cshtml” in the Views/Home folder.

Code Ref

Code Description

This Index file will be shown when the file is found or the Controller Name/Controller Action Method Name is there.

Step 6

Visual Studio, by default, is creating two cshtml files, i.e. _Layout.cshtml and Error.cshtml inside the Shared folder.

  1. The _Layout.cshtml file is for creating any Master Page file in MVC.
  2. In this cshtml file, put your own layout for master page purposes, as we did it in ASP.NET earlier.
  3. The _Layout.cshtml fileis referred to in the _ViewStart.cshtml file.
  4. The _ViewStart.cshtml file contains the _Layout.cshtml to show the master page on every page by mentioning it in other cshtml files, like the Index.cshtml file.
  5. If you want to apply the Master page in MVC, only mention the cshtml page reference of ViewStart.cshtml in other child cshtml files instead of _Layout.cshtml.

Step 7

Now, put your own code in the Error.cshtml file by removing the existing code.

Code Ref

This file will be shown while processing your request or while the view of the corresponding controller and controller action method is there.

Step 8

Go to the Web.config file. Add some code for the ‘file not found’ exception.

Code Ref

Code Description

Similar to the code given above, you can create other exceptions related to the page (Controllers and Controller Action Methods).

Step 9

Go to the RouteConfig.cs file in the App_Start folder, add some code to set the start page.

Code Ref

Output

Available Home Controller and Controller Action Method and Index View name are given.

If you type in the below URL >>

Home Controller and Controller Action Method name are available there, but the Index1 View name is not there.

Your request or the view of the corresponding Controller and Controller Action Method are not there. So, you will get error page like this.

Home Controller and Controller Action Method are available but the View name is not there, i.e. Home1 and Index1.

So, for the page you are looking for, the file is not found or the Controller Name/Controller Action Method Name is not there.

In the URL given above, the path /Error/NotFound is configured in the Web.Config file.

The HTML Action Link Helper class acts like the ASP.NET Link button and it will redirect the user to the mentioned page or the proper Controller name and Action method name.

Code Ref

The output of the redirected page is mentioned in the Action Link.

Summary

Here, we’ve learned how to reconfigure an error page in the web.config file and show the error of the file not found on an exception page to the end user.

Happy coding and best of luck!

Opinions expressed by DZone contributors are their own.

Источник

Common Issues

This page provides solutions to common issues you may encounter while working with Telerik UI for ASP.NET MVC.

Because Telerik UI for ASP.NET MVC is powered by Kendo UI, check the general article on Kendo UI troubleshooting for more issues and their solutions.

Troubleshooting

Kendo.Mvc.Examples upgraded to 4.6.2

The examples project is 4.6.2 targetFramework. Installation of Microsoft .NET Framework 4.6.2 is required. If you cannot install it, you could switch the targetFramework to 4.5 and run the examples without using Telerik.Web.PDF dependency. Telerik.Web.PDF is a netstandard project that uses DPL libraries to convert PDF documents into json that is utilized by the PDFViewer component.

I Am Still Getting the Old Version

Sometimes the .NET Framework caches the old Kendo.MVC dll. As a result, the upgrade may seem to have failed.

Solution

  1. From the Windows Task Manager, terminate the IIS process and close Visual Studio.
  2. Clean up the Temporary ASP.NET files from :WindowsMicrosoft.NETFramework[64] Temporary ASP.NET Files .
  3. Delete your browser cache. For Internet Explorer, select Tools >Internet Options >Delete Files.
  4. Clean up the Windows WebSite Cache from Users AppDataLocalMicrosoftWebsiteCache . The location of this cache may vary from one operating system to another.
  5. Clean up the Visual Studio Backup from :Users DocumentsVisual Studio Backup Files . The exact location depends on your Visual Studio settings and installation.

The Icons Are Missing after the Upgrade

As of the Kendo UI R1 2017 release, the Telerik UI for ASP.NET MVC uses font icons, which might lead to compatibility issues.

Solution

If you upgrade your project from a prior version to the R1 2017 version (2017.1.118) or later, you have to change the classes of the custom CSS rules that you use accordingly.

If the icons are still missing after you change the classes, verify that the version is fully updated.

JavaScript

jQuery Is Unavailable or Undefined

This error is triggered in the following cases:

  • jQuery is not included at all.
  • jQuery is included after the Telerik UI for ASP.NET MVC script files.
  • jQuery is included after a Kendo UI widget or an MVC wrapper declaration.

For more symptoms on that, refer to the article on JavaScript errors.

Solution

Make sure that jQuery is included before the Telerik UI for ASP.NET MVC JavaScript files, and before any Kendo UI widget or MVC wrapper declarations, unless deferred initialization is used. If you use the ASP.NET bundles, move the Scripts.Render(«

/bundles/jquery») block before the Telerik UI for ASP.NET MVC JavaScript files.

Widgets Are Unavailable or Undefined

If jQuery is included more than once in the page, all existing jQuery plugins (including Kendo UI) are wiped out. This issue also occurs if the required Kendo UI JavaScript files are not included.

Solution

  1. Make sure that jQuery is not included more than once in your page.
  2. Remove any duplicate script references to jQuery.
  3. Include all required Kendo UI JavaScript files.

If the application is using Telerik Extensions for ASP.NET MVC, indicate to the ScriptRegistrar not to include jQuery.

If the application is using ASP.NET bundles, make sure that the Scripts.Render(«

/bundles/jquery») block appears before the Kendo UI JavaScript files. If not, do not include jQuery as a script element.

The System.Web.Mvc Versions Referenced in the Application and Used by Kendo.Mvc.dll Are Different

Kendo.Mvc.dll is regularly updated to support the latest ASP.NET MVC 5 version. If you try to use the latest version of Telerik UI for ASP.NET MVC in an ASP.NET MVC 5 application that uses an older version of System.Web.Mvc , an exception is thrown saying that the versions of the System.Web.Mvc do not match.

If an older version of Kendo.Mvc.dll is referenced and it uses a version of System.Web.Mvc older than the one referenced in the application, a warning will be displayed.

Solution

    Upgrade ASP.NET MVC 5 which is used in the application to the newest version ASP.NET MVC 5 Nuget.

Update the binding redirect for System.Web.Mvc in the web.config file.

Live Method Is Unavailable, Undefined or Unsupported

This error occurs after upgrading jQuery to 1.9. The live method is no longer available in this version of jQuery. As a result, some JavaScript libraries which are often used in ASP.NET MVC applications, throw errors.

These libraries are:

  • jquery.unobtrusive-ajax
  • jquery.validate
  • jquery.validate.unobtrusive

Solution

Below are listed the packages you need to update through NuGet.

In ASP.NET MVC 3 applications jquery.unobtrusive-ajax and jquery.validate.unobtrusive are not installed as NuGet packages. Install them separately. The packages are Microsoft.jQuery.Unobtrusive.Ajax and Microsoft.jQuery.Unobtrusive.Validation . First, delete jquery.unobtrusive-ajax.js , jquery.unobtrusive-ajax.min.js , jquery.validate.unobtrusive.js , and jquery.validate.unobtrusive.min.js from your

/Sripts folder. Then, install Microsoft.jQuery.Unobtrusive.Ajax and Microsoft.jQuery.Unobtrusive.Validation .

DOM-Based Open Redirection Issue in kendo.aspnetmvc.min.js Is Reported

Some JavaScript security tools report a possible DOM-based open redirection issue in the kendo.aspnetmvc.min.js file.

The relevant part of the source code is used when a Kendo UI Grid is server-bound and data operations, such as paging and sorting, reload the whole web page. The code takes the query string portion of the current URL, manipulates some of the parameter values, such as the page number, and sets it as a new location.href . In standard scenarios, the same page will be loaded as a result, but with different query string parameters which, anyway, should be subject to server-side validation as a best practice.

In theory, it is possible to configure a different URL rather than the current page in the DataSource settings of the Grid. However, this is under the control of the developer. If the configured URL is changed by a third party, the application is already compromised.

Solution

This issue does not represent a justifiable reason for concern and can be marked as a false positive.

Server Side

Visual Studio Server IntelliSense Does Not Show MVC Helper Extension Methods

Solution

Below are listed the steps for you to follow to fix this issue.

Make sure the Kendo.Mvc.UI namespace is imported in web.config .

If you are using the WebForms view engine, open the web.config file in the root folder of your application. Add before the closing namespaces tag.

If you are using the Razor view engine, open the web.config file which is in the Views folder of your application. Add before the closing namespaces tag.

Rebuild your solution.

Close and open again the view you were editing. IntelliSense should be working now.

Html.Kendo().SomeKendoWidgetFor() Does Not Update Bound Properties on Server

Most probably this is happening because you have a specified Name() for the widget which is different from the property name. Since the Name() controls not only the id attribute of the input element, but also the name attribute as well, the MVC model binder fails to bind the value.

Solution

Omit specifying the Name() or use the same Name() as the name of the property.

Nesting MVC Wrappers Produces Server-Side Exceptions When Using WebForms View Engine

This can happen if the nested wrappers are declared within code blocks, which output content directly, for example, or . An Invalid expression term ‘)’ exception is thrown.

The following example demonstrates a wrong approach to avoid the issue.

Solution

The following example demonstrates the proper approach to avoid the issue.

Nesting MVC Wrappers Produces Server-Side Exceptions When Using Razor View Engine

This can happen if there are nested

tags, which is not allowed by the Razor view engine. An Inline markup blocks cannot be nested. Only one level of inline markup is allowed exception is thrown.

Solution

In such scenarios, the inner widget can be included through a custom helper.

High Memory Consumption On Server

Using the ASP.NET Bundling with the large, pre-minified files, such as kendo.all.min , can result in a high memory usage.

Solution

Use a plain Bundle instead of ScriptBudle for these files.

Performance

The Menu has security trimming functionality, which is enabled by default. Under the hood, it creates an AuthorizationContext for every menu item with set Action/Controller. In the debug mode these context objects— ControllerContext , ActionContext , and the resulting AuthorizationContext —are not cached and are recreated each time the Menu is rendered. As a result, there may be delay in rendering the menu in case there are a lot of items. When your application is deployed and debug mode is disabled, the authorization context objects are cached.

For more information on the ASP.NET debug mode, refer to the Scott Guthrie’s Don’t Run Production ASP.NET Applications with debug=»true» Enabled blog post.

Solution

Below are listed the steps for you to follow while handling this issue.

Disable security trimming if not needed or during development. Enable it again when deploying the site.

Disable debug mode. Set the debug attribute of the compilation element in the web.config to false .

Kendo UI MVC Wrappers Do Not Work Inside Client Templates

This can happens if the wrapper is declared without ToClientTemplate() .

Solution

For more information on this issue, refer to the article on Kendo UI wrappers fundamentals

On the other hand, note that template script expressions that include brackets (function calls) or arithmetic operators cannot be included in the Name() method of Kendo UI MVC wrappers. For example, the following implementations will trigger invalid template JavaScript errors:

In other words, the Name() of a Kendo UI MVC widget can only contain a Kendo UI template with a reference to a variable.

Widget Value Is Not Bound to Model Property

If the name of a widget is different from the property of the Model, the ModelBinder is not able to update the model.

Solution

Verify that the name of the widget is the same as the Model’s property you want to update.

If strongly-typed widget is used, do not set the Name manually, because a name is generated automatically.

Widget Loading Icon Continues Spinning

This issue refers to the Kendo UI AutoComplete, ComboBox, DropDownList, and MultiSelect widgets. The most common cause is an internal server error.

Solution

Apply either of the two options below:

Verify that GET requests are allowed.

Change HTTP verb of the DataSource.

Widgets Do Not Work with Remote Binding and Throw No Errors

This issue refers to the Kendo UI AutoComplete, ComboBox, DropDownList, and MultiSelect widgets. The most common cause is the usage of the ToDataSourceResult extension method when returning Data. Note that the method returns the result in a JSON structure, which is understandable only for the Grid widget.

Solution

Apply either of the two options below:

Return a simple array of data.

Return the Data property only.

More information on how to configure Kendo UI widgets for Ajax binding and return data to the client, refer to the overview article of each widget.

Widgets Display Zero Values

This issue refers to the Kendo UI ComboBox widget. It supports item selection or custom values. In the latter case, the custom value is displayed as text , because this is how the custom value is treated.

The widget displays a 0 value if it is bound to the non-nullable integer or other number type. In this case, the widget retrieves the default value which is 0 and sets it, and it is a perfectly valid value. When the widget is initialized on the client, it cannot find such a data item and considers the value as a custom one. This is why it is displayed in the visible input.

Solution

To avoid this default behavior, clear the value of the widget using its Value method.

Only One Widget Instance Works on Page

This happens if two or more widgets or MVC server wrappers have the same Name() . The value specified via the Name() method is used as the id HTML attribute of the widget. The latter must be unique in the page.

Solution

Always use unique widget or MVC server wrappers names. For example, append an index to make the name unique.

Loading Partial Views Containing Widgets Work Only the First Time

This happens because there is more than one Kendo UI widget with the same Name() .

Solution

Check the solution of the previous problem.

MVC Wrappers Cause Double AJAX Postback in Debug Mode Using Ajax.Beginform()

Solution

Add the line from the example below to the bundleconfig.cs file.

This prevents the unobtrusive Ajax script from loading twice—the minified and non-minified—in debug mode, which is what causes the double postback.

Alternatively, just remove the non-minified script from the project. Obviously, this has implications for debugging, if you are inclined to debug the scripts included in the project template.

Theme Images Do Not Appear When Using CSS Bundling

Solution

When the Kendo UI theme images do not appear in this case, refer to the article on CSS bundling.

MVC Wrapper with Ajax Binding Shows Outdated Data

If a widget does not show the updated data on a page visit, the most common reason for this is a cached Ajax request. The Internet Explorer is notorious with its requests caching, which returns the cached XmlHttpRequest result instead of making a new request.

Solution

Choose either of the options to overcome this behavior:

    Force the check for newer versions of stored pages (link).

Disable caching using HTTP headers.

Date Picker HtmlHelpers

Display the DateTimeOffset Value in a Widget

The DatePicker, DateTimePicker, and TimePicker widgets support only the DateTime structure.

Solution

Convert DateTimeOffset into a DatePicker, DateTimePicker, or TimePicker to show the date and time correctly.

Client Validation Fails with Invalid Date

By default, the ASP.NET MVC project uses jQuery validate framework, which does not provide support for internationalized dates. This means that every string which Date.parse is not able to define as a valid date, is reported as invalid.

Solution

As extending open source libraries is outside the Kendo UI scope, you need to resolve this issue manually. For more information, check this link, or use the Kendo UI Validator, which supports the validation of internationalized dates.

Editor HtmlHelper

Editor Shows HTML Tags after Validation

After the server-side validation, the Editor displays the posted encoded value from the ModelState . The Razor view engine encodes it once again and, as a result, HTML tags appear inside the widget content area. More information about this behavior related to ASP.NET MVC is available at the blog post on wrong value rendering by ASP.NET MVC’s HtmlHelpers.

Solution

You have two alternative options to tackle this scenario:

  • Clear the ModelState in the controller’s action method after the POST .
  • Set Encode(false) for the Editor and set an [AllowHtml] attribute to the model property, so that the Editor’s value is submitted non-encoded.

For additional tips on the Editor widget, refer to the troubleshooting article on common Kendo UI Editor issues.

Источник

Сегодня обсудим, как на asp.net mvc можно настроить обработку ошибок 404, 500, ну и любых других. Рассмотрим на примере 404 и 500, как наиболее популярных и важных. Как вместо стандартного не очень красивого желтого окна ошибки показывать свои собственные красивые интересные страницы, и при этом как правильно отдавать код ошибки в браузер пользователя.

Казалось бы, задача довольно тривиальная и может быть решена написанием буквально пары строк кода. Действительно, так и есть, если вы используете любую популярную серверную технологию. Но только не ASP.NET. Если ваше приложение написано на ASP.NET MVC, и вы первый раз сталкиваетесь с проблемой обработки ошибок, очень легко запутаться и сделать неправильные настройки. Что впоследствии негативно отразится на продвижении сайта в поисковых системах, удобстве работы для пользователя, SEO-оптимизации.

Рассмотрим два подхода, как настроить страницы ошибок. Они в целом похожи, какой выбрать – решать вам.

Для начала вспомним, что означают наиболее популярные коды ошибок, которые отдает сервер.

Код ответа 200. Это значит что все ОК. Запрос клиента обработан успешно, и сервер отдал затребованные клиентом данные в полном объеме. Например, пользователь кликнул по гиперссылке, и в ответ на это в браузере отобразилась нужная ему информация.

Код ответа 404. Это означает, что запрошенный клиентом ресурс не найден на сервере. Например, указанная в адресе гиперссылки статья не найдена, или *.pdf файл был удален и теперь недоступен для скачивания.

Код ответа 500. Внутренняя ошибка на сайте. Что-то сломалось. Это может быть все что угодно, от неправильно написанного кода программистом, до отказа оборудования на сервере.

Допустим, мы только что создали новое веб-приложение типа MVC. На текущий момент, если никаких дополнительных действий для обработки ошибок не принимать, то стандартный сценарий обработки ошибок будет работать как нужно. В браузер пользователя будет отдаваться правильный код ошибки, пользователю будет показана стандартная страница с ошибкой и ее описанием.

Стандартная страница ошибки

Стандартная страница ошибки

Теперь займемся настройкой собственных страниц ошибок. При этом для нас важно не только показать пользователю красивую страницу ошибки, но также сохранить правильный код ответа сервера.

Вариант 1. Ссылка на статичные заранее подготовленные html-страницы.

Первым делом в файле web.config в разделе system.web добавляем новую секцию customErrors со следующими настройками:

web.config

<system.web>
  <customErrors mode="On" redirectMode="ResponseRewrite" defaultRedirect="~/404.aspx">
    <error statusCode="404" redirect="~/404.aspx"/>
    <error statusCode="500" redirect="~/500.aspx"/>
  </customErrors>
  ...
</system.web>

Эта секция служит для обработки ошибок на уровне платформы ASP.NET.

Атрибут mode=»On» определяет, что пользовательские страницы ошибок включены. Также допустимы значения Off / RemoteOnly.

Атрибут redirectMode=»ResponseRewrite» определяет, следует ли изменять URL-адрес запроса при перенаправлении на пользовательскую страницу ошибки. Естественно, нам этого не нужно.

Атрибут defaultRedirect=»~/404.aspx» указывает на то, какая страница ошибки будет показана в случае возникновения кода ответа сервера, который мы не описали в настройках. Пусть при любых других ошибках пользователь будет думать, что страница не найдена.

И уже внутри этой секции мы определяем два кода, для которых у нас будут кастомные страницы ошибок.

Далее, как видно из настроек выше, нам понадобятся *.aspx файлы, на которые будет делаться редирект. Обратите внимание, что мы ссылаемся именно на *.aspx файлы, а не на *.html. Эти файлы являются проходными, служебными, в них содержатся настройки для ответа сервера. Содержимое файла 404.aspx:

404.aspx

<%@ Page Language="C#" %>

<%
    var filePath = MapPath("~/404.html");
    Response.StatusCode = 404;
    Response.ContentType = "text/html; charset=utf-8";
    Response.WriteFile(filePath);
%>

В коде выше мы указываем путь непосредственно до конечного *.html файла, а также дополняем настройки ответа сервера. Указываем код ответа, тип отдаваемого контента и кодировку. Если не указать кодировку, то браузер пользователя может интерпретировать ответ от сервера как не отформатированную строку, и, соответственно, не преобразует ее в html-разметку. А если не указать StatusCode = 404 , то получится следующая интересная ситуация:

Код ответа сервера отдается неверно

Код ответа сервера отдается неверно

И хотя на рисунке выше нам показывается пользовательская страница с ошибкой, при этом код ответа 200 — это конечно же неверно. Когда-то давно на форумах Microsoft такое поведение зарепортили как баг. Однако Microsoft возразила, что это не баг, а фича и не стала ничего менять в будущих релизах ASP.NET. Поэтому приходится это исправлять вручную, и вручную в *.aspx файле в ответе сервера указывать код ответа 404.

Попробуйте собственноручно намеренно убрать какую-нибудь из объявленных на данный момент настроек из секции customErrors и понаблюдайте за результатом.

Также по аналогии создаем подобный *.aspx файл для ошибки 500.

И уже после этого нам нужно создать статичные html-файлы, соответственно для ошибок 404 и 500. Пусть они лежат в корне нашего проекта.

Статичные файлы расположены в корне проекта

Статичные файлы расположены в корне проекта

Здесь же в файле web.config определяем раздел system.WebServer, если он еще не определен, и в нем объявляем секцию httpErrors:

web.config

  <system.webServer>
    <httpErrors errorMode="Custom" defaultResponseMode="File" defaultPath="c:projectsmysite404.html">
      <remove statusCode="404" />
      <remove statusCode="500" />
      <error statusCode="404" path="404.html" responseMode="File" />
      <error statusCode="500" path="500.html" responseMode="File" />
    </httpErrors>
  </system.webServer>

Эта секция служит для обработки ошибок на уровне сервера IIS. Суть в том, что иногда обработка запроса происходит непосредственно на уровне ASP.NET. А иногда ASP.NET просто определяет нужный код ответа и пропускает запрос выше, на уровень сервера. Такой сценарий может случиться, если, например, мы в действии контроллера возвращаем экземпляр класса HttpNotFound:

Или же когда система маршрутизации в MVC-приложении не может определить, к какому маршруту отнести запрошенный пользователем URL-адрес:

https://site.com/long/long/long/long/path

Для секции httpErrors важно отметить следующее. Так как мы ссылаемся на статичные *.html файлы, то и в качестве значений для нужных атрибутов здесь также указываем File . Для атрибута defaultPath необходимо указать абсолютный путь до файла ошибки. Относительный путь именно в этом месте работать не будет. Сам атрибут defaultPath определяет файл, который будет выбран для всех других ошибок, которые мы явно не указали. Но здесь есть одна небольшая проблема. Дело в том, что этот атрибут по умолчанию заблокирован на сервере IIS Express. Если вы разрабатываете свое приложение именно на локальном сервере, то это ограничение нужно снять. Для этого в директории своего проекта нужно найти файл конфигурации сервера и удалить этот атрибут из заблокированных, как это показано на рисунке:

Расположение файла applicationhost.config

Расположение файла applicationhost.config

Также проверьте папку App_Start. Если вы создали не пустое приложение, а работаете над реальным проектом, там может находиться класс FilterConfig, в котором регистрируются все глобальные фильтры в приложении. В методе регистрации удалите строчку кода, где регистрируется HandleErrorAttribute, в нашем случае он не понадобится.

Вот такой комплекс мер нужно предпринять, чтобы настроить обработку ошибок 404, 500, и любых других. Это настройки в файле web.config, и добавление в наш проект статичных файлов.

Вариант 2. Обработка ошибок с использованием специального контроллера.

Второй подход немного отличается от первого. Здесь нам не понадобится секция customErrors, так как обработку всех ошибок мы будем передавать сразу из приложения на уровень сервера, и он уже будет решать что делать. Можно удалить или закомментировать эту секцию в файле web.config.

Далее создадим специальный контроллер, который будет принимать все ошибки, которые мы хотим обрабатывать:

public class ErrorController : Controller
{
    public ActionResult NotFound()
    {
        Response.StatusCode = 404;
        return View();
    }

    public ActionResult Internal()
    {
        Response.StatusCode = 500;
        return View();
    }
}

Также создадим соответствующие представления с нужной нам красивой разметкой.

Также в файле web.config нам нужно изменить настройки в секции httpErrors. Если раньше мы ссылались на статичные html-файлы, то теперь мы будем обращаться по указанным URL, которые мы определили в ErrorController’е, чтобы именно там обрабатывать ошибки:

web.config

<httpErrors errorMode="Custom" existingResponse="Replace" defaultResponseMode="ExecuteURL" defaultPath="/Error/NotFound">
  <remove statusCode="404"/>
  <remove statusCode="500"/>
  <error statusCode="404" path="/Error/NotFound" responseMode="ExecuteURL"/>
  <error statusCode="500" path="/Error/Internal" responseMode="ExecuteURL"/>
</httpErrors>

Вариант 3. Фильтр HandleErrorAttribute

Замечу, что есть еще один способ взять под свой контроль обработку ошибок в приложении – это наследоваться от стандартного класса HandleErrorAttribute и написать свой фильтр. Но это уже более частный случай, когда нужно реализовать какую-то особенную логику при возникновении той или иной ошибки. В большинстве же более менее стандартных приложений наша проблема решается двумя выше описанными способами и в этом фильтре нет необходимости. Более подробную информацию, как работать с классом HandleErrorAttribute можно найти в официальной документации в интернете по этой ссылке.

Итого

Мы посмотрели на два разных подхода, которые можно применить при обработке ошибок на платформе ASP.NET. Опять же повторюсь, что если для вас не принципиально настраивать собственные страницы ошибок, то лучше не изменять эти настройки, так как даже одна упущенная деталь или неверно сконфигурированный параметр может очень сильно навредить репутации вашего сайта для конечного пользователя и в поисковых системах.

When I refactored an existing Sitecore 8.2 project into the Helix structure, I had a server error in ‘/’ application when I first tried to get into the sitecore admin console. This type of error is usually simple to fix. It means the version of dll in the bin folder of the web root folder is different from the one in the config file.

The fix is not complicated, but it took me a bit to figure out why this was happening. So, I am going to document the steps I took to trouble shoot this.

Error message

Parser Error Message: Could not load file or assembly 'System.Web.Mvc, Version=5.2.3.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies.
The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

Source Error:
Line 142:        
Line 143:        
Line 144:        
Line 145:        
Line 146:        

Source File: C:InetpubwwwrootSitecoreWebsiteweb.config    Line: 144

Trouble shooting steps

(1) Check the version of the package across the projects

Go to Tools -> NuGet package manager -> Manage Nuget Packages for Solution… -> select Installed tab ->click Microsoft.AspNet.Mvc

There you go, one of the projects was using 5.2.7 version while others are using 5.2.3.

(2) Check the log

When I checked the log file in the Data folder in the web root folder, Sitecore was loading 5.2.7 version of System.Web.Mvc.dll.

3672 23:32:26 INFO  c:inetpubwwwrootsitecorewebsitebinsystem.web.mvc.dll
(Microsoft ASP.NET MVC, System.Web.Mvc.dll, 5.2.7-61128 (39d3064baf13181f5718ec5d85ba644b47d0704b))

(3) Re-install the correct version

Uninstall the existing package, select the right version and install.

(4) Republish the project

Go to reference of the project in the Visual Studio, right click System.Web.Mvc, select property and make sure Copy Local is set to true. This will ensure that the package will be published to the web root.

If this doesn’t work, you can go into the bin folder of the web root folder and physically delete System.Web.Mvc.dll and republish the project.

Now the error is gone.

Hurray!

  • Remove From My Forums
  • Question

  • I’ve had a look at similar postings but haven’t found one that has helped fix this issue.

    Just briefly, I have an mvc3 project running on azure. A couple of days ago it lost it’s reference to System.Web.MVC for some reason. So I added the reference and changed the Copy Local property to True. It built and ran on the local emulator ok. I then
    published it and got the following message when visting the website.

    «Could not load file or assembly ‘System.Web.Mvc, Version=3.0.0.0»

    It turns out I only version 3.0.0.1 and not 3.0.0.0 which is stated in my web.congig file. I’ve tried changing the value in web.config in both the assembly and runtime sections to 3.0.0.1 but this throws another exception in azure.(although didn’t change
    the Public Token)

    I’ve also tried Add Deployable Dependency but this has made no difference and I’ve tried downloading and adding vers 3.0.0.0 to the project but vs didn’t like this dll when publishing.

    I’ve also tried changing the property Specifc Version for the assembly to False but this hasn’t worked.

    So for some reason I don’t have v3.0.0.0 anymore but don’t know how to change my project to use v3.0.0.1 I guess.

    Thanks

    Server Error in ‘/’ Application.

    Configuration Error

    Description: An error occurred during the processing of a configuration
    file required to service this request. Please review the specific error details below and modify your configuration file appropriately. 
    Parser Error Message: Could not load file or assembly ‘System.Web.Mvc, Version=3.0.0.0, Culture=neutral,
    PublicKeyToken=31bf3856ad364e35’ or one of its dependencies. The located assembly’s manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
    Source Error: 

    Line 39:         <add assembly="System.Web.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    Line 40:         <add assembly="System.Web.Routing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    Line 41:         <add assembly="System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    Line 42:         <add assembly="System.Web.WebPages, Version=1.0.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
    Line 43:       <add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" /></assemblies>


    Source File: E:sitesrootweb.config   
    Line: 
    41 Assembly Load Trace: The following information can be helpful to determine why the assembly
    ‘System.Web.Mvc, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35’ could not be loaded.

    WRN: Assembly binding logging is turned OFF.
    To enable assembly bind failure logging, set the registry value [HKLMSoftwareMicrosoftFusion!EnableLog] (DWORD) to 1.
    Note: There is some performance penalty associated with assembly bind failure logging.
    To turn this feature off, remove the registry value [HKLMSoftwareMicrosoftFusion!EnableLog].

    :)

Answers

  • Thank’s guy’s. I actually just commented out the assembly line of code for the mvc assemble and changed the runtime binding code to look for v 3.0.0.1 in web.config and this has done the trick. I’m not sure if that was the best solution but having spent
    over a day on it time was a big factor.


    :)

    • Marked as answer by

      Monday, October 20, 2014 8:53 AM

In this article, we will be discussing various ways of handling an exception in ASP.NET MVC Web API.

Introduction

For error handling, the major difference between ASP.NET MVC Web API from MVC or a Web application is that MVC or a Web app will return a web page to handle the error while Web API is to return a RESTfule output, JSON. In ASP.NET MVC Web API, we may have three ways to handle exceptions:

  • HttpResponseException, associated with HttpStatusCode, — Locally in Try-catch-final
  • Exception filter, — in the level of Action, Controller, and Globally
  • Exception Handler, — Globally

Note:

When you try to create a ASP.NET Web API app, the MVC is selected automatically. So, the Web API app actually is an added on one of the MVC app. Therefore, we have discussed the features of exception handling for ASP.NET MVC will still hold, such as:

  • Try-catch-finally: Step 3
  • Exception filter
    • Default: customError mode=»On» in Web.Config, Step 1-1
      • Associated with [HandleError] attribute): Step 1-2
      • Add statusCode in Web.Config: Step 1-3
  • Application_Error event: Step 4

We will set up a test sample app first, and then discuss the three above one by onve.

Set up the test sample app

Step 1 — Create an ASP.NET MVC Web API app

We use the current version of Visual Studio 2019 16.8 and .NET Framework 4.7.2 to build the app.

  • Start Visual Studio and select Create a new project.
  • In the Create a new project dialog, select ASP.NET Web Application (.NET Framework) > Next.
  • In the Configure your new project dialog, enter ErrorHandlingWebAPI for Project name > Create.
  • In the Create a new ASP.NET Web Application dialog, select Web API > Creat

Note:

When you try to create a ASP.NET Web API app, the MVC is selected automatically. So, the Web API app actually is an added on part of the MVC app.

Different from MVC app, the Web API (associated with MVC) has two more files added:

While the WebApiConfig.cs file defines the class WebApiConfig, including the WebApi routing: 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace ErrorHandlingWebAPI_1
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

the ValuesController.cs defines a sample ApiController:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web.Http;

namespace ErrorHandlingWebAPI_1.Controllers
{
    public class ValuesController : ApiController
    {
        // GET api/values
        public IEnumerable<string> Get()
        {
            return new string[] { "value1", "value2" };
        }

        // GET api/values/5
        public string Get(int id)
        {
            return "value";
        }

        // POST api/values
        public void Post([FromBody] string value)
        {
        }

        // PUT api/values/5
        public void Put(int id, [FromBody] string value)
        {
        }

        // DELETE api/values/5
        public void Delete(int id)
        {
        }
    }
}

Build and run the app, you will see the following image shows the app,

Step 2 — Add one empty apiController

Add one empty apiController into the app, with the name as ErrorHandlingWebAPIController:

  • Right click Controllers > add > controller.
  • In the Add New Scaffolded Item dialog, select Web API in the left pane, and
  • Web API 2 Controller — Empty > Add.
  • In the Add Controller dialog, Change ErrorHandlingWebAPIController for controller name > Add.

Step 3 — Add Swagger Client

To test Web API, we could use Postman or Fiddler, here we use Swagger that can test the Web API automatically, and actually is by default installed for the Web API Core. 

Installing Swagger from NuGet Package Manager, from Visual Studio project: 

  • Right click Tools > NuGet Package Manager > Manage NuGet for Solution
  • In the opened NuGet-Solution dialog: Click Browse, then Search Swagger
  • Install Swashbuckle v5.6.0

After installation, and App_Start folder, there will be a file, SwaggerConfig.cs, added with code,

public class SwaggerConfig  
{  
    public static void Register()  
    {  
        var thisAssembly = typeof(SwaggerConfig).Assembly;  
        GlobalConfiguration.Configuration  
          .EnableSwagger(c => c.SingleApiVersion("v1", "ErrorHandlingWebAPI"))  
          .EnableSwaggerUi();   
    }  
} 

Step 4 — Change the default start up page to the swagger

Right click Project > Properties to open the properties page, then choose Web, in Start Url, add /swagger,

We will demonstrate the result from the next section, after adding a web api controller.

HttpResponseException

Add code into controller

We add the following code into the controller,

[Route("CheckId/{id}")]  
[HttpGet]     
public IHttpActionResult CheckId(int id)  
{         
    if (id < 10) // No error hanbdling at all:  
    {  
        int a = 1;  
        int b = 0;  
        int c = 0;  
        c = a / b; //it would cause exception.     
    }  
    else if (id <20) // Error handling by HttpResponseException with HttpStatusCode  
    {  
        throw new HttpResponseException(HttpStatusCode.BadRequest);  
    }  
    else if (id < 30) // Error handling by HttpResponseException with HttpResponseMessage  
    {  
        var response = new HttpResponseMessage(HttpStatusCode.BadRequest)  
        {  
            Content = new StringContent(string.Format("No Employee found with ID = {0}", 10)),  
            ReasonPhrase = "Employee Not Found"  
        };  
  
        throw new HttpResponseException(response);  
    }  
  
    return Ok(id);  
}  

Run the app, we have 

Discussion

Without Error Handling

What happens if a Web API controller throws an uncaught exception? By default, most exceptions are translated into an HTTP response with status code 500, Internal Server Error.

In our sample, // No error hanbdling at all case: we choos id = 1

The result in Swagger: only indicated that «An error has occurred.» without detailed info,, and the response code is 500 — Internal Server Error,

 

Error handled by HttpResponseException

The HttpResponseException type is a special case. This exception returns any HTTP status code that you specify in the exception constructor. For our sample, // Error handling by HttpResponseException with HttpStatusCode, the returns 400, BadRequest, if the id = 11.

For more control over the response, you can also construct the entire response message and include it with the HttpResponseException,

// Error handling by HttpResponseException with HttpResponseMessage, id = 21

Note

if you use Postman as a client, you can get one more piece of info: Employee Not Found associated with error code 400

Exception Filters

Exception Eilter

An exception filter is executed when a controller method throws any unhandled exception that is not an HttpResponseException exception. The HttpResponseException type is a special case, because it is designed specifically for returning an HTTP response.

Web API Exception filters implement the System.Web.Http.Filters.IExceptionFilter interface, which is different from MVC filters that implement System.Web.mvc.IExceptionFilter Interface that is derived from both

  • System.Web.Mvc.HandleErrorAttribute and
  • System.Web.Mvc.Controller

Therefore, for Web API, there is no more local exception filter defined under ApiController as OnException method as MVC Controller does.

The simplest way to write an exception filter is to derive from the System.Web.Http.Filters.ExceptionFilterAttribute class and override the OnException method. 

public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute  
{  
    public override void OnException(HttpActionExecutedContext context)  
    {  
        if (context.Exception is NotImplementedException)  
        {  
            var resp = new HttpResponseMessage(HttpStatusCode.NotFound)  
            {  
                Content = new StringContent("This method is not implemented"),  
                ReasonPhrase = "Not implemented"  
            };  
            throw new HttpResponseException(resp);  
        }  
    }  
} 

Register Exception Eilter

Exception filter must be registered in order to be used. There are three ways to register a Web API exception filter,

  • By action
  • By controller
  • Globally

We add another apiController named as TestController with code,

using System;  
using System.Web.Http;  
  
namespace ErrorHandlingWebAPI.Controllers  
{  
    [NotImplExceptionFilter]
    public class TestController : ApiController  
    {  
        [Route("Test/{id}")]  
        [HttpGet]  
        [NotImplExceptionFilter]  
        public IHttpActionResult Test(int id)  
        {  
            throw new NotImplementedException("This method is not implemented");  
        }  
  
        [Route("Test1/{id}")]  
        [HttpGet]  
          
        public IHttpActionResult Test1(int id)  
        {  
            throw new NotImplementedException("This method is not implemented");  
        }  
    }  
}  

Add attribute [NotImplExceptionFilter] in Test action level or in the controller level, or globally register in App_Start/WebApiConfig file to add: config.Filters.Add(new NotImplExceptionFilterAttribute());

public static class WebApiConfig  
{  
    public static void Register(HttpConfiguration config)  
    {  
        // Web API configuration and services  
        config.Filters.Add(new NotImplExceptionFilterAttribute());  
  
        // Web API routes  
        config.MapHttpAttributeRoutes();  
  
        config.Routes.MapHttpRoute(  
            name: "DefaultApi",  
            routeTemplate: "api/{controller}/{id}",  
            defaults: new { id = RouteParameter.Optional }  
        );  
    }  
}  

Note:

For ASP.NET MVC, there are three configuration files:

For ASP.NET Web API, there are four configuration files:

  • For MVC, When we derive an exception filter class from HandleErrorAttribute class, then we need to register it in FilterConfig.cs file, add into GlobalFilerCollection. While on the other hand,
  • For Web API, When we derive an exception filter class from ExceptionFilterAttribute class, then we need to register it in WebApiConfig.cs file, add into HttpConfiguration.

We add one more option in the previous controller/action: ErrorHandlingWebAPIController/CheckID to test the global registered exception filter

else if (id < 50)  
{  
    throw new NotImplementedException();  
}  

Then, run the app, and test the results,

 This is the for action level test result,

Exception Handler

Unhandled exceptions can be processed via exception filters, but there are a number of cases that exception filters can’t handle. For example,

  1. Exceptions thrown from controller constructors.
  2. Exceptions thrown from message handlers.
  3. Exceptions thrown during routing.
  4. Exceptions thrown during response content serialization.

Those could be handled by Exception Handler.

We add a global error handler into Global.asax file,

public class GlobalExceptionHandler : ExceptionHandler  
{  
    public override void Handle(ExceptionHandlerContext context)  
    {  
        var response = new HttpResponseMessage(HttpStatusCode.BadRequest)  
        {  
            Content = new StringContent("This is handled by Global Exception Handler"),  
            ReasonPhrase = "Exception Handler"  
        };  
  
        context.Result = new ResponseMessageResult(response);  
    }  
}  

and register in App_Start/WebApiConfig file,

public static void Register(HttpConfiguration config)  
{  
    // Web API configuration and services  
    config.Filters.Add(new NotImplExceptionFilterAttribute());  
    config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());  
  
    // Web API routes  
    config.MapHttpAttributeRoutes();  
  
    config.Routes.MapHttpRoute(  
        name: "DefaultApi",  
        routeTemplate: "api/{controller}/{id}",  
        defaults: new { id = RouteParameter.Optional }  
    );  
}  

Add one more test option in the testController

using System;  
using System.Web.Http;  
  
namespace ErrorHandlingWebAPI.Controllers  
{  
    [NotImplExceptionFilter]  
    public class TestController : ApiController  
    {  
        [Route("Test/{id}")]  
        [HttpGet]  
        [NotImplExceptionFilter]  
        public IHttpActionResult Test(int id)  
        {  
            throw new NotImplementedException("This method is not implemented");  
        }  
  
        [Route("Test1/{id}")]  
        [HttpGet]  
          
        public IHttpActionResult Test1(int id)  
        {  
            throw new NotImplementedException("This method is not implemented");  
        }  
  
        [Route("Test2/{id}")]  
        [HttpGet]  
  
        public IHttpActionResult Test2(int id)  
        {  
            throw new DivideByZeroException();  
        }  
    }  
}  

Due to the exception DivideByZeroException() not handled by exception filter we made privously, it will be caught by the global error handler,

Summary

In ASP.NET MVC Web API, we usually have three ways to handle exceptions,

  • HttpResponseException, associated with HttpStatusCode, — Locally in Try-catch-final
  • Exception filter, — in the level of Action, Controller, and Globally
  • Exception Handler, — Globally

 The order to exection is HttpResponseException ==> Exception filter ==> Exception Handler.

References

  • 《Exception Handling in ASP.NET Web API》— MS
  • 《Global Error Handling in ASP.NET Web API 2》— MS
  • 《Exception Handling in ASP.NET Web API》 — C-sharpcorner
  • 《Exception Handling in ASP.NET Web API — A Guided Tour》 

ASP Errors (handling exceptions)

NB: not data validation! For WebAPI it’s a little different- see below

Raising errors

You can return «RESTful» HTTP status codes:

//404
if (category > 0)
    return HttpNotFound(«No such category»); //new HttpNotFoundResult()

 
//400
if (category == -1)
    return new HttpStatusCodeResult(System.Net.HttpStatusCode.BadRequest,
        «Logical error.»);

 
//401, when AuthorizeAttribute is not enough
if (User.Identity.IsAuthenticated && !User.IsInRole(«Admin»))
    return new HttpUnauthorizedResult(«Unauthorized»);

 
//500
if (category == -2)
    throw new HttpException(«Generic error»);
if (category == -3)
    throw new InvalidOperationException(«Generic error»); //also gets wrapped in HttpException

Catching errors

The stack (from closest to exception upwards)

  • Controller.OnException. Rarely used.
  • [HandleError]. Normally needs logging action filter as well, and just having the Shared/Error.cshtml is limiting.
  • global.asax Application_Error. Good idea, if you don’t do HandleError with logging filter.
  • web.config customErrors. Required.
  • web.config httpErrors (IIS). Normally required.

HandleError

By default, App_Start/FilterConfig will add a global [HandleError] attribute.

You can also add other HandleError attributes on controllers or actions, for specific errors and using specific views (set Order to control precedence — high order = high priority).

[HandleError(ExceptionType = typeof(InvalidOperationException))]

HandleError detects normal exceptions (not 404s) and redirects to a view Error.cshtml, either in the same controller or /Shared.

NB: system.web/customErrors[mode=»On»] must be set, otherwise it ignores exceptions (and shows the YSOD, which in debug is what you want)

The default templated Error.cshtml is full html, but you can use _Layout and use a HandleErrorInfo model.

@model System.Web.Mvc.HandleErrorInfo

 
@{
    ViewBag.Title = «Test»;
}

 
<h1>Error Handled</h1>
<p>Controller=@Model.ControllerName action=@Model.ActionName exception=@Model.Exception.Message</p>

A view with no controller is awkward. You can’t log errors (you shouldn’t do logic in the view). You may prefer to not use a global HandleError and use web.config customErrors or global.asax Application_Error instead.

You can add a new logging filter in App_Start/FilterConfig before the HandleError

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
    filters.Add(new ErrorLoggerFilter());
    filters.Add(new HandleErrorAttribute());
}

The Error logging filter looks like this. Substitute the logging framework of your choice.

public class ErrorLoggerFilter : IExceptionFilter
{
    public void OnException(ExceptionContext filterContext)
    {
        System.Diagnostics.Trace.TraceError(
            «LogFilter: « + filterContext.Exception);

 
        //if using ELMAH
        if (filterContext.ExceptionHandled)
            Elmah.ErrorSignal.FromCurrentContext().Raise(filterContext.Exception);
    }
}

Routing 404s

«Catch-all» routes (with asterisk prefix) don’t work well. This has to be after the default «controller/action/id» route, but any url of the form x/y or /y/z never hits the catch all (you will trap 1/2/3/4)

routes.MapRoute(
    «404»,
    «{*url}»,
    new { controller = «Error», action = «NotFound» }
);

As this is basically useless, it’s better to just use customErrors, below

web.config customErrors

The traditional ASP config: system.web/customErrors[mode=»On»]. By default this does a 302.

<system.web>
  <customErrors mode=«On« defaultRedirect=«/Error/«>
    <error statusCode=«404« redirect=«/Error/NotFound« />
  </customErrors>

redirectMode=»ResponseRewrite» cannot redirect to a route, only to a physical html or aspx file.

[HandleError] intercepts most errors before this (but not 404s). Unlike [HandleError] you redirect to a controller, but the exception isn’t passed on so you can’t log it (use a logging exception filter or global.asax Application_Error).

httpErrors

This is only used by IIS7. customErrors will trap errors first, and httpErrors catches higher level IIS level exceptions like 404s on .html files.

<system.webServer>
  <httpErrors errorMode=«Custom«>
    <!— catch all non-ASP 404s (.jpg, .html) —>
    <remove statusCode=«404« />
    <error statusCode=«404« path=«/Error/NotFound« />
  </httpErrors>

customErrors mode should still be set to On

Error controller

You simply set the HTTP status code and Response.TrySkipIisCustomErrors to true. But you don’t have access to the original exception (you arrive at the controller from a 302 redirect).

public class ErrorController : Controller
{
    // GET: /Error/
    public ActionResult Index()
    {
        Response.StatusCode = (int)System.Net.HttpStatusCode.InternalServerError; //500
        Response.TrySkipIisCustomErrors = true;
        return View();
    }

 
    // GET: /Error/NotFound
    public ActionResult NotFound()
    {
        Response.StatusCode = (int)System.Net.HttpStatusCode.NotFound; //404
        Response.TrySkipIisCustomErrors = true;
        return View();
    }
}

Global.asax Application_Error

The «classic» asp.net solution is still preferable to HandleError. It fires before customErrors. If you don’t call Server.ClearError the customErrors takes over. It is not fired if there is a [HandleError] attribute. If you are not logging exceptions through an action filter, you can reliably log here.

protected void Application_Error()
{
    var exception = Server.GetLastError();
    Response.Clear();

 
    //customErrors=On/RemoteOnly+nonLocal
    if (!HttpContext.Current.IsCustomErrorEnabled)
        return; //wants to see YSOD

 
    //log it if necessary
    System.Diagnostics.Trace.TraceError(exception.ToString());

 
    //is this a specific error?
    var httpException = exception as HttpException;
    string action = null;
    if (httpException != null)
    {
        var code = httpException.GetHttpCode();
        if (code == 404)
            action = «NotFound»;
    }
    Server.ClearError(); //make sure customErrors doesn’t take over
    Response.TrySkipIisCustomErrors = true; //don’t let IIS7 take over
    Response.Redirect(String.Format(«~/Error/{0}«, action));
}

WebAPI

global.asax Application_Error is NOT fired, but it does obey customErrors mode for whether an exception is returned in Json/xml.

www.asp.net overview

From 2014, webapi has ErrorLogger and ExceptionHandler base classes which can be inherited and applied for true global logging and handling.

if (id == 1)
    throw new HttpResponseException(HttpStatusCode.NotFound);
if (id == 2)
{
    var responce = new HttpResponseMessage(HttpStatusCode.NotFound);
    responce.ReasonPhrase = «Item not found»; //HTTP level
    responce.Content = new StringContent(«No item with id 2»); //message
    throw new HttpResponseException(responce);
}

HttpResponseMessage methods

if (id == 0) //createResponse
    return Request.CreateResponse(HttpStatusCode.NotFound, «Cannot find id»);
if (id == 1) //using HttpError
    return Request.CreateResponse(HttpStatusCode.BadRequest, new HttpError(«Bad input»));
if (id == 2) //createErrorResponse
    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, «Bad input»);
if (!ModelState.IsValid) //modelstate
    return Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);

The standard json error response is { Message: x }

WebAPI filters

[HandleError] doesn’t work on webapi!

You can use a limited equivalent by implementing the abstract ExceptionFilterAttribute. It is limited as it only traps raw .net exceptions, and ignores HttpResponseExceptions (which prior to WebApi 2.1 can’t be logged…)

public class HandleExceptionAttribute : System.Web.Http.Filters.ExceptionFilterAttribute
{
    //MVC’s [HandleError] doesn’t work (it returns a view)

 
    public override void OnException(System.Web.Http.Filters.HttpActionExecutedContext actionExecutedContext)
    {
        //log it
        Trace.TraceError(actionExecutedContext.Exception.ToString());
        //handle it
        actionExecutedContext.Response = new HttpResponseMessage(HttpStatusCode.InternalServerError);
    }
}

Then apply the attribute on action or controller:

[HandleExceptionAttribute]
public int Post(Order order)

Or into GlobalConfiguration filters in App_Start (NB: not MVC action filters!!)

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Web API configuration and services
        config.Filters.Add(new HandleExceptionAttribute());

WebAPI 2.1 Loggers and Handlers

Global logging and handling is only available from WebApi 2.1 (January 2014+)

// There can be multiple exception loggers (by default there are 0)
config.Services.Add(typeof(System.Web.Http.ExceptionHandling.IExceptionLogger),
    new MyExceptionLogger());

 
// There must be exactly 1 exception handler. (There is a default one that may be replaced.)
config.Services.Replace(typeof(System.Web.Http.ExceptionHandling.IExceptionHandler),
    new MyExceptionHandler());

Implementations:

public class MyExceptionLogger : System.Web.Http.ExceptionHandling.ExceptionLogger
{
    public override void Log(System.Web.Http.ExceptionHandling.ExceptionLoggerContext context)
    {
        Trace.TraceError(«Method {0} url {1} exception {2}»,
            context.Request.Method,
            context.Request.RequestUri,
            context.Exception);
    }
}

 
public class MyExceptionHandler : System.Web.Http.ExceptionHandling.ExceptionHandler
{
    public override void Handle(System.Web.Http.ExceptionHandling.ExceptionHandlerContext context)
    {
        //return an IHttpActionResult
        context.Result = new InternalServerErrorResult(context.Request);
    }
}

Async Disconnect Errors (.net 4.5)

In .net 4.5 you can use async Task actions. Because they are async, disconnects trigger the standard escalation policy to terminate the process. Opps. Put this in Global.asax Application_Start:

//log and swallow the async disconnect errors «The remote host closed the connection. The error code is 0x80070057.»
TaskScheduler.UnobservedTaskException += (sender, e) =>
{
    e.SetObserved();
    Trace.TraceError(e.Exception.ToString());
};

Index

  • 1. Introduction
  • 2. HandleErrorAttribute
  • 3. Limitations of HandleError
  • 4. HandleError vs Application_Error
  • 5. Extending HandleError
  • 6. Returning views from Application_Error
  • 7. ELMAH
  • 8. Summary

Introduction

Exception handling is a serious matter in any application, whether it’s web or desktop. Implementing a proper exception handling is important in any application.
In most cases once we catch the exception we have to log the exception details to database or text file and show a friendly message to the user.

In ASP.NET applications, error handling is done mostly in two ways: at local level using try-catch blocks and at global level using application events.
ASP.NET MVC comes with some built-in support for exception handling through exception filters. The HandleError is the default built-in exception filter.
Unfortunately, the HandleError filter not gives a complete answer to the exception handling problem and that makes us to still rely on the Application_Error event.

In this article, we will learn about the HandleError filter and discuss about the different exception handling
mechanisms that will fit to an MVC application.

HandleError Attribute

Exception filters

The exception filters are attributes that can be applied over an action or a controller or even at a global level. When you apply the filter at the global level then it will
handle the exceptions raised by all the actions of all the controllers. The exception filters not only catches the exceptions
that are raised by the actions but also the ones that are raised by the action filters that are applied over the actions.

All the exception filters implements the IExceptionFilter interface. Listing 1. shows the definition of this interface.
The IExceptionFilter contains a single method called OnException which will be called whenever an exception occurs. The ExceptionContext parameter which derives from ControllerContext provides access to the controller,
route data and HttpContext.

public interface IExceptionFilter
{
	void OnException(ExceptionContext filterContext);
}

Listing 1. IExceptionFilter definition

The HandleErrorAttribute is the default implementation of the IExceptionFilter. When you create a MVC application you will see the HandleErrorAttribute is added to the
GlobalFiltersCollection in the Global.asax.cs.

public static void RegisterGlobalFilters(GlobalFiltersCollection filters)
{
	filters.Add(new HandleErrorAttribute());
}

Listing 2. Registering HandleErrorAttribute to GlobalFiltersCollection

What the HandleError filter does?

The HandleError filter handles the exceptions that are raised by the controller actions, filters and views, it returns a custom view named Error which is placed
in the Shared folder. The HandleError filter works only if the <customErrors> section is turned on in web.config.

The HandleError filter handle exceptions only if the <customErrors> is turned on in web.config

Error View

The Error view that is created by default contains the following html.

@{
   Layout = null;
}

<!DOCTYPE html>
<html>
<head>
   <meta name="viewport" content="width=device-width" />
   <title>Error</title>
</head>
<body>
   <h2>
       Sorry, an error occurred while processing your request.
   </h2>
</body>
</html>

Listing 3. Error View

It contains nothing other than a simple text message. The Layout property is set to null so that the Error view doesn’t inherits the application’s style.

Accessing the exception details in Error view

In some cases, we have to access the exception information from the Error view. The HandleError filter not only just
returns the Error view but it also creates and passes the HandleErrorInfo model to the view. The HandleErrorInfo model contains
the details about the exception and the names of the controller and action that caused the exception.

Here is the definition of the HandleErrorInfo.

public class HandleErrorInfo
{   
	public HandleErrorInfo(Exception exception, string controllerName, 
		string actionName);

	public string ActionName { get; }

	public string ControllerName { get; }

	public Exception Exception { get; }
}

Listing 4. HandleErrorInfo error model

Though it’s not necessary let’s strongly type the Error view to the HandleErrorInfo model.

@model System.Web.Mvc.HandleErrorInfo

Listing 5. Strongly typing Error view to HandleErrorInfo model

We can easily show the exception and other information by accessing the model through the Model property.

<h2>Exception details</h2>
<p>
	Controller: @Model.ControllerName <br>
	Action: @Model.ActionName
	Exception: @Model.Exception
</p>

Listing 6. Displaying exception details in Error view

Returning different views for different exceptions

We can return different views from the HandleError filter. For ex. if you want to return one view for database exceptions and another view for application exceptions,
you could easily do that by specifying the View and Exception properties as shown in the below listing.

[HandleError(Exception = typeof(DbException), View = "DatabaseError")]
[HandleError(Exception = typeof(AppException), View = "ApplicationError")]
public class ProductController
{
	
}

Listing 7. Setting views for exceptions

The HandleErrorAttribute can be applied multiple times over a controller or action or at global level.

Limitations of HandleError

The HandleError filter has some limitations by the way.

1. Not support to log the exceptions
2. Doesn’t catch HTTP exceptions other than 500
3. Doesn’t catch exceptions that are raised outside controllers
4. Returns error view even for exceptions raised in AJAX calls

Let see one by one.

1. Not support to log the exceptions

Logging is very important in error handling and even simple applications get much benefit by logging the errors to a text file or database.
The HandleError filter suppresses the exceptions once they are handled and all it does is showing a custom view to the user.

2. Doesn’t catch HTTP exceptions other than 500.

The HandleError filter captures only the HTTP exceptions having status code 500 and by-passes the others.
Let’s assume we have an action that returns all the posts published for a particular category.
If the category not exists then we are throwing a 404 HTTP exception.

public ViewResult Posts(string category)
{
	if(_blogRepository.Category(category) == null)
		throw new HttpException(404, "Category not found");

	return _blogRepository.Posts(category);
}

Listing 8. Throwing HttpException from action

If any user passes an invalid category a 404 exception will be thrown from the action and the HandleError don’t catch this error.
Usually in this case, programmers like to show a custom view with a message «The requested category is not found or invalid».
Not only the 404 exceptions, the HandleError doesn’t catch any HTTP exception other than 500.

Handling the HTTP exceptions in filters is right or wrong is a thing for debate. In some cases we may have to bypass the HTTP exceptions to the framework
to take proper action against it. So handling HTTP exceptions in filters depends upon the application and it’s not mandatory.

3. Doesn’t catch exceptions that are raised outside controllers

The HandleError is an exception filter and exception filters are called
only if any exception happens inside the action or in the action filters that are applied over the action.
So if the exception happens some other place the filter will be silent.

For ex. say we have set up a route constraint for a specific route as shown in the below listing.

routes.MapRoute(
	 "Default", 
	 "Strange~Action",
	 new { controller = "NonIE", action = "Action"  },
	 new { browserConstraint = new UserAgentConstraint("IE") } 
);

Listing 9. Adding constraints to routes

Route Constraints restricts a route against matching URLs.

The UserAgentConstraint that we set up in the above route restricts the route to handle requests from only Internet Explorer browsers.
In the implementation of UserAgentConstraint I’m purposely throwing an exception.

public class UserAgentConstraint : IRouteConstraint
{
	private readonly string _restrictAgent;

	public UserAgentConstraint(string restrictAgent)
	{
		_restrictAgent = restrictAgent;
	}

	public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
	{
	  // TODO: return true if the browser is not restricted one.
		throw new NotImplementedException("You forget to implement me");
	}
}

Listing 9. UserAgentConstraint

This exception is thrown at very early stage and HandleError filter won’t be there to catch this. When we access the route
where the above constraint is applied we will see the yellow screen instead of the custom error page.

4. Return error view even in exceptions occurred in AJAX calls.

In case of AJAX calls, if some exception happens the HandleError filter returns the custom error view, which is not useful in the client-side.
It would be great to return a piece of JSON in AJAX exceptions and for that we have to extend the HandleError filter or have to create a custom exception filter.

HandleError vs. Application_Error

Exception filters are not global error handlers and this is an important reason that forces us to still rely on Application_Error event.
Some programmers don’t even use the HandleError filter in their application at all and use only the Application_Error event for doing all the
error handling and logging work. The important problem we face in the Application_Error event is, once the program execution reaches
this point then we are out of MVC context and because of that we can miss some context information related to the exception.

Another important feature that exception filters brings to us is we can handle the exceptions in different ways at different scopes,
this is important in some cases, for ex. when exceptions are raised from one controller we have to return a custom error view and
for other controllers we have to return a different error view, this could be easily accomplished through exception filters
but not easily through the Application_Error event.

The bottom-line is, we need to use the Application_Error event at most of the cases in applications unless we are using a framework like
ELMAH which magically handles all the exceptions. But whether we need to use the HandleError filter or not is totally depend upon the application.
When we need a controller or action level exception handling then we can use the HandleError filter along with the Application_Error event else we can simply ignore the HandleError filter.

Extending HandleError

Most of the cases we have to extend the built-in HandleError filter or have to create a custom exception filter to do some useful job like
logging. Here is an example that shows how to extend the built-in filter to log the exceptions using log4net and return a JSON object for AJAX calls.

public class CustomHandleErrorAttribute : HandleErrorAttribute
{
	private readonly ILog _logger;

	public CustomHandleErrorAttribute()
	{
		_logger = LogManager.GetLogger("MyLogger");
	}

	public override void OnException(ExceptionContext filterContext)
	{
		if (filterContext.ExceptionHandled || !filterContext.HttpContext.IsCustomErrorEnabled)
		{
			return;
		}

		if (new HttpException(null, filterContext.Exception).GetHttpCode() != 500)
		{
			return;
		}

		if (!ExceptionType.IsInstanceOfType(filterContext.Exception))
		{
			return;
		}

		// if the request is AJAX return JSON else view.
		if (filterContext.HttpContext.Request.Headers["X-Requested-With"] == "XMLHttpRequest")
		{
			filterContext.Result = new JsonResult 
			{ 
				JsonRequestBehavior = JsonRequestBehavior.AllowGet, 
				Data = new 
				{ 
					error = true,
					message = filterContext.Exception.Message
				} 
			};
		}
		else
		{
			var controllerName = (string)filterContext.RouteData.Values["controller"];
			var actionName = (string)filterContext.RouteData.Values["action"];
			var model = new HandleErrorInfo(filterContext.Exception, controllerName, actionName);
			
			filterContext.Result = new ViewResult
			{
				ViewName = View,
				MasterName = Master,
				ViewData = new ViewDataDictionary<HandleErrorInfo>(model),
				TempData = filterContext.Controller.TempData
			};
		}

		// log the error using log4net.
		_logger.Error(filterContext.Exception.Message, filterContext.Exception);

		filterContext.ExceptionHandled = true;
		filterContext.HttpContext.Response.Clear();
		filterContext.HttpContext.Response.StatusCode = 500;

		filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;      
	}
}

Listing 10. Extending HandleError

Most of the code are same as in the built-in filter. Notice we have ignored the HTTP exceptions so anyway we need to
wire-up the Application_Error event to catch and log the missed exceptions. If the request is an AJAX call then we are returning a JSON object
that contains a boolean and the exception message else we are returning the error view. We are setting the response status code as 500 and
the HandleError filter also does the same, this is important in terms of REST and HTTP standards.

Returning views from Application_Error

In some applications we have to depend upon the Application_Error event for handling all the exceptions or the ones that are missed
by the exception filters. Mostly programmers like to return an MVC view instead of a static page. Though we are out of the MVC context still we
can return a view using a controller (thanks to StackOverflow).

Let’s create an Error controller that return different views for different errors as shown in the below listing.

public class ErrorController : Controller
{
	public ActionResult Index()
	{
		return View();
	}

	public ActionResult NotFound()
	{
		return View();
	}
}

Listing 11. Error Controller

We have to invoke this Error controller from the Application_Error to return a view after the exception is logged.

protected void Application_Error(object sender, EventArgs e)
{
	var httpContext = ((MvcApplication)sender).Context;
	var currentController = " ";
	var currentAction = " ";
	var currentRouteData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(httpContext));

	if (currentRouteData != null)
	{
		if (currentRouteData.Values["controller"] != null && !String.IsNullOrEmpty(currentRouteData.Values["controller"].ToString()))
		{
			currentController = currentRouteData.Values["controller"].ToString();
		}

		if (currentRouteData.Values["action"] != null && !String.IsNullOrEmpty(currentRouteData.Values["action"].ToString()))
		{
			currentAction = currentRouteData.Values["action"].ToString();
		}
	}

	var ex = Server.GetLastError();
	var controller = new ErrorController();
	var routeData = new RouteData();
	var action = "Index";

	if (ex is HttpException)
	{
		var httpEx = ex as HttpException;

		switch (httpEx.GetHttpCode())
		{
			case 404:
				action = "NotFound";
				break;

			// others if any
		}
	}

	httpContext.ClearError();
	httpContext.Response.Clear();
	httpContext.Response.StatusCode = ex is HttpException ? ((HttpException)ex).GetHttpCode() : 500;
	httpContext.Response.TrySkipIisCustomErrors = true;
	
	routeData.Values["controller"] = "Error";
	routeData.Values["action"] = action;

	controller.ViewData.Model = new HandleErrorInfo(ex, currentController, currentAction);
	((IController)controller).Execute(new RequestContext(new HttpContextWrapper(httpContext), routeData));
}

Listing 12. Returning views from Application_Error

We are doing many things in the above code, mainly we are instantiating the Error controller and invoking it by calling the Execute()
method passing the HandleErrorInfo model and this is the model used by the HandleError filter as well.
To know the controller and action that handled the request we have to access the GetRouteData method of RouteTable.Routes passing the httpcontext.

We are using a switch statement just to demonstrate how we can return different error views for different HTTP exceptions.
If you want to take care of AJAX calls you have to change the implementation little as we did in the custom HandleError filter but to keep things simple I’ve ignored that part.

ELMAH

ELMAH (Error Logging Modules and Handlers) is an application-wide error logging facility that is completely pluggable.
You can easily configure ELMAH for an ASP.NET MVC application without much code. The other benefits brought up by ELMAH is, it provides
a custom page where the admin can view the errors including the original yellow screen, also it provides options to send emails, generate RSS etc.

ELMAH logs only unhandled exceptions so we have to signal ELMAH to log the exceptions that are handled. When we use the HandleError filter
and ELMAH in an application we will confused seeing no exceptions are logged by ELMAH, it’s because once the exceptions are handled by the HandleError filter
it sets the ExceptionHandled property of the ExceptionContext object to true and that hides the errors from logged by ELMAH.
A better way to overcome this problem is extend the HandleError filter and signal to ELMAH as shown in the below listing.

public class ElmahHandleErrorAttribute : HandleErrorAttribute
{
	public override void OnException(ExceptionContext filterContext)
	{
		var exceptionHandled = filterContext.ExceptionHandled;
		
		base.OnException(filterContext);
		
		// signal ELMAH to log the exception
		if (!exceptionHandled && filterContext.ExceptionHandled)
			ErrorSignal.FromCurrentContext().Raise(filterContext.Exception);
	}
}

Listing 13. Signaling to Elmah

Summary

In this article we saw about the built-in HandleError filter available with ASP.NET MVC to handle the exceptions.
The HandleError filter has some limitations and most importantly it doesn’t handle all the exceptions that are raised by the application.

Although HandleError filter bring some benefits in customizing error handling at a controller or action level still we have to rely on the Application_Error event.
ELMAH is an error handling module that is easily pluggable to an ASP.NET application. Unlike HandleError, ELMAH catches all the exceptions raised by the application.

Download

Понравилась статья? Поделить с друзьями:
  • System thread exception not handled windows 10 как исправить ошибку
  • System thread exception not handled win 10 ошибка
  • System thread exception not handled win 10 как исправить
  • System temperature 90d hp как исправить
  • System stack error