StoreConnection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / WCF / infocard / Service / managed / Microsoft / InfoCards / StoreConnection.cs / 2 / StoreConnection.cs

                            //------------------------------------------------------------------------------ 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//-----------------------------------------------------------------------------
//
// Presharp uses the c# pragma mechanism to supress its warnings. 
// These are not recognised by the base compiler so we need to explictly
// disable the following warnings. See http://winweb/cse/Tools/PREsharp/userguide/default.asp 
// for details. 
//
#pragma warning disable 1634, 1691      // unknown message, unknown pragma 



namespace Microsoft.InfoCards 
{
    using System; 
    using System.Collections; 
    using System.Collections.Generic;
    using System.Collections.Specialized; 
    using System.ComponentModel;
    using System.Runtime.InteropServices;
    using System.Security;
    using System.Security.Cryptography; 
    using System.Security.Principal;
    using System.Text; 
    using System.Threading; 
    using System.IO;
    using IDT = Microsoft.InfoCards.Diagnostics.InfoCardTrace; 


    //
    // Summary: 
    //  Utility class for managing the multiple data files that the infocard system requires.
    //  Also managed a list of "connections" for each user. 
    // 
    internal class StoreConnection : IDisposable
    { 

        public const string DEFAULTFILENAME = "CardSpace.db";
        public const string STOREFILENAMEV2 = "CardSpaceSP2.db";
        public const string STORAGEPATH = @"Microsoft\CardSpace\"; 

        //  
        static Hashtable s_instanceCache = CollectionsUtil.CreateCaseInsensitiveHashtable(); 

        string m_path; 
        Int32 m_refCount;


        // 
        // We do not really need multiple sources because
        // we now deal only with ONE source (the actual store file). 
        // However leave it in to support our tools -- specifically infocardimporter tool that is 
        // used in perf batch scripts.
        // 
        // We could of course re-write/remove the StoreConnection class altogether but that
        // will involve too much code churn both in sources and tools at this point as we pass the
        // StoreConnection as arguments to lots of function within the code.
        // 

        //  
        Hashtable  m_sources; 
        string m_instanceId;
        string m_activeSource; 
        string m_localSource;
        bool m_isLoaded;
        WindowsIdentity m_identity;
        bool m_disposed; 
        object m_sync;
 
 
        //
        // Summary: 
        //  Creates a new StoreConnection, using the provided identity to initialize
        //
        // Parameters:
        //  identity:       The windows identity to use to find the data files, and to open them. 
        //
        protected StoreConnection( WindowsIdentity identity ) 
        { 

            m_identity = new WindowsIdentity( identity.Token ); 
            m_instanceId = m_identity.User.Value;
            m_sync = new object();
            m_disposed = false;
 

            m_path = Path.Combine( Environment.GetFolderPath( Environment.SpecialFolder.LocalApplicationData ), STORAGEPATH ) ; 
 
            m_localSource = m_path + STOREFILENAMEV2;
            m_activeSource = m_localSource; 

            m_sources = CollectionsUtil.CreateCaseInsensitiveHashtable();

        } 

        // 
        // Summary: 
        //  Gets the hashtable of all data sources currently loaded into this connection
        // 
        public Hashtable DataSources
        {
            get
            { 
                return m_sources;
            } 
        } 

        // 
        // Summary:
        //  Gets the currently active data source for roaming objects.
        //
        public string ActiveDataSource 
        {
            get 
            { 
                return m_activeSource;
            } 
        }

        //
        // Summary: 
        //  Gets the name of the local user datasource
        // 
        public string LocalDataSource 
        {
            get 
            {
                return m_localSource;
            }
        } 

 
 
        //
        // Summary: 
        //  Get the ID of this instance.
        //
        // Remarks:
        //  This should be the string sid of the user that owns it. 
        //
        public string InstanceId 
        { 
            get
            { 
                return m_instanceId;
            }
        }
 
        //
        // Summary: 
        //  Gets the WindowsIdentity that owns the store files. 
        //
        public WindowsIdentity Identity 
        {
            get
            {
                return m_identity; 
            }
        } 
 
        //
        // Summary: 
        //  Gets the current outstanding Reference count
        //
        protected int ReferenceCount
        { 
            get { return m_refCount; }
            set { m_refCount = value; } 
        } 

 

        public static StoreConnection CreateConnection()
        {
            WindowsIdentity identity = WindowsIdentity.GetCurrent(); 

            IDT.Assert( !identity.IsSystem, "Identity should not be LSA" ); 
 
            return GetConnection( identity, true );
        } 



        public static StoreConnection GetConnection() 
        {
 
            WindowsIdentity identity = WindowsIdentity.GetCurrent(); 

            IDT.Assert( !identity.IsSystem, "Identity should not be LSA" ); 

            return GetConnection( identity );
        }
 
        //
        // Summary: 
        //  Gets or Creates the currently loaded StoreConnection for a given user. 
        //
        // Parameters: 
        //  identity:       The user whos store is needed.
        //
        public static StoreConnection GetConnection( WindowsIdentity identity )
        { 
            return GetConnection( identity, false );
        } 
 

 
        static StoreConnection GetConnection( WindowsIdentity identity, bool allowCreate )
        {
            StoreConnection instance = null;
 
            lock( s_instanceCache.SyncRoot )
            { 
                instance = ( StoreConnection )s_instanceCache[ identity.User.Value ]; 
                if( null == instance )
                { 
                    if( !allowCreate )
                    {
                        throw IDT.ThrowHelperError( new DataAccessException(
                                                        SR.GetString( SR.StoreFailedToOpenStore ) ) ); 
                    }
 
                    instance = new StoreConnection( identity ); 

                    // 
                    // Perform all loading operation before we add it to the collection.
                    //
                    instance.Load();
 
                    s_instanceCache[ identity.User.Value ] = instance;
 
                } 
                else
                { 
                    //
                    // If it was previously attached.
                    //
                    if( !instance.m_isLoaded ) 
                    {
                        instance.Load(); 
                    } 
                }
 
                //
                // Becuase we have a global lock around all modification of the
                //      refcount, we have no need to use Interlocked.* methods.
                // 
                instance.ReferenceCount++;
 
            } 

            return instance; 
        }

        //
        // Summary: 
        //  Sets the active data source for this connection.
        //  This will cause the target of the default methods to change. 
        // 
        // Parameters:
        //  id:         the SourceId of the DataSource to make active 
        //
        //
        // This function is there to support tools
        // 
        public void SetActiveDataSource( string id )
        { 
            ThrowIfNotLoaded(); 

            if( !m_sources.ContainsKey( id ) ) 
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    "id",
                                    id, 
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) );
            } 
 
            if( ( (DataSource) m_sources[ m_activeSource ] ).IsProcessingTransaction() )
            { 
                throw IDT.ThrowHelperError( new InvalidOperationException( SR.GetString( SR.StoreProcessingTransaction ) ) );
            }

            m_activeSource = id; 
        }
 
        // 
        // Summary:
        //  Deref and if all dereffed, we are up for disposal 
        //
        public void Close()
        {
            ThrowIfNotLoaded(); 

            lock( s_instanceCache.SyncRoot ) 
            { 
                //
                // Becuase we have a global lock around all modification of the 
                //      refcount, we have no need to use Interlocked.* methods.
                //
                ReferenceCount--;
                if( 0 == ReferenceCount ) 
                {
                    // 
                    //  No more refs, so we can remove. 
                    //
                    s_instanceCache.Remove( m_identity.User.Value ); 

                    m_isLoaded = false;

                    foreach( string key in m_sources.Keys ) 
                    {
                        ( ( DataSource )m_sources[ key ] ).Close(); 
                    } 

                    m_sources.Clear(); 
                }
            }
        }
 
        void IDisposable.Dispose()
        { 
            lock( m_sync ) 
            {
                if( !m_disposed ) 
                {
                    m_disposed = true;
                    if( null != m_identity )
                    { 
                        ( ( IDisposable )m_identity ).Dispose();
                        m_identity  = null; 
                    } 
                }
            } 
        }

        //
        // Summary: 
        //  Finds if the data source was cleared at load time.
        // 
        // Remarks: 
        //  This deletes the source used to create the data source. The functionality will
        //  depend on the type of datasource. 
        //
        // Parameters:
        //  sourceId:         The SourceId of the DataSource to clear.
        // 
        public bool IsDataSourceCleared( string sourceId )
        { 
            if( !m_sources.ContainsKey( sourceId ) ) 
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "sourceId",
                                    sourceId,
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) );
            } 

            DataSource source = (DataSource)m_sources[ sourceId ]; 
            return source.IsCleared; 
        }
 
        //
        // Summary:
        //  This resets the clear value of the data source. This is required so that
        //  subsequent queries to the system do not return the same value. 
        //
        // 
        // Parameters: 
        //  sourceId:         The SourceId of the DataSource to clear.
        // 
        public void ResetDataSourceClearedFlag( string sourceId )
        {
            if( !m_sources.ContainsKey( sourceId ) )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    "sourceId", 
                                    sourceId, 
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) );
            } 

            DataSource source = (DataSource)m_sources[sourceId];
            source.IsCleared = false;
        } 

        // 
        // Summary: 
        //  Fetches a single row from the active data source matching the criteria.
        // 
        // Remarks:
        //  If the query results in more than one row, an exception will be thrown.
        //
        // Parameters: 
        //  details:        The level of detail to return from the query.
        //  objectQuery:    the QueryParameter list to use in the query. 
        // 
        // Returns:
        //  The data row filled to the specified detail. 
        //
        public DataRow GetSingleRow( QueryDetails details, params QueryParameter[ ] objectQuery )
        {
            return GetSingleRow( details, m_activeSource, objectQuery ); 
        }
 
        // 
        // Summary:
        //  Fetches a single row from the active data source matching the criteria. 
        //
        // Remarks:
        //  If the query results in more than one row, an exception will be thrown.
        // 
        // Parameters:
        //  objectQuery:    the QueryParameter list to use in the query. 
        // 
        // Returns:
        //  The a FullRow filled dataRow. 
        //
        public DataRow GetSingleRow( params QueryParameter[ ] objectQuery )
        {
            return GetSingleRow( m_activeSource, objectQuery ); 
        }
        // 
        // Summary: 
        //  Fetches a single row from the specified data source matching the criteria.
        // 
        // Remarks:
        //  If the query results in more than one row, an exception will be thrown.
        //
        // Parameters: 
        //  sourceId:       The SourceId of the DataSource to target
        //  objectQuery:    the QueryParameter list to use in the query. 
        // 
        // Returns:
        //  The a FullRow filled dataRow. 
        //
        public DataRow GetSingleRow( string sourceId, params QueryParameter[ ] objectQuery )
        {
            return GetSingleRow( QueryDetails.FullRow, sourceId, objectQuery ); 
        }
 
 
        //
        // Summary: 
        //  Fetches a single row from the specified data source matching the criteria.
        //
        // Remarks:
        //  If the query results in more than one row, an exception will be thrown. 
        //
        // Parameters: 
        //  details:        The level of detail to return from the query. 
        //  sourceId:       The SourceId of the DataSource to target
        //  objectQuery:    the QueryParameter list to use in the query. 
        //
        // Returns:
        //  The data row filled to the specified detail.
        // 
        public DataRow GetSingleRow( QueryDetails details, string sourceId, params QueryParameter[ ] objectQuery )
        { 
            ThrowIfNotLoaded(); 
            if( null == objectQuery || 0 == objectQuery.Length )
            { 
                throw IDT.ThrowHelperArgumentNull( "objectQuery" );
            }

            if( !m_sources.ContainsKey( sourceId ) ) 
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "sourceId", 
                                    sourceId,
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) ); 
            }

            DataSource source = ( DataSource )m_sources[ sourceId ];
 
            return source.GetSingleRow( details, objectQuery );
        } 
 

        // 
        // Summary:
        //  Fetches all rows from the active data source matching the criteria.
        //
        // Remarks: 
        //
        // Parameters: 
        //  details:        The level of detail to return from the query. 
        //  query:          The QueryParameter list to use in the query.
        // 
        // Returns:
        //  The list of data rows filled to the specified detail.
        //
        public ICollection Query( QueryDetails details, params QueryParameter[ ] query ) 
        {
            return Query( details, m_activeSource, query ); 
        } 

        // 
        // Summary:
        //  Fetches all rows from the active data source matching the criteria.
        //
        // Remarks: 
        //  FullRow is the detail level
        // 
        // Parameters: 
        //  query:          The QueryParameter list to use in the query.
        // 
        // Returns:
        //  The list of data rows filled to the FullRow detail.
        //
        public ICollection Query( params QueryParameter[ ] query ) 
        {
            return Query( m_activeSource, query ); 
        } 

        // 
        // Summary:
        //  Fetches all rows from the specified data source matching the criteria.
        //
        // Remarks: 
        //  FullRow is the detail level
        // 
        // Parameters: 
        //  sourceId:       The SourceId of the DataSource to target
        //  query:          The QueryParameter list to use in the query. 
        //
        // Returns:
        //  The list of data rows filled to the FullRow detail.
        // 
        public ICollection Query( string sourceId, params QueryParameter[ ] query )
        { 
            return Query( QueryDetails.FullRow, sourceId, query ); 
        }
 
        //
        // Summary:
        //  Fetches all rows from the specified data source matching the criteria.
        // 
        // Remarks:
        // 
        // Parameters: 
        //  details:        The level of detail to return from the query.
        //  sourceId:       The SourceId of the DataSource to target 
        //  query:          The QueryParameter list to use in the query.
        //
        // Returns:
        //  The list of data rows filled to the specified detail. 
        //
        public ICollection Query( QueryDetails details, string sourceId, params QueryParameter[ ] query ) 
        { 
            ThrowIfNotLoaded();
            if( null == query || 0 == query.Length ) 
            {
                throw IDT.ThrowHelperArgumentNull( "query" );
            }
 
            if( !m_sources.ContainsKey( sourceId ) )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "sourceId",
                                    sourceId, 
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) );
            }

            DataSource source; 
            source = ( DataSource )m_sources[ sourceId ];
 
            return source.Query( details, query ); 
        }
 
        //
        // Summary:
        //  Saves the specified DataRow to the specified DataSource.
        // 
        // Parameters:
        //  sourceId:       the SourceId of the DataSource to target the save 
        //  row:            The data row to save. 
        //
        public void Save( string sourceId, DataRow row ) 
        {
            ThrowIfNotLoaded();

            DataSource source; 

            if( null == row ) 
            { 
                throw IDT.ThrowHelperArgumentNull( "row" );
            } 

            if( !m_sources.ContainsKey( sourceId ) )
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    "sourceId",
                                    sourceId, 
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) ); 
            }
 
            source = ( DataSource )m_sources[ sourceId ];

            source.Save( row );
 
        }
 
        // 
        // Summary:
        //  Saves the specified DataRow to the active DataSource. 
        //
        // Parameters:
        //  row:            The data row to save.
        // 
        public void Save( DataRow row )
        { 
            ThrowIfNotLoaded(); 

            if( null == row ) 
            {
                throw IDT.ThrowHelperArgumentNull( "row" );
            }
 
            if( !String.IsNullOrEmpty( row.SourceId ) )
            { 
                Save( row.SourceId, row ); 
            }
            else 
            {

                Save( m_activeSource, row );
 
            }
        } 
 
        //
        // Summary: 
        //  Deletes the specified DataRow to the specified DataSource.
        //
        // Parameters:
        //  sourceId:       the SourceId of the DataSource to target the delete 
        //  row:            The data row to delete.
        // 
        public void Delete( string sourceId, DataRow row ) 
        {
            ThrowIfNotLoaded(); 

            if( row.InstanceId != m_instanceId )
            {
                throw IDT.ThrowHelperError( new InvalidOperationException( 
                                SR.GetString( SR.StoreRowOwnedByOtherDataSource ) ) );
            } 
 
            if( !m_sources.ContainsKey( sourceId ) )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    "sourceId",
                                    sourceId,
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) ); 
            }
 
 
            DataSource source = ( DataSource )m_sources[ sourceId ];
            source.Delete( row ); 

        }

        // 
        // Summary:
        //  Deletes the specified DataRow to the active DataSource. 
        // 
        // Parameters:
        //  row:            The data row to delete. 
        //
        public void Delete( DataRow row )
        {
            Delete( row.SourceId, row ); 
        }
 
 
        //
        // Summary 
        // Begin a transaction
        //
        public void BeginTransaction()
        { 
            BeginTransaction( m_activeSource );
        } 
 
        //
        // Summary 
        // Begin a transaction
        //
        // Parameters
        //  sourceId - The source for which transaction has to be started. 
        //
        public void BeginTransaction( string sourceId ) 
        { 
            if( !m_sources.ContainsKey( sourceId ) )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    " sourceId ",
                                    sourceId,
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) ); 
            }
            DataSource source = ( DataSource )m_sources[ sourceId ]; 
            source.BeginTransaction(); 
        }
 
        //
        // Summary
        // Commit a transaction
        // 
        public void CommitTransaction()
        { 
            CommitTransaction( m_activeSource ); 
        }
 
        //
        // Summary
        // Commit a transaction
        // 
        // Parameters
        //  sourceId - The source for which transaction has to be commited. 
        // 
        public void CommitTransaction( string sourceId )
        { 
            if( !m_sources.ContainsKey( sourceId ) )
            {
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException(
                                    " sourceId ", 
                                    sourceId,
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) ); 
            } 

 
            DataSource source = ( DataSource )m_sources[ sourceId ];
            source.CommitTransaction();
        }
 
        //
        // Summary 
        // Rollback a transaction 
        //
        public void RollbackTransaction() 
        {
            RollbackTransaction( m_activeSource );
        }
 
        //
        // Summary 
        // Rollback a transaction 
        //
        // Parameters 
        //  sourceId - The source for which transaction has to be rolled back.
        //
        public void RollbackTransaction( string sourceId )
        { 
            if( !m_sources.ContainsKey( sourceId ) )
            { 
                throw IDT.ThrowHelperError( new ArgumentOutOfRangeException( 
                                    " sourceId ",
                                    sourceId, 
                                    SR.GetString( SR.StoreSourceIdOutOfRange ) ) );
            }
            DataSource source = ( DataSource )m_sources[ sourceId ];
            source.RollbackTransaction(); 
        }
 
 

        protected virtual void CreateDefaultDataSources( Hashtable list ) 
        {

            string oldStoreFilePath = m_path + DEFAULTFILENAME;
            // 
            // File.Exists needs right permissions...
            // 
            using ( SystemIdentity lsa = new SystemIdentity( true ) ) 
            {
                if( File.Exists( m_localSource ) ) 
                {
                    //
                    // check to see if oldStoreFile is newer than the newStoreFile
                    // 
                    if( File.Exists( oldStoreFilePath ) )
                    { 
                        if( DateTime.Compare( File.GetLastWriteTime( oldStoreFilePath ), File.GetLastWriteTime( m_localSource ) ) > 0 ) 
                        {
                            // 
                            // First delete the new file as that is outdated
                            //
                            File.Delete( m_localSource );
                            if( File.Exists( m_localSource + ".shadow" ) ) 
                            {
                                File.Delete( m_localSource + ".shadow" ); 
                            } 
                            AtomicFileCopy( oldStoreFilePath, m_localSource );
                        } 
                    }

                }
                else if( !File.Exists( m_localSource ) && File.Exists( m_localSource + ".shadow" ) ) 
                {
                    // 
                    // If the store file is missing and the shadow file has a size of 0, the store 
                    // is in an invalid state. We delete the shadow file as a new default store will
                    // be created as required. 
                    //
                    FileInfo fl = new FileInfo( m_localSource + ".shadow" );
                    if( 0 == fl.Length )
                    { 
                        fl.Delete();
                    } 
 
                }
                else 
                {
                    //
                    // This can be a first time scenario where we have an existing old format StoreFile
                    // In this case, we will simply copy over the old file to the new one and move ahead 
                    // We will do this only when the old file is in a valid state, else we anyways start
                    // by creating a new store 
 
                    if( File.Exists( oldStoreFilePath ) )
                    { 
                       AtomicFileCopy( oldStoreFilePath, m_localSource );
                    }
                    else
                    { 
                        //
                        // Check to see if we have a valid shadow else, move on to create a new store 
                        // 
                        if( File.Exists( oldStoreFilePath + ".shadow" ) )
                        { 
                            FileInfo shadowfl = new FileInfo( oldStoreFilePath + ".shadow" );
                            if( 0 == shadowfl.Length )
                            {
                                shadowfl.Delete(); 
                            }
                            else 
                            { 
                                AtomicFileCopy( oldStoreFilePath + ".shadow", m_localSource );
                            } 
                        }

                    }
 
                }
            } 
 
            list.Add(
                    m_localSource, 
                    new FileDataSource(
                        m_identity,
                        m_localSource,
                        m_instanceId, 
                        SecondaryIndexDefinition.MasterIndexes ) );
        } 
 

        // 
        // Summary
        //  Atomically copies the one file to the other
        //
        protected void AtomicFileCopy( string source, string destination ) 
        {
            if( File.Exists( source ) ) 
            { 
                File.Copy( source, source + ".atomic", true );
                FileInfo fl = new FileInfo( source + ".atomic" ); 
                if( fl.Length != 0 )
                {
                    fl.MoveTo( destination );
                } 
            }
 
        } 

 
        //
        // Summary:
        //  Loads all currently Mounted sources that are not already loaded.
        // 
        protected void Load()
        { 
            IDT.Assert( !m_isLoaded, "Store is already loaded" ); 

            CreateDefaultDataSources( m_sources ); 

            foreach( string key in m_sources.Keys )
            {
                if( !( (DataSource)m_sources[key] ).IsLoaded ) 
                {
                    // 
                    // Try to load the datasource. If we encounter a failure during loading the datasource and 
                    // and it is a recoverable failure, we will clear the datasource and then try to load again.
                    // This is equivalent to creating a brand new data source. 
                    //
                    bool isloaded = false;
                    try
                    { 
                        ( (DataSource)m_sources[key] ).Load();
                        isloaded = true; 
                    } 
                    catch( CorruptStoreException )
                    { 
                        ( (DataSource)m_sources[key] ).Clear();
                    }
                    catch( InvalidStoreProtectionKeyException )
                    { 
                        ( (DataSource)m_sources[key] ).Clear();
                    } 
                    if( !isloaded ) 
                    {
                        ( (DataSource)m_sources[key] ).Load(); 
                    }
                }
            }
            m_isLoaded = true; 
        }
 
        // 
        // Protected becuase used by tools.
        // 
        protected void ThrowIfNotLoaded()
        {
            IDT.Assert( m_isLoaded, "store is not loaded" );
        } 

    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

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