ASP.NET Coding Standards And Practice
Assembly Naming
This will follow the following convention:
Namespace Naming
Namespaces will follow a similar pattern to the assembly naming convention. If multiple namespaces are used within a project, it is preferable to define the namespace within the code itself instead of within the project configuration.
Strong Naming
All assemblies will be strongly named before they are deployed into each environment (QA, Prod, Dev, DR, etc). It is possible to deploy multiple versions of the same assembly and have them run side-by-side. Multiple version deployments should be decided judiciously based on application requirements, business realities, and usage volume. Side-by-side deployment should be used primarily for troubleshooting purposes unless special business circumstances dictate otherwise.
Naming Conventions
We should adhere to the guidelines outlined by Microsoft for .Net for classes, interfaces, attributes, enumerations, static fields, parameters, methods, properties, and events. These guidelines can be found at
(http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpgenref/html/cpconNamingGuidelines.asp).
Note that these guidelines are, at times, a departure from Hungarian notation. Local variables can use Hungarian style. Variable names should be as descriptive as possible
Classes
Examine if your class design needs to be stateful. If not, consider developing your class as a static (singleton). Member data, member methods, and member properties should also be marked static if appropriate.
Accessibility
Member data should be private or protected whenever possible. Public class properties or accessor-type methods are acceptable. However the use of public members or friend functions would require justification.
Type Declaration
Know the difference between primitive types, reference types, and value types. Use value types whenever possible. Here is a link to the ValueType Hierarchy:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemvaluetypeclasshierarchy.asp
Here is a link to the reference type (object) Hierarchy:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpref/html/frlrfsystemobjectclasshierarchy.asp
For more information on this subject and its importance, please see the following:
http://msdn.microsoft.com/msdnmag/issues/1200/dotnet/
String Handling
Do not overuse the ‘&' operator. Use the StringBuilder class to improve performance.
String Comparisons
It is faster to compare the Length of a string, than it is checking for "" or NOT ""
Try to avoid doing this:
If (strName.Text = "") Then
Do this
If (Len(strName.Text) = 0) Then
String Conversions
Use the Parse functions instead of CInt, CDbl, CSng, CBool, etc... The
Example:
Dim strTemp As String = "123456"
Dim intValue As Integer
Instead of doing this
intValue = CInt(strTemp)
Do this
intValue = Integer.Parse(strTemp)
Logic Operations
When possible, use AndAlso and OrElse instead of just AND or OR. When performing an If statement in VB.NET, VB actually evaluates both expressions to see if the who expression is true. This will occur even when the first expression is false. This is especially helpful when using Functions as expressions in the If statement. Here is an example:
Instead of doing this
If(Foo() And Bar()) Then
Do this
If(Function1() AndAlso Function2()) Then
The first snipped of code will evaluate the result of Function2(), even if Function1() returned false. The second will only evaluate Function2() if Function1() returned true.
Design Guideline - Exception Handling
The use of exceptions in custom applications is allowable and encouraged. When designing an application around exceptions, please keep the following definitions and best practices in mind:
Actionable Exception – Any exception the code is designed to handle.
Un-actionable Exception – Any exception the code cannot handle, thus letting it pass up the call stack to a higher-level handler.
Generic Exception Handler – This type of handler catches the base exception object (System.Exception) and is therefore designed to treat all exceptions as actionable. Handlers of this kind must log Exception.ToString() or ex.StackTrace.ToString() which contain the stack trace data.
Specific Exception Handler – Specific exceptions are configured to be caught in this type of handler because the code knows what to do when they are encountered. A retry is an example of an action taken by a specific exception handler.
High-Level Exception Handling – Generic exception handlers placed at logical boundaries (common components, business tier, presentation tier, application or class entry point, etc)
Function-Level Exception Handling – Generic exception handlers placed inside every function of a given class.
1) Do not use exceptions to control the flow of an application or as part of application logic. Exceptions should be used when a task cannot be completed due to something unexpected.
2) Do not use exceptions to indicate the absence of a resource. The Microsoft APIs adhere to this design. In almost all cases, this can be considered a common situation.
3) Do not use exception handling as a means of returning information from a method.
4) Do not handle an exception you are not ready to take action upon. Good code throws exceptions as needed, and handles only the exceptions it knows how to handle. Exceptions which are deemed “actionable" will be left up to the discretion of the application developer. “Un-actionable" exceptions should be allowed to propagate back up the call stack to a generic handler.
5) Don't throw a new System.Exception. If you are going to explicitly throw a new exception, create your own exception class. This will aid clarity and allow for specific exception handlers to be implemented. If you do not want to explicitly throw a new exception and instead are looking to rethrow an exception already handled use either the rethrow keyword (C#) or the throw keyword (VB.Net) instead of throwing a new System.Exception.
6) Eliminate any OnError Goto statements which might exist in a VB6 project.
7) All exception handlers (generic, specific, high-level and function-level) should include a finally block, when necessary, to cleanup shared resources (dbase connections, etc). The use of try/finally blocks is also encouraged when using shared resources. Per the design of the CLR all finally blocks involved in the call stack will be executed even if the exception is caught by a high-level handler.
8) Never leave a Catch block empty.
9) High-level exception handling should be used instead of function-level exception handling whenever it is practical to do so. When implementing high-level exception handling, make sure to log the StackTrace property of any exception that is handled. This will aid in the troubleshooting process.
ASP.Net Layout
Use Flow Control Layout, rather then Grid Control Layout when creating WebForms. The Grid Control uses absolute style positioning and sizing of controls, which isn't supported on all browsers.
ASP.Net Labels
Don't use Labels on a WebForm unless it is absolutely necessary to the code and the application (changing the label text, making it invisible, etc). If what is needed is static (unchanging) text, just type it directly into the page. Labels are server controls which have their own Render() method. Avoiding labels that have no server control interaction should help avoid unnecessary overhead.
ASP.Net Display
Avoid using Response.Write in conjunction with Server Controls. The ASP.Net Render phase fires after Response.Write. This can cause issues with the display.
ASP.Net Events
We will be using the code-behind files to handle events. Autowireup should be set to false (default).
ADO.Net DataSets versus DataReaders
A data reader can and should be used as an optimization when:
1) Access is going to be read only, forward only, once only.
2) We are not anticipating needing to change that piece of code (and thus having to convert the code to a data set in the future).
3) The data set being read is large (this providing significant savings from using a data reader).
4) The developer is prepared to implement their own connection management and error handling.
ADO.Net Grid Paging
For large data resultsets, implement the paging code in stored procedures rather than the paging with the DataGrid. If your table contains a unique key, you can use the key in a WHERE clause to create a result set starting from a specific row. Here is a generic example on how this could be accomplished in an Oracle stored proc:
select *
from ( select a.*, rownum r
from ( select *
from t
where x = :host_variable
order by y ) a
where rownum < :HigerBound )
where r > :LowerBound
Design Guideline – When to use stored procedures
For business operations that write to multiple data tables, normally create a stored procedure that handles the data table access. This provides best performance, encapsulates the physical data tables, and allows the database to manage the transaction. Note that XML can be passed to a stored procedure and parsed in PL/SQL. This avoids a lengthy parameter list to the stored procedure.
For business operations that read the database only, it is fine to compose a dynamic SQL query in the business component class. A stored procedure can also be used if that seems best.
Design Guideline – Use of SQL in the Presentation Tier
Usually avoid executing SQL statements directly from the ASPX code-behind. However, for simple presentation layer tasks such as reading a list of static values from the database to populate a list box, SQL from the code-behind is okay. If you are executing small, static, containable queries (such as reading a static list) others may be doing the same. Look for possibly creating a sharable object.
DesignGuideline – Webforms and event-driven design vs. Classic form design
The advantages and disadvantages that accompany a pure ASP.Net webform design versus a classic HTML form design. This includes, but is not limited to, JScript validation versus the built-in .Net validators. Use of either approach is allowed but should be decided judiciously based on application requirements, business realities, and usage volume.
Design Guideline – Properties, Fields, and Methods
Fields are simply public variables, properties use property procedures to control how values are set or returned. ‘Get' and ‘Set' are property procedures
Use property procedures when:
1) You need to control when and how a value is set or retrieved.
2) The property has a well-defined set of values that need to be validated.
3) Setting the value causes some perceptible change in the object's state, such as a visible property.
4) Setting the property causes changes to other internal variables or to the values of other properties.
5) A set of steps must be performed before the property can be set or retrieved.
Use fields when:
1) The value is of a self-validating type. For example, an error or automatic data conversion occurs if a value other than True or False is assigned to a Boolean variable.
2) Any value in the range supported by the data type is valid. This is true of many properties of type Single or Double.
3) The property is a String data type, and there is no constraint on the size or value of the string.
Properties vs. Methods:
In general, properties store data for an object, and methods are actions an object can be asked to perform. In most cases the choice is clear. In some cases, it is not obvious which class members should be properties and which should be methods. For the non-obvious situations, the choice will be left to the discretion of the developer.
Design Guideline – Website folder deployment
The current website folder structure should be preserved. Deployment of aspx pages will be to the same folder where the asp pages currently reside. Once the production deployment has been complete, the asp pages can be removed.
ViewState
Disable viewstate for controls that don't need it. For example: if you're using a grid for non-interactive output, the added viewstate can be unnecessarily expensive
Dispose and Finalize
Any public object should implement both Dispose and Finalize. The Dispose method should release all the resources that the object owns and any resources owned by its base objects. Since the Dispose method will already do the work to clean up the object, it is not necessary for the garbage collector to call the object's Finalize method. GC.SuppressFinalize(true) should be called from within the Dispose method to avoid the finalizer from performing a second cleanup. Here is some pseudo-code:
Public Sub Dispose() Implements IDisposable.Dispose
'1) Call the Dispose methods of any base or dependant objects
'2) Explicitly clean up resources (close or set to Nothing)
'3) Since we've already cleaned up everything, no need to
Finalize
GC.SuppressFinalize(Me)
End Sub
Protected Overrides Sub Finalize()
' Instead of re-creating Dispose clean-up code here,
' We will just call Dispose(). This is optimal in terms of
' readability and maintainability.
Me.Dispose()
End Sub
Integer Overflow Checking
If the code being created does not perform integer operations which could be subject to overflows, the overflow checking should be disabled. This will optimize the IL produced and can be disabled for the Visual Basic .NET compiler using the /removeintchecks flag. Note that this is off by default on the C# compiler.
Option Strict
All code should be compiled with Option Strict enabled. This implies that late binding will not be available.
Option Compare Binary
Unless a special circumstance dictates the need for case-insensitivity or culture-awareness, we should configure Option Compare Binary instead of Option Compare Text. This optimizes string comparisons by comparing the numeric value of each Char instead of ignoring case and comparing based on rules for the configured culture.
Thanks,
Rahul Saxena.