Coding guideline - CatGlobe

From Catglobe Wiki
Revision as of 08:39, 18 December 2008 by Catglobe (talk | contribs)
Jump to: navigation, search

Introduction

This guideline contains CatGlobe-specific coding rules.

Exception

Exception handling

  • Only catch exception if you can do some thing with it.
  • All re-thrown exception must include the original exception in its inner exception.
  • DO: always catch specific exception type. You are allowed to catch generic exception and re-throw a specific exception; for example in CGScript all exceptions are caught and a RuntimeException is re-thrown afterward.
  • DO NOT: empty and undocumented catches; using unspecific catches, unless they are documented well in the design document and are approved by the PMs.

Create a new custom of exception

  • Naming rule: the new exception must be suffixed with “Exception”.
  • All custom exceptions must inherit from another exception class.
  • The exception should be serializable in order to use in CatTask service. Refer to Serializable exceptions for more details. Notice: when the new CatTask service is done, this may be obsolete.
  • Namespace rule:

        - If the being created exception is used in multiple places, it must be placed in the CatGlobe.Framework.Exceptions namespace.

        - Otherwise, if it is used for a specific class only, it can be placed in the namespace where it is used.

Working with threads

  • Usages of threads must be specified in the Technical design and approved by PMs.
  • Use CatGlobe.Framework.Security.AsyncHelper class to start a thread with auto-impersonate, access factory and webconfig manager.

Web pages – web controls

Code behind (ASPX and ASCX)

  • Code behind must be documented with request parameters, usage, purpose.
  • Use Register…(JavascriptConstant…) to include javascript files in the code behind.
  • Web page must inherit from the PageBase class, control must inherit from the ControlBase class and Web Service must inherit from the WebServiceBase class.
  • DO NOT override the OnError event, unless it is approved in the technical design.

ASPX file

  • Replace the auto-generated DOCTYPE by this one: <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
  • A page must have a title using text resource.
  • All the validation warnings which the Visual Studio shows must be fixed.
  • Adding references to user controls and using of tagPrefixes: must following this guideline Tag prefixes for user controls and web controls
  • You are allowed to reference to javascript files in the aspx files directly. However, you must use the JavascriptConstant to reference to them.
  • If a page or a control contains more than 3 methods or more than 20 lines, move it to a separate js file.

ASCX file

  • DO NOT reference to javascript files in the ascx files.

Text resources

  • When you need to register a text resource to the client side, use the PageBase.CGClientScript.RegisterTextResource method. The method will encode registered text resources for you.
  • Setting for text resource files of web pages:

        - Need to be set to the [filename].aspx.resx file only.

        - Custom tool namespace: x (yes, only the letter 'x').

        - Build action: None

        - Custom tool: ResXFileCodeGeneratorEx

  • Setting for text resource files of an enumeration file:

        - Custom tool namespace: aenum

        - Build action: Embedded Resource

        - Custom tool: ResXFileCodeGeneratorEx

Events handling

  • When you override an event, always call to base class method.
  • Only handle an event when you have something to do with it. On this example, the OnInit method should be removed because we have nothing to do with it:
1 protected override void OnInit(EventArgs e)<br>{<br>base.OnInit(e);<br>}

Request

  • All the arguments which can be passed to the url must be documented.
  • Each request parameter must have it own getter property. Handling of the request parameters must always be inside the getter properties.
  • All request parameter getters must be put in a region called “REQUEST PARAMETERS”.

Session

  • Use SessionManager to work with Session.
  • Objects which are put into the Session must be serializable.
  • Examples about good and bad usages of Session, in the share-data-between-pages context:

         - Good if the data is complicated and cannot be render to the clientside or pass via url easily. A good example is the search criterion of the search page.

         - Good if the data is incompleted, so it is not ready to be saved to the database yet, for example the data which is collected through a wizard: we collect some pieces of information in step 1, put them into Session and navigate to the step 2, and so on...

         - Good if the data takes too much resources (IO, CPU, time) to retrieved. For example a fully-initialized Questionnaire, means all of its questions, question properties, sub questions, answer options are initialized.

         - Bad if the data in Session can be changed by multiple pages/forms by multiple ways. For example: the page A shows some information about a report, which is put in the session. The user opens the Report compact dialog in another tab. When the user saves the report in the CRD, it is the database is updated, not the report object in the Session. Now the user backs to the page A and modifies the report. Obviously he will get a concurrency problem.

Javascript

  • Do not use browser-specific script. All the javascript must work in both IE and FireFox.
  • Javascript should be written in OOP style using AJAX .NET. One class should be in one file.
  • Functions must be documented about their usages and their parameters. Types of parameters must also be specified.
  • In order to utilize the intellisense feature of VS2008:

       - Put summary inside function:

Javascriptsummary.jpg

  • To get intellisense work in a javascript file, you have to add a reference to the source JavaScript file. There are two situations need to be considered here:

      - If the source JavaScript file is a embedded resource, use the declaration below:

               /// <reference name="registered name of that embeded JavaScript file" />

      - If the source JavaScript file is an included file, use the declaration below:

               /// <reference path="path file name of that JavaScript file"/>

Javascriptreference.jpg

  • To get intellisense work in a ASPX file:

      - If your page is implementing AJAX, reference to the source JavaScript file in ScriptManager control:

<asp:ScriptManager runat="server" id="scriptManager">
<Scripts>
<asp:ScriptReference path="virtual path file name of the JavaScript file" />
</Scripts>
</asp:ScriptManager>

      - Otherwise, reference to the source JavaScript file in a script element declaration:

                <script src="virtual path file name of the JavaScript file" type="text/javascript" >

Data access layer

AccessFactory

  • Special uses of AF must be approved in the TD. They can be:

        - Where you need to create an AF by yourself.

        - Where you need to call Commit or Abort.

        - Where you need to call CloseOverwritenConnectionWithNoGlobalTransaction and OverwriteConnectionToNoGlobalTransaction. 

Access class

  • Every access class of a domain class needs two callback methods and two delegates which are used when creating and saving objects.
  • The callback method which is used when creating object is named Create. In this method, data is read from the IDataReader to build an object. Signature of the Create method is:

static private T Create(ref CreateOrd co, IDataReader reader)

where T is a domain class, for example User, Attachment or EmailAddress.

  • The callback method which is used when saving object is named Save. In this method, the primary key of the being saved object is read from the IDataReader and update to the object. If the object is a Resource, version is read and update too. Signature of the Save method is:

static private void Save(T emailerror, IDataReader reader)

create two delegates for the two methods above. These delegates are passed to the AccessBase.Execute[Action] methods:

static readonly CreateDelegateGen<T> create = Create;

static readonly SaveDelegateGen<T> save = Save;

Building query

When building a query:

  • Only make your own sql builder function if you can’t find an appropriate one in the GenericSqlBuilder class.
  • All the methods in the MySqlBuilder layer must begin with “Build” and end with “Sql”.
  • Use StringBuilder to build your queries.
  • Always use provider constant to get table names and column names.
  • MySqlBuilder methods should take the same parameters as calling method from the Access layer, except when multiple methods from the Access layer call the same builder.
  • Make your input parameters as strict as possible. For example, if the input is a provider table of a resource view, its type shouldn’t be ProviderTable, but ProviderResourceViewTable.
  • Always use GetLiteral functions to convert a value to a string which can be appended to the query. Usage of GetLiteral is not required when data type of the value is number.
  • Append every condition of the where clause in a separate line. Operants of an OR operator should be written in one line.
  • Example:

Wrong:

StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.Append("SELECT ID");
sqlBuilder.Append(" FROM ");
sqlBuilder.Append(" USER_RESOURCE ");
sqlBuilder.Append(" WHERE ");
sqlBuilder.Append(" NAME ");
sqlBuilder.Append(" = ");
sqlBuilder.Append(userName);
sqlBuilder.Append(" AND ");
sqlBuilder.Append(" (Access_Expiration <= ");
sqlBuilder.Append(CGDateTime.Now.ToString());
sqlBuilder.Append(" OR ");
sqlBuilder.Append(" Access_Expiration is NULL) ");


Correct:
StringBuilder sqlBuilder = new StringBuilder();
sqlBuilder.AppendFormat("SELECT {0} ", PC.UserResource.Id);
sqlBuilder.AppendFormat("FROM {0} ", PC.UserResource.TableName);
sqlBuilder.Append("WHERE ");
sqlBuilder.AppendFormat("{0} = {1} ", PC.UserResource.ShortName.Name,
GetLiteral(userName));
sqlBuilder.AppendFormat("AND ({0} <= {1} OR {0} is NULL)", PC.UserResource.AccessExpiration.Name, GetLiteral(CGDateTime.Now));