Uncategorized

Triggers/Rowcount And NHibernate

 

The Short Story

If you have seen this error, whist using NHibernate with Triggers, this may be the right post for you

“Batch update returned unexpected row count from update; actual row count: 2; expected: 1″.

 

Long Story

So today I had to create some audit tables, ok some of you will surely go hey why didn’t you just use CQRS for that? Yes yes I know that by using CQRS and event sourcing I would indeed get full audit by way of the stored events, in fact I will be writing about that soon, but for now lets forget about that and just stick to the current situation which is :

 

  1. I have a table that I want to provide auditing for
  2. I am using SQL Server
  3. I am using Fluent NHibernate

 

Now there are numerous ways you may perform auditing in SQL server, in fact later versions of SQL Server come with inbuilt Audit functionality, or you could use a general all purpose audit table which records very generic information such as

 

  • The table name
  • The action performed (insert, update, delete)
  • The old value
  • The new value
  • Some narrative
  • Some date information

 

This is fine, but for my requirements, what I wanted was a full row copy from the original table, plus some extra columns such as

 

  • AuditId (Primary key auto generated by DB (Identity))
  • OperationType : I for Insert, D for delete, U for update

 

So lets have a look at some of this using some code example

 

SQL Server Table(s)

Let say I have the following table called “Deposit” in SQL Server

 

Deposit Table (source for Audit)

 

CREATE TABLE [dbo].[Deposit](
      [Id] [int] IDENTITY(1,1) NOT NULL,
      ….
      ….
      ….
      [Version] [timestamp] NOT NULL
CONSTRAINT [PK_Deposit] PRIMARY KEY CLUSTERED
(
      [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

 

And I also have the following Audit table

Deposit_Audit table

 

CREATE TABLE [dbo].[Deposit_Audit](
      [AuditId] [int] IDENTITY(1,1) NOT NULL,
      [OperationType] [nvarchar](1) NOT NULL,
      [Id] [int] NOT NULL,
      ….
      ….
      ….
      ….
CONSTRAINT [PK_Deposit_Audit] PRIMARY KEY CLUSTERED
(
      [AuditId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

GO

 

The Fluent NHibernate Entities

So lets say I have a simple class called “Deposit” which looks like this. Note that for Fluent NHibernate/NHiberate to do their magic properties MUST be virtual

 

using System;
namespace Entities
{
    public class Deposit : Entity<int>
    {
        //NOTE : Do not remove this, as NHibernate needs default ctor to allow proxying
        public Deposit() { }
        public virtual int Id { get; set; }
        ….
        ….
        ….
        ….
        public virtual byte[] Version { get; set; }
    }
}

 

The Fluent NHibernate Mapping Files

Where I then have a Fluent NHibernate mapping file that looks like this

 

namespace Entities
{
    public class DepositMap : ClassMap<Deposit>
    {
        public DepositMap()
        {
            this.Schema("[dbo]");
            OptimisticLock.Version();
            this.Table("[Deposit]");
            this.Id(x => x.Id).Column("Id");
            ….
            ….
            ….
            Version(x => x.Version).Generated.Always();
        }
    }
}

 

 

The Trigger To Do The Audit

Then I have this trigger in place in SQL server to actually do the inserting of the data into the audit table

 

CREATE TRIGGER [dbo].[triDeposit_Audit]
   ON [dbo].[Deposit]
   AFTER INSERT, DELETE, UPDATE
AS

BEGIN

      DECLARE @rc AS INT;
      DECLARE @Id INT
      DECLARE @OperationType NVARCHAR(1)
      DECLARE @rcDel AS INT;
      DECLARE @rcInserted AS INT;

      SET @rc = (SELECT COUNT(*) FROM inserted);
      IF @rc = 0 RETURN;

      DECLARE @keycol AS INT;

      SELECT

            @keycol = ISNULL(inserted.Id, deleted.Id),
            @OperationType  =
            CASE

                              WHEN inserted.Id IS NULL THEN 'D' - we don't use this for now
                              WHEN deleted.Id IS NULL THEN 'I'
                              ELSE 'U'
            END
            FROM inserted
            FULL OUTER JOIN deleted
            ON inserted.Id = deleted.Id

     

      - single row
      IF @rc = 1

            BEGIN

                  INSERT INTO [Options].[dbo].[Deposit_Audit]

                  (    [OperationType]
                        ,[Id]
            		…..
            		…..
            		…..
            		…..
                  )             

                  SELECT     
                        @OperationType         
                	….
                	….
                	….
                	….
                  FROM [Options].[dbo].[Deposit] WHERE Id = @keycol
            END 
     

      - multiple rows
      ELSE
            BEGIN
                  SELECT DISTINCT * INTO #I FROM inserted;

                  BEGIN

                        INSERT INTO [Options].[dbo].[Deposit_Audit]
                        (
                           [OperationType]
                          ,[Id]
                            ……
                            ……
                            ……
                        )

                        SELECT     

                           'U'
                           ,[Id]
                            ……
                            ……
                            ……
                        FROM #I
                  END
            END  
END
GO

 

 

All good so far, so I then used my handy NHibernate ISession / Repository to do an INSERT, and then I got something that I was not expecting, I got this:

 

In NHibernate I got this error: “Batch update returned unexpected row count from update; actual row count: 2; expected: 1″. 

 

Yikes.

 

Turns out there is a simple fix for this, which to my mind was not obvious (even though I seem to recall seeing this before, and mindfully forgetting about it), you just need to include the following line at the start of your SQL Server trigger

 

SET NOCOUNT ON

 

By doing that you are saying that the code that runs inside the trigger will not effect the overall row count of the transaction. After adding this one line to my trigger everything worked as expected.

Uncategorized

VS2013 Setup Project

I am fortunate enough to have been working on a big app for a while now, which means we have our deployment pretty sorted out, using a manner of different tools/scripts.

Then the other day I was asked to help out another team with a small bit of help, where they needed a small app written to allow them to analyse some data. The other team in question are not DEVS, so they need an installer really.

As I say I have not had to create an installer for quite a while now, I was obviously aware of the lack of “Setup Project” in VS2012/VS2013, but since I have not had a need for it lately I was like “meph”.

Until today.

Luckily help is at hand, there is a Visual Studio 2013 extension to get the ability to create Installer Projects in VS2013 again. God knows why Microsoft took that out in the first place, all that would have done is moved people to use other things such as

Anyway for those that want to use the old (probably familiar) VS Installer style project you can grab it from here:

https://visualstudiogallery.msdn.microsoft.com/9abe329c-9bba-44a1-be59-0fbf6151054d

Hopefully some of you will find that useful

 

C#

Bulk Insert Into SQL From C#

The other day at work I had a task that required me to do a bulk insert of data into a SQL server database table. I have obliviously come across (and used in the past) the bcp.exe command line utility. Which is all well and good when you are wanting to run scripts etc etc

This time however I wanted to do the bulk insert, programmatically using some standard .NET code. As I say this is not something I have had to do in code before. So I set out to find out how to do this, and after a few minutes of Googling found the answer I was looking for, which is the

This class has been available in .NET since v2.0, I guess if you don’t need these things they sometimes slip you by, which is the case here, for me anyway!

The main method that you would use in this class are the WriteToServer(..) where there are a few overloads that make use of DataTable/DataRow[] and IDataReader.

  • WriteToServer(DataRow[])
  • WriteToServer(DataTable)
  • WriteToServer(IDataReader)
  • WriteToServer(DataTable, DataRowState)
  • WriteToServerAsync(DataRow[])
  • WriteToServerAsync(DataTable)
  • WriteToServerAsync(IDataReader)
  • WriteToServerAsync(DataRow[], CancellationToken)
  • WriteToServerAsync(DataTable, DataRowState)
  • WriteToServerAsync(DataTable, CancellationToken)
  • WriteToServerAsync(IDataReader, CancellationToken)
  • WriteToServerAsync(IDataReader, CancellationToken)

 

You generally want to make use of the methods above that make use of IDataReader, this is because DataReader is a forward-only, read-only stream. It does not hold the data and thus is much faster then DataTable and DataRows[]

The scenario I was trying to deal with was how to do bulk inserts, and I can across this very good post by Mike Goatly, which goes into a lot of detail

And there was also this one over at Codeproject by AzamSharp

Azam demonstrates how to do use the SqlBulkCopy to do a bulk copy, so if that is what you are after check out his article. My scenario was that I wanted to do a bulk insert,  luckily this exactly what Mike Goatly writes about in his post which I listed above.

 

Bulk Insert

The trick to this is to using the SqlBulkCopy to do a bulk insert we need to create a custom IDataReader. This would be a cinch if we could do something like ObjectDataReader<SomeObject> and use that to feed WriteToServer() with a set of objects.

Unfortunately this doesn’t exist, so you’re going to have to implement your own.

public interface IDataReader : IDisposable, IDataRecord
{
   int Depth { get; }
   bool IsClosed { get; }
   int RecordsAffected { get; }
   void Close();
   DataTable GetSchemaTable();
   bool NextResult();
   bool Read();
}

Mike Goatley gives us a working implementation of this, which is as follows:

namespace SqlBulkCopyExample
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Reflection;

    public class ObjectDataReader<TData> : IDataReader
    {
        /// <summary>
        /// The enumerator for the IEnumerable{TData} passed to the constructor for 
        /// this instance.
        /// </summary>
        private IEnumerator<TData> dataEnumerator;

        /// <summary>
        /// The lookup of accessor functions for the properties on the TData type.
        /// </summary>
        private Func<TData, object>[] accessors;

        /// <summary>
        /// The lookup of property names against their ordinal positions.
        /// </summary>
        private Dictionary<string, int> ordinalLookup;

        /// <summary>
        /// Initializes a new instance of the <see cref="ObjectDataReader&lt;TData&gt;"/> class.
        /// </summary>
        /// <param name="data">The data this instance should enumerate through.</param>
        public ObjectDataReader(IEnumerable<TData> data)
        {
            this.dataEnumerator = data.GetEnumerator();

            // Get all the readable properties for the class and
            // compile an expression capable of reading it
            var propertyAccessors = typeof(TData)
                .GetProperties(BindingFlags.Instance | BindingFlags.Public)
                .Where(p => p.CanRead)
                .Select((p, i) => new
                    {
                        Index = i,
                        Property = p,
                        Accessor = CreatePropertyAccessor(p)
                    })
                .ToArray();

            this.accessors = propertyAccessors.Select(p => p.Accessor).ToArray();
            this.ordinalLookup = propertyAccessors.ToDictionary(
                p => p.Property.Name,
                p => p.Index,
                StringComparer.OrdinalIgnoreCase);
        }

        /// <summary>
        /// Creates a property accessor for the given property information.
        /// </summary>
        /// <param name="p">The property information to generate the accessor for.</param>
        /// <returns>The generated accessor function.</returns>
        private Func<TData, object> CreatePropertyAccessor(PropertyInfo p)
        {
            // Define the parameter that will be passed - will be the current object
            var parameter = Expression.Parameter(typeof(TData), "input");

            // Define an expression to get the value from the property
            var propertyAccess = Expression.Property(parameter, p.GetGetMethod());

            // Make sure the result of the get method is cast as an object
            var castAsObject = Expression.TypeAs(propertyAccess, typeof(object));

            // Create a lambda expression for the property access and compile it
            var lamda = Expression.Lambda<Func<TData, object>>(castAsObject, parameter);
            return lamda.Compile();
        }

        #region IDataReader Members

        public void Close()
        {
            this.Dispose();
        }

        public int Depth
        {
            get { return 1; }
        }

        public DataTable GetSchemaTable()
        {
            return null;
        }

        public bool IsClosed
        {
            get { return this.dataEnumerator == null; }
        }

        public bool NextResult()
        {
            return false;
        }

        public bool Read()
        {
            if (this.dataEnumerator == null)
            {
                throw new ObjectDisposedException("ObjectDataReader");
            }

            return this.dataEnumerator.MoveNext();
        }

        public int RecordsAffected
        {
            get { return -1; }
        }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected void Dispose(bool disposing)
        {
            if (disposing)
            {
                if (this.dataEnumerator != null)
                {
                    this.dataEnumerator.Dispose();
                    this.dataEnumerator = null;
                }
            }
        }

        #endregion

        #region IDataRecord Members

        public int FieldCount
        {
            get { return this.accessors.Length; }
        }

        public bool GetBoolean(int i)
        {
            throw new NotImplementedException();
        }

        public byte GetByte(int i)
        {
            throw new NotImplementedException();
        }

        public long GetBytes(int i, long fieldOffset, byte[] buffer, int bufferoffset, int length)
        {
            throw new NotImplementedException();
        }

        public char GetChar(int i)
        {
            throw new NotImplementedException();
        }

        public long GetChars(int i, long fieldoffset, char[] buffer, int bufferoffset, int length)
        {
            throw new NotImplementedException();
        }

        public IDataReader GetData(int i)
        {
            throw new NotImplementedException();
        }

        public string GetDataTypeName(int i)
        {
            throw new NotImplementedException();
        }

        public DateTime GetDateTime(int i)
        {
            throw new NotImplementedException();
        }

        public decimal GetDecimal(int i)
        {
            throw new NotImplementedException();
        }

        public double GetDouble(int i)
        {
            throw new NotImplementedException();
        }

        public Type GetFieldType(int i)
        {
            throw new NotImplementedException();
        }

        public float GetFloat(int i)
        {
            throw new NotImplementedException();
        }

        public Guid GetGuid(int i)
        {
            throw new NotImplementedException();
        }

        public short GetInt16(int i)
        {
            throw new NotImplementedException();
        }

        public int GetInt32(int i)
        {
            throw new NotImplementedException();
        }

        public long GetInt64(int i)
        {
            throw new NotImplementedException();
        }

        public string GetName(int i)
        {
            throw new NotImplementedException();
        }

        public int GetOrdinal(string name)
        {
            int ordinal;
            if (!this.ordinalLookup.TryGetValue(name, out ordinal))
            {
                throw new InvalidOperationException("Unknown parameter name " + name);
            }

            return ordinal;
        }

        public string GetString(int i)
        {
            throw new NotImplementedException();
        }

        public object GetValue(int i)
        {
            if (this.dataEnumerator == null)
            {
                throw new ObjectDisposedException("ObjectDataReader");
            }

            return this.accessors[i](this.dataEnumerator.Current);
        }

        public int GetValues(object[] values)
        {
            throw new NotImplementedException();
        }

        public bool IsDBNull(int i)
        {
            throw new NotImplementedException();
        }

        public object this[string name]
        {
            get { throw new NotImplementedException(); }
        }

        public object this[int i]
        {
            get { throw new NotImplementedException(); }
        }

        #endregion
    }
}

With this very useful code that Mike provides all we need to do is something like this to bulk insert using a IDataReader using the SqlBulkCopy class:








namespace SqlBulkCopyExample
{
    using System;
    using System.Collections.Generic;
    using System.Data;
    using System.Data.SqlClient;
    using System.Diagnostics;
    using System.Linq;
    using SqlBulkCopyExample.Properties;

    class Program
    {
        static void Main(string[] args)
        {
            var people = CreateSamplePeople(10000);

            using (var connection = new SqlConnection(
		"Server=.;Database=MostWanted;Integrated Security=SSPI"))
            {
                connection.Open();
                InsertDataUsingSqlBulkCopy(people, connection);
            }
        }

       

        private static void InsertDataUsingSqlBulkCopy(
		IEnumerable<Person> people, SqlConnection connection)
        {
            var bulkCopy = new SqlBulkCopy(connection);
            bulkCopy.DestinationTableName = "Person";
            bulkCopy.ColumnMappings.Add("Name", "Name");
            bulkCopy.ColumnMappings.Add("DateOfBirth", "DateOfBirth");

            using (var dataReader = new ObjectDataReader<Person>(people))
            {
                bulkCopy.WriteToServer(dataReader);
            }
        }

       
        private static IEnumerable<Person> CreateSamplePeople(int count)
        {
            return Enumerable.Range(0, count)
                .Select(i => new Person
                    {
                        Name = "Person" + i,
                        DateOfBirth = new DateTime(
				1950 + (i % 50), 
				((i * 3) % 12) + 1, 
				((i * 7) % 29) + 1)
                    });
        }
    }
}

I grabbed the bulk of this code from Mikes original post, where he does a much more thorough job of explaining things and has a nice little demo project that you can compare the difference between using standard 1 by 1 inserts and using this approach, the difference is huge.

Happy days, thanks Mike certainly made my day a lot easier

C#

To Use Repositories Or NOT

I have been using NHibernate for a while now and am happy writing test cases / mocks for Repository implementations such that my code never need hit a database. I have also used Entity Framework in the past and have a soft spot for it, and recently came across a post by the Entity Framework team saying that EF v6 is actually very testable and we can/could use it directly in our codebase.

Naturally I wanted to try this out, so I tried it out using EF6 using Repositories and directly and was pleasantly surprised with the results which I have documented in this article:

http://www.codeproject.com/Articles/875165/To-Repository-Or-NOT

Hope that helps someone out. Enjoy

C#

Transient Exception Handling

I am in the process of reading this very book : Cloud Design Patterns which discusses a great many patterns for the cloud (geared primarily at Azure), and there is talk of a “Circuit Breaker” and “Retry Pattern”.

The “Circuit Breaker” pattern is a new one to me, but the “Retry Pattern” is  certainly something I have seen many times before. The basic idea is this

You want to run a bit of code, but some Exception could occur, so you have some sort of retry policy in place, say one that retries every 10 seconds, that might work, if the Exception is a transient one caused by the network say.

Now I don’t know about you but I have hand coded this sort of thing a lot and never spent too much time (apart from this attempt I did when using Rx  which does actually work very well: http://stackoverflow.com/questions/20189166/rx-back-off-and-retry

Thing is, this is a recurring issue, so surely there is help out there for this issue. Turns out there is.

I have seen a few library that help out in this area, here are a few that I have found:

Palmer

This project is hosted at GutHub : https://github.com/mitchdenny/palmer/

And here are a few examples (taken from Github)

Retry  For Some Time

Retry for 15 seconds

Retry.On<WebException>().For(TimeSpan.FromSeconds(15)).With(context =>
  {
    // Code that might periodically fail due to connectivity issues.
  });

Retry Forever

Keep Retrying

Retry.On<WebException>().Indefinitely().With(context =>
    {
        // Code that might throw a web exception.
    });

Multiple Exceptions

You can also deal with multiple Exceptions

Retry.On<WebException>().For(5).AndOn<SqlException>().For(5).With(context =>
    {
        // Code that might throw a web exception, or a sql exception.
    });

For more examples check out the Palmer github link posted above

 

Polly

There is another nice library, which you can use which is also hosted at GitHub, it is called “Polly” : https://github.com/michael-wolfenden/Polly

So lets see some example, again this are taken directly from the GitHub readme

Step 1 : Specify the type of exceptions you want the policy to handle

// Single exception type
Policy
  .Handle<DivideByZeroException>()

// Single exception type with condition
Policy
  .Handle<SqlException>(ex => ex.Number == 1205)

// Multiple exception types
Policy
  .Handle<DivideByZeroException>()
  .Or<ArgumentException>()

// Multiple exception types with condition
Policy
  .Handle<SqlException>(ex => ex.Number == 1205)
  .Or<ArgumentException>(ex => x.ParamName == "example")

Step 2 : Specify how the policy should handle those exceptions

Retry
// Retry once
Policy
  .Handle<DivideByZeroException>()
  .Retry()

// Retry multiple times
Policy
  .Handle<DivideByZeroException>()
  .Retry(3)

// Retry multiple times, calling an action on each retry 
// with the current exception and retry count
Policy
    .Handle<DivideByZeroException>()
    .Retry(3, (exception, retryCount) =>
    {
        // do something 
    });

// Retry multiple times, calling an action on each retry 
// with the current exception, retry count and context 
// provided to Execute()
Policy
    .Handle<DivideByZeroException>()
    .Retry(3, (exception, retryCount, context) =>
    {
        // do something 
    });
Retry forever
// Retry forever
Policy
  .Handle<DivideByZeroException>()
  .RetryForever()

// Retry forever, calling an action on each retry with the 
// current exception
Policy
  .Handle<DivideByZeroException>()
  .RetryForever(exception =>
  {
        // do something       
  });

// Retry forever, calling an action on each retry with the
// current exception and context provided to Execute()
Policy
  .Handle<DivideByZeroException>()
  .RetryForever((exception, context) =>
  {
        // do something       
  });
Retry and Wait
// Retry, waiting a specified duration between each retry
Policy
  .Handle<DivideByZeroException>()
  .WaitAndRetry(new[]
  {
    TimeSpan.FromSeconds(1),
    TimeSpan.FromSeconds(2),
    TimeSpan.FromSeconds(3)
  });

// Retry, waiting a specified duration between each retry, 
// calling an action on each retry with the current exception
// and duration
Policy
  .Handle<DivideByZeroException>()
  .WaitAndRetry(new[]
  {
    1.Seconds(),
    2.Seconds(),
    3.Seconds()
  }, (exception, timeSpan) => {
    // do something    
  }); 

// Retry, waiting a specified duration between each retry, 
// calling an action on each retry with the current exception, 
// duration and context provided to Execute()
Policy
  .Handle<DivideByZeroException>()
  .WaitAndRetry(new[]
  {
    1.Seconds(),
    2.Seconds(),
    3.Seconds()
  }, (exception, timeSpan, context) => {
    // do something    
  });

// Retry a specified number of times, using a function to 
// calculate the duration to wait between retries based on 
// the current retry attempt (allows for exponential backoff)
// In this case will wait for
//  1 ^ 2 = 2 seconds then
//  2 ^ 2 = 4 seconds then
//  3 ^ 2 = 8 seconds then
//  4 ^ 2 = 16 seconds then
//  5 ^ 2 = 32 seconds
Policy
  .Handle<DivideByZeroException>()
  .WaitAndRetry(5, retryAttempt => 
    TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)) 
  );

// Retry a specified number of times, using a function to 
// calculate the duration to wait between retries based on 
// the current retry attempt, calling an action on each retry 
// with the current exception, duration and context provided 
// to Execute()
Policy
  .Handle<DivideByZeroException>()
  .WaitAndRetry(
    5, 
    retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), 
    (exception, timeSpan, context) => {
      // do something
    }
  )

Step 3 : Execute the policy

// Execute an action
var policy = Policy
              .Handle<DivideByZeroException>()
              .Retry();

policy.Execute(() => DoSomething());

// Execute an action passing arbitrary context data
var policy = Policy
    .Handle<DivideByZeroException>()
    .Retry(3, (exception, retryCount, context) =>
    {
        var methodThatRaisedException = context["methodName"];
        Log(exception, methodThatRaisedException);
    });

policy.Execute(
    () => DoSomething(),
    new Dictionary<string, object>() {{ "methodName", "some method" }}
);

// Execute a function returning a result
var policy = Policy
              .Handle<DivideByZeroException>()
              .Retry();

var result = policy.Execute(() => DoSomething());

// Execute a function returning a result passing arbitrary context data
var policy = Policy
    .Handle<DivideByZeroException>()
    .Retry(3, (exception, retryCount, context) =>
    {
        object methodThatRaisedException = context["methodName"];
        Log(exception, methodThatRaisedException)
    });

var result = policy.Execute(
    () => DoSomething(),
    new Dictionary<string, object>() {{ "methodName", "some method" }}
);

// You can of course chain it all together
Policy
  .Handle<SqlException>(ex => ex.Number == 1205)
  .Or<ArgumentException>(ex => ex.ParamName == "example")
  .Retry()
  .Execute(() => DoSomething());

Transient Application Block

There is also the Microsoft Patterns & Practices offering “Transient Application Block”. Now P&P pattern can be, well a bit over the top to be frank. This one is not so bad though, its mainly geared toward working with Azure, but like a lot of stuff in Azure can be used outside of Azure.

There is a nice codeproject article on how to use this application block outside of Azure which you can read right here: Transient Fault Handling Application Block Simplified

Here is small example of how to use this block taken from the article noted here:

static void Main(string[] args)
{
    try
    {
        // Step 1
        var retryStrategy = new Incremental(RETRY_COUNT, TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(2));

        // Step 2 
        var retryPolicy = new RetryPolicy<CustomTransientErrorDetectionStrategy>(retryStrategy);

        // Step 3
        retryPolicy.ExecuteAction(NavigateTo);
    }
    catch (Exception e)
    {
        Console.WriteLine(e.Message);
    }
}

// This is the code that may experience transient errors
static private void NavigateTo()
{
    Console.WriteLine(DateTime.Now);

    WebClient wc = new WebClient();
    wc.DownloadString("c:\\temp.txt");
}

Where the above code makes use of this custom ITransientErrorDetectionStrategy implementation

internal class CustomTransientErrorDetectionStrategy : ITransientErrorDetectionStrategy
{
    public bool IsTransient(Exception ex)
    {
        if (ex is WebException)
            return true;
        return false;
    }
}

Conclusion

Anyway there you go, I know I have done nothing more than paste a few links to other peoples work here, but there may be some people that did not know about these very useful libraries and you may think aha that is the one for me. So happy fault handling.

Until next time