Tuesday 4 March 2014

c# Winforms coding standards



Threading Design Guidelines
.NET Framework 1.1
5 out of 14 rated this helpful - Rate this topic
The following rules outline the design guidelines for implementing threading:
  • Avoid providing static methods that alter static state. In common server scenarios, static state is shared across requests, which means multiple threads can execute that code at the same time. This opens up the possibility for threading bugs. Consider using a design pattern that encapsulates data into instances that are not shared across requests.
  • Static state must be thread safe.
  • Instance state does not need to be thread safe. By default, class libraries should not be thread safe. Adding locks to create thread-safe code decreases performance, increases lock contention, and creates the possibility for deadlock bugs to occur. In common application models, only one thread at a time executes user code, which minimizes the need for thread safety. For this reason, the .NET Framework class libraries are not thread safe by default. In cases where you want to provide a thread-safe version, provide a static Synchronized method that returns a thread-safe instance of a type. For an example, see the System.Collections.ArrayList.Synchronized Method and the System.Collections.ArrayList.IsSynchronized Method.
  • Design your library with consideration for the stress of running in a server scenario. Avoid taking locks whenever possible.
  • Be aware of method calls in locked sections. Deadlocks can result when a static method in class A calls static methods in class B and vice versa. If A and B both synchronize their static methods, this will cause a deadlock. You might discover this deadlock only under heavy threading stress.
  • Performance issues can result when a static method in class A calls a static method in class A. If these methods are not factored correctly, performance will suffer because there will be a large amount of redundant synchronization. Excessive use of fine-grained synchronization might negatively impact performance. In addition, it might have a significant negative impact on scalability.
  • Be aware of issues with the lock statement (SyncLock in Visual Basic). It is tempting to use the lock statement to solve all threading problems. However, the System.Threading.Interlocked Class is superior for updates that must be atomic. It executes a single lock prefix if there is no contention. In a code review, you should watch out for instances like the one shown in the following example.
VB
SyncLock Me
   myField += 1
End SyncLock
[C#]
lock(this)
{
   myField++;
}
If you replace the previous example with the following one, you will improve performance.
VB
System.Threading.Interlocked.Increment(myField)
[C#]
System.Threading.Interlocked.Increment(myField);
Another example is to update an object type variable only if it is null (Nothing in Visual Basic). You can use the following code to update the variable and make the code thread safe.
VB
If x Is Nothing Then
   SyncLock Me
      If x Is Nothing Then
         x = y
      End If
   End SyncLock
End If
[C#]
if (x == null)
{
   lock (this)
   {
      if (x == null)
      {
         x = y;
      }
   }
}
You can improve the performance of the previous sample by replacing it with the following code.
VB
System.Threading.Interlocked.CompareExchange(x, y, Nothing)
[C#]
System.Threading.Interlocked.CompareExchange(ref x, y, null);
  • Avoid the need for synchronization if possible. For high traffic pathways, it is best to avoid synchronization. Sometimes the algorithm can be adjusted to tolerate race conditions rather than eliminate them.

Array Usage Guidelines

.NET Framework 1.1
Description: http://i3.msdn.microsoft.com/Areas/Epx/Content/Images/ImageSprite.png
7 out of 12 rated this helpful - Rate this topic
For a general description of arrays and array usage see Arrays, and System.Array Class.

Arrays vs. Collections

Class library designers might need to make difficult decisions about when to use an array and when to return a collection. Although these types have similar usage models, they have different performance characteristics. In general, you should use a collection when Add, Remove, or other methods for manipulating the collection are supported.
For more information on using collections, see Grouping Data in Collections.

Array Usage

Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
VB
Imports System
Imports System.Collections
Imports Microsoft.VisualBasic
 
Public Class ExampleClass
   NotInheritable Public Class Path      
      Private Sub New()
      End Sub
 
      Private Property Path
         Get
         End Get
         Set
         End Set
      End Property
 
      Private Shared badChars() As Char = {Chr(34),"<"c,">"c}
      
      Public Shared Function GetInvalidPathChars() As Char()
         Return badChars
      End Function
 
   End Class
   
   Public Shared Sub Main()
      ' The following code displays the elements of the 
      ' array as expected.
      Dim c As Char
      For Each c In  Path.GetInvalidPathChars()
         Console.Write(c)
      Next c
      Console.WriteLine()
      
      ' The following code sets all the values to A.
      Path.GetInvalidPathChars()(0) = "A"c
      Path.GetInvalidPathChars()(1) = "A"c
      Path.GetInvalidPathChars()(2) = "A"c
      
      ' The following code displays the elements of the array to the
      ' console. Note that the values have changed.
      For Each c In  Path.GetInvalidPathChars()
         Console.Write(c)
      Next c
 
   End Sub
End Class
[C#]
using System;
using System.Collections;
 
public class ExampleClass
{
   public sealed class Path
   {
      private Path(){}
      private static char[] badChars = {'\"', '<', '>'};
      public static char[] GetInvalidPathChars()
      {
         return badChars;
      }
   }
   public static void Main()
   {
      // The following code displays the elements of the 
      // array as expected.
      foreach(char c in Path.GetInvalidPathChars())
      {
         Console.Write(c);
      }
      Console.WriteLine();
 
      // The following code sets all the values to A.
      Path.GetInvalidPathChars()[0] = 'A';
      Path.GetInvalidPathChars()[1] = 'A';
      Path.GetInvalidPathChars()[2] = 'A';
 
      // The following code displays the elements of the array to the
      // console. Note that the values have changed.
      foreach(char c in Path.GetInvalidPathChars())
      {
         Console.Write(c);
      }
   }
}
You can correct the problem in the preceding example by making the badChars collection readonly (ReadOnly in Visual Basic). Alternately, you can clone the badChars collection before returning. The following example demonstrates how to modify the GetInvalidPathChars method to return a clone of the badChars collection.
VB
Public Shared Function GetInvalidPathChars() As Char()
   Return CType(badChars.Clone(), Char())
End Function
[C#]
public static char[] GetInvalidPathChars()
{
   return (char[])badChars.Clone();
}
Do not use readonly (ReadOnly in Visual Basic) fields of arrays. If you do, the array is readonly and cannot be changed, but the elements in the array can be changed. The following example demonstrates how the elements of the readonly array InvalidPathChars can be changed.
Operator Overloading Usage Guidelines
.NET Framework 1.1
5 out of 7 rated this helpful - Rate this topic
The following rules outline the guidelines for operator overloading:
  • Define operators on value types that are logical built-in language types, such as the System.Decimal Structure.
  • Provide operator-overloading methods only in the class in which the methods are defined. The C# compiler enforces this guideline.
  • Use the names and signature conventions described in the Common Language Specification (CLS). The C# compiler does this for you automatically.
  • Use operator overloading in cases where it is immediately obvious what the result of the operation will be. For example, it makes sense to be able to subtract one Time value from another Time value and get a TimeSpan. However, it is not appropriate to use the or operator to create the union of two database queries, or to use shift to write to a stream.
  • Overload operators in a symmetric manner. For example, if you overload the equality operator (==), you should also overload the not equal operator(!=).
  • Provide alternate signatures. Most languages do not support operator overloading. For this reason, it is a CLS requirement for all types that overload operators to include a secondary method with an appropriate domain-specific name that provides the equivalent functionality. It is a Common Language Specification (CLS) requirement to provide this secondary method. The following example is CLS-compliant.
C#
public struct DateTime
{
   public static TimeSpan operator -(DateTime t1, DateTime t2) { }
   public static TimeSpan Subtract(DateTime t1, DateTime t2) { }
}
The following table contains a list of operator symbols and the corresponding alternative methods and operator names.
C++ operator symbol
Name of alternative method
Name of operator
Not defined
ToXxx or FromXxx
op_Implicit
Not defined
ToXxx or FromXxx
op_Explicit
+ (binary)
Add
op_Addition
- (binary)
Subtract
op_Subtraction
* (binary)
Multiply
op_Multiply
/
Divide
op_Division
%
Mod
op_Modulus
^
Xor
op_ExclusiveOr
& (binary)
BitwiseAnd
op_BitwiseAnd
|
BitwiseOr
op_BitwiseOr
&&
And
op_LogicalAnd
||
Or
op_LogicalOr
=
Assign
op_Assign
<< 
LeftShift
op_LeftShift
>> 
RightShift
op_RightShift
Not defined
LeftShift
op_SignedRightShift
Not defined
RightShift
op_UnsignedRightShift
==
Equals
op_Equality
Compare
op_GreaterThan
Compare
op_LessThan
!=
Compare
op_Inequality
>=
Compare
op_GreaterThanOrEqual
<=
Compare
op_LessThanOrEqual
*=
Multiply
op_MultiplicationAssignment
-=
Subtract
op_SubtractionAssignment
^=
Xor
op_ExclusiveOrAssignment
<<=
LeftShift
op_LeftShiftAssignment
%=
Mod
op_ModulusAssignment
+=
Add
op_AdditionAssignment
&=
BitwiseAnd
op_BitwiseAndAssignment
|=
BitwiseOr
op_BitwiseOrAssignment
,
None assigned
op_Comma
/=
Divide
op_DivisionAssignment
--
Decrement
op_Decrement
++
Increment
op_Increment
- (unary)
Negate
op_UnaryNegation
+ (unary)
Plus
op_UnaryPlus
~
OnesComplement
op_OnesCo

Security in Class Libraries

.NET Framework 1.1
1 out of 15 rated this helpful - Rate this topic
Class library designers must understand code access security in order to write secure class libraries. When writing a class library, be aware of two security principles: use permissions to help protect objects, and write fully trusted code. The degree to which these principles apply will depend upon the class you are writing. Some classes, such as the System.IO.FileStream Class, represent objects that need protection with permissions. The implementation of these classes is responsible for checking the permissions of callers and allowing only authorized callers to perform operations for which they have permission. The System.Security Namespace contains classes that can help you perform these checks in the class libraries that you write. Class library code often is fully trusted or at least highly trusted code. Because class library code often accesses protected resources and unmanaged code, any flaws in the code represent a serious threat to the integrity of the entire security system. To help minimize security threats, follow the guidelines described in this topic when writing class library code. For more information, see Writing Secure Class Libraries.

Protecting Objects with Permissions

Permissions are defined to help protect specific resources. A class library that performs operations on protected resources must be responsible for enforcing this protection. Before acting on any request on a protected resource, such as deleting a file, class library code first must check that the caller (and usually all callers, by means of a stack walk) has the appropriate delete permission for the resource. If the caller has the permission, the action should be allowed to complete. If the caller does not have the permission, the action should not be allowed to complete and a security exception should be raised. Protection is typically implemented in code with either a declarative or an imperative check of the appropriate permissions.
It is important that classes protect resources, not only from direct access, but from all possible kinds of exposure. For example, a cached file object is responsible for checking for file read permissions, even if the actual data is retrieved from a cache in memory and no actual file operation occurs. This is because the effect of handing the data to the caller is the same as if the caller had performed an actual read operation.

Fully Trusted Class Library Code

Many class libraries are implemented as fully trusted code that encapsulates platform-specific functionality as managed objects, such as COM or system APIs. Fully trusted code can expose a weakness to the security of the entire system. However, if class libraries are written correctly with respect to security, placing a heavy security burden on a relatively small set of class libraries and the core runtime security allows the larger body of managed code to acquire the security benefits of these core class libraries.
In a common class library security scenario, a fully trusted class exposes a resource that is protected by a permission; the resource is accessed by a native code API. A typical example of this type of resource is a file. The File class uses a native API to perform file operations, such as a deletion. The following steps are taken to protect the resource.
  1. A caller requests the deletion of file c:\test.txt by calling the File.Delete Method.
  2. The Delete method creates a permission object representing the delete c:\test.txt permission.
  3. The File class's code checks all callers on the stack to see if they have been granted the demanded permission; if not, a security exception is raised.
  4. The File class asserts FullTrust in order to call native code, because its callers might not have this permission.
  5. The File class uses a native API to perform the file delete operation.
  6. The File class returns to its caller, and the file delete request is completed successfully.

Precautions for Highly Trusted Code

Code in a trusted class library is granted permissions that are not available to most application code. In addition, an assembly might contain classes that do not need special permissions but are granted these permissions because the assembly contains other classes that do require them. These situations can expose a security weakness to the system. Therefore, you must be take special care when writing highly or fully trusted code.
Design trusted code so that it can be called by any semi-trusted code on the system without exposing security holes. Resources are normally protected by a stack walk of all callers. If a caller has insufficient permissions, attempted access is blocked. However, any time trusted code asserts a permission, the code takes responsibility for checking for required permissions. Normally, an assert should follow a permission check of the caller as described earlier in this topic. In addition, the number of higher permission asserts should be minimized to reduce the risk of unintended exposure.
Fully trusted code is implicitly granted all other permissions. In addition, it is allowed to violate rules of type safety and object usage. Independent of the protection of resources, any aspect of the programmatic interface that might break type safety or allow access to data not normally available to the caller can lead to a security problem.

Performance

Security checks involve checking the stack for the permissions of all callers. Depending upon the depth of the stack, these operations have the potential to be very expensive. If one operation actually consists of a number of actions at a lower level that require security checks, it might greatly improve performance to check caller permissions once and then assert the necessary permission before performing the actions. The assert will stop the stack walk from propagating further up the stack so that the check will stop there and succeed. This technique typically results in a performance improvement if three or more permission checks can be covered at once.

Summary of Class Library Security Issues

  • Any class library that uses protected resources must ensure that it does so only within the permissions of its callers.
  • Assertion of permissions should be done only when necessary, and should be preceded by the necessary permission checks.
  • To improve performance, aggregate operations that will involve security checks and consider the use of assert to limit stack walks without compromising security.
  • Be aware of how a semi-trusted malicious caller might potentially use a class to bypass security.
  • Do not assume that code will be called only by callers with certain permissions.
  • Do not define non-type-safe interfaces that might be used to bypass security elsewhere.
  • Do not expose functionality in a class that allows a semi-trusted caller to take advantage of the higher trust of the class.

See Also

Design Guidelines for Class Library Developers | Writing Secure Class Libraries | Code Access Security | Security and Culture-Aware String Operations
Asynchronous programming is a feature supported by many areas of the common language runtime, such as Remoting, ASP.NET, and Windows Forms. Asynchronous programming is a core concept in the .NET Framework. This topic introduces the design pattern for asynchronous programming.
The philosophy behind these guidelines is as follows:
  • The client should decide whether a particular call should be asynchronous.
  • It is not necessary for a server to do additional programming in order to support its clients' asynchronous behavior. The runtime should be able to manage the difference between the client and server views. As a result, the situation where the server has to implement IDispatch and do a large amount of work to support dynamic invocation by clients is avoided.
  • The server can choose to explicitly support asynchronous behavior either because it can implement asynchronous behavior more efficiently than a general architecture, or because it wants to support only asynchronous behavior by its clients. It is recommended that such servers follow the design pattern outlined in this document for exposing asynchronous operations.
  • Type safety must be enforced.
  • The runtime provides the necessary services to support the asynchronous programming model. These services include the following:
    • Synchronization primitives, such as critical sections and ReaderWriterLock instances.
    • Synchronization constructs such as containers that support the WaitForMultipleObjects method.
    • Thread pools.
    • Exposure to the underlying infrastructure, such as Message and ThreadPool objects.

No comments:

Post a Comment

Angular Tutorial (Update to Angular 7)

As Angular 7 has just been released a few days ago. This tutorial is updated to show you how to create an Angular 7 project and the new fe...