From Michael Flanakin's Web Log
Introduction to ASP.NET HTTP Modules and Handlers
After endless searching for answers to my handler setup questions, I finally decided to write an all-inclusive set of articles about how someone should go about this. If you find any errors or see room for improvement in any way, please let me know - I will make sure to note any contributions in the "Special Thanks" section. This will be my first contribution to this article-set.
Introduction
All requests to IIS are handled through Internet Server Application Programming Interface (ISAPI) extensions. ASP.NET has its own filter to ensure pages are processed appropriately. By default, the ASP.NET ISAPI filter (aspnet_isapi.dll) only handles ASPX, ASMX, and all other non-display file formats used by .NET and Visual Studio. However, this filter can be registered with other extensions in order to handle requests to those file types, too, but that will be covered later.
Every request flows through a number of HTTP modules, which cover various areas of the application (i.e. authentication and session intofmation). After passing through each module, the request is assigned to a single HTTP handler, which determines how the system will respond to the request. Upon completion of the request handler, the response flows back through the HTTP modules to the user.
HTTP Module
HTTP modules are executed before and after the handler and provide a method for interacting with the request. Custom modules must implement the System.Web.IHttpModule interface. Modules are typically synchronized with events of the System.Web.IHttpModule class (implemented within the Global.asax.cs or .vb file). The following consists of a list of events that should be considered when implementing your module:
BeginRequest
AuthenticateRequest
AuthorizeRequest
ResolveRequestCache
AcquireRequestState
PreRequestHandlerExecute
PostRequestHandlerExecute
ReleaseRequestState
UpdateRequestCache
EndRequest
PreSendRequestHeaders*
PreSendRequestContent*
Error*
The events identified by an asterisk (*) can occur at any time within the request; all others are listed in their calling order.
HTTP Handlers
HTTP handlers proces the request and are generally responsible for initiating necessary business logic tied to the request. Custom handlers must implement the System.Web.IHttpHandler interface. Additionally, a handler factory can be created which will analyze a request to determine what HTTP handler is appropriate. Custom handler factories implement the System.Web.IHttpHandlerFactory interface.
More on Handlers...
When to use Modules and Handlers
With all of the options available in ASP.NET, it is sometimes hard to determine what solution best fits your needs. Of course, it's always best to keep things simple; but, you still need to take evolutionary considerations and experience levels of current and future team members who have a potential of working on teh project into account. Both modules and handlers add a layer of indirection that can be daunting to beginners and/or programmers who are not used to implementing quality designs (read: design patterns).
First, consider what it is that you want to do within your module or handler. Some functions, such as authentication and intstrumentation can be added within modules. Modules should be considered only when there is a need for pass-through and/or intercepting interaction with the request. Alternatively, handlers should be put in place when there is a need to direct functional actions to one or more parts of an application. Probably the most noted use of HTTP handlers is to the FrontController pattern, which allows requests to be refactored and assigned to different components within your application without implementing such changes in every page.
Second, is it worth it? Most applications do not require this level of indirection, which can be hard to understand and/or implement when not documented properly. Some methods, such as the PageController pattern, allow for common functionality to be reused across multiple pages by including this logic in a base System.Web.UI.Page object, and inheriting from this for every web page. When reviewing the PageController implementation, you should know and understand the appropriate use of inheritence. Although certain things can be done this way (i.e. authorization and instrumentation), this is not always the correct means. You should fully understand the pros/cons of utilizing both modules and handlers before deciding on one implementation over the other.
With each of these considerations, and more, the decision to implement modules and/or handlers can be a daunting one. Such decisions should be led by an experienced .NET architect. In the absense of a skilled architect, you will be looking at a lot of leg-work to determine the best solution.
Conclusion
HTTP modules and handlers can be complex. Take the time to fully understand their pros/cons before implementing a solution. I recommend exploiting the experience of software architects whether in your organization or in the community. Whatever you choose, good luck on your ventures. I am finalizing my HTTP handler project, so I should be releasing an article with a sample implementation as well as any recommendations I may have for approaching the job within the next few weeks.
References
ASP.NET HTTP Modules and HTTP Handlers Overview
http://support.microsoft.com/default.aspx?scid=kb;EN-US;Q307985
Wednesday, December 22, 2010
Tuesday, November 16, 2010
SQL Server Error : String or binary data would be truncated
http://www.sql-server-performance.com/faq/string_or_binary_data_truncated_p1.aspx
Error Message:
Msg 8152, Level 16, State 14, Line 5
String or binary data would be truncated.
Severity level:
16.
Description:
This error message appears when you try to insert a string with more characters than the column can maximal accommodate.
Consequences:
The T-SQL statement can be parsed, but causes the error at runtime.
Resolution:
Errors of the Severity Level 16 are generated by the user and are corrigible by the user. The statement cannot be executed this way. You must either shorten the string to be isnerted to widen the column.
Error Message:
Msg 8152, Level 16, State 14, Line 5
String or binary data would be truncated.
Severity level:
16.
Description:
This error message appears when you try to insert a string with more characters than the column can maximal accommodate.
Consequences:
The T-SQL statement can be parsed, but causes the error at runtime.
Resolution:
Errors of the Severity Level 16 are generated by the user and are corrigible by the user. The statement cannot be executed this way. You must either shorten the string to be isnerted to widen the column.
Thursday, September 16, 2010
ReportViewer Control DLLs
Recently I was working on adding a ReportViewer control to our website to display reports created in ReportingServices 2008. We had created a custom error page for any errors that are unhandled by the application so our customers would not see the more serious and angry looking "Server Error" page when an error occured ..After the application was promoted to our web server, it started showing an error related to the CustomeErrors tag in the web.config file being not set appropriately. I had this flag set to "On" so the CustomErrors page would show instead of the Server Error page, but the application continued to display the "Server Error" kind of page..I had my mentor/coach/supervisor Wes take a look at this and he suggested that it seemed like it was a website-wide error, which the custom error handling functionality could not trap. He set the CustomErrors Mode flag to "off" and then ran the application. Now the application showed that the error had to do with the ReportViewer control which could not be recognized by the source code.
Solution - I had referenced the two ReportViewer DLLs in the Bin folder of my WebSite. He suggested to actually copy them into the Bin folder instead of just referencing them and after this the application worked just fine. (We put the CustomErrors mode flag to "On" at this point).
Conclusion -- Sometimes just "Referencing" DLLs in the Bin folder is not enough for the source code to identify the new component/control we are using. And secondly, I learnt that even though we may place CustomError handling on our website, there may be system-wide errors that this error handling will not be able to catch.
The two ReportViewer DLLs were : Microsoft.ReportViewer.Common.dll and Microsoft.ReportViewer.WebForms.dll. We were using version 10.0 of these Dlls.
A new update on the ReportViewer control version 10.0.0 -- When a ReportViewer control is placed on an aspx page with other controls on it, it causes JavaScript errors, especially when viewed in Internet Explorer. In order to avoid these errors, the ReportViewer control should be placed on a page by itself with no other controls on it.
Solution - I had referenced the two ReportViewer DLLs in the Bin folder of my WebSite. He suggested to actually copy them into the Bin folder instead of just referencing them and after this the application worked just fine. (We put the CustomErrors mode flag to "On" at this point).
Conclusion -- Sometimes just "Referencing" DLLs in the Bin folder is not enough for the source code to identify the new component/control we are using. And secondly, I learnt that even though we may place CustomError handling on our website, there may be system-wide errors that this error handling will not be able to catch.
The two ReportViewer DLLs were : Microsoft.ReportViewer.Common.dll and Microsoft.ReportViewer.WebForms.dll. We were using version 10.0 of these Dlls.
A new update on the ReportViewer control version 10.0.0 -- When a ReportViewer control is placed on an aspx page with other controls on it, it causes JavaScript errors, especially when viewed in Internet Explorer. In order to avoid these errors, the ReportViewer control should be placed on a page by itself with no other controls on it.
Monday, September 13, 2010
How to shift focus to next textbox on a ASP.Net web page
I encountered this situation when one of my co-workers was testing a web page I had been helping to develop. After entering text in a textbox on the page and hitting the enter key, the control was getting passed down randomly to any next control on the page, which would be unfriendly and inconvenient to the user.
I searched various posts on the web to find the best solution to this situation and the one that worked best for me was provided here :
In this article Suprotim Agarwal shows how to shift focus to the next TextBox control using JQuery. I used the script part of the code on my webpage :
<script type="text/javascript">
$(function() {
$('input:text:first').focus();
var $inp = $('input:text');
$inp.bind('keydown', function(e) {
//var key = (e.keyCode ? e.keyCode : e.charCode);
var key = e.which;
if (key == 13) {
e.preventDefault();
var nxtIdx = $inp.index(this) + 1;
$(":input:text:eq(" + nxtIdx + ")").focus();
}
});
});
script>
When I ran the application, the TextBoxes on the page received focus in the order they were expected to.
Wednesday, September 1, 2010
Tuesday, August 31, 2010
Friday, March 5, 2010
Thursday, March 4, 2010
ReportViewer control does not render appropriately on IIS7 websites
http://blogs.msdn.com/vijaysk/archive/2009/01/14/report-viewer-toolbar-does-not-render-properly-on-iis-7-0.aspx
In case the URL above stopped working, I thought it might be a good idea to copy its contents here.
I was recently working on a reporting web application that uses the Report Viewer ( ReportViewer ) control that ships with SQL Server Reporting Services (SSRS). The Report Viewer control was rendering perfectly when I was developing using Visual Studio 2008. The trouble started when I published the web application to an IIS 7.0 server. The Toolbar was completely broken and showed up something like this.
Initially it looked like just the images where missing. But the toolbar was completely broken. The toolbar of the Report Viewer control relies on images and JavaScript that are generated dynamically. It uses a call to the Reserved.ReportViewerWebControl.axd to dynamically generate the images and the JavaScript. Something like
GET /Reserved.ReportViewerWebControl.axd?OpType=Resource&Version=9.0.30729.1&Name=Microsoft.Reporting.WebForms.Icons.NextPage.gif HTTP/1.1
GET /Reserved.ReportViewerWebControl.axd?OpType=Resource&Version=9.0.30729.1&Name=Microsoft.Reporting.WebForms.Icons.LastPage.gif HTTP/1.1
When you use the Report Viewer Control Visual Studio edits your web.config to map a Http Handler to respond to these requests.
The above entry tells ASP.NET that whenever a call is made to ReportViewerWebControl.axd use the Microsoft.Reporting.WebForms.HttpHandler assembly to execute it.
This mapping is very important because if you remove it the web server will return a 404 “File Not Found” error code because the ReportViewerWebControl.axd does not exist physically on the server.
Strangely when I checked the IIS 7.0 logs for the broken scenario I found that all requests for ReportViewerWebControl.axd had failed with a 404.
With IIS 7.0 there was an architectural change. There were changes to the web.config structure as well. The section that was under the has now moved to under
Visual Studio had edited the web.config based on the IIS 6.0 model and had made an entry for the Http Handler under the section. With IIS 7.0 this section is no longer read. So we need to make the proper entries for the Http Handler that handles the calls to ReportViewerWebControl.axd
IIS 7.0 will now understand that whenever a call is made to ReportViewerWebControl.axd it needs to route it to the Http Handler Microsoft.Reporting.WebForms.HttpHandler
In case the URL above stopped working, I thought it might be a good idea to copy its contents here.
I was recently working on a reporting web application that uses the Report Viewer ( ReportViewer ) control that ships with SQL Server Reporting Services (SSRS). The Report Viewer control was rendering perfectly when I was developing using Visual Studio 2008. The trouble started when I published the web application to an IIS 7.0 server. The Toolbar was completely broken and showed up something like this.
Initially it looked like just the images where missing. But the toolbar was completely broken. The toolbar of the Report Viewer control relies on images and JavaScript that are generated dynamically. It uses a call to the Reserved.ReportViewerWebControl.axd to dynamically generate the images and the JavaScript. Something like
GET /Reserved.ReportViewerWebControl.axd?OpType=Resource&Version=9.0.30729.1&Name=Microsoft.Reporting.WebForms.Icons.NextPage.gif HTTP/1.1
GET /Reserved.ReportViewerWebControl.axd?OpType=Resource&Version=9.0.30729.1&Name=Microsoft.Reporting.WebForms.Icons.LastPage.gif HTTP/1.1
When you use the Report Viewer Control Visual Studio edits your web.config to map a Http Handler to respond to these requests.
The above entry tells ASP.NET that whenever a call is made to ReportViewerWebControl.axd use the Microsoft.Reporting.WebForms.HttpHandler assembly to execute it.
This mapping is very important because if you remove it the web server will return a 404 “File Not Found” error code because the ReportViewerWebControl.axd does not exist physically on the server.
Strangely when I checked the IIS 7.0 logs for the broken scenario I found that all requests for ReportViewerWebControl.axd had failed with a 404.
With IIS 7.0 there was an architectural change. There were changes to the web.config structure as well. The
Visual Studio had edited the web.config based on the IIS 6.0 model and had made an entry for the Http Handler under the
IIS 7.0 will now understand that whenever a call is made to ReportViewerWebControl.axd it needs to route it to the Http Handler Microsoft.Reporting.WebForms.HttpHandler
Notes : ConnectionString Checks ...
1. When you pull in the DB tables into a dbml file, the ConnectionString property under the Properties window of the dbml file gets set to/points to the DB whose tables you pulled into the dbml file.
2. So, what we need to do is always clear the ConnectionString property and set it to None.
3. The reason we need to always make sure that the ConnectionString property in the property pages of the .dbml file is set to None is as follows :
let us say, we created the dbml file off of Dev/Test DB tables, the connectionString will automatically get updated to point to DEV/Test. Now you keep working on your changes/updates in the code and when it is time to promote to live, all that you do is change the Web.Config file to point to Live DB (you have forgotten in the long process of making changes that you had created your dbml from a DEV/Test DB). But the ConnectionString of the dbml file is still pointing to DEV/TEST...This can lead to a lot of problems, which will show up in the form of data not showing appropriately/suitably for the front-end users, because what they are entering may be partly going into Live, partly into DEV, who knows where ..
To AVOID these issues always make sure you follow these steps to ensure that your dataSource is what it needs to be, both at the time of Testing and Promoting to LIVE :
Say you are promoting to LIVE :
a. Your dbml file should contain tables from the LIVE DB.
b. The ConnectionString property in the Property pages of the dbml file should be set to NONE.
c. Everywhere where it needs to be, the Web.Config should have the ConnectionString set to the LIVE DB.
d. Inside the source code you should be explicitly passing the DSN to any calls to the DataContext Class objects, defined in the dbml designer file. DataContext classes contain definitions of all the tables and fields inside the database.
In other words, do not use any parameterless DataContext class constructors -- pass to them the specific ConnectionString variable that you want your source code to point to.
e. before promoting, put a Breakpoint on one of the constructors of a DataContext class and check the value of the DSN/ConnectionString in the Watch window to make sure it is pointing to the right Database.
When DEPLOYING REPORTS (REPORTING SERVICES REPORTS TO THE REPORTS SERVER)
1. If there are going to be several reports based on the data in one common database, create a SHARED DATASOURCE. Make sure it points to the correct datasource. You may want to deploy this Shared dataSource to the report server.
2. Make sure that each report is pointing to this shared datasource or if each report has its own datasource, make sure it is pointing to the correct datasource (Test/DEV/Live) before deploying to the Report server.
3. Also, always go under Project Properties to make sure that you are pointing to the correct Report Server URL/address so when you deploy your reports, they get deployed on the correct Report server.
2. So, what we need to do is always clear the ConnectionString property and set it to None.
3. The reason we need to always make sure that the ConnectionString property in the property pages of the .dbml file is set to None is as follows :
let us say, we created the dbml file off of Dev/Test DB tables, the connectionString will automatically get updated to point to DEV/Test. Now you keep working on your changes/updates in the code and when it is time to promote to live, all that you do is change the Web.Config file to point to Live DB (you have forgotten in the long process of making changes that you had created your dbml from a DEV/Test DB). But the ConnectionString of the dbml file is still pointing to DEV/TEST...This can lead to a lot of problems, which will show up in the form of data not showing appropriately/suitably for the front-end users, because what they are entering may be partly going into Live, partly into DEV, who knows where ..
To AVOID these issues always make sure you follow these steps to ensure that your dataSource is what it needs to be, both at the time of Testing and Promoting to LIVE :
Say you are promoting to LIVE :
a. Your dbml file should contain tables from the LIVE DB.
b. The ConnectionString property in the Property pages of the dbml file should be set to NONE.
c. Everywhere where it needs to be, the Web.Config should have the ConnectionString set to the LIVE DB.
d. Inside the source code you should be explicitly passing the DSN to any calls to the DataContext Class objects, defined in the dbml designer file. DataContext classes contain definitions of all the tables and fields inside the database.
In other words, do not use any parameterless DataContext class constructors -- pass to them the specific ConnectionString variable that you want your source code to point to.
e. before promoting, put a Breakpoint on one of the constructors of a DataContext class and check the value of the DSN/ConnectionString in the Watch window to make sure it is pointing to the right Database.
When DEPLOYING REPORTS (REPORTING SERVICES REPORTS TO THE REPORTS SERVER)
1. If there are going to be several reports based on the data in one common database, create a SHARED DATASOURCE. Make sure it points to the correct datasource. You may want to deploy this Shared dataSource to the report server.
2. Make sure that each report is pointing to this shared datasource or if each report has its own datasource, make sure it is pointing to the correct datasource (Test/DEV/Live) before deploying to the Report server.
3. Also, always go under Project Properties to make sure that you are pointing to the correct Report Server URL/address so when you deploy your reports, they get deployed on the correct Report server.
Subscribe to:
Comments (Atom)