Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / EntityClient / EntityConnection.cs / 1 / EntityConnection.cs
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....], [....]
//---------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.Common.EntitySql;
using System.Configuration;
using System.IO;
using System.Diagnostics;
using System.Data.Metadata;
using System.Xml;
using System.Data.Mapping;
using System.Transactions;
namespace System.Data.EntityClient
{
using Metadata.Edm;
///
/// Class representing a connection for the conceptual layer. An entity connection may only
/// be initialized once (by opening the connection). It is subsequently not possible to change
/// the connection string, attach a new store connection, or change the store connection string.
///
public sealed class EntityConnection : DbConnection
{
#region Constants
private const string s_metadataPathSeparator = "|";
private const string s_semicolonSeparator = ";";
private const string s_entityClientProviderName = "System.Data.EntityClient";
private const string s_dataDirectory = "|datadirectory|";
private const string s_metadataid = "metadata id";
private const string s_providerInvariantName = "provider";
private const string s_providerConnectionString = "provider connection string";
#endregion
private readonly object _connectionStringLock = new object();
private static readonly DbConnectionOptions s_emptyConnectionOptions = new DbConnectionOptions(String.Empty, null, false);
// The connection options object having the connection settings needed by this connection
private DbConnectionOptions _userConnectionOptions;
private DbConnectionOptions _effectiveConnectionOptions;
// The internal connection state of the entity client, which is distinct from that of the
// store connection it aggregates.
private ConnectionState _entityClientConnectionState = ConnectionState.Closed;
private DbProviderFactory _providerFactory;
private DbConnection _storeConnection;
private MetadataWorkspace _metadataWorkspace;
private EntityTransaction _currentTransaction;
private Guid _metadataID; //set only when constructed using MetadataWorkspace
private bool _initialized;
// will only have a value while waiting for the ssdl to be loaded. we should
// never have a value for this when _initialized == true
private MetadataArtifactLoader _artifactLoader;
private static int _objectTypeCount; // Bid counter
internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
///
/// Constructs the EntityConnection object with a connection not yet associated to a particular store
///
public EntityConnection()
: this(String.Empty)
{
}
///
/// Constructs the EntityConnection object with a connection string
///
/// The connection string, may contain a list of settings for the connection or
/// just the name of the connection to use
public EntityConnection(string connectionString)
{
GC.SuppressFinalize(this);
this.ChangeConnectionString(connectionString);
}
///
/// Constructs the EntityConnection from Metadata loaded in memory
///
/// Workspace containing metadata information.
public EntityConnection(MetadataWorkspace workspace, DbConnection connection)
{
EntityUtil.CheckArgumentNull(workspace, "workspace");
EntityUtil.CheckArgumentNull(connection, "connection");
if (!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("EdmItemCollection"));
}
if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StoreItemCollection"));
}
if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StorageMappingItemCollection"));
}
if (connection.State != ConnectionState.Closed)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionMustBeClosed);
}
if (connection.ProviderFactory == null)
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_DbConnectionHasNoProvider(connection));
}
StoreItemCollection collection = (StoreItemCollection)workspace.GetItemCollection(DataSpace.SSpace);
ValidateThatConnectionAndMetadataProvidersAreEqual(connection.ProviderFactory, null, collection.StoreProviderFactory);
GC.SuppressFinalize(this);
_providerFactory = connection.ProviderFactory;
_storeConnection = connection;
_metadataWorkspace = workspace;
_initialized = true;
_metadataID = System.Guid.NewGuid();
}
///
/// Get or set the entity connection string associated with this connection object
///
public override string ConnectionString
{
get
{
//EntityConnection created using MetadataWorkspace
// _userConnectionOptions is not null when empty Constructor is used
// Therefore it is sufficient to identify whether EC(MW, DbConnection) is used
if (this._userConnectionOptions == null)
{
Debug.Assert(_storeConnection != null);
string invariantName;
if(!EntityUtil.TryGetProviderInvariantName(_storeConnection.ProviderFactory, out invariantName))
{
Debug.Fail("Provider Invariant Name not found");
invariantName = "";
}
return string.Format(Globalization.CultureInfo.InvariantCulture,
"{0}={3};{1}={4};{2}=\"{5}\";",
s_metadataid,
s_providerInvariantName,
s_providerConnectionString,
_metadataID.ToString(),
invariantName,
FormatProviderString(_storeConnection.ConnectionString));
}
string userConnectionString = this._userConnectionOptions.UsersConnectionString(false);
// In here, we ask the store connection for the connection string only if the user didn't specify a name
// connection (meaning effective connection options == user connection options). If the user specified a
// named connection, then we return just that. Otherwise, if the connection string is different from what
// we have in the connection options, which is possible if the store connection changed the connection
// string to hide the password, then we use the builder to reconstruct the string. The parameters will be
// shuffled, which is unavoidable but it's ok because the connection string cannot be the same as what the
// user originally passed in anyway. However, if the store connection string is still the same, then we
// simply return what the user originally passed in.
if (object.ReferenceEquals(_userConnectionOptions, _effectiveConnectionOptions) && this._storeConnection != null)
{
string storeConnectionString = null;
try
{
storeConnectionString = this._storeConnection.ConnectionString;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ConnectionString", e);
}
throw;
}
// SQLBU 514721, 515024 - Defer connection string parsing to ConnectionStringBuilder
// if the 'userStoreConnectionString' and 'storeConnectionString' are unequal, except
// when they are both null or empty (we treat null and empty as equivalent here).
//
string userStoreConnectionString = this._userConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
if ((storeConnectionString != userStoreConnectionString)
&& !(string.IsNullOrEmpty(storeConnectionString) && string.IsNullOrEmpty(userStoreConnectionString)))
{
// Feeds the connection string into the connection string builder, then plug in the provider connection string into
// the builder, and then extract the string from the builder
EntityConnectionStringBuilder connectionStringBuilder = new EntityConnectionStringBuilder(userConnectionString);
connectionStringBuilder.ProviderConnectionString = storeConnectionString;
return connectionStringBuilder.ConnectionString;
}
}
return userConnectionString;
}
set
{
ValidateChangesPermitted();
this.ChangeConnectionString(value);
}
}
///
/// Formats provider string to replace " with \" so it can be appended within quotation marks "..."
///
private static string FormatProviderString(string providerString)
{
return providerString.Trim().Replace("\"", "\\\"");
}
///
/// Get the time to wait when attempting to establish a connection before ending the try and generating an error
///
public override int ConnectionTimeout
{
get
{
if (this._storeConnection == null)
return 0;
try
{
return this._storeConnection.ConnectionTimeout;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ConnectionTimeout", e);
}
throw;
}
}
}
///
/// Get the name of the current database or the database that will be used after a connection is opened
///
public override string Database
{
get
{
return String.Empty;
}
}
///
/// Gets the ConnectionState property of the EntityConnection
///
public override ConnectionState State
{
get
{
try
{
if (this._entityClientConnectionState == ConnectionState.Open)
{
Debug.Assert(this.StoreConnection != null);
if (this.StoreConnection.State != ConnectionState.Open)
{
return ConnectionState.Broken;
}
}
return this._entityClientConnectionState;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"State", e);
}
throw;
}
}
}
///
/// Gets the name or network address of the data source to connect to
///
public override string DataSource
{
get
{
if (this._storeConnection == null)
return String.Empty;
try
{
return this._storeConnection.DataSource;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"DataSource", e);
}
throw;
}
}
}
///
/// Gets a string that contains the version of the data store to which the client is connected
///
public override string ServerVersion
{
get
{
if (this._storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
try
{
return this._storeConnection.ServerVersion;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ServerVersion", e);
}
throw;
}
}
}
///
/// Gets the provider factory associated with EntityConnection
///
override protected DbProviderFactory DbProviderFactory
{
get
{
return EntityProviderFactory.Instance;
}
}
///
/// Gets the DbProviderFactory for the underlying provider
///
internal DbProviderFactory StoreProviderFactory
{
get
{
return this._providerFactory;
}
}
///
/// Gets the DbConnection for the underlying provider connection
///
public DbConnection StoreConnection
{
get
{
return this._storeConnection;
}
}
///
/// Gets the metadata workspace used by this connection
///
public MetadataWorkspace GetMetadataWorkspace()
{
return GetMetadataWorkspace(true /* initializeAllCollections */);
}
internal MetadataWorkspace GetMetadataWorkspace(bool initializeAllCollections)
{
Debug.Assert(_metadataWorkspace != null || _effectiveConnectionOptions != null, "The effective connection options is null, which should never be");
if (_metadataWorkspace == null ||
(initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)))
{
// This lock is to ensure that the connection string and the metadata workspace are in a consistent state, that is, you
// don't get a metadata workspace not matching what's described by the connection string
lock (_connectionStringLock)
{
EdmItemCollection edmItemCollection = null;
if (_metadataWorkspace == null)
{
MetadataWorkspace workspace = new MetadataWorkspace();
_artifactLoader = SplitPaths(_effectiveConnectionOptions[EntityConnectionStringBuilder.MetadataParameterName]);
edmItemCollection = LoadEdmItemCollection(workspace, _artifactLoader);
_metadataWorkspace = workspace;
}
else
{
edmItemCollection = (EdmItemCollection)_metadataWorkspace.GetItemCollection(DataSpace.CSpace);
}
if (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
{
LoadStoreItemCollections(_metadataWorkspace, _storeConnection, _providerFactory, _effectiveConnectionOptions, edmItemCollection, _artifactLoader);
_artifactLoader = null;
_initialized = true;
}
}
}
return _metadataWorkspace;
}
///
/// Gets the current transaction that this connection is enlisted in
///
internal EntityTransaction CurrentTransaction
{
get
{
// Null out the current transaction if the state is closed or zombied
if ((null != _currentTransaction) && ((null == _currentTransaction.StoreTransaction.Connection) || (this.State == ConnectionState.Closed)))
{
ClearCurrentTransaction();
}
return _currentTransaction;
}
}
///
/// Establish a connection to the data store by calling the Open method on the underlying data provider
///
public override void Open()
{
if (this._storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Closed)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_CannotReopenConnection);
}
bool closeStoreConnectionOnFailure = false;
OpenStoreConnectionIf(this._storeConnection.State != ConnectionState.Open,
this._storeConnection,
null,
EntityRes.EntityClient_ProviderSpecificError,
@"Open",
ref closeStoreConnectionOnFailure);
// the following guards against the case when the user closes the underlying store connection
// in the state change event handler, as a consequence of which we are in the 'Broken' state
if (this._storeConnection == null || this._storeConnection.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
InitializeMetadata(this._storeConnection, this._storeConnection, closeStoreConnectionOnFailure);
SetEntityClientConnectionStateToOpen();
}
///
/// Helper method that conditionally opens a specified store connection
///
/// The condition to evaluate
/// The store connection to open
/// The original store connection associated with the entity client
/// A flag that is set on if the connection is opened
/// successfully
private void OpenStoreConnectionIf(bool openCondition,
DbConnection storeConnectionToOpen,
DbConnection originalConnection,
string exceptionCode,
string attemptedOperation,
ref bool closeStoreConnectionOnFailure)
{
try
{
if (openCondition)
{
storeConnectionToOpen.Open();
closeStoreConnectionOnFailure = true;
}
ResetStoreConnection(storeConnectionToOpen, originalConnection, false);
// With every successful open of the store connection, always null out the current
// transaction (if there is one)
ClearCurrentTransaction();
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
string exceptionMessage = string.IsNullOrEmpty(attemptedOperation) ?
EntityRes.GetString(exceptionCode) :
EntityRes.GetString(exceptionCode, attemptedOperation);
throw EntityUtil.ProviderExceptionWithMessage(exceptionMessage, e);
}
throw;
}
}
///
/// Helper method to initialize the metadata workspace and reset the store connection
/// associated with the entity client
///
/// The new connection to associate with the entity client
/// The original connection associated with the entity client
/// A flag to indicate whether the original
/// store connection needs to be closed on failure
private void InitializeMetadata(DbConnection newConnection,
DbConnection originalConnection,
bool closeOriginalConnectionOnFailure)
{
try
{
// Ensure metadata is loaded and the workspace is appropriately initialized.
GetMetadataWorkspace();
}
catch (Exception ex)
{
// Undo the open if something failed
if (EntityUtil.IsCatchableExceptionType(ex))
{
ResetStoreConnection(newConnection, originalConnection, closeOriginalConnectionOnFailure);
}
throw;
}
}
///
/// Set the entity client connection state to Open, and raise an appropriate event
///
private void SetEntityClientConnectionStateToOpen()
{
this._entityClientConnectionState = ConnectionState.Open;
OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeOpen);
}
///
/// This method sets the store connection and hooks up the event
///
/// The DbConnection to set
/// The original DbConnection to be closed - this argument could be null
/// Indicates whether the original store connection should be closed
private void ResetStoreConnection(DbConnection newConnection, DbConnection originalConnection, bool closeOriginalConnection)
{
this._storeConnection = newConnection;
if (closeOriginalConnection && (originalConnection != null))
{
originalConnection.Close();
}
}
///
/// Create a new command object that uses this connection object
///
public new EntityCommand CreateCommand()
{
return new EntityCommand(null, this);
}
///
/// Create a new command object that uses this connection object
///
protected override DbCommand CreateDbCommand()
{
return this.CreateCommand();
}
internal EntityConnection Clone()
{
return new EntityConnection(_userConnectionOptions.UsersConnectionString(false));
}
///
/// Close the connection to the data store
///
public override void Close()
{
// It's a no-op if there isn't an underlying connection
if (this._storeConnection == null)
return;
this.CloseHelper();
}
///
/// Changes the current database for this connection
///
/// The name of the database to change to
public override void ChangeDatabase(string databaseName)
{
throw EntityUtil.NotSupported();
}
///
/// Begins a database transaction
///
/// An object representing the new transaction
public new EntityTransaction BeginTransaction()
{
return base.BeginTransaction() as EntityTransaction;
}
///
/// Begins a database transaction
///
/// The isolation level of the transaction
/// An object representing the new transaction
public new EntityTransaction BeginTransaction(IsolationLevel isolationLevel)
{
return base.BeginTransaction(isolationLevel) as EntityTransaction;
}
///
/// Begins a database transaction
///
/// The isolation level of the transaction
/// An object representing the new transaction
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
{
if (CurrentTransaction != null)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_TransactionAlreadyStarted);
}
if (this._storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
DbTransaction storeTransaction = null;
try
{
storeTransaction = this._storeConnection.BeginTransaction(isolationLevel);
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.ProviderExceptionWithMessage(
System.Data.Entity.Strings.EntityClient_ErrorInBeginningTransaction,
e
);
}
throw;
}
// The provider is problematic if it succeeded in beginning a transaction but returned a null
// for the transaction object
if (storeTransaction == null)
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("BeginTransaction", _storeConnection.GetType().Name));
}
_currentTransaction = new EntityTransaction(this, storeTransaction);
return _currentTransaction;
}
///
/// Enlist in the given transaction
///
/// The transaction object to enlist into
public override void EnlistTransaction(Transaction transaction)
{
if (_storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
try
{
_storeConnection.EnlistTransaction(transaction);
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"EnlistTransaction", e);
}
throw;
}
}
///
/// Cleans up this connection object
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_currentTransaction")]
protected override void Dispose(bool disposing)
{
ClearCurrentTransaction();
bool raiseStateChangeEvent = EntityCloseHelper(false, this.State);
if (disposing)
{
if (this._storeConnection != null)
{
StoreCloseHelper(); // closes store connection
if (this._storeConnection != null)
{
this._storeConnection.Dispose();
this._storeConnection = null;
}
}
}
// Change the connection string to just an empty string, ChangeConnectionString should always succeed here,
// it's unnecessary to pass in the connection string parameter name in the second argument, which we don't
// have anyway
this.ChangeConnectionString(String.Empty);
if (raiseStateChangeEvent) // we need to raise the event explicitly
{
OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed);
}
base.Dispose(disposing);
}
///
/// Reinitialize this connection object to use the new connection string
///
/// The new connection string
private void ChangeConnectionString(string newConnectionString)
{
DbConnectionOptions userConnectionOptions = s_emptyConnectionOptions;
if (!String.IsNullOrEmpty(newConnectionString))
{
userConnectionOptions = new DbConnectionOptions(newConnectionString, EntityConnectionStringBuilder.Synonyms, false);
}
DbProviderFactory factory = null;
DbConnection storeConnection = null;
DbConnectionOptions effectiveConnectionOptions = userConnectionOptions;
if (!userConnectionOptions.IsEmpty)
{
// Check if we have the named connection, if yes, then use the connection string from the configuration manager settings
string namedConnection = userConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
if (!string.IsNullOrEmpty(namedConnection))
{
// There cannot be other parameters when the named connection is specified
if (1 < userConnectionOptions.Parsetable.Count)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ExtraParametersWithNamedConnection);
}
// Find the named connection from the configuration, then extract the settings
ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[namedConnection];
if (setting == null || setting.ProviderName != EntityConnection.s_entityClientProviderName)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidNamedConnection);
}
effectiveConnectionOptions = new DbConnectionOptions(setting.ConnectionString, EntityConnectionStringBuilder.Synonyms, false);
// Check for a nested Name keyword
string nestedNamedConnection = effectiveConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
if (!string.IsNullOrEmpty(nestedNamedConnection))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_NestedNamedConnection(namedConnection));
}
}
//Validate the connection string has the required Keywords( Provider and Metadata)
//We trim the values for both the Keywords, so a string value with only spaces will throw an exception
//reporting back to the user that the Keyword was missing.
ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.MetadataParameterName);
string providerName = ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.ProviderParameterName);
// Get the correct provider factory
factory = GetFactory(providerName);
// Create the underlying provider specific connection and give it the connection string from the DbConnectionOptions object
storeConnection = GetStoreConnection(factory);
try
{
// When the value of 'Provider Connection String' is null, it means it has not been present in the entity connection string at all.
// Providers should still be able handle empty connection strings since those may be explicitly passed by clients.
string providerConnectionString = effectiveConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
if (providerConnectionString != null)
{
storeConnection.ConnectionString = providerConnectionString;
}
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ConnectionString", e);
}
throw;
}
}
// This lock is to ensure that the connection string matches with the provider connection and metadata workspace that's being
// managed by this EntityConnection, so states in this connection object are not messed up.
// It's not for security, but just to help reduce user error.
lock (_connectionStringLock)
{
// Now we have sufficient information and verified the configuration string is good, use them for this connection object
// Failure should not occur from this point to the end of this method
this._providerFactory = factory;
this._metadataWorkspace = null;
ClearCurrentTransaction();
ResetStoreConnection(storeConnection, null, false);
// Remembers the connection options objects with the connection string set by the user
this._userConnectionOptions = userConnectionOptions;
this._effectiveConnectionOptions = effectiveConnectionOptions;
}
}
private static string ValidateValueForTheKeyword(DbConnectionOptions effectiveConnectionOptions,
string keywordName)
{
string keywordValue = effectiveConnectionOptions[keywordName];
if (!string.IsNullOrEmpty(keywordValue))
keywordValue = keywordValue.Trim(); // be nice to user, always trim the value
// Check that we have a non-null and non-empty value for the keyword
if (string.IsNullOrEmpty(keywordValue))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionStringMissingInfo(keywordName));
}
return keywordValue;
}
private static EdmItemCollection LoadEdmItemCollection(MetadataWorkspace workspace, MetadataArtifactLoader artifactLoader)
{
// Build a string as the key and look up the MetadataCache for a match
string edmCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(DataSpace.CSpace), null, null);
// Check the MetadataCache for an entry with this key
object entryToken;
EdmItemCollection edmItemCollection = MetadataCache.GetOrCreateEdmItemCollection(edmCacheKey,
artifactLoader,
out entryToken);
workspace.RegisterItemCollection(edmItemCollection);
// Adding the edm metadata entry token to the workspace, to make sure that this token remains alive till workspace is alive
workspace.AddMetadataEntryToken(entryToken);
return edmItemCollection;
}
private static void LoadStoreItemCollections(MetadataWorkspace workspace,
DbConnection storeConnection,
DbProviderFactory factory,
DbConnectionOptions connectionOptions,
EdmItemCollection edmItemCollection,
MetadataArtifactLoader artifactLoader)
{
Debug.Assert(workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace), "C-Space must be loaded before loading S or C-S space");
// The provider connection string is optional; if it has not been specified,
// we pick up the store's connection string.
//
string providerConnectionString = connectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
if (string.IsNullOrEmpty(providerConnectionString) && (storeConnection != null))
{
providerConnectionString = storeConnection.ConnectionString;
}
// Build a string as the key and look up the MetadataCache for a match
string storeCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(),
connectionOptions[EntityConnectionStringBuilder.ProviderParameterName],
providerConnectionString);
// Load store metadata.
object entryToken;
StorageMappingItemCollection mappingCollection =
MetadataCache.GetOrCreateStoreAndMappingItemCollections(storeCacheKey,
artifactLoader,
edmItemCollection,
out entryToken);
ValidateThatConnectionAndMetadataProvidersAreEqual(factory, connectionOptions[EntityConnectionStringBuilder.ProviderParameterName], mappingCollection.StoreItemCollection.StoreProviderFactory);
workspace.RegisterItemCollection(mappingCollection.StoreItemCollection);
workspace.RegisterItemCollection(mappingCollection);
// Adding the store metadata entry token to the workspace
workspace.AddMetadataEntryToken(entryToken);
}
private static void ValidateThatConnectionAndMetadataProvidersAreEqual(DbProviderFactory connectionFactory, string connectionProviderName, DbProviderFactory metadataFactory)
{
if (metadataFactory.GetType() != connectionFactory.GetType())
{
string metadataProviderName = GetErrorMessageWorthyProviderName(metadataFactory);
if (string.IsNullOrEmpty(connectionProviderName))
{
connectionProviderName = GetErrorMessageWorthyProviderName(connectionFactory);
}
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionAndMetadataProviderMismatch(metadataProviderName, connectionProviderName));
}
}
private static string GetErrorMessageWorthyProviderName(DbProviderFactory factory)
{
EntityUtil.CheckArgumentNull(factory, "factory");
string providerName;
if (!EntityUtil.TryGetProviderInvariantName(factory, out providerName))
{
providerName = factory.GetType().FullName;
}
return providerName;
}
///
/// Create a key to be used with the MetadataCache from a connection options object
///
/// A list of metadata file paths
/// The provider name
/// The provider connection string
/// The key
private static string CreateMetadataCacheKey(IList paths, string providerName, string providerConnectionString)
{
int resultCount = 0;
string result;
// Do a first pass to calculate the output size of the metadata cache key,
// then another pass to populate a StringBuilder with the exact size and
// get the result.
CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString,
false, ref resultCount, out result);
CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString,
true, ref resultCount, out result);
return result;
}
///
/// Create a key to be used with the MetadataCache from a connection options
/// object.
///
/// A list of metadata file paths
/// The provider name
/// The provider connection string
/// Whether the result variable should be built.
///
/// On entry, the expected size of the result (unused if buildResult is false).
/// After execution, the effective result.
/// The key.
///
/// This method should be called once with buildResult=false, to get
/// the size of the resulting key, and once with buildResult=true
/// and the size specification.
///
private static void CreateMetadataCacheKeyWithCount(IList paths,
string providerName, string providerConnectionString,
bool buildResult, ref int resultCount, out string result)
{
// Build a string as the key and look up the MetadataCache for a match
StringBuilder keyString;
if (buildResult)
{
keyString = new StringBuilder(resultCount);
}
else
{
keyString = null;
}
// At this point, we've already used resultCount. Reset it
// to zero to make the final debug assertion that our computation
// is correct.
resultCount = 0;
if (!string.IsNullOrEmpty(providerName))
{
resultCount += providerName.Length + 1;
if (buildResult)
{
keyString.Append(providerName);
keyString.Append(EntityConnection.s_semicolonSeparator);
}
}
if (paths != null)
{
for (int i = 0; i < paths.Count; i++)
{
if (paths[i].Length > 0)
{
if (i > 0)
{
resultCount++;
if (buildResult)
{
keyString.Append(EntityConnection.s_metadataPathSeparator);
}
}
resultCount += paths[i].Length;
if (buildResult)
{
keyString.Append(paths[i]);
}
}
}
resultCount++;
if (buildResult)
{
keyString.Append(EntityConnection.s_semicolonSeparator);
}
}
if (!string.IsNullOrEmpty(providerConnectionString))
{
resultCount += providerConnectionString.Length;
if (buildResult)
{
keyString.Append(providerConnectionString);
}
}
if (buildResult)
{
result = keyString.ToString();
}
else
{
result = null;
}
System.Diagnostics.Debug.Assert(
!buildResult || (result.Length == resultCount));
}
///
/// A helper function for splitting up a string that is a concatenation of strings delimited by the metadata
/// path separator into a string list. The resulting list is NOT sorted.
///
/// The paths to split
/// An array of strings
private static MetadataArtifactLoader SplitPaths(string paths)
{
string[] results;
// This is the registry of all URIs in the global collection.
HashSet uriRegistry = new HashSet(StringComparer.OrdinalIgnoreCase);
List loaders = new List();
if (!string.IsNullOrEmpty(paths))
{
// If the argument contains one or more occurrences of the macro '|DataDirectory|', we
// pull those paths out so that we don't lose them in the string-splitting logic below.
// Note that the macro '|DataDirectory|' cannot have any whitespace between the pipe
// symbols and the macro name. Also note that the macro must appear at the beginning of
// a path (else we will eventually fail with an invalid path exception, because in that
// case the macro is not expanded). If a real/physical folder named 'DataDirectory' needs
// to be included in the metadata path, whitespace should be used on either or both sides
// of the name.
//
List dataDirPaths = new List();
int indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase);
while (indexStart != -1)
{
int prevSeparatorIndex = indexStart == 0 ? -1 : paths.LastIndexOf(
EntityConnection.s_metadataPathSeparator,
indexStart - 1, // start looking here
StringComparison.Ordinal
);
int macroPathBeginIndex = prevSeparatorIndex + 1;
// The '|DataDirectory|' macro is composable, so identify the complete path, like
// '|DataDirectory|\foo\bar'. If the macro appears anywhere other than at the
// beginning, splice out the entire path, e.g. 'C:\foo\|DataDirectory|\bar'. In this
// latter case the macro will not be expanded, and downstream code will throw an exception.
//
int indexEnd = paths.IndexOf(EntityConnection.s_metadataPathSeparator,
indexStart + EntityConnection.s_dataDirectory.Length,
StringComparison.Ordinal);
if (indexEnd == -1)
{
dataDirPaths.Add(paths.Substring(macroPathBeginIndex));
paths = paths.Remove(macroPathBeginIndex); // update the concatenated list of paths
break;
}
dataDirPaths.Add(paths.Substring(macroPathBeginIndex, indexEnd - macroPathBeginIndex));
// Update the concatenated list of paths by removing the one containing the macro.
//
paths = paths.Remove(macroPathBeginIndex, indexEnd - macroPathBeginIndex);
indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase);
}
// Split the string on the separator and remove all spaces around each parameter value
results = paths.Split(new string[] { EntityConnection.s_metadataPathSeparator }, StringSplitOptions.RemoveEmptyEntries);
// Now that the non-macro paths have been identified, merge the paths containing the macro
// into the complete list.
//
if (dataDirPaths.Count > 0)
{
dataDirPaths.AddRange(results);
results = dataDirPaths.ToArray();
}
for (int i = 0; i < results.Length; i++)
{
// Trim out all the spaces for this parameter and add it only if it's not blank
results[i] = results[i].Trim();
if (results[i].Length > 0)
{
loaders.Add(MetadataArtifactLoader.Create(
results[i],
MetadataArtifactLoader.ExtensionCheck.All, // validate the extension against all acceptable values
null,
uriRegistry
));
}
}
}
return MetadataArtifactLoader.Create(loaders);
}
///
/// Clears the current transaction for this connection
///
internal void ClearCurrentTransaction()
{
_currentTransaction = null;
}
///
/// Helper method invoked as part of Close()/Dispose() that releases the underlying
/// store connection and raises the appropriate event.
///
private void CloseHelper()
{
ConnectionState previousState = this.State; // the public connection state before cleanup
StoreCloseHelper();
EntityCloseHelper(
true, // raise the state change event
previousState
);
}
///
/// Store-specific helper method invoked as part of Close()/Dispose().
///
private void StoreCloseHelper()
{
try
{
if (this._storeConnection != null && (this._storeConnection.State != ConnectionState.Closed))
{
this._storeConnection.Close();
}
// Need to disassociate the transaction object with this connection
ClearCurrentTransaction();
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.ProviderExceptionWithMessage(
System.Data.Entity.Strings.EntityClient_ErrorInClosingConnection,
e
);
}
throw;
}
}
///
/// Entity-specific helper method invoked as part of Close()/Dispose().
///
/// Indicates whether we need to raise the state change event here
/// The public state of the connection before cleanup began
/// true if the caller needs to raise the state change event
private bool EntityCloseHelper(bool fireEventOnStateChange, ConnectionState previousState)
{
bool result = false;
this._entityClientConnectionState = ConnectionState.Closed;
if (previousState == ConnectionState.Open)
{
if (fireEventOnStateChange)
{
OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed);
}
else
{
result = true; // we didn't raise the event here; the caller should do that
}
}
return result;
}
///
/// Call to determine if changes to the entity object are currently permitted.
///
private void ValidateChangesPermitted()
{
if (_initialized)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_SettingsCannotBeChangedOnOpenConnection);
}
}
///
/// Returns the DbProviderFactory associated with specified provider string
///
private DbProviderFactory GetFactory(string providerString)
{
try
{
return DbProviderFactories.GetFactory(providerString);
}
catch (ArgumentException e)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidStoreProvider, e);
}
}
///
/// Uses DbProviderFactory to create a DbConnection
///
private DbConnection GetStoreConnection(DbProviderFactory factory)
{
DbConnection storeConnection = factory.CreateConnection();
if (storeConnection == null)
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("CreateConnection", factory.GetType().Name));
}
return storeConnection;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//----------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// @owner [....], [....]
//---------------------------------------------------------------------
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.Common;
using System.Data.Common.EntitySql;
using System.Configuration;
using System.IO;
using System.Diagnostics;
using System.Data.Metadata;
using System.Xml;
using System.Data.Mapping;
using System.Transactions;
namespace System.Data.EntityClient
{
using Metadata.Edm;
///
/// Class representing a connection for the conceptual layer. An entity connection may only
/// be initialized once (by opening the connection). It is subsequently not possible to change
/// the connection string, attach a new store connection, or change the store connection string.
///
public sealed class EntityConnection : DbConnection
{
#region Constants
private const string s_metadataPathSeparator = "|";
private const string s_semicolonSeparator = ";";
private const string s_entityClientProviderName = "System.Data.EntityClient";
private const string s_dataDirectory = "|datadirectory|";
private const string s_metadataid = "metadata id";
private const string s_providerInvariantName = "provider";
private const string s_providerConnectionString = "provider connection string";
#endregion
private readonly object _connectionStringLock = new object();
private static readonly DbConnectionOptions s_emptyConnectionOptions = new DbConnectionOptions(String.Empty, null, false);
// The connection options object having the connection settings needed by this connection
private DbConnectionOptions _userConnectionOptions;
private DbConnectionOptions _effectiveConnectionOptions;
// The internal connection state of the entity client, which is distinct from that of the
// store connection it aggregates.
private ConnectionState _entityClientConnectionState = ConnectionState.Closed;
private DbProviderFactory _providerFactory;
private DbConnection _storeConnection;
private MetadataWorkspace _metadataWorkspace;
private EntityTransaction _currentTransaction;
private Guid _metadataID; //set only when constructed using MetadataWorkspace
private bool _initialized;
// will only have a value while waiting for the ssdl to be loaded. we should
// never have a value for this when _initialized == true
private MetadataArtifactLoader _artifactLoader;
private static int _objectTypeCount; // Bid counter
internal readonly int ObjectID = System.Threading.Interlocked.Increment(ref _objectTypeCount);
///
/// Constructs the EntityConnection object with a connection not yet associated to a particular store
///
public EntityConnection()
: this(String.Empty)
{
}
///
/// Constructs the EntityConnection object with a connection string
///
/// The connection string, may contain a list of settings for the connection or
/// just the name of the connection to use
public EntityConnection(string connectionString)
{
GC.SuppressFinalize(this);
this.ChangeConnectionString(connectionString);
}
///
/// Constructs the EntityConnection from Metadata loaded in memory
///
/// Workspace containing metadata information.
public EntityConnection(MetadataWorkspace workspace, DbConnection connection)
{
EntityUtil.CheckArgumentNull(workspace, "workspace");
EntityUtil.CheckArgumentNull(connection, "connection");
if (!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("EdmItemCollection"));
}
if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StoreItemCollection"));
}
if(!workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSSpace))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ItemCollectionsNotRegisteredInWorkspace("StorageMappingItemCollection"));
}
if (connection.State != ConnectionState.Closed)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionMustBeClosed);
}
if (connection.ProviderFactory == null)
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_DbConnectionHasNoProvider(connection));
}
StoreItemCollection collection = (StoreItemCollection)workspace.GetItemCollection(DataSpace.SSpace);
ValidateThatConnectionAndMetadataProvidersAreEqual(connection.ProviderFactory, null, collection.StoreProviderFactory);
GC.SuppressFinalize(this);
_providerFactory = connection.ProviderFactory;
_storeConnection = connection;
_metadataWorkspace = workspace;
_initialized = true;
_metadataID = System.Guid.NewGuid();
}
///
/// Get or set the entity connection string associated with this connection object
///
public override string ConnectionString
{
get
{
//EntityConnection created using MetadataWorkspace
// _userConnectionOptions is not null when empty Constructor is used
// Therefore it is sufficient to identify whether EC(MW, DbConnection) is used
if (this._userConnectionOptions == null)
{
Debug.Assert(_storeConnection != null);
string invariantName;
if(!EntityUtil.TryGetProviderInvariantName(_storeConnection.ProviderFactory, out invariantName))
{
Debug.Fail("Provider Invariant Name not found");
invariantName = "";
}
return string.Format(Globalization.CultureInfo.InvariantCulture,
"{0}={3};{1}={4};{2}=\"{5}\";",
s_metadataid,
s_providerInvariantName,
s_providerConnectionString,
_metadataID.ToString(),
invariantName,
FormatProviderString(_storeConnection.ConnectionString));
}
string userConnectionString = this._userConnectionOptions.UsersConnectionString(false);
// In here, we ask the store connection for the connection string only if the user didn't specify a name
// connection (meaning effective connection options == user connection options). If the user specified a
// named connection, then we return just that. Otherwise, if the connection string is different from what
// we have in the connection options, which is possible if the store connection changed the connection
// string to hide the password, then we use the builder to reconstruct the string. The parameters will be
// shuffled, which is unavoidable but it's ok because the connection string cannot be the same as what the
// user originally passed in anyway. However, if the store connection string is still the same, then we
// simply return what the user originally passed in.
if (object.ReferenceEquals(_userConnectionOptions, _effectiveConnectionOptions) && this._storeConnection != null)
{
string storeConnectionString = null;
try
{
storeConnectionString = this._storeConnection.ConnectionString;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ConnectionString", e);
}
throw;
}
// SQLBU 514721, 515024 - Defer connection string parsing to ConnectionStringBuilder
// if the 'userStoreConnectionString' and 'storeConnectionString' are unequal, except
// when they are both null or empty (we treat null and empty as equivalent here).
//
string userStoreConnectionString = this._userConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
if ((storeConnectionString != userStoreConnectionString)
&& !(string.IsNullOrEmpty(storeConnectionString) && string.IsNullOrEmpty(userStoreConnectionString)))
{
// Feeds the connection string into the connection string builder, then plug in the provider connection string into
// the builder, and then extract the string from the builder
EntityConnectionStringBuilder connectionStringBuilder = new EntityConnectionStringBuilder(userConnectionString);
connectionStringBuilder.ProviderConnectionString = storeConnectionString;
return connectionStringBuilder.ConnectionString;
}
}
return userConnectionString;
}
set
{
ValidateChangesPermitted();
this.ChangeConnectionString(value);
}
}
///
/// Formats provider string to replace " with \" so it can be appended within quotation marks "..."
///
private static string FormatProviderString(string providerString)
{
return providerString.Trim().Replace("\"", "\\\"");
}
///
/// Get the time to wait when attempting to establish a connection before ending the try and generating an error
///
public override int ConnectionTimeout
{
get
{
if (this._storeConnection == null)
return 0;
try
{
return this._storeConnection.ConnectionTimeout;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ConnectionTimeout", e);
}
throw;
}
}
}
///
/// Get the name of the current database or the database that will be used after a connection is opened
///
public override string Database
{
get
{
return String.Empty;
}
}
///
/// Gets the ConnectionState property of the EntityConnection
///
public override ConnectionState State
{
get
{
try
{
if (this._entityClientConnectionState == ConnectionState.Open)
{
Debug.Assert(this.StoreConnection != null);
if (this.StoreConnection.State != ConnectionState.Open)
{
return ConnectionState.Broken;
}
}
return this._entityClientConnectionState;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"State", e);
}
throw;
}
}
}
///
/// Gets the name or network address of the data source to connect to
///
public override string DataSource
{
get
{
if (this._storeConnection == null)
return String.Empty;
try
{
return this._storeConnection.DataSource;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"DataSource", e);
}
throw;
}
}
}
///
/// Gets a string that contains the version of the data store to which the client is connected
///
public override string ServerVersion
{
get
{
if (this._storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
try
{
return this._storeConnection.ServerVersion;
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ServerVersion", e);
}
throw;
}
}
}
///
/// Gets the provider factory associated with EntityConnection
///
override protected DbProviderFactory DbProviderFactory
{
get
{
return EntityProviderFactory.Instance;
}
}
///
/// Gets the DbProviderFactory for the underlying provider
///
internal DbProviderFactory StoreProviderFactory
{
get
{
return this._providerFactory;
}
}
///
/// Gets the DbConnection for the underlying provider connection
///
public DbConnection StoreConnection
{
get
{
return this._storeConnection;
}
}
///
/// Gets the metadata workspace used by this connection
///
public MetadataWorkspace GetMetadataWorkspace()
{
return GetMetadataWorkspace(true /* initializeAllCollections */);
}
internal MetadataWorkspace GetMetadataWorkspace(bool initializeAllCollections)
{
Debug.Assert(_metadataWorkspace != null || _effectiveConnectionOptions != null, "The effective connection options is null, which should never be");
if (_metadataWorkspace == null ||
(initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace)))
{
// This lock is to ensure that the connection string and the metadata workspace are in a consistent state, that is, you
// don't get a metadata workspace not matching what's described by the connection string
lock (_connectionStringLock)
{
EdmItemCollection edmItemCollection = null;
if (_metadataWorkspace == null)
{
MetadataWorkspace workspace = new MetadataWorkspace();
_artifactLoader = SplitPaths(_effectiveConnectionOptions[EntityConnectionStringBuilder.MetadataParameterName]);
edmItemCollection = LoadEdmItemCollection(workspace, _artifactLoader);
_metadataWorkspace = workspace;
}
else
{
edmItemCollection = (EdmItemCollection)_metadataWorkspace.GetItemCollection(DataSpace.CSpace);
}
if (initializeAllCollections && !_metadataWorkspace.IsItemCollectionAlreadyRegistered(DataSpace.SSpace))
{
LoadStoreItemCollections(_metadataWorkspace, _storeConnection, _providerFactory, _effectiveConnectionOptions, edmItemCollection, _artifactLoader);
_artifactLoader = null;
_initialized = true;
}
}
}
return _metadataWorkspace;
}
///
/// Gets the current transaction that this connection is enlisted in
///
internal EntityTransaction CurrentTransaction
{
get
{
// Null out the current transaction if the state is closed or zombied
if ((null != _currentTransaction) && ((null == _currentTransaction.StoreTransaction.Connection) || (this.State == ConnectionState.Closed)))
{
ClearCurrentTransaction();
}
return _currentTransaction;
}
}
///
/// Establish a connection to the data store by calling the Open method on the underlying data provider
///
public override void Open()
{
if (this._storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Closed)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_CannotReopenConnection);
}
bool closeStoreConnectionOnFailure = false;
OpenStoreConnectionIf(this._storeConnection.State != ConnectionState.Open,
this._storeConnection,
null,
EntityRes.EntityClient_ProviderSpecificError,
@"Open",
ref closeStoreConnectionOnFailure);
// the following guards against the case when the user closes the underlying store connection
// in the state change event handler, as a consequence of which we are in the 'Broken' state
if (this._storeConnection == null || this._storeConnection.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
InitializeMetadata(this._storeConnection, this._storeConnection, closeStoreConnectionOnFailure);
SetEntityClientConnectionStateToOpen();
}
///
/// Helper method that conditionally opens a specified store connection
///
/// The condition to evaluate
/// The store connection to open
/// The original store connection associated with the entity client
/// A flag that is set on if the connection is opened
/// successfully
private void OpenStoreConnectionIf(bool openCondition,
DbConnection storeConnectionToOpen,
DbConnection originalConnection,
string exceptionCode,
string attemptedOperation,
ref bool closeStoreConnectionOnFailure)
{
try
{
if (openCondition)
{
storeConnectionToOpen.Open();
closeStoreConnectionOnFailure = true;
}
ResetStoreConnection(storeConnectionToOpen, originalConnection, false);
// With every successful open of the store connection, always null out the current
// transaction (if there is one)
ClearCurrentTransaction();
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
string exceptionMessage = string.IsNullOrEmpty(attemptedOperation) ?
EntityRes.GetString(exceptionCode) :
EntityRes.GetString(exceptionCode, attemptedOperation);
throw EntityUtil.ProviderExceptionWithMessage(exceptionMessage, e);
}
throw;
}
}
///
/// Helper method to initialize the metadata workspace and reset the store connection
/// associated with the entity client
///
/// The new connection to associate with the entity client
/// The original connection associated with the entity client
/// A flag to indicate whether the original
/// store connection needs to be closed on failure
private void InitializeMetadata(DbConnection newConnection,
DbConnection originalConnection,
bool closeOriginalConnectionOnFailure)
{
try
{
// Ensure metadata is loaded and the workspace is appropriately initialized.
GetMetadataWorkspace();
}
catch (Exception ex)
{
// Undo the open if something failed
if (EntityUtil.IsCatchableExceptionType(ex))
{
ResetStoreConnection(newConnection, originalConnection, closeOriginalConnectionOnFailure);
}
throw;
}
}
///
/// Set the entity client connection state to Open, and raise an appropriate event
///
private void SetEntityClientConnectionStateToOpen()
{
this._entityClientConnectionState = ConnectionState.Open;
OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeOpen);
}
///
/// This method sets the store connection and hooks up the event
///
/// The DbConnection to set
/// The original DbConnection to be closed - this argument could be null
/// Indicates whether the original store connection should be closed
private void ResetStoreConnection(DbConnection newConnection, DbConnection originalConnection, bool closeOriginalConnection)
{
this._storeConnection = newConnection;
if (closeOriginalConnection && (originalConnection != null))
{
originalConnection.Close();
}
}
///
/// Create a new command object that uses this connection object
///
public new EntityCommand CreateCommand()
{
return new EntityCommand(null, this);
}
///
/// Create a new command object that uses this connection object
///
protected override DbCommand CreateDbCommand()
{
return this.CreateCommand();
}
internal EntityConnection Clone()
{
return new EntityConnection(_userConnectionOptions.UsersConnectionString(false));
}
///
/// Close the connection to the data store
///
public override void Close()
{
// It's a no-op if there isn't an underlying connection
if (this._storeConnection == null)
return;
this.CloseHelper();
}
///
/// Changes the current database for this connection
///
/// The name of the database to change to
public override void ChangeDatabase(string databaseName)
{
throw EntityUtil.NotSupported();
}
///
/// Begins a database transaction
///
/// An object representing the new transaction
public new EntityTransaction BeginTransaction()
{
return base.BeginTransaction() as EntityTransaction;
}
///
/// Begins a database transaction
///
/// The isolation level of the transaction
/// An object representing the new transaction
public new EntityTransaction BeginTransaction(IsolationLevel isolationLevel)
{
return base.BeginTransaction(isolationLevel) as EntityTransaction;
}
///
/// Begins a database transaction
///
/// The isolation level of the transaction
/// An object representing the new transaction
protected override DbTransaction BeginDbTransaction(IsolationLevel isolationLevel)
{
if (CurrentTransaction != null)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_TransactionAlreadyStarted);
}
if (this._storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
DbTransaction storeTransaction = null;
try
{
storeTransaction = this._storeConnection.BeginTransaction(isolationLevel);
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.ProviderExceptionWithMessage(
System.Data.Entity.Strings.EntityClient_ErrorInBeginningTransaction,
e
);
}
throw;
}
// The provider is problematic if it succeeded in beginning a transaction but returned a null
// for the transaction object
if (storeTransaction == null)
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("BeginTransaction", _storeConnection.GetType().Name));
}
_currentTransaction = new EntityTransaction(this, storeTransaction);
return _currentTransaction;
}
///
/// Enlist in the given transaction
///
/// The transaction object to enlist into
public override void EnlistTransaction(Transaction transaction)
{
if (_storeConnection == null)
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionStringNeededBeforeOperation);
if (this.State != ConnectionState.Open)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionNotOpen);
}
try
{
_storeConnection.EnlistTransaction(transaction);
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"EnlistTransaction", e);
}
throw;
}
}
///
/// Cleans up this connection object
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "_currentTransaction")]
protected override void Dispose(bool disposing)
{
ClearCurrentTransaction();
bool raiseStateChangeEvent = EntityCloseHelper(false, this.State);
if (disposing)
{
if (this._storeConnection != null)
{
StoreCloseHelper(); // closes store connection
if (this._storeConnection != null)
{
this._storeConnection.Dispose();
this._storeConnection = null;
}
}
}
// Change the connection string to just an empty string, ChangeConnectionString should always succeed here,
// it's unnecessary to pass in the connection string parameter name in the second argument, which we don't
// have anyway
this.ChangeConnectionString(String.Empty);
if (raiseStateChangeEvent) // we need to raise the event explicitly
{
OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed);
}
base.Dispose(disposing);
}
///
/// Reinitialize this connection object to use the new connection string
///
/// The new connection string
private void ChangeConnectionString(string newConnectionString)
{
DbConnectionOptions userConnectionOptions = s_emptyConnectionOptions;
if (!String.IsNullOrEmpty(newConnectionString))
{
userConnectionOptions = new DbConnectionOptions(newConnectionString, EntityConnectionStringBuilder.Synonyms, false);
}
DbProviderFactory factory = null;
DbConnection storeConnection = null;
DbConnectionOptions effectiveConnectionOptions = userConnectionOptions;
if (!userConnectionOptions.IsEmpty)
{
// Check if we have the named connection, if yes, then use the connection string from the configuration manager settings
string namedConnection = userConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
if (!string.IsNullOrEmpty(namedConnection))
{
// There cannot be other parameters when the named connection is specified
if (1 < userConnectionOptions.Parsetable.Count)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ExtraParametersWithNamedConnection);
}
// Find the named connection from the configuration, then extract the settings
ConnectionStringSettings setting = ConfigurationManager.ConnectionStrings[namedConnection];
if (setting == null || setting.ProviderName != EntityConnection.s_entityClientProviderName)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidNamedConnection);
}
effectiveConnectionOptions = new DbConnectionOptions(setting.ConnectionString, EntityConnectionStringBuilder.Synonyms, false);
// Check for a nested Name keyword
string nestedNamedConnection = effectiveConnectionOptions[EntityConnectionStringBuilder.NameParameterName];
if (!string.IsNullOrEmpty(nestedNamedConnection))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_NestedNamedConnection(namedConnection));
}
}
//Validate the connection string has the required Keywords( Provider and Metadata)
//We trim the values for both the Keywords, so a string value with only spaces will throw an exception
//reporting back to the user that the Keyword was missing.
ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.MetadataParameterName);
string providerName = ValidateValueForTheKeyword(effectiveConnectionOptions, EntityConnectionStringBuilder.ProviderParameterName);
// Get the correct provider factory
factory = GetFactory(providerName);
// Create the underlying provider specific connection and give it the connection string from the DbConnectionOptions object
storeConnection = GetStoreConnection(factory);
try
{
// When the value of 'Provider Connection String' is null, it means it has not been present in the entity connection string at all.
// Providers should still be able handle empty connection strings since those may be explicitly passed by clients.
string providerConnectionString = effectiveConnectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
if (providerConnectionString != null)
{
storeConnection.ConnectionString = providerConnectionString;
}
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.Provider(@"ConnectionString", e);
}
throw;
}
}
// This lock is to ensure that the connection string matches with the provider connection and metadata workspace that's being
// managed by this EntityConnection, so states in this connection object are not messed up.
// It's not for security, but just to help reduce user error.
lock (_connectionStringLock)
{
// Now we have sufficient information and verified the configuration string is good, use them for this connection object
// Failure should not occur from this point to the end of this method
this._providerFactory = factory;
this._metadataWorkspace = null;
ClearCurrentTransaction();
ResetStoreConnection(storeConnection, null, false);
// Remembers the connection options objects with the connection string set by the user
this._userConnectionOptions = userConnectionOptions;
this._effectiveConnectionOptions = effectiveConnectionOptions;
}
}
private static string ValidateValueForTheKeyword(DbConnectionOptions effectiveConnectionOptions,
string keywordName)
{
string keywordValue = effectiveConnectionOptions[keywordName];
if (!string.IsNullOrEmpty(keywordValue))
keywordValue = keywordValue.Trim(); // be nice to user, always trim the value
// Check that we have a non-null and non-empty value for the keyword
if (string.IsNullOrEmpty(keywordValue))
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_ConnectionStringMissingInfo(keywordName));
}
return keywordValue;
}
private static EdmItemCollection LoadEdmItemCollection(MetadataWorkspace workspace, MetadataArtifactLoader artifactLoader)
{
// Build a string as the key and look up the MetadataCache for a match
string edmCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(DataSpace.CSpace), null, null);
// Check the MetadataCache for an entry with this key
object entryToken;
EdmItemCollection edmItemCollection = MetadataCache.GetOrCreateEdmItemCollection(edmCacheKey,
artifactLoader,
out entryToken);
workspace.RegisterItemCollection(edmItemCollection);
// Adding the edm metadata entry token to the workspace, to make sure that this token remains alive till workspace is alive
workspace.AddMetadataEntryToken(entryToken);
return edmItemCollection;
}
private static void LoadStoreItemCollections(MetadataWorkspace workspace,
DbConnection storeConnection,
DbProviderFactory factory,
DbConnectionOptions connectionOptions,
EdmItemCollection edmItemCollection,
MetadataArtifactLoader artifactLoader)
{
Debug.Assert(workspace.IsItemCollectionAlreadyRegistered(DataSpace.CSpace), "C-Space must be loaded before loading S or C-S space");
// The provider connection string is optional; if it has not been specified,
// we pick up the store's connection string.
//
string providerConnectionString = connectionOptions[EntityConnectionStringBuilder.ProviderConnectionStringParameterName];
if (string.IsNullOrEmpty(providerConnectionString) && (storeConnection != null))
{
providerConnectionString = storeConnection.ConnectionString;
}
// Build a string as the key and look up the MetadataCache for a match
string storeCacheKey = CreateMetadataCacheKey(artifactLoader.GetOriginalPaths(),
connectionOptions[EntityConnectionStringBuilder.ProviderParameterName],
providerConnectionString);
// Load store metadata.
object entryToken;
StorageMappingItemCollection mappingCollection =
MetadataCache.GetOrCreateStoreAndMappingItemCollections(storeCacheKey,
artifactLoader,
edmItemCollection,
out entryToken);
ValidateThatConnectionAndMetadataProvidersAreEqual(factory, connectionOptions[EntityConnectionStringBuilder.ProviderParameterName], mappingCollection.StoreItemCollection.StoreProviderFactory);
workspace.RegisterItemCollection(mappingCollection.StoreItemCollection);
workspace.RegisterItemCollection(mappingCollection);
// Adding the store metadata entry token to the workspace
workspace.AddMetadataEntryToken(entryToken);
}
private static void ValidateThatConnectionAndMetadataProvidersAreEqual(DbProviderFactory connectionFactory, string connectionProviderName, DbProviderFactory metadataFactory)
{
if (metadataFactory.GetType() != connectionFactory.GetType())
{
string metadataProviderName = GetErrorMessageWorthyProviderName(metadataFactory);
if (string.IsNullOrEmpty(connectionProviderName))
{
connectionProviderName = GetErrorMessageWorthyProviderName(connectionFactory);
}
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_ConnectionAndMetadataProviderMismatch(metadataProviderName, connectionProviderName));
}
}
private static string GetErrorMessageWorthyProviderName(DbProviderFactory factory)
{
EntityUtil.CheckArgumentNull(factory, "factory");
string providerName;
if (!EntityUtil.TryGetProviderInvariantName(factory, out providerName))
{
providerName = factory.GetType().FullName;
}
return providerName;
}
///
/// Create a key to be used with the MetadataCache from a connection options object
///
/// A list of metadata file paths
/// The provider name
/// The provider connection string
/// The key
private static string CreateMetadataCacheKey(IList paths, string providerName, string providerConnectionString)
{
int resultCount = 0;
string result;
// Do a first pass to calculate the output size of the metadata cache key,
// then another pass to populate a StringBuilder with the exact size and
// get the result.
CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString,
false, ref resultCount, out result);
CreateMetadataCacheKeyWithCount(paths, providerName, providerConnectionString,
true, ref resultCount, out result);
return result;
}
///
/// Create a key to be used with the MetadataCache from a connection options
/// object.
///
/// A list of metadata file paths
/// The provider name
/// The provider connection string
/// Whether the result variable should be built.
///
/// On entry, the expected size of the result (unused if buildResult is false).
/// After execution, the effective result.
/// The key.
///
/// This method should be called once with buildResult=false, to get
/// the size of the resulting key, and once with buildResult=true
/// and the size specification.
///
private static void CreateMetadataCacheKeyWithCount(IList paths,
string providerName, string providerConnectionString,
bool buildResult, ref int resultCount, out string result)
{
// Build a string as the key and look up the MetadataCache for a match
StringBuilder keyString;
if (buildResult)
{
keyString = new StringBuilder(resultCount);
}
else
{
keyString = null;
}
// At this point, we've already used resultCount. Reset it
// to zero to make the final debug assertion that our computation
// is correct.
resultCount = 0;
if (!string.IsNullOrEmpty(providerName))
{
resultCount += providerName.Length + 1;
if (buildResult)
{
keyString.Append(providerName);
keyString.Append(EntityConnection.s_semicolonSeparator);
}
}
if (paths != null)
{
for (int i = 0; i < paths.Count; i++)
{
if (paths[i].Length > 0)
{
if (i > 0)
{
resultCount++;
if (buildResult)
{
keyString.Append(EntityConnection.s_metadataPathSeparator);
}
}
resultCount += paths[i].Length;
if (buildResult)
{
keyString.Append(paths[i]);
}
}
}
resultCount++;
if (buildResult)
{
keyString.Append(EntityConnection.s_semicolonSeparator);
}
}
if (!string.IsNullOrEmpty(providerConnectionString))
{
resultCount += providerConnectionString.Length;
if (buildResult)
{
keyString.Append(providerConnectionString);
}
}
if (buildResult)
{
result = keyString.ToString();
}
else
{
result = null;
}
System.Diagnostics.Debug.Assert(
!buildResult || (result.Length == resultCount));
}
///
/// A helper function for splitting up a string that is a concatenation of strings delimited by the metadata
/// path separator into a string list. The resulting list is NOT sorted.
///
/// The paths to split
/// An array of strings
private static MetadataArtifactLoader SplitPaths(string paths)
{
string[] results;
// This is the registry of all URIs in the global collection.
HashSet uriRegistry = new HashSet(StringComparer.OrdinalIgnoreCase);
List loaders = new List();
if (!string.IsNullOrEmpty(paths))
{
// If the argument contains one or more occurrences of the macro '|DataDirectory|', we
// pull those paths out so that we don't lose them in the string-splitting logic below.
// Note that the macro '|DataDirectory|' cannot have any whitespace between the pipe
// symbols and the macro name. Also note that the macro must appear at the beginning of
// a path (else we will eventually fail with an invalid path exception, because in that
// case the macro is not expanded). If a real/physical folder named 'DataDirectory' needs
// to be included in the metadata path, whitespace should be used on either or both sides
// of the name.
//
List dataDirPaths = new List();
int indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase);
while (indexStart != -1)
{
int prevSeparatorIndex = indexStart == 0 ? -1 : paths.LastIndexOf(
EntityConnection.s_metadataPathSeparator,
indexStart - 1, // start looking here
StringComparison.Ordinal
);
int macroPathBeginIndex = prevSeparatorIndex + 1;
// The '|DataDirectory|' macro is composable, so identify the complete path, like
// '|DataDirectory|\foo\bar'. If the macro appears anywhere other than at the
// beginning, splice out the entire path, e.g. 'C:\foo\|DataDirectory|\bar'. In this
// latter case the macro will not be expanded, and downstream code will throw an exception.
//
int indexEnd = paths.IndexOf(EntityConnection.s_metadataPathSeparator,
indexStart + EntityConnection.s_dataDirectory.Length,
StringComparison.Ordinal);
if (indexEnd == -1)
{
dataDirPaths.Add(paths.Substring(macroPathBeginIndex));
paths = paths.Remove(macroPathBeginIndex); // update the concatenated list of paths
break;
}
dataDirPaths.Add(paths.Substring(macroPathBeginIndex, indexEnd - macroPathBeginIndex));
// Update the concatenated list of paths by removing the one containing the macro.
//
paths = paths.Remove(macroPathBeginIndex, indexEnd - macroPathBeginIndex);
indexStart = paths.IndexOf(EntityConnection.s_dataDirectory, StringComparison.OrdinalIgnoreCase);
}
// Split the string on the separator and remove all spaces around each parameter value
results = paths.Split(new string[] { EntityConnection.s_metadataPathSeparator }, StringSplitOptions.RemoveEmptyEntries);
// Now that the non-macro paths have been identified, merge the paths containing the macro
// into the complete list.
//
if (dataDirPaths.Count > 0)
{
dataDirPaths.AddRange(results);
results = dataDirPaths.ToArray();
}
for (int i = 0; i < results.Length; i++)
{
// Trim out all the spaces for this parameter and add it only if it's not blank
results[i] = results[i].Trim();
if (results[i].Length > 0)
{
loaders.Add(MetadataArtifactLoader.Create(
results[i],
MetadataArtifactLoader.ExtensionCheck.All, // validate the extension against all acceptable values
null,
uriRegistry
));
}
}
}
return MetadataArtifactLoader.Create(loaders);
}
///
/// Clears the current transaction for this connection
///
internal void ClearCurrentTransaction()
{
_currentTransaction = null;
}
///
/// Helper method invoked as part of Close()/Dispose() that releases the underlying
/// store connection and raises the appropriate event.
///
private void CloseHelper()
{
ConnectionState previousState = this.State; // the public connection state before cleanup
StoreCloseHelper();
EntityCloseHelper(
true, // raise the state change event
previousState
);
}
///
/// Store-specific helper method invoked as part of Close()/Dispose().
///
private void StoreCloseHelper()
{
try
{
if (this._storeConnection != null && (this._storeConnection.State != ConnectionState.Closed))
{
this._storeConnection.Close();
}
// Need to disassociate the transaction object with this connection
ClearCurrentTransaction();
}
catch (Exception e)
{
if (EntityUtil.IsCatchableExceptionType(e))
{
throw EntityUtil.ProviderExceptionWithMessage(
System.Data.Entity.Strings.EntityClient_ErrorInClosingConnection,
e
);
}
throw;
}
}
///
/// Entity-specific helper method invoked as part of Close()/Dispose().
///
/// Indicates whether we need to raise the state change event here
/// The public state of the connection before cleanup began
/// true if the caller needs to raise the state change event
private bool EntityCloseHelper(bool fireEventOnStateChange, ConnectionState previousState)
{
bool result = false;
this._entityClientConnectionState = ConnectionState.Closed;
if (previousState == ConnectionState.Open)
{
if (fireEventOnStateChange)
{
OnStateChange(System.Data.ProviderBase.DbConnectionInternal.StateChangeClosed);
}
else
{
result = true; // we didn't raise the event here; the caller should do that
}
}
return result;
}
///
/// Call to determine if changes to the entity object are currently permitted.
///
private void ValidateChangesPermitted()
{
if (_initialized)
{
throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.EntityClient_SettingsCannotBeChangedOnOpenConnection);
}
}
///
/// Returns the DbProviderFactory associated with specified provider string
///
private DbProviderFactory GetFactory(string providerString)
{
try
{
return DbProviderFactories.GetFactory(providerString);
}
catch (ArgumentException e)
{
throw EntityUtil.Argument(System.Data.Entity.Strings.EntityClient_InvalidStoreProvider, e);
}
}
///
/// Uses DbProviderFactory to create a DbConnection
///
private DbConnection GetStoreConnection(DbProviderFactory factory)
{
DbConnection storeConnection = factory.CreateConnection();
if (storeConnection == null)
{
throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.EntityClient_ReturnedNullOnProviderMethod("CreateConnection", factory.GetType().Name));
}
return storeConnection;
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- BinaryUtilClasses.cs
- SecurityDocument.cs
- Int16Animation.cs
- TreeViewCancelEvent.cs
- FloatMinMaxAggregationOperator.cs
- TripleDESCryptoServiceProvider.cs
- DesignerMetadata.cs
- PageThemeBuildProvider.cs
- RegexParser.cs
- WorkerRequest.cs
- EventEntry.cs
- GridViewColumn.cs
- HostedTransportConfigurationManager.cs
- ExportException.cs
- __TransparentProxy.cs
- _FixedSizeReader.cs
- ManagedWndProcTracker.cs
- httpstaticobjectscollection.cs
- GatewayDefinition.cs
- XmlSignatureProperties.cs
- MailWebEventProvider.cs
- FlowNode.cs
- DataRowCollection.cs
- XmlChildEnumerator.cs
- DataGridViewImageColumn.cs
- WorkflowMessageEventHandler.cs
- XmlElementCollection.cs
- InputLanguageCollection.cs
- CodeDelegateInvokeExpression.cs
- WindowsTab.cs
- XmlCharType.cs
- StrongNamePublicKeyBlob.cs
- OracleCommandBuilder.cs
- ComplusEndpointConfigContainer.cs
- RenderCapability.cs
- Visual.cs
- ExclusiveCanonicalizationTransform.cs
- WindowsContainer.cs
- SolidBrush.cs
- SQLMoneyStorage.cs
- ResourceDictionary.cs
- PeekCompletedEventArgs.cs
- DateRangeEvent.cs
- ExpressionConverter.cs
- ColumnClickEvent.cs
- RequestTimeoutManager.cs
- AccessText.cs
- StringOutput.cs
- PathFigure.cs
- messageonlyhwndwrapper.cs
- ValidationRuleCollection.cs
- storepermissionattribute.cs
- DataGridViewCellStateChangedEventArgs.cs
- MultiAsyncResult.cs
- GrammarBuilderDictation.cs
- WindowsContainer.cs
- MembershipSection.cs
- PenCursorManager.cs
- ImageAutomationPeer.cs
- ConfigurationProviderException.cs
- Expander.cs
- CroppedBitmap.cs
- ReadOnlyAttribute.cs
- SQLDoubleStorage.cs
- CommunicationException.cs
- CompilerGlobalScopeAttribute.cs
- HitTestWithGeometryDrawingContextWalker.cs
- DataSourceIDConverter.cs
- GestureRecognitionResult.cs
- CodeNamespaceImportCollection.cs
- TextRangeSerialization.cs
- PersonalizableTypeEntry.cs
- IfElseDesigner.xaml.cs
- X509CertificateEndpointIdentity.cs
- XmlDataSourceNodeDescriptor.cs
- Library.cs
- Marshal.cs
- RSAPKCS1KeyExchangeFormatter.cs
- InputProcessorProfilesLoader.cs
- TableLayoutSettingsTypeConverter.cs
- TextTreeFixupNode.cs
- JsonQNameDataContract.cs
- _LocalDataStoreMgr.cs
- TimerEventSubscriptionCollection.cs
- SectionUpdates.cs
- DBDataPermission.cs
- XamlValidatingReader.cs
- CornerRadius.cs
- ToolStripDropDownClosingEventArgs.cs
- CreateUserWizardStep.cs
- TextClipboardData.cs
- DataGridViewRowContextMenuStripNeededEventArgs.cs
- ReachSerializableProperties.cs
- FloaterParaClient.cs
- RijndaelCryptoServiceProvider.cs
- CompoundFileStreamReference.cs
- Error.cs
- SerializationEventsCache.cs
- HttpModuleAction.cs
- DoWorkEventArgs.cs