SqlPersistenceProviderFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx35 / System.WorkflowServices / System / ServiceModel / Persistence / SqlPersistenceProviderFactory.cs / 1305376 / SqlPersistenceProviderFactory.cs

                            //------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------
namespace System.ServiceModel.Persistence
{ 
    using System;
    using System.Collections.Generic; 
    using System.Collections.Specialized; 
    using System.Configuration;
    using System.Data; 
    using System.Data.SqlClient;
    using System.Diagnostics;
    using System.Diagnostics.CodeAnalysis;
    using System.Globalization; 
    using System.IO;
    using System.Runtime; 
    using System.Runtime.Diagnostics; 
    using System.Runtime.Serialization;
    using System.ServiceModel.Diagnostics; 
    using System.Text;
    using System.Xml;

    public class SqlPersistenceProviderFactory : PersistenceProviderFactory 
    {
        static readonly TimeSpan maxSecondsTimeSpan = TimeSpan.FromSeconds(int.MaxValue); 
        const string connectionStringNameParameter = "connectionStringName"; 
        const string lockTimeoutParameter = "lockTimeout";
        const string serializeAsTextParameter = "serializeAsText"; 
        List activeCommands;
        string canonicalConnectionString;

        string connectionString; 
        CreateHandler createHandler;
        DeleteHandler deleteHandler; 
        Guid hostId; 
        LoadHandler loadHandler;
        TimeSpan lockTimeout; 
        bool serializeAsText;
        UnlockHandler unlockHandler;
        UpdateHandler updateHandler;
 
        public SqlPersistenceProviderFactory(string connectionString)
            : this(connectionString, false, TimeSpan.Zero) 
        { 
        }
 
        public SqlPersistenceProviderFactory(string connectionString, bool serializeAsText)
            : this(connectionString, serializeAsText, TimeSpan.Zero)
        {
        } 

        public SqlPersistenceProviderFactory(string connectionString, bool serializeAsText, TimeSpan lockTimeout) 
        { 
            this.ConnectionString = connectionString;
            this.LockTimeout = lockTimeout; 
            this.SerializeAsText = serializeAsText;
            this.loadHandler = new LoadHandler(this);
            this.createHandler = new CreateHandler(this);
            this.updateHandler = new UpdateHandler(this); 
            this.unlockHandler = new UnlockHandler(this);
            this.deleteHandler = new DeleteHandler(this); 
        } 

        public SqlPersistenceProviderFactory(NameValueCollection parameters) 
        {
            if (parameters == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters"); 
            }
 
            this.connectionString = null; 
            this.LockTimeout = TimeSpan.Zero;
            this.SerializeAsText = false; 

            foreach (string key in parameters.Keys)
            {
                switch (key) 
                {
                    case connectionStringNameParameter: 
                        ConnectionStringSettings settings = ConfigurationManager.ConnectionStrings[parameters[key]]; 

                        if (settings == null) 
                        {
                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(
                                SR2.GetString(SR2.ConnectionStringNameIncorrect, parameters[key]));
                        } 

                        this.connectionString = settings.ConnectionString; 
                        break; 
                    case serializeAsTextParameter:
                        this.SerializeAsText = bool.Parse(parameters[key]); 
                        break;
                    case lockTimeoutParameter:
                        this.LockTimeout = TimeSpan.Parse(parameters[key], CultureInfo.InvariantCulture);
                        break; 
                    default:
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument( 
                            key, 
                            SR2.GetString(SR2.UnknownSqlPersistenceConfigurationParameter, key, connectionStringNameParameter, serializeAsTextParameter, lockTimeoutParameter));
                } 
            }

            if (this.connectionString == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(
                    SR2.GetString(SR2.ConnectionStringNameParameterRequired, connectionStringNameParameter)); 
            } 

            this.loadHandler = new LoadHandler(this); 
            this.createHandler = new CreateHandler(this);
            this.updateHandler = new UpdateHandler(this);
            this.unlockHandler = new UnlockHandler(this);
            this.deleteHandler = new DeleteHandler(this); 
        }
 
        public string ConnectionString 
        {
            get 
            {
                return this.connectionString;
            }
            set 
            {
                if (string.IsNullOrEmpty(value)) 
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value");
                } 
                this.connectionString = value;
            }
        }
 
        public TimeSpan LockTimeout
        { 
            get 
            {
                return this.lockTimeout; 
            }
            set
            {
                // Allowed values are TimeSpan.Zero (no locking), TimeSpan.MaxValue (infinite locking), 
                // and any values between 1 and int.MaxValue seconds
                if (value < TimeSpan.Zero || 
                    (value > TimeSpan.FromSeconds(int.MaxValue) && value != TimeSpan.MaxValue)) 
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        new ArgumentOutOfRangeException(
                        "value",
                        SR2.GetString(SR2.LockTimeoutOutOfRange)));
                } 
                this.lockTimeout = value;
            } 
        } 

        public bool SerializeAsText 
        {
            get
            {
                return this.serializeAsText; 
            }
            set 
            { 
                this.serializeAsText = value;
            } 
        }

        protected override TimeSpan DefaultCloseTimeout
        { 
            get { return PersistenceProvider.DefaultOpenClosePersistenceTimout; }
        } 
 
        protected override TimeSpan DefaultOpenTimeout
        { 
            get { return PersistenceProvider.DefaultOpenClosePersistenceTimout; }
        }

        bool IsLockingTurnedOn 
        {
            get { return this.lockTimeout != TimeSpan.Zero; } 
        } 

        int LockTimeoutAsInt 
        {
            get
            {
                // Consider storing lockTimeout as int32 TotalSeconds instead 
                if (this.lockTimeout == TimeSpan.Zero)
                { 
                    return -1; 
                }
                else if (this.lockTimeout == TimeSpan.MaxValue) 
                {
                    return 0;
                }
                else 
                {
                    Fx.Assert(this.lockTimeout <= TimeSpan.FromSeconds(int.MaxValue), 
                        "The lockTimeout should have been checked in the constructor."); 

                    return Convert.ToInt32(this.lockTimeout.TotalSeconds); 
                }
            }
        }
 
        public override PersistenceProvider CreateProvider(Guid id)
        { 
            base.ThrowIfDisposedOrNotOpen(); 

            if (Guid.Empty == id) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("id", SR2.GetString(SR2.SqlPersistenceProviderRequiresNonEmptyGuid));
            }
 
            return new SqlPersistenceProvider(id, this);
        } 
 
        protected override void OnAbort()
        { 
            if (this.activeCommands != null)
            {
                lock (this.activeCommands)
                { 
                    foreach (SqlCommand command in this.activeCommands)
                    { 
                        command.Cancel(); 
                    }
                } 
            }
        }

        protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) 
        {
            ValidateCommandTimeout(timeout); 
 
            return new CloseAsyncResult(this, timeout, callback, state);
        } 

        protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
        {
            ValidateCommandTimeout(timeout); 

            return new OpenAsyncResult(this, timeout, callback, state); 
        } 

        protected override void OnClose(TimeSpan timeout) 
        {
        }

        protected override void OnEndClose(IAsyncResult result) 
        {
            if (result == null) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
            } 

            CloseAsyncResult.End(result);
        }
 
        protected override void OnEndOpen(IAsyncResult result)
        { 
            if (result == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 
            }

            OpenAsyncResult.End(result);
        } 

        protected override void OnOpen(TimeSpan timeout) 
        { 
            ValidateCommandTimeout(timeout);
 
            try
            {
                PerformOpen(timeout);
            } 
            catch (Exception e)
            { 
                if (Fx.IsFatal(e)) 
                {
                    throw; 
                }

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                    new PersistenceException( 
                    SR2.GetString(SR2.ErrorOpeningSqlPersistenceProvider),
                    e)); 
            } 
        }
 
        static int ConvertTimeSpanToSqlTimeout(TimeSpan timeout)
        {
            if (timeout == TimeSpan.MaxValue)
            { 
                return 0;
            } 
            else 
            {
                Fx.Assert(timeout <= TimeSpan.FromSeconds(int.MaxValue), 
                    "Timeout should have been validated before entering this method.");

                return Convert.ToInt32(timeout.TotalSeconds);
            } 
        }
 
        IAsyncResult BeginCreate(Guid id, object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 
        {
            base.ThrowIfDisposedOrNotOpen(); 

            if (instance == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance"); 
            }
 
            ValidateCommandTimeout(timeout); 

            return new OperationAsyncResult(this.createHandler, this, id, timeout, callback, state, instance, unlockInstance); 
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801")]
        IAsyncResult BeginDelete(Guid id, object instance, TimeSpan timeout, AsyncCallback callback, object state) 
        {
            base.ThrowIfDisposedOrNotOpen(); 
 
            ValidateCommandTimeout(timeout);
 
            return new OperationAsyncResult(this.deleteHandler, this, id, timeout, callback, state);
        }

        IAsyncResult BeginLoad(Guid id, TimeSpan timeout, bool lockInstance, AsyncCallback callback, object state) 
        {
            base.ThrowIfDisposedOrNotOpen(); 
 
            ValidateCommandTimeout(timeout);
 
            return new OperationAsyncResult(this.loadHandler, this, id, timeout, callback, state, lockInstance);
        }

        IAsyncResult BeginUnlock(Guid id, TimeSpan timeout, AsyncCallback callback, object state) 
        {
            base.ThrowIfDisposedOrNotOpen(); 
 
            ValidateCommandTimeout(timeout);
 
            return new OperationAsyncResult(this.unlockHandler, this, id, timeout, callback, state);
        }

        IAsyncResult BeginUpdate(Guid id, object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 
        {
            base.ThrowIfDisposedOrNotOpen(); 
 
            if (instance == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance");
            }

            ValidateCommandTimeout(timeout); 

            return new OperationAsyncResult(this.updateHandler, this, id, timeout, callback, state, instance, unlockInstance); 
        } 

        void CleanupCommand(SqlCommand command) 
        {
            lock (this.activeCommands)
            {
                this.activeCommands.Remove(command); 
            }
 
            command.Dispose(); 
        }
 
        object Create(Guid id, object instance, TimeSpan timeout, bool unlockInstance)
        {
            base.ThrowIfDisposedOrNotOpen();
 
            if (instance == null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance"); 
            }
 
            ValidateCommandTimeout(timeout);

            PerformOperation(this.createHandler, id, timeout, instance, unlockInstance);
 
            return null;
        } 
 
        SqlCommand CreateCommand(SqlConnection connection, TimeSpan timeout)
        { 
            SqlCommand command = connection.CreateCommand();
            command.CommandTimeout = ConvertTimeSpanToSqlTimeout(timeout);

            lock (this.activeCommands) 
            {
                this.activeCommands.Add(command); 
            } 

            return command; 
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801")]
        void Delete(Guid id, object instance, TimeSpan timeout) 
        {
            base.ThrowIfDisposedOrNotOpen(); 
 
            ValidateCommandTimeout(timeout);
 
            PerformOperation(this.deleteHandler, id, timeout);
        }

        object DeserializeInstance(object serializedInstance, bool isText) 
        {
            object instance; 
 
            NetDataContractSerializer serializer = new NetDataContractSerializer();
            if (isText) 
            {
                StringReader stringReader = new StringReader((string) serializedInstance);
                XmlReader xmlReader = XmlReader.Create(stringReader);
 
                instance = serializer.ReadObject(xmlReader);
 
                xmlReader.Close(); 
                stringReader.Close();
            } 
            else
            {
                XmlDictionaryReader dictionaryReader = XmlDictionaryReader.CreateBinaryReader((byte[]) serializedInstance, XmlDictionaryReaderQuotas.Max);
 
                instance = serializer.ReadObject(dictionaryReader);
 
                dictionaryReader.Close(); 
            }
 
            return instance;
        }

        object EndCreate(IAsyncResult result) 
        {
            if (result == null) 
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
            } 

            OperationAsyncResult.End(result);

            return null; 
        }
 
        void EndDelete(IAsyncResult result) 
        {
            if (result == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
            }
 
            OperationAsyncResult.End(result);
        } 
 
        object EndLoad(IAsyncResult result)
        { 
            if (result == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result");
            } 

            return OperationAsyncResult.End(result); 
        } 

        void EndUnlock(IAsyncResult result) 
        {
            OperationAsyncResult.End(result);
        }
 
        object EndUpdate(IAsyncResult result)
        { 
            if (result == null) 
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("result"); 
            }

            OperationAsyncResult.End(result);
 
            return null;
        } 
 
        byte[] GetBinarySerializedForm(object instance)
        { 
            NetDataContractSerializer serializer = new NetDataContractSerializer();
            MemoryStream memStr = new MemoryStream();
            XmlDictionaryWriter dictionaryWriter = XmlDictionaryWriter.CreateBinaryWriter(memStr);
 
            serializer.WriteObject(dictionaryWriter, instance);
            dictionaryWriter.Flush(); 
 
            byte[] bytes = memStr.ToArray();
 
            dictionaryWriter.Close();
            memStr.Close();

            return bytes; 
        }
 
        string GetConnectionString(TimeSpan timeout) 
        {
            if (this.canonicalConnectionString != null) 
            {
                StringBuilder sb = new StringBuilder(this.canonicalConnectionString);
                sb.Append(ConvertTimeSpanToSqlTimeout(timeout));
                return sb.ToString(); 
            }
 
            return this.connectionString; 
        }
 
        string GetXmlSerializedForm(object instance)
        {
            NetDataContractSerializer serializer = new NetDataContractSerializer();
            MemoryStream memStr = new MemoryStream(); 

            serializer.WriteObject(memStr, instance); 
 
            string xml = UnicodeEncoding.UTF8.GetString(memStr.ToArray());
 
            memStr.Close();

            return xml;
        } 

        object Load(Guid id, TimeSpan timeout, bool lockInstance) 
        { 
            base.ThrowIfDisposedOrNotOpen();
 
            ValidateCommandTimeout(timeout);

            return PerformOperation(this.loadHandler, id, timeout, lockInstance);
        } 

        SqlConnection OpenConnection(TimeSpan timeout) 
        { 
            // Do I need to do timeout decrementing?
            SqlConnection connection = new SqlConnection(GetConnectionString(timeout)); 
            connection.Open();

            return connection;
        } 

        void PerformOpen(TimeSpan timeout) 
        { 
            string lowerCaseConnectionString = this.connectionString.ToUpper(CultureInfo.InvariantCulture);
 
            if (!lowerCaseConnectionString.Contains("CONNECTION TIMEOUT") &&
                !lowerCaseConnectionString.Contains("CONNECTIONTIMEOUT"))
            {
                this.canonicalConnectionString = this.connectionString.Trim(); 

                if (this.canonicalConnectionString.EndsWith(";", StringComparison.Ordinal)) 
                { 
                    this.canonicalConnectionString += "Connection Timeout=";
                } 
                else
                {
                    this.canonicalConnectionString += ";Connection Timeout=";
                } 
            }
 
            // Check that the connection string is valid 
            using (SqlConnection connection = new SqlConnection(GetConnectionString(timeout)))
            { 
                if (DiagnosticUtility.ShouldTraceInformation)
                {
                    Dictionary openParameters = new Dictionary(2)
                    { 
                        { "IsLocking", this.IsLockingTurnedOn ? "True" : "False" },
                        { "LockTimeout", this.lockTimeout.ToString() } 
                    }; 

                    TraceRecord record = new DictionaryTraceRecord(openParameters); 

                    TraceUtility.TraceEvent(TraceEventType.Information,
                        TraceCode.SqlPersistenceProviderOpenParameters, SR.GetString(SR.TraceCodeSqlPersistenceProviderOpenParameters),
                        record, this, null); 
                }
 
                connection.Open(); 
            }
 
            this.activeCommands = new List();
            this.hostId = Guid.NewGuid();
        }
 
        object PerformOperation(OperationHandler handler, Guid id, TimeSpan timeout, params object[] additionalParameters)
        { 
            int resultCode; 
            object returnValue = null;
 
            if (DiagnosticUtility.ShouldTraceInformation)
            {
                string traceText = SR2.GetString(SR2.SqlPrsistenceProviderOperationAndInstanceId, handler.OperationName, id.ToString());
                TraceUtility.TraceEvent(TraceEventType.Information, 
                    TraceCode.SqlPersistenceProviderSQLCallStart, SR.GetString(SR.TraceCodeSqlPersistenceProviderSQLCallStart),
                    new StringTraceRecord("OperationDetail", traceText), 
                    this, null); 
            }
 
            try
            {
                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout);
 
                using (SqlConnection connection = OpenConnection(timeoutHelper.RemainingTime()))
                { 
                    SqlCommand command = CreateCommand(connection, timeoutHelper.RemainingTime()); 

                    try 
                    {
                        handler.SetupCommand(command, id, additionalParameters);

                        if (handler.ExecuteReader) 
                        {
                            using (SqlDataReader reader = command.ExecuteReader()) 
                            { 
                                returnValue = handler.ProcessReader(reader);
                            } 
                        }
                        else
                        {
                            command.ExecuteNonQuery(); 
                        }
 
                        resultCode = (int) command.Parameters["@result"].Value; 
                    }
                    finally 
                    {
                        CleanupCommand(command);
                    }
                } 
            }
            catch (Exception e) 
            { 
                if (Fx.IsFatal(e))
                { 
                    throw;
                }

                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                    new PersistenceException(
                    SR2.GetString(SR2.PersistenceOperationError, handler.OperationName), 
                    e)); 
            }
 
            Exception toThrow = handler.ProcessResult(resultCode, id, returnValue);

            if (DiagnosticUtility.ShouldTraceInformation)
            { 
                string traceText = SR2.GetString(SR2.SqlPrsistenceProviderOperationAndInstanceId, handler.OperationName, id.ToString());
                TraceUtility.TraceEvent(TraceEventType.Information, 
                    TraceCode.SqlPersistenceProviderSQLCallEnd, SR.GetString(SR.TraceCodeSqlPersistenceProviderSQLCallEnd), 
                    new StringTraceRecord("OperationDetail", traceText),
                    this, null); 
            }

            if (toThrow != null)
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(toThrow);
            } 
 
            return returnValue;
        } 

        void Unlock(Guid id, TimeSpan timeout)
        {
            base.ThrowIfDisposedOrNotOpen(); 

            if (this.unlockHandler.ShortcutExecution) 
            { 
                return;
            } 

            ValidateCommandTimeout(timeout);

            PerformOperation(this.unlockHandler, id, timeout); 
        }
 
        object Update(Guid id, object instance, TimeSpan timeout, bool unlockInstance) 
        {
            base.ThrowIfDisposedOrNotOpen(); 

            if (instance == null)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("instance"); 
            }
 
            ValidateCommandTimeout(timeout); 

            PerformOperation(this.updateHandler, id, timeout, instance, unlockInstance); 

            return null;
        }
 
        void ValidateCommandTimeout(TimeSpan timeout)
        { 
            if (timeout <= TimeSpan.Zero || 
                (timeout > SqlPersistenceProviderFactory.maxSecondsTimeSpan && timeout != TimeSpan.MaxValue))
            { 
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(
                    "timeout",
                    SR2.GetString(SR2.CommandTimeoutOutOfRange));
            } 
        }
 
        class CloseAsyncResult : AsyncResult 
        {
            public CloseAsyncResult(SqlPersistenceProviderFactory provider, TimeSpan timeout, AsyncCallback callback, object state) 
                : base(callback, state)
            {
                // There is no point in even pretending SqlConnection.Close needs async
                provider.OnClose(timeout); 

                Complete(true); 
            } 

            public static void End(IAsyncResult result) 
            {
                AsyncResult.End(result);
            }
        } 

        class CreateHandler : OperationHandler 
        { 
            public CreateHandler(SqlPersistenceProviderFactory provider)
                : base(provider) 
            {
            }

            public override string OperationName 
            {
                get { return "Create"; } 
            } 

            public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 
            {
                switch (resultCode)
                {
                    case 0: // Success 
                        return null;
                    case 1: // Already exists 
                        return new PersistenceException(SR2.GetString(SR2.InstanceAlreadyExists, id)); 
                    case 2: // Some other error
                        return new PersistenceException(SR2.GetString(SR2.InsertFailed, id)); 
                    default:
                        return
                            new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult));
                } 
            }
 
            public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 
            {
                Fx.Assert(additionalParameters != null && additionalParameters.Length == 2, 
                    "Should have had 2 additional parameters.");

                Fx.Assert(additionalParameters[1].GetType() == typeof(bool),
                    "Parameter at index 1 should have been a boolean."); 

                object instance = additionalParameters[0]; 
 
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "InsertInstance"; 

                SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier);
                idParameter.Value = id;
                command.Parameters.Add(idParameter); 

                SqlParameter instanceParameter = new SqlParameter("@instance", SqlDbType.Image); 
                SqlParameter instanceXmlParameter = new SqlParameter("@instanceXml", SqlDbType.Xml); 

                if (this.provider.serializeAsText) 
                {
                    instanceXmlParameter.Value = this.provider.GetXmlSerializedForm(instance);
                    instanceParameter.Value = null;
                } 
                else
                { 
                    instanceParameter.Value = this.provider.GetBinarySerializedForm(instance); 
                    instanceXmlParameter.Value = null;
                } 

                command.Parameters.Add(instanceParameter);
                command.Parameters.Add(instanceXmlParameter);
 
                SqlParameter unlockInstanceParameter = new SqlParameter("@unlockInstance", SqlDbType.Bit);
                unlockInstanceParameter.Value = (bool) additionalParameters[1]; 
                command.Parameters.Add(unlockInstanceParameter); 

                SqlParameter lockOwnerParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 
                lockOwnerParameter.Value = this.provider.hostId;
                command.Parameters.Add(lockOwnerParameter);

                SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 
                lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt;
                command.Parameters.Add(lockTimeoutParameter); 
 
                SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int);
                resultParameter.Direction = ParameterDirection.Output; 
                command.Parameters.Add(resultParameter);
            }
        }
 
        class DeleteHandler : OperationHandler
        { 
            public DeleteHandler(SqlPersistenceProviderFactory provider) 
                : base(provider)
            { 
            }

            public override string OperationName
            { 
                get { return "Delete"; }
            } 
 
            public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance)
            { 
                switch (resultCode)
                {
                    case 0: // Success
                        return null; 
                    case 1: // Instance not found
                        return 
                            new InstanceNotFoundException(id); 
                    case 2: // Could not acquire lock
                        return new InstanceLockException(id, SR2.GetString(SR2.DidNotOwnLock, id, OperationName)); 
                    default:
                        return
                            new PersistenceException(
                            SR2.GetString(SR2.UnknownStoredProcResult)); 
                }
            } 
 
            public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)
            { 
                Fx.Assert(additionalParameters == null || additionalParameters.Length == 0,
                    "Should not have gotten any additional parameters.");

                command.CommandType = CommandType.StoredProcedure; 
                command.CommandText = "DeleteInstance";
 
                SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier); 
                idParameter.Value = id;
                command.Parameters.Add(idParameter); 

                SqlParameter hostIdParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier);
                hostIdParameter.Value = this.provider.hostId;
                command.Parameters.Add(hostIdParameter); 

                SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 
                lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt; 
                command.Parameters.Add(lockTimeoutParameter);
 
                SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int);
                resultParameter.Direction = ParameterDirection.Output;
                command.Parameters.Add(resultParameter);
            } 
        }
 
        class LoadHandler : OperationHandler 
        {
            public LoadHandler(SqlPersistenceProviderFactory provider) 
                : base(provider)
            {
            }
 
            public override bool ExecuteReader
            { 
                get { return true; } 
            }
 
            public override string OperationName
            {
                get { return "Load"; }
            } 

            public override object ProcessReader(SqlDataReader reader) 
            { 
                if (reader.Read())
                { 
                    bool isXml = ((int) reader["isXml"] == 0 ? false : true);
                    object serializedInstance;

                    if (isXml) 
                    {
                        serializedInstance = reader["instanceXml"]; 
                    } 
                    else
                    { 
                        serializedInstance = reader["instance"];
                    }

                    if (serializedInstance != null) 
                    {
                        return this.provider.DeserializeInstance(serializedInstance, isXml); 
                    } 
                }
 
                return null;
            }

            public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 
            {
                Exception toReturn = null; 
 
                switch (resultCode)
                { 
                    case 0: // Success
                        break;
                    case 1: // Instance not found
                        toReturn = new InstanceNotFoundException(id); 
                        break;
                    case 2: // Could not acquire lock 
                        toReturn = new InstanceLockException(id); 
                        break;
                    default: 
                        toReturn =
                            new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult));
                        break;
                } 

                if (toReturn == null) 
                { 
                    if (loadedInstance == null)
                    { 
                        toReturn = new PersistenceException(SR2.GetString(SR2.SerializationFormatMismatch));
                    }
                }
 
                return toReturn;
            } 
 
            public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters)
            { 
                Fx.Assert(additionalParameters != null && additionalParameters.Length == 1,
                    "Should have had 1 additional parameter.");

                Fx.Assert(additionalParameters[0].GetType() == typeof(bool), 
                    "Parameter 0 should have been a boolean.");
 
                command.CommandType = CommandType.StoredProcedure; 
                command.CommandText = "LoadInstance";
 
                SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier);
                idParameter.Value = id;
                command.Parameters.Add(idParameter);
 
                SqlParameter lockInstanceParameter = new SqlParameter("@lockInstance", SqlDbType.Bit);
                lockInstanceParameter.Value = (bool) additionalParameters[0]; 
                command.Parameters.Add(lockInstanceParameter); 

                SqlParameter hostIdParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 
                hostIdParameter.Value = this.provider.hostId;
                command.Parameters.Add(hostIdParameter);

                SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 
                lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt;
                command.Parameters.Add(lockTimeoutParameter); 
 
                SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int);
                resultParameter.Direction = ParameterDirection.Output; 
                command.Parameters.Add(resultParameter);
            }
        }
 
        class OpenAsyncResult : AsyncResult
        { 
            SqlPersistenceProviderFactory provider; 
            TimeSpan timeout;
 
            public OpenAsyncResult(SqlPersistenceProviderFactory provider, TimeSpan timeout, AsyncCallback callback, object state)
                : base(callback, state)
            {
                Fx.Assert(provider != null, 
                    "Provider should never be null.");
 
                this.provider = provider; 
                this.timeout = timeout;
 
 		ActionItem.Schedule(ScheduledCallback, null);
            }

            public static void End(IAsyncResult result) 
            {
                AsyncResult.End(result); 
            } 

            void ScheduledCallback(object state) 
            {
                Exception completionException = null;

                try 
                {
                    this.provider.PerformOpen(this.timeout); 
                } 
                catch (Exception e)
                { 
                    if (Fx.IsFatal(e))
                    {
                        throw;
                    } 

                    completionException = 
                        new PersistenceException( 
                        SR2.GetString(SR2.ErrorOpeningSqlPersistenceProvider),
                        e); 
                }

                Complete(false, completionException);
            } 
        }
 
        class OperationAsyncResult : AsyncResult 
        {
            protected SqlPersistenceProviderFactory provider; 
            static AsyncCallback commandCallback = Fx.ThunkCallback(new AsyncCallback(CommandExecutionComplete));

            SqlCommand command;
            OperationHandler handler; 
            Guid id;
 
            object instance; 

            // We are using virtual methods from the constructor on purpose 
            [SuppressMessage("Microsoft.Usage", "CA2214")]
            public OperationAsyncResult(OperationHandler handler, SqlPersistenceProviderFactory provider, Guid id, TimeSpan timeout, AsyncCallback callback, object state, params object[] additionalParameters)
                : base(callback, state)
            { 
                Fx.Assert(provider != null,
                    "Provider should never be null."); 
 
                this.handler = handler;
                this.provider = provider; 
                this.id = id;

                if (this.handler.ShortcutExecution)
                { 
                    Complete(true);
                    return; 
                } 

                TimeoutHelper timeoutHelper = new TimeoutHelper(timeout); 
                SqlConnection connection = this.provider.OpenConnection(timeoutHelper.RemainingTime());

                bool completeSelf = false;
                Exception delayedException = null; 
                try
                { 
                    this.command = this.provider.CreateCommand(connection, timeoutHelper.RemainingTime()); 

                    this.handler.SetupCommand(this.command, this.id, additionalParameters); 

                    IAsyncResult result = null;

                    if (this.handler.ExecuteReader) 
                    {
                        result = this.command.BeginExecuteReader(commandCallback, this); 
                    } 
                    else
                    { 
                        result = this.command.BeginExecuteNonQuery(commandCallback, this);
                    }

                    if (result.CompletedSynchronously) 
                    {
                        delayedException = CompleteOperation(result); 
 
                        completeSelf = true;
                    } 
                }
                catch (Exception e)
                {
                    if (Fx.IsFatal(e)) 
                    {
                        throw; 
                    } 

                    try 
                    {
                        connection.Close();
                        this.provider.CleanupCommand(this.command);
                    } 
                    catch (Exception e1)
                    { 
                        if (Fx.IsFatal(e1)) 
                        {
                            throw; 
                        }
                        // do not rethrow non-fatal exceptions thrown from cleanup code
                    }
                    finally 
                    {
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                            new PersistenceException( 
                            SR2.GetString(SR2.PersistenceOperationError, this.handler.OperationName), e));
                    } 
                }

                if (completeSelf)
                { 
                    connection.Close();
                    this.provider.CleanupCommand(this.command); 
 
                    if (delayedException != null)
                    { 
                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(delayedException);
                    }

                    Complete(true); 
                }
            } 
 
            public object Instance
            { 
                get { return this.instance; }
            }

            public static object End(IAsyncResult result) 
            {
                OperationAsyncResult operationResult = AsyncResult.End(result); 
 
                return operationResult.Instance;
            } 

            static void CommandExecutionComplete(IAsyncResult result)
            {
                if (result.CompletedSynchronously) 
                {
                    return; 
                } 

                OperationAsyncResult operationResult = (OperationAsyncResult) result.AsyncState; 

                Exception completionException = null;
                try
                { 
                    completionException = operationResult.CompleteOperation(result);
                } 
                catch (Exception e) 
                {
                    if (Fx.IsFatal(e)) 
                    {
                        throw;
                    }
 
                    completionException =
                        new PersistenceException( 
                        SR2.GetString(SR2.PersistenceOperationError, operationResult.handler.OperationName), e); 
                }
                finally 
                {
                    try
                    {
                        operationResult.command.Connection.Close(); 
                        operationResult.provider.CleanupCommand(operationResult.command);
                    } 
                    catch (Exception e1) 
                    {
                        if (Fx.IsFatal(e1)) 
                        {
                            throw;
                        }
                        // do not rethrow non-fatal exceptions thrown from cleanup code 
                    }
                } 
 
                operationResult.Complete(false, completionException);
            } 

            Exception CompleteOperation(IAsyncResult result)
            {
                Exception delayedException = null; 

                if (this.handler.ExecuteReader) 
                { 
                    using (SqlDataReader reader = this.command.EndExecuteReader(result))
                    { 
                        this.instance = this.handler.ProcessReader(reader);
                    }
                }
                else 
                {
                    this.command.EndExecuteNonQuery(result); 
                } 

                int resultCode = (int) this.command.Parameters["@result"].Value; 

                delayedException = this.handler.ProcessResult(resultCode, this.id, this.instance);

                return delayedException; 
            }
        } 
 
        abstract class OperationHandler
        { 
            protected SqlPersistenceProviderFactory provider;

            public OperationHandler(SqlPersistenceProviderFactory provider)
            { 
                this.provider = provider;
            } 
 
            public virtual bool ExecuteReader
            { 
                get { return false; }
            }

            public abstract string OperationName 
            { get; }
 
            public virtual bool ShortcutExecution 
            {
                get { return false; } 
            }


            public virtual object ProcessReader(SqlDataReader reader) 
            {
                return null; 
            } 

            public abstract Exception ProcessResult(int resultCode, Guid id, object loadedInstance); 

            public abstract void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters);
        }
 
        class SqlPersistenceProvider : LockingPersistenceProvider
        { 
            SqlPersistenceProviderFactory factory; 

            public SqlPersistenceProvider(Guid id, SqlPersistenceProviderFactory factory) 
                : base(id)
            {
                this.factory = factory;
            } 

            protected override TimeSpan DefaultCloseTimeout 
            { 
                get { return TimeSpan.FromSeconds(15); }
            } 

            protected override TimeSpan DefaultOpenTimeout
            {
                get { return TimeSpan.FromSeconds(15); } 
            }
 
            public override IAsyncResult BeginCreate(object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 
            {
                base.ThrowIfDisposedOrNotOpen(); 
                return this.factory.BeginCreate(this.Id, instance, timeout, unlockInstance, callback, state);
            }

            public override IAsyncResult BeginDelete(object instance, TimeSpan timeout, AsyncCallback callback, object state) 
            {
                base.ThrowIfDisposedOrNotOpen(); 
                return this.factory.BeginDelete(this.Id, instance, timeout, callback, state); 
            }
 
            public override IAsyncResult BeginLoad(TimeSpan timeout, bool lockInstance, AsyncCallback callback, object state)
            {
                base.ThrowIfDisposedOrNotOpen();
                return this.factory.BeginLoad(this.Id, timeout, lockInstance, callback, state); 
            }
 
            public override IAsyncResult BeginUnlock(TimeSpan timeout, AsyncCallback callback, object state) 
            {
                base.ThrowIfDisposedOrNotOpen(); 
                return this.factory.BeginUnlock(this.Id, timeout, callback, state);
            }

            public override IAsyncResult BeginUpdate(object instance, TimeSpan timeout, bool unlockInstance, AsyncCallback callback, object state) 
            {
                base.ThrowIfDisposedOrNotOpen(); 
                return this.factory.BeginUpdate(this.Id, instance, timeout, unlockInstance, callback, state); 
            }
 
            public override object Create(object instance, TimeSpan timeout, bool unlockInstance)
            {
                base.ThrowIfDisposedOrNotOpen();
                return this.factory.Create(this.Id, instance, timeout, unlockInstance); 
            }
 
            public override void Delete(object instance, TimeSpan timeout) 
            {
                base.ThrowIfDisposedOrNotOpen(); 
                this.factory.Delete(this.Id, instance, timeout);
            }

            public override object EndCreate(IAsyncResult result) 
            {
                return this.factory.EndCreate(result); 
            } 

            public override void EndDelete(IAsyncResult result) 
            {
                this.factory.EndDelete(result);
            }
 
            public override object EndLoad(IAsyncResult result)
            { 
                return this.factory.EndLoad(result); 
            }
 
            public override void EndUnlock(IAsyncResult result)
            {
                this.factory.EndUnlock(result);
            } 

            public override object EndUpdate(IAsyncResult result) 
            { 
                return this.factory.EndUpdate(result);
            } 

            public override object Load(TimeSpan timeout, bool lockInstance)
            {
                base.ThrowIfDisposedOrNotOpen(); 
                return this.factory.Load(this.Id, timeout, lockInstance);
            } 
 
            public override void Unlock(TimeSpan timeout)
            { 
                base.ThrowIfDisposedOrNotOpen();
                this.factory.Unlock(this.Id, timeout);
            }
 
            public override object Update(object instance, TimeSpan timeout, bool unlockInstance)
            { 
                base.ThrowIfDisposedOrNotOpen(); 
                return this.factory.Update(this.Id, instance, timeout, unlockInstance);
            } 

            protected override void OnAbort()
            {
            } 

            protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback callback, object state) 
            { 
                return new CompletedAsyncResult(callback, state);
            } 

            protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback callback, object state)
            {
                return new CompletedAsyncResult(callback, state); 
            }
 
            protected override void OnClose(TimeSpan timeout) 
            {
            } 

            protected override void OnEndClose(IAsyncResult result)
            {
                CompletedAsyncResult.End(result); 
            }
 
            protected override void OnEndOpen(IAsyncResult result) 
            {
                CompletedAsyncResult.End(result); 
            }

            protected override void OnOpen(TimeSpan timeout)
            { 
            }
        } 
 
        class UnlockHandler : OperationHandler
        { 
            public UnlockHandler(SqlPersistenceProviderFactory provider)
                : base(provider)
            {
            } 

            public override string OperationName 
            { 
                get { return "Unlock"; }
            } 

            public override bool ShortcutExecution
            {
                get { return !this.provider.IsLockingTurnedOn; } 
            }
 
            public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance) 
            {
                switch (resultCode) 
                {
                    case 0: // Success
                        return null;
                    case 1: // Instance not found 
                        return
                            new InstanceNotFoundException(id); 
                    case 2: // Could not acquire lock 
                        return new InstanceLockException(id, SR2.GetString(SR2.DidNotOwnLock, id, OperationName));
                    default: 
                        return
                            new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult));
                }
            } 

            public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 
            { 
                Fx.Assert(additionalParameters == null || additionalParameters.Length == 0,
                    "There should not be any additional parameters."); 

                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "UnlockInstance";
 
                SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier);
                idParameter.Value = id; 
                command.Parameters.Add(idParameter); 

                SqlParameter hostIdParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier); 
                hostIdParameter.Value = this.provider.hostId;
                command.Parameters.Add(hostIdParameter);

                SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int); 
                lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt;
                command.Parameters.Add(lockTimeoutParameter); 
 
                SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int);
                resultParameter.Direction = ParameterDirection.Output; 
                command.Parameters.Add(resultParameter);
            }
        }
 
        class UpdateHandler : OperationHandler
        { 
            public UpdateHandler(SqlPersistenceProviderFactory provider) 
                : base(provider)
            { 
            }

            public override string OperationName
            { 
                get { return "Update"; }
            } 
 
            public override Exception ProcessResult(int resultCode, Guid id, object loadedInstance)
            { 
                switch (resultCode)
                {
                    case 0: // Success
                        return null; 
                    case 1: // Instance did not exist
                        return new InstanceNotFoundException(id, SR2.GetString(SR2.InstanceNotFoundForUpdate, id)); 
                    case 2: // Did not have lock 
                        return new InstanceLockException(id, SR2.GetString(SR2.DidNotOwnLock, id, OperationName));
                    default: 
                        return
                            new PersistenceException(SR2.GetString(SR2.UnknownStoredProcResult));
                }
            } 

            public override void SetupCommand(SqlCommand command, Guid id, params object[] additionalParameters) 
            { 
                Fx.Assert(additionalParameters != null && additionalParameters.Length == 2,
                    "Should have had 2 additional parameters."); 

                Fx.Assert(additionalParameters[1].GetType() == typeof(bool),
                    "Parameter at index 1 should have been a boolean.");
 
                object instance = additionalParameters[0];
 
                command.CommandType = CommandType.StoredProcedure; 
                command.CommandText = "UpdateInstance";
 
                SqlParameter idParameter = new SqlParameter("@id", SqlDbType.UniqueIdentifier);
                idParameter.Value = id;
                command.Parameters.Add(idParameter);
 
                SqlParameter instanceParameter = new SqlParameter("@instance", SqlDbType.Image);
                SqlParameter instanceXmlParameter = new SqlParameter("@instanceXml", SqlDbType.Xml); 
 
                if (this.provider.serializeAsText)
                { 
                    instanceXmlParameter.Value = this.provider.GetXmlSerializedForm(instance);
                    instanceParameter.Value = null;
                }
                else 
                {
                    instanceParameter.Value = this.provider.GetBinarySerializedForm(instance); 
                    instanceXmlParameter.Value = null; 
                }
 
                command.Parameters.Add(instanceParameter);
                command.Parameters.Add(instanceXmlParameter);

                SqlParameter unlockInstanceParameter = new SqlParameter("@unlockInstance", SqlDbType.Bit); 
                unlockInstanceParameter.Value = (bool) additionalParameters[1];
                command.Parameters.Add(unlockInstanceParameter); 
 
                SqlParameter lockOwnerParameter = new SqlParameter("@hostId", SqlDbType.UniqueIdentifier);
                lockOwnerParameter.Value = this.provider.hostId; 
                command.Parameters.Add(lockOwnerParameter);

                SqlParameter lockTimeoutParameter = new SqlParameter("@lockTimeout", SqlDbType.Int);
                lockTimeoutParameter.Value = this.provider.LockTimeoutAsInt; 
                command.Parameters.Add(lockTimeoutParameter);
 
                SqlParameter resultParameter = new SqlParameter("@result", SqlDbType.Int); 
                resultParameter.Direction = ParameterDirection.Output;
                command.Parameters.Add(resultParameter); 
            }
        }
    }
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK