When MVC was introduced, it made web development much easier with the model, view, controller structure. But it also introduced its own complications, and many.NET programmers ran into challenges when switching to MVC.
In this article, we’ve compiled some of the most common errors in ASP.NET and how to resolve them.
High Response Execution Time
Request time in any application is a combination of good code and optimized server configurations. Just one poorly optimized component in a web application can result in high execution times and eventually time out. Performance issues are one of the most difficult issues to resolve because the root cause could be any number of issues. Poorly written code, poorly written database queries, inadequate server resources, low bandwidth, and even malfunctioning hardware can be the root cause of a slow-performing application.
When applications time out, a server administrator might first take a quick look at server resources using Windows Task Manager on the server.
High CPU, memory or Ethernet utilization could mean that it’s time to upgrade resources, but it could also mean that code is poorly optimized. Should you find the application is failing due to high resource usage, a quick workaround is to restart the application pool in IIS. Note that this will take the application offline while the app pool restarts, but it’s a quick emergency solution if the application is timing out and crashing.
Slow First Page Load
When initializing a web application in IIS, several server procedures fire up the application including processing static content, cached resources, the generation of dynamic data, and a server response sent to the user. Until the initialization finishes, user requests can appear to “hang,” which could lead to a high bounce rate.
IIS 8.0 has an “Application Initialization” feature to improve perceived site speed by proactively initializing content before receiving the first request. If it does receive a request, it can send a relevant static page to the user while the application initialization procedure completes. The feature is installed from the Server Manager tool.
After installing the feature, you must add configuration entries into the applicationHost.config and web.config files.
In the applicationHost.config file, add the following entry to the <applicationPools> section. Make sure you change the .NET version with the running version for the application.
<add name=".NET v4.5" startMode="AlwaysRunning" managedRuntimeVersion="v4.0" />
Next, scroll down to the <sites> section and add the following configuration within the <application> subsection. Again, use the .NET version relevant to the application.
<application path="/appinit" preloadEnabled="true" applicationPool=".NET v4.5">
In the web.config file for the application, add the following section to the <system.webServer> section.
<applicationInitialization remapManagedRequestsTo="StaticHome.htm" skipManagedModules="true" > <add initializationPage="/" /> </applicationInitialization>
In the above configuration, the “StaticHome.htm” file will serve as the “splash page” when the application initializes.
After you make these configurations, you must restart the IIS web service.
Showing Custom Errors
Error handling is essential in any application, and sending a custom message to users will salvage potential sales. .NET default errors are too general, and leave your users unable to move beyond the “yellow error of death” page. You can handle errors and provide your own custom message or handler using the application’s Web.config or Global.asax files.
You need a view to display messages and a controller to process the view. In the following code examples, the “Error” controller is used to send the user to the “ErrorMessage” view. The first step is to modify the “Application_Error” method in global.asax. We’ll use a 404 error message as an example.
protected void Application_Error(object sender, EventArgs e) { Exception exc = Server.GetLastError(); Response.Clear(); HttpException httpException = exc as HttpException; if (httpException != null) { string controllerAction = System.string.Empty; switch (httpException.GetHttpCode()) { case 404: // page not found controllerAction = "Error404"; break; } // clear error on server Server.ClearError(); Response.Redirect(String.Format("~/Error/{0}/?message={1}", controllerAction, exc.Message)); } }
In the code above, the user is redirected to a URL generated using the controllerAction and the error message. In the following example, the Error controller uses the controllerAction to determine which method to run, and uses the message to determine which View to render. In this case, it displays a 404 error.
public ActionResult Error404(string message) { return View("ErrorMessage", message); }
For instance, you can search for a 404 based on a page name. In the following example, we logged a fatal error when the user attempted to access the path /example404. The exception was captured in the global.asax file by adding the following code to the Application_Error event.
protected void Application_Error(object sender, EventArgs e) { Exception lastException = Server.GetLastError(); NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger(); logger.Fatal(lastException); }
Ajax Error Handling
Ajax in MVC sends input from a user to a back-end controller. The controller processes input and sends JSON back to the Ajax request without refreshing the entire page. Similar to the previous example, you could have an error during controller processing and need to handle it from the front end. Ajax does not know when an error occurs unless the controller sends a success or failed response to the Ajax call. A simple controller action is shown below.
public ActionResult TestAjax() { bool success = true; return Json(success, JsonRequestBehavior.AllowGet); }
The controller sends “true” to Ajax, but your own logic should send either true or false back to the Ajax function. The following jQuery code is an example of calling the controller’s action from the user’s browser and displaying a message should the processing return an error. If the “response” variable is set to false, then an alert displays. Otherwise, “Success” is displayed in the browser.
$.ajax({ url: "/MyController/TestAjax/", type: "GET", dataType: 'json', error: function (response) { if(!(response)) { alert('error'); } }, success: function (response) { if(response) { alert('Success'); } } });
To enable this message, add the following code to any Controller action:
bool success = false; if (!success) //processing failed { Logger logger = LogManager.GetCurrentClassLogger(); logger.Info("An Ajax exception occurred in the Home controller and TestAjax() method."); }
403 Forbidden Error
When developing an application, it’s standard to deploy it to a staging server and then a production server. Although the application runs fine on your local computer, when you deploy it to either staging or production, you might receive a 403 forbidden error when you point the browser to the domain. This can be an issue with anonymous and Windows authentication configured in IIS.
The “Anonymous Authentication” configuration in IIS allows unauthenticated users to access your content. For most public applications on the internet such as a website, the “Anonymous Authentication” setting should be set to true. If you do not want the general public to have access to your application, this setting should be set to false.
For internal applications where you want network users to access an internal website, the “Windows Authentication” setting should be set to “true.” This allows you to integrate Windows authentication (Active Directory) and a web application. Unauthenticated users cannot access the web application.
To solve the issue, go to the Windows IIS manager and click the site in your list of configured IIS sites. Double-click the “Authentication” module. Two configurations display:
To allow users to browse your site, “Anonymous Authentication” should be enabled. Should you ever decide to create folders where only authenticated users can access them, add the “Windows Authentication” setting and set it to true.
Internal Server Error 500
Next to performance issues, internal 500 server errors are also some of the most difficult to resolve. Because it’s a general error, it could be anywhere in the application or even a server configuration. To solve this issue, you need to be able to trace back to the error if you are unable to identify it by reproducing it in development or staging environments.
In development, you can set the application to display detailed errors to find the issue, but you should not leave detailed errors enabled in the production environment. This introduces a security issue, since this information can be used by an attacker. However, in a development environment, detailed errors show you the location of the exception or logical error in your code. Add the following code to your web.config to see detailed errors:
<configuration> <system.webServer> <httpErrors errorMode="Detailed" /> </system.webServer> <system.web> <customErrors mode="Off" /> <compilation debug="true" /> </system.web> </configuration>
Database Connection Errors
Almost every dynamic website runs using a back-end database. The database could be on the same local machine (for instance, in development) or a database hosted on a remote server. The wrong port, server address, or user credentials could result in database connection errors. The most common error is to input the server name without specifying the database instance.
In environments where a development, staging, and production server are set up, it’s common to have multiple connection strings in a web.config file. Developers avoid accidentally using the wrong connection string by either keeping a production-only web.config on the deployment server, or by setting flags that use a connection string based on some application server attribute.
MVC .NET introduced the “SqlConnectionStringBuilder” class in the “System.Data.SqlClient” namespace. This class lets you dynamically build a connection string based on attributes and business logic that the developer assigns. The following code is an example:
SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(); // set the connection string based on the server name switch (System.Environment.MachineName) { case "PRODUCTION": builder.ConnectionString = "server=(production-database);user id=test;" + "password= test_prod;initial catalog=prod"; break; case "DEVELOPMENT": builder.ConnectionString = "server=(development-database);user id=test;" + "password= test_prod;initial catalog=dev"; break; default: builder.ConnectionString = "server=(development-database);user id=test;" + "password= test_prod;initial catalog=dev"; Logger logger = LogManager.GetCurrentClassLogger(); logger.Info("ALERT: Default database connection pointing to DEV server."); break; } builder.AsynchronousProcessing = true; builder["Connect Timeout"] = 1000; string connectionString = builder.ConnectionString;
In addition to building a dynamic connection string based on machine name, should the “default” section of the switch statement trigger, an alert is logged to let administrators know that the code is running on neither production or development servers, which could lead to critical issues.
Conclusion
Before ever deploying an application, always thoroughly test either manually or using scripts. Some exceptions can be avoided by just thoroughly testing, but even the most exhaustive QA process could miss critical errors. Monitoring and logging these events will reduce and mitigate their effects on users, productivity, and the application.
Javier is Content Specialist and also .NET developer. He writes helpful guides and articles, assist with other marketing and .NET community work