Wednesday, April 1, 2009

Class Design Guidelines

Introduction

One of the most common tasks is to add a new class to a project. But what cares should be taken when writing its source code? I the last years I have moved from a product development mindset to a framework development mindset. Several new challenges arise from this shift, such as:

Thinking in the perspective of who is using the framework. A framework usage has at least two viewpoints:

  • The users of the products when there are user interfaces.
  • The programmers that build applications with it.

UsersAndCoders

In my opinion the best designs win because they:

  • Know the programming habits of the target audience
  • Name the class and methods so that they are the first thought.

If we think on what is in front of our eyes when coding in visual studio it is easy to see why. Most programmers don’t search the documentation when they want to do something. They type in the name of the class that sounds the best (first hint) and then the method that sounds the best. If a framework uses well chosen names the first hint will be the correct one most of the times, this makes it more productive, less frustrating and these things sell.

Intellisense

Abstractions

It is sometimes a good idea to associate a class to an abstraction, either another class but abstract or an interface. Typically inheritance is used when the association between the parent and the child class can be read as “is a” and interfaces are used when the association is read as “can do”, “is capable of”, “is able to” and so one.

In this article I will use a fictitious blog engine to provide for small examples an highlights about the ideas presented here.

   1: /// <summary>
   2:   /// Base class for all entries in the blog that provides a common API and 
   3:   /// attributes to all kinds of posts.
   4:   /// </summary>
   5:   /// <remarks>
   6:   /// This class will be specialized according the the formats of the Posts. Some of
   7:   /// the supported formats are RTF, HTML and PlainText.
   8:   /// </remarks>
   9:   public abstract class Post : IFullTextSearchable
  10:   {
  11:       /// <summary>
  12:       /// Validates the posted content, making sure it complies with all the blog
  13:       /// host rules and if not throws a <see cref="ValidationException"/>.
  14:       /// </summary>
  15:       public abstract void Validate();
  16:  
  17:       /// <summary>
  18:       /// Loads the post entry from the given value that should contain a serialized post.
  19:       /// </summary>
  20:       /// <param name="value">The string containing the serialized post object.</param>
  21:       public abstract void Load(string value);
  22:  
  23:       /// <summary>
  24:       /// Loads the post entry from the given value that should point to a text stream with a serialized post object.
  25:       /// </summary>
  26:       /// <param name="value">The  text reader pointing to a serialized post object.</param>
  27:       public abstract void Load(TextReader value);
  28:  
  29:       /// <summary>
  30:       /// Saves the post entry to a serialized representation, converting it afterwards to a string.
  31:       /// </summary>
  32:       /// <returns>The string containing the serialization result.</returns>
  33:       public abstract string Save();
  34:  
  35:       /// <summary>
  36:       /// Saves the post entry to a serialized representation, apending it afterwards to the given string writer.
  37:       /// </summary>
  38:       /// <param name="writer">The text writer that will be used to write the serialization result.</param>
  39:       public abstract void Save(TextWriter writer);
  40:  
  41:       /// <summary>
  42:       /// Tries to find matches for the given pattern.
  43:       /// </summary>
  44:       /// <param name="pattern">The pattern to search for.</param>
  45:       /// <returns>The hits that match the search pattern.</returns>
  46:       public IList<FullTextSearchHit> Search(string pattern)
  47:       {
  48:           if (pattern == null)
  49:           {
  50:               throw new ArgumentNullException("pattern");
  51:           }
  52:  
  53:           try
  54:           {
  55:               // wrap the given pattern in the corresponding object and validate it
  56:  
  57:               FullTextSearchPattern searchPattern = new FullTextSearchPattern(pattern);
  58:               searchPattern.Validate();
  59:  
  60:               // ask the inheritors to do the search
  61:  
  62:               var result = this.OnSearch(searchPattern);
  63:  
  64:               // don't trust the implementations to provide a valid value
  65:  
  66:               if (result == null)
  67:               {
  68:                   // return an empty search and assume the search had no hits
  69:  
  70:                   return new List<FullTextSearchHit>();
  71:               }
  72:  
  73:               // and if it is valid return it
  74:  
  75:               return result;
  76:           }
  77:           catch (InvalidPatternException ex)
  78:           {
  79:               throw new SearchException(Properties.Resources.SearchFailed, ex);
  80:           }
  81:       }
  82:  
  83:       /// <summary>
  84:       /// Called when a full text search is required.
  85:       /// </summary>
  86:       /// <param name="pattern">The validated pattern to search for.</param>
  87:       /// <returns>The hits that match the search pattern.</returns>
  88:       protected abstract IQueryable<FullTextSearchHit> OnSearch(FullTextSearchPattern pattern);
  89:   }

In this design there are two key points:

  1. Post is made abstract and will be extended through inheritance because all objects in this context share a common identity. They are posts, though they vary in format they always are posts.
  2. For the full text search I choose interfaces because I might want to do a full text search in the registered users. Maybe to find an email. So the objects that implement this interface share a capability, doing full text search.

Notice that in the documentation all the overloads have a similar starting sentence an then are specialized according to their input arguments.

Also notice how the implementation of search is handover to the classes inheriting post. I provide a abstract protected method where developers must implement the feature but do not trust the implementation and check for both input and output constraints in the public part. Virtual and abstract methods should be considered public and should not be trusted. When possible overloading them should not compromise the main features. For instance it is very common for developers to forget to call the base implementation.

Finally when accepting or returning class instances (specially collections) it is a good idea to use the most abstract representation possible, eg. a Stream instead of a FileStream. For collections I tend to use the ReadOnlyCollection<T> or interfaces like IEnumerable<T>, IQueryable<T> or IList<T> depending on the requirements.

There is one development style that I find annoying that consists in splitting a concept in an interface and its realization and do it for everything including classes that only carry data. This is a nightmare when you have to add a new feature into the product. We have to add methods, properties and events in multiple places.

I have this personal common sense rules:

  1. Objects that mainly carry data should not be hidden behind an interface. If I want to stop people from creating instances of a base class in a hierarchy I make it abstract.
  2. Objects that represent an algorithm or strategy to do something should be represented by an interface. I also find a common good practice to provide a base class for implementing the interface.

When I use dependency containers I tend to represent the components that are to be revolved by the container by interfaces.

Message Exchange Between Class Methods

In most cases methods have access to the state that is internal to the class. So one recurring issue is when should those state variables be passed as arguments or when should they be access directly. I haven’t yet found a good rule for this problem but learned the hard way this is a good place to spend some thinking. Any comments on this are most welcome.

Exceptions

When I don’t think on exceptions FxCop remembers me :).

There is a small group of exceptions provided by the .NET framework that everyone should now about and use:

- ArgumentNullException

- InvalidOperationException

This is a good practice because developers tend to learn when they apply and put the necessary handling logic without having to think to much on it. Habit always wins.

But besides these “universal” exceptions classes should throw exceptions that have something to do with they purpose and that tell either the user or the developer what they are doing wrong.

   1:     /// <summary>
   2:     /// The exception that is thrown when an invalid search pattern is entered.
   3:     /// </summary>
   4:     [Serializable]
   5:     public class InvalidPatternException : ApplicationException
   6:     {
   7:         /// <summary>
   8:         /// Initializes a new instance of the <see cref="InvalidPatternException"/> class.
   9:         /// </summary>
  10:         public InvalidPatternException()
  11:             : base()
  12:         {
  13:         }
  14:  
  15:         /// <summary>
  16:         /// Initializes a new instance of the <see cref="InvalidPatternException"/> class.
  17:         /// </summary>
  18:         /// <param name="message">The message.</param>
  19:         public InvalidPatternException(string message)
  20:             : base(message)
  21:         {
  22:         }
  23:  
  24:         /// <summary>
  25:         /// Initializes a new instance of the <see cref="InvalidPatternException"/> class.
  26:         /// </summary>
  27:         /// <param name="message">The message.</param>
  28:         /// <param name="innerException">The inner exception.</param>
  29:         public InvalidPatternException(string message, Exception innerException)
  30:             : base(message, innerException)
  31:         {
  32:         }
  33:  
  34:         /// <summary>
  35:         /// Initializes a new instance of the <see cref="InvalidPatternException"/> class.
  36:         /// </summary>
  37:         /// <param name="info">The object that holds the serialized object data.</param>
  38:         /// <param name="context">The contextual information about the source or destination.</param>
  39:         protected InvalidPatternException(SerializationInfo info, StreamingContext context)
  40:             : base(info, context)
  41:         {
  42:         }
  43:     }

The constructors in the above example are the minimal set to comply with the .NET framework conventions. Also it is important to mark exceptions as serializable making them transportable over the wire and over AppDomains.

When targeting the end-user one good practice is to start by building an exception hierarchy that divides the exceptions you are throwing in groups. There are at least two groups that all applications should have: the ones that can be presented to the user as is or the ones that should be shielded and presented with a generic message.

When this is done one it becomes easier to define a global exception handling policy (what gets silenced, what gets wrapped, what gets thrown). One can design a exception policy per group instead of per exception.

Also in N-Tier applications I find it useful to wrap exceptions in each layer. Each layer should add context about where and how the problem happened. With this in place UI developers can than extract the context information from the exceptions and build a nice dialog that clearly explains what was the error and what was being done. The maintenance team will also love you because they will get a lot more information.

Logging

What we are developing will one day leave our machine. Face it. When it does say good bye to the debugger. It is very rare to be able to remotely debug in a customer machine :). So your ability to isolate and fix a defect depends on how much information you can get about what was happing when the failure happened. So most products have some way of outputting their state changes and execution paths.This is one aspect of logging.

The other aspect of logging is when the users need to now what is happening in the product or what happened. This is the other aspect and is closely related with concepts like auditing.

Dependencies on other classes

This is far the most complex and the major fire starter in software, dependencies. Imagine you have an MVC based UI and an Application main class. Should the concrete view A access the application directly. I say hell no. In the pattern the view talks to the controller. Also I would try to have the controller as independent as possible from the Application. Maybe if it needs something about the application it can receive that in the moment of construction and be notified if eventually it changes.

There are some posts on this blog about this problematic:

Law of demeter.

Dependency injection.

Data Exposure

Classes that expose all their fields are either DTOs or a problem. Automatic properties are new nice feature in .NET but are a devil’s temptation for our laziness, if one fails to resist the public or protected modifiers. We build classes to achieve encapsulation. If it wasn’t for that maybe we could just put all program variables in a file and live with C.

This seams quite obvious but there are a lot of people ignoring this simple rule.

Once you expose something you increase the amount of testing required, you increase the chances of having to break something in a refactoring operation or off ending up with a design that is very hard to augment.

Events

The observer pattern is so important that .NET supports it natively, it is built on the programming language.

   1: /// <summary>
   2:     /// Contais data for the PostPublished event.
   3:     /// </summary>
   4:     [Serializable]
   5:     public class PostPublishedEventArgs : EventArgs
   6:     {
   7:         /// <summary>
   8:         /// Initializes a new instance of the <see cref="PostPublishedEventArgs"/> class.
   9:         /// </summary>
  10:         public PostPublishedEventArgs()
  11:         {
  12:         }
  13:  
  14:         /// <summary>
  15:         /// Gets or sets the user that did the post.
  16:         /// </summary>
  17:         public string PostedBy
  18:         {
  19:             get;
  20:             set;
  21:         }
  22:  
  23:         /// <summary>
  24:         /// Gets or sets the moment when the publication was made-
  25:         /// </summary>
  26:         public DateTime PostedAt
  27:         {
  28:             get;
  29:             set;
  30:         }
  31:  
  32:         /// <summary>
  33:         /// Gets or sets the title of publication.
  34:         /// </summary>
  35:         public string Title
  36:         {
  37:             get;
  38:             set;
  39:         }
  40:  
  41:         /// <summary>
  42:         /// Gets or sets the tags that where associated with the post.
  43:         /// </summary>
  44:         public string[] Tags
  45:         {
  46:             get;
  47:             set;
  48:         }
  49:     }

Each component should publish key notifications about changes to its state. There is no rule of thumb on what notifications should be included. One most consider what kind of information would be interested in. For this concept these where chosen:

   1: /// <summary>
   2:     /// Contains the logic for handling the posts in the blog.
   3:     /// </summary>
   4:     public abstract class BlogEngine
   5:     {
   6:         #region Events
   7:  
   8:         /// <summary>
   9:         /// Occurs when the post is published.
  10:         /// </summary>
  11:         public event EventHandler<PostPublishedEventArgs> PostPublished;
  12:  
  13:         /// <summary>
  14:         /// Occurs when a post is selected via a resolve url operation.
  15:         /// </summary>
  16:         public event EventHandler<PostSelectedEventArgs> PostSelected;

 

In most cases event are raised in a On<EventName> protected virtual method that takes the event class instance as argument. This allows for developers to include some logic before the event is raised.

   1: /// <summary>
   2:         /// Raises the <see cref="E:PostPublished"/> event.
   3:         /// </summary>
   4:         /// <param name="ev">
   5:         /// The <see cref="Pedrosal.DesignNotes.ObjectModels.BlogEngine.PostPublishedEventArgs"/> 
   6:         /// instance containing the event data.</param>
   7:         protected virtual void OnPostPublished(PostPublishedEventArgs ev)
   8:         {
   9:             if (this.PostPublished != null)
  10:             {
  11:                 this.PostPublished(this, ev);
  12:             }
  13:         }
  14:  
  15:         /// <summary>
  16:         /// Raises the <see cref="E:PostSelected"/> event.
  17:         /// </summary>
  18:         /// <param name="ev">
  19:         /// The <see cref="Pedrosal.DesignNotes.ObjectModels.BlogEngine.PostSelectedEventArgs"/> 
  20:         /// instance containing the event data.</param>
  21:         protected virtual void OnPostSelected(PostSelectedEventArgs ev)
  22:         {
  23:             if (this.PostSelected != null)
  24:             {
  25:                 this.PostSelected(this, ev);
  26:             }
  27:         }

Extensibility Vectors

Everyone gets to code a class that has to be extended somehow. Events are a nice extensibility feature but sometimes we really need to change the implementation of some features.

Specialization or inheritance is the process to change the behavior of an object (class) by making it less abstract than its base. For instance a FileStream is less abstract than Stream as we already now the stream is stored as a file.

When designing we should plan for these cases by:

Allowing the developers to override the features that lead to specialization by making it virtual.

Exposing some of the state of the object with protected properties.

Minimizing the effects that overrides can have on a object.

Avoid calling virtual methods on constructors.

As a programming rule of thumb the protected keyword for non sealed classes should be considered public in terms of testing and thrust.

Documentation

The summary should be a short simple phrase stating what is the purpose of the member. Documentation is not literature, it is a working tool as important as the IDE or the debugger. The phrase should go right to the point.

On overloads I find it better to start by documenting the longest overload and paste the documentation removing the unneeded parameters. Also in a overload it is common to use the same initial phrase to state what the method does and them add a brief description of how that method differs from the others. 

When overloading is a way to overcome the lack of default parameter values we can use the optionally word to describe what else you can do if you pass in the extra arguments.

Another good practice is to document the exceptions that are known to be thrown.

A really great tool to have installed in visual studio is GhostDoc.

Naming

Find the best name is the difference between something that developers will hate or be passionate with. The rule for naming is habit always wins. There are some patterns that are used everywhere. If the name you choose is the first thing that a developer starts typing when we needs that feature than it is a success.

Looking at the .NET framework is a good place to start. This doesn’t mean that it is the best in the world it just means that everyone is using it, they will eventually get it on their finger tips and when it is time to use your component those habits will guide them to your well chosen.

One example, if I design a set in C# and name the API as in STL C++ developers will love me but C# developers will hate me. By the way this is the second law of naming. Now your developers and their culture. Lean what is on their finger tips. Remember that in other things in life we like standards. Think on light switches, on cars and on roads. Now imagine if the guys designing these had our creative culture and kept changing the rules! Every day you would have to learn all this basic stuff again and at least for me it would be quite frustrating.

There are times where we challenge these orthodoxies and are really innovative but on these times we are doing it intentionally.

Implement IDisposable

Implementing this pattern in the main classes doesn’t hurt and I can come in hand. When applications get larger programmers often come to need a reliable way of releasing large hierarchies of objects. Disposable is the perfect way of achieving it. Also getting used to wrap IDisposable objects inside a using statement (when supported) is a good practice. I find it useful to implement even when I don’t use unmanaged resources.

Friday, February 20, 2009

Understanding memory management in mixed mode applications (Managed and Unmanaged).

 

All developers are familiar with the GC class and .NET and its important role in memory management. It was designed to take out the burden of allocating and releasing memory to hold objects. This is a great feature though it comes at a price; you are not in control of when memory is released. This is not an issue for most applications and most objects. The problems start when you allocate large objects.

In the references I include references to information about what is going internally in CLR but here goes a summary:

The .NET garbage collector is a generational collector. It has three generations: generation 0, generation 1, and generation 2. Generations are the logical view of the garbage collector heap.

Objects live on managed heap segments that are chunks of memory that the garbage collector reserves from the OS by calling VirtualAlloc. Large objects have more that 85kb and belong to generation 2, and are collected only in generation 2.

The collection of an older generation triggers the collection of the younger ones. When a generation 1 garbage collection happens, both generation 1 and 0 are collected.

A garbage collection occurs if one of the following conditions happens:

1. Allocation Exceeds the Generation 0 or Large Object Threshold. Most GCs happen because of allocations on the managed heap (this is the most typical case).

2. System.GC.Collect Is called.

3. System Is in Low Memory Situation. The high memory notification is sent by the OS.

The threshold is a property of each generation. Allocating objects into a generation gets the amount of memory used closer to the generation's threshold. If the threshold is exceeded a garbage collection is triggered on that generation.

The CLR clears the memory for every new object. Imagining it takes two cycles to clear 1 byte, it means it takes closely 170,000 cycles to clear the smallest large object (85kb).

When an application makes both managed and unmanaged memory allocations it is a good practice to tell the GC how much memory is being allocated by the unmanaged threads. This is done using the AddMemoryPressure API. This call will not trigger GC by itself but it will allow the GC to tune memory management.

References

http://msdn.microsoft.com/en-us/magazine/cc534993.aspx

http://social.msdn.microsoft.com/Forums/en-US/clr/thread/bfdcbad3-7405-4ef0-8457-88add656f0ca

Monday, November 17, 2008

Distributed Transactions in .NET 3.5

My on-going notes on the topic…

Modern SOA Coordination, Transactions, Business Activities, Orchestration and Choreography

Modern SOA solutions are composed of several services, sometimes structured in layers from the most elementary services to complex business services.

There are cases where the technologies and frameworks used to build them are different. This is a major benefit but also complexity that demands technology to manage it.

One important field of study is how services exchange messages. This field brought some patterns know as Message Exchange Patterns.

Message Exchange Patterns – MEPs

The most basic exchange patterns are Request/Response, Fire-And-Forget and Solicit-Response.

The Request/Response is the basic pattern where a consumer emits a request message to a provider and receives the response back with the result of its request.

The Fire-And-Forget pattern is used when a consumer doesn’t require or care about the response of an operation. It emits the message and goes one with its life.

The Solicit-Response is the inverse of the Request/Response pattern.

Complex MEPs

By using groups of the previous patterns complex MEPs are created. One complex MEP that is popular is the Publish-Subscribe MEP. It this pattern a party contacts another one requesting it to be notified when a given event (also known as topic) happens. The second party, when the event happens, will go through its list of subscribers and publish a notification to them.

Service Activities and Coordination

A business process is composed by multiple steps in multiple services. A service activity is any service interaction required to complete business tasks.

In a business process the order of activities is important; there are constraints limiting when an activity can be initiated or concluded. This introduces contextual information in the runtime environment so that it can keep track of the process state.

WS-Coordination is WS-* standard describing a protocol to introduce and manage this contextual information. It is based on the coordinator service model:

  • Activation Service - Creates contexts and associates them to activities.
  • Registration Service - Where participant services register to use contextual information from a certain activity and a supported protocol.
  • Coordinator - The controller service that manages the composition.
  • Protocol-Specific-Services - WS-Coordination is a building block for other protocols like WS-AtomicTransactions. These protocols require specific services for managing details not covered on the WS-Coordination standard.

WS-AtomicTransaction

WS-AtomicTransaction is a coordination type, an extension to use with the WS-Coordination context management framework.

A service participates in an atomic transaction by first receiving a coordination context from the activation service, after that it is allowed to register for the available transaction protocols.

The primary transaction protocols are:

  • Completion protocol to initiate the commit or abort states.
  • Durable2PC protocol for services representing permanent data repositories.
  • Volatitle2PC protocol for services representing volatile data repositories.

An atomic transaction should be as short as possible in terms of duration. For the time it lasts there will be resources locked and concurrent requests will have to wait. Naturally the scalability of the application is greatly influenced by this.

Two Phase Commit Protocol Basic algorithm

Commit-request phase

1. The coordinator sends a query to commit message to all transaction participants and waits until it has received a reply from all of them.

2. Each participant executes the transaction up to the point where it has to decide to commit or abort.

3. It replies with an agreement message (votes Yes to commit), if the transaction succeeded, or an abort message (No, not to commit), if the transaction failed.

Commit phase

Success

If the coordinator received an agreement message from all participants during the commit-request phase:

1. The coordinator sends a commit message to all the cohorts. 2. Each cohort completes the operation, and releases all the locks and resources held during the transaction. 3. Each cohort sends an acknowledgment to the coordinator. 4. The coordinator completes the transaction when acknowledgments have been received.

Failure

If any cohort sent an abort message during the commit-request phase:

1. The coordinator sends a rollback message to all the cohorts. 2. Each cohort undoes the transaction using the undo log, and releases the resources and locks held during the transaction. 3. Each cohort sends an acknowledgement to the coordinator. 4. The coordinator completes the transaction when acknowledgements have been received.

Business Activities

Business Activities manage long-running service activities. They do not support rolling back operations and are different from atomic transactions in the way they deal with error. It is not possible to hold locks on data to ensure ACID on these interaction patterns.

Business Activities deal with concurrency and errors by providing alternative business logic to reverse previously made changes to the system's state.

WS-BusinessActivity is the WS-* protocol for these interaction patterns.

On top of this Orchestration allows business logic to be expressed in a standardized way using services. This is the role of WS-BPEL but is out of the scope of this talk.

Distributed Transactions in the WCF way

WCF is able to propagate transactions across the service boundary. This feature is known as transaction flow.

Transaction flow must be enabled at the binding in both communication sides to work.

<bindings>
<netTcpBinding>
  <binding name="netTcpWithTransactions" transactionFlow="true" />
</netTcpBinding>
</bindings>

Distributed transactions do not require reliability in the transport but enabling it reduces the number of transactions aborted by timeout (caused by lost messages).

<bindings>
  <netTcpBinding>
      <binding name="netTcpWithTransactions" transactionFlow="true" >
          <reliableSession enabled="true" />
      </binding>
  </netTcpBinding>
</bindings&gt;

The transaction flow is configured per service operation with the TransactionFlow attribute:

· Allowed – The operation will accept incoming transactions.

· NotAllowed – The operation will not accept incoming transactions.

· Mandatory – The operation will only work if there is an incoming transaction.

Transaction flow is not allowed for one way calls (the client would not be able to abort the transaction).

Supported Transaction Protocols

WCF Supports the following list of transaction protocols:

· Lightweight – Used inside the same AppDomain.

· OleTx – Used to propagate across AppDomain, process boundaries and machine boundaries. It uses RPC calls in a format that is Windows specific. When crossing over the internet it can cause problems because it uses ports that typically closed.

· WS-AtomicTransactions – Use to propagate across AppDomain, process boundaries and machine boundaries. Unlike OleTx it can cross the internet because it is HTTP based, supported by SOAP extensions.

The bindings that support transactions are designed to switch to the “best” (lighter) protocol depending on the operation conditions.

Transaction Managers

Associated with each transaction protocol and with a resource kind there is a transaction manager:

· LTM – Lightweight transaction manager manages transactions inside a single AppDomain and when there is only one opened connection in the transaction. If two connections are opened in the same transaction and AppDomain DTC is used. In SQL Server 2008 this is not true and LTM can be used with multiple opened connections in the same AppDomain.

· KTM – Is specific to Vista and manages kernel resources that support transactions.

· DTC – Distributed Transaction Coordinator. Manages both OleTx and WS-AT transactions.

resourcesXtransactionmanagers

WCF assigns the appropriate transaction manager; it starts at the lightest possible. When new resource managers enlist in the transaction, WCF can promote the transaction to a next level manager. Once promote there is no going back, it will run elevated until abort or commit.

Ambient Transaction

The ambient transaction is the transaction in which the current code executes. It is available in the static property Transaction.Current. It is stored per thread.

Local Transaction and Distributed Transaction

The Transaction object is used both for distributed and local transactions. There are two identifiers available in the Transacton object. LocalIdentifier and DistributedIdentifier. The local is always assign, but the DistributedIdentifier is created when the TransactionManager is promoted to a DTC Transaction Manager.

Transactional Service Development

As mentioned by the book Programming WCF Services. WCF provides both explicit and implicit transaction programming modes. The explicit mode is used when the transactional objects are created explicitly in the code. The implicit mode is used when the code is marked with special attributes.

When TransactionScopeRequired property of the the OperationBeahavior attribute is marked as true a transaction object is made available; either by using a transaction that is flowing through the execution chain or by providing a new one.

What will actually happen depends on the way the Transaction Flow is configured. The following picture summarizes the available options:

TransactionModes

  • In the Client/Service mode the service will use the client transaction if possible. When it is not available it will create a service side transaction.
  • In the Client mode the service only uses the client transaction.
  • In the Service mode the service always has a transaction and it must differ from any transaction the client may or may not have.
  • In the None mode the service never has a transaction.

WCF manages almost every aspect of transactions except for the fact that it does not know if it should abort or commit. For that intervenient parties most vote to either abort or commit.

The voting can be configured declaratively with the TransactionAutoComplete property in the OperationBehavior attribute. In this case WCF will vote commit if there are not errors (exceptions) in the operation.

The other option is explicit voting. In this case the operation must call the SetTransactionComplete method in the Operation Context. It must do so if there are no errors and it must do it only once. A second call would raise an InvalidOperationException.

Isolation Modes (enumeration in System.Transactions)

· Unspecified

· ReadUncommited

· ReadCommited

· RepeatableRead

· Serializable

· Chaos

· Snapshot

A short summary of the main concurrency effects

  • Lost Updates - When different operations select the same row to update based on the value originally selected.
  • Dirty Read - Actions dependent on a certain row can follow wrong paths based on values that have not been committed. The data can be modified before being committed leading the system to a state that violates business rules.
  • Non-repeatable read - Several reads to the same row contain different values because those are being modified by other transactions.
  • Phantom reads -Reading a set of rows contains rows that will be deleted on commit. Those rows will not come up again.

How to analyze what locks are in place at a given instant?

Use windows performance counters.

Use sql profiler.

Query sys.dm_tran_locks.

Use the EnumLocks API.

How to discover long running transactions

Query the system table sys.dm_tran_database_transactions.

Important rules to minimize deadlocks

  • Access objects in the same order.
  • Avoid user interaction in transactions.
  • Keep transactions short and in one batch.
  • Use a lower isolation level.
  • Use a row versioning-based isolation level.
  • Set READ_COMMITTED_SNAPSHOT database option ON to enable read-committed transactions to use row versioning.
  • Use snapshot isolation.
  • Use bound connections.

Enable snapshot and row versioning

Read committed isolation using row versioning is enabled by setting the READ_COMMITTED_SNAPSHOT database option ON. Snapshot isolation is enabled by setting the ALLOW_SNAPSHOT_ISOLATION database option on. When either option is enabled for a database, the Database Engine maintains versions of each row that is modified. Whenever a transaction modifies a row, image of the row before modification is copied into a page in the version store.

Distributed Transactions in .NET 3.5 - Demo

It was a long October working on a hot release :). Finally got the time to get back to the transaction series. The demo uses a very simple system metaphor where services are decomposed in:

  • Data Contracts to transport business entity data across the wire in an optimized fashion.
  • Message Contracts to represent the services request and response and to allow service operation changes without breaking contracts.
  • Service Contracts to represent the service operations.
  • Fault Contracts to represent errors in the services (not explored in this demo).
  • Services Web Site.
  • Entity Framework Domain Model.
  • ASP.NET Web Pages for data consulting.

Transactions are enabled at the WS HTTP binding:

<wsHttpBinding>
    <binding name="wsHttp" transactionFlow="true" />
</wsHttpBinding>
The Isolation Level is set to ReadCommited:
[ServiceBehavior(TransactionIsolationLevel = IsolationLevel.ReadCommitted)]
public class CustomersService : ICustomersService
{
...
}
Transactional Operations use the TransactionScope attribute to manage transactions:
[OperationBehavior(TransactionScopeRequired = true)]
public CreateCustomerResponse CreateCustomer(CreateCustomerRequest request)
{
...
}
And the Entity Framework integrates just fine with WCF distributed transactions:
using (DemosEntities entities = new DemosEntities())
{
    // create the entity

    Customer customer = new Customer();

    // translate the data contract to the entity
    
    customer.Name = request.Customer.Name;
    customer.Id = Guid.NewGuid();

    // add it to the set

    entities.AddToCustomerSet(customer);

    // "commit" changes

    entities.SaveChanges();
}

Distributed Transactions Demo v1