EntityDataSourceDesignerHelper.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataWebControlsDesign / System / Data / WebControls / Design / EntityDataSourceDesignerHelper.cs / 1 / EntityDataSourceDesignerHelper.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//----------------------------------------------------------------------------- 

using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.Configuration;
using System.ComponentModel.Design;
using System.Data; 
using System.Data.Common;
using System.Data.EntityClient; 
using System.Data.Mapping; 
using System.Data.Metadata.Edm;
using System.Web.UI.Design.WebControls.Util; 
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq; 
using System.Reflection;
using System.Text; 
using System.Web.Configuration; 
using System.Web.UI;
using System.Web.UI.Design; 
using System.Web.UI.WebControls;
using System.Windows.Forms;
using System.Xml;
 
namespace System.Web.UI.Design.WebControls
{ 
    internal class EntityDataSourceDesignerHelper 
    {
        #region Private and Internal static constants 
        private static readonly string s_virtualRoot = "~/";
        private static readonly string s_ecmPublicKeyToken = "PublicKeyToken=" + AssemblyRef.EcmaPublicKey;
        private static readonly string s_entityClientProviderName = "System.Data.EntityClient";
        private static readonly string s_metadataPathSeparator = "|"; 
        private static readonly string s_resPathPrefix = "res://";
        private static readonly string s_relativeParentFolder = "../"; 
        private static readonly string s_relativeCurrentFolder = "./"; 
        private static readonly string s_altRelativeParentFolder = @"..\";
        private static readonly string s_altRelativeCurrentFolder = @".\"; 
        private static readonly string s_dataDirectoryNoPipes = "DataDirectory";
        private static readonly string s_dataDirectory = "|DataDirectory|";
        private static readonly string s_dataDirectoryPath = String.Concat(s_virtualRoot, "app_data");
        private static readonly string s_resolvedResPathFormat = String.Concat(s_resPathPrefix, "{0}/{1}"); 
        private static readonly string DesignerStateDataSourceSchemaKey = "EntityDataSourceSchema";
        private static readonly string DesignerStateDataSourceConnectionStringKey = "EntityDataSourceConnectionString"; 
        private static readonly string DesignerStateDataSourceDefaultContainerNameKey = "EntityDataSourceDefaultContainerName"; 
        private static readonly string DesignerStateDataSourceEntitySetNameKey = "EntityDataSourceEntitySetNameKey";
        private static readonly string DesignerStateDataSourceSelectKey = "EntityDataSourceSelectKey"; 
        private static readonly string DesignerStateDataSourceCommandTextKey = "EntityDataSourceCommandTextKey";

        internal static readonly string DefaultViewName = "DefaultView";
        #endregion 

        #region Private instance fields 
        private readonly EntityDataSource _entityDataSource; 
        private EntityConnection _entityConnection;
        private readonly IWebApplication _webApplication; 
        // determines if any errors or warnings are displayed and if the EntityConnection and metadata are automatically loaded when accessed
        private bool _interactiveMode;
        private HashSet _assemblies;
        private EntityDesignerDataSourceView _view; 
        private bool _forceSchemaRetrieval;
        private readonly EntityDataSourceDesigner _owner; 
        private bool _canLoadWebConfig; 
        #endregion
 
        internal EntityDataSourceDesignerHelper(EntityDataSource entityDataSource, bool interactiveMode)
        {
            Debug.Assert(entityDataSource != null, "null entityDataSource");
 
            _entityDataSource = entityDataSource;
            _interactiveMode = interactiveMode; 
 
            _canLoadWebConfig = true;
 
            IServiceProvider serviceProvider = _entityDataSource.Site;
            if (serviceProvider != null)
            {
                // Get the designer instance associated with the specified data source control 
                IDesignerHost designerHost = (IDesignerHost)serviceProvider.GetService(typeof(IDesignerHost));
                if (designerHost != null) 
                { 
                    _owner = designerHost.GetDesigner(this.EntityDataSource) as EntityDataSourceDesigner;
                } 

                // Get other services used to determine design-time information
                _webApplication = serviceProvider.GetService(typeof(IWebApplication)) as IWebApplication;
 
            }
            Debug.Assert(_owner != null, "expected non-null owner"); 
            Debug.Assert(_webApplication != null, "expected non-null web application service"); 
        }
 
        internal void AddSystemWebEntityReference()
        {
            IServiceProvider serviceProvider = _entityDataSource.Site;
            if (serviceProvider != null) 
            {
                ITypeResolutionService typeResProvider = (ITypeResolutionService)serviceProvider.GetService(typeof(ITypeResolutionService)); 
                if (typeResProvider != null) 
                {
                    try 
                    {
                        // Adding the reference using just the name and public key since we don't want to be
                        // tied to a particular version here.
                        typeResProvider.ReferenceAssembly( 
                            new AssemblyName("System.Web.Entity,PublicKeyToken=" + AssemblyRef.EcmaPublicKey));
                    } 
                    catch (FileNotFoundException) 
                    {
                        Debug.Fail("Failed to find System.Web.Entity assembly."); 
                        // Intentionally ignored exception - the assembly should always be
                        // found, but if it isn't, then we don't want to stop the rest of the
                        // control from working, especially since the assembly may not always
                        // be required. 
                    }
                } 
            } 
        }
 
        #region Helpers for EntityDataSource properties
        internal bool AutoGenerateWhereClause
        {
            get 
            {
                return _entityDataSource.AutoGenerateWhereClause; 
            } 
        }
 
        internal bool AutoGenerateOrderByClause
        {
            get
            { 
                return _entityDataSource.AutoGenerateOrderByClause;
            } 
        } 

        internal bool CanPage 
        {
            get
            {
                DataSourceView view = ((IDataSource)_entityDataSource).GetView(DefaultViewName); 
                if (view != null)
                { 
                    return view.CanPage; 
                }
 
                return false;
            }
        }
 
        internal bool CanSort
        { 
            get 
            {
                DataSourceView view = ((IDataSource)_entityDataSource).GetView(DefaultViewName); 
                if (view != null)
                {
                    return view.CanSort;
                } 

                return false; 
            } 
        }
 
        internal string ConnectionString
        {
            get
            { 
                return _entityDataSource.ConnectionString;
            } 
            set 
            {
                if (value != ConnectionString) 
                {
                    _entityDataSource.ConnectionString = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                } 
            }
        } 
 
        internal string CommandText
        { 
            get
            {
                return _entityDataSource.CommandText;
            } 
            set
            { 
                if (value != CommandText) 
                {
                    _entityDataSource.CommandText = value; 
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                }
            }
        } 

        internal ParameterCollection CommandParameters 
        { 
            get
            { 
                return _entityDataSource.CommandParameters;
            }
        }
 
        internal string DefaultContainerName
        { 
            get 
            {
                return _entityDataSource.DefaultContainerName; 
            }
            set
            {
                if (value != DefaultContainerName) 
                {
                    _entityDataSource.DefaultContainerName = value; 
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                }
            } 
        }

        internal bool EnableDelete
        { 
            get
            { 
                return _entityDataSource.EnableDelete; 
            }
        } 

        internal bool EnableInsert
        {
            get 
            {
                return _entityDataSource.EnableInsert; 
            } 
        }
 
        internal bool EnableUpdate
        {
            get
            { 
                return _entityDataSource.EnableUpdate;
            } 
        } 

        internal string EntitySetName 
        {
            get
            {
                return _entityDataSource.EntitySetName; 
            }
            set 
            { 
                if (value != EntitySetName)
                { 
                    _entityDataSource.EntitySetName = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                }
            } 
        }
 
        internal string EntityTypeFilter 
        {
            get 
            {
                return _entityDataSource.EntityTypeFilter;
            }
            set 
            {
                if (value != EntityTypeFilter) 
                { 
                    _entityDataSource.EntityTypeFilter = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                }
            }
        }
 
        internal string GroupBy
        { 
            get 
            {
                return _entityDataSource.GroupBy; 
            }
        }

        internal string OrderBy 
        {
            get 
            { 
                return _entityDataSource.OrderBy;
            } 
            set
            {
                if (value != OrderBy)
                { 
                    _entityDataSource.OrderBy = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                } 
            }
        } 

        internal ParameterCollection OrderByParameters
        {
            get 
            {
                return _entityDataSource.OrderByParameters; 
            } 
        }
 
        internal string Select
        {
            get
            { 
                return _entityDataSource.Select;
            } 
            set 
            {
                if (value != Select) 
                {
                    _entityDataSource.Select = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                } 
            }
        } 
 
        internal ParameterCollection SelectParameters
        { 
            get
            {
                return _entityDataSource.SelectParameters;
            } 
        }
 
        internal string Where 
        {
            get 
            {
                return _entityDataSource.Where;
            }
            set 
            {
                if (value != Where) 
                { 
                    _entityDataSource.Where = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                }
            }
        }
 
        internal ParameterCollection WhereParameters
        { 
            get 
            {
                return _entityDataSource.WhereParameters; 
            }
        }
        #endregion
 
        private EntityDataSource EntityDataSource
        { 
            get 
            {
                return _entityDataSource; 
            }
        }

        private EdmItemCollection EdmItemCollection 
        {
            get 
            { 
                // In interactive mode, we will explicitly load metadata when needed, so never load it here
                // When not in interactive mode, we only need to load metadata once, which is determined by the presence of an EntityConnection 
                if (!_interactiveMode && _entityConnection == null)
                {
                    LoadMetadata();
                } 

                // _entityConnection may still be null if the load failed or if we are in interactive mode and the metadata has not been explicitly loaded 
                if (_entityConnection != null) 
                {
                    ItemCollection itemCollection = null; 

                    try
                    {
                        _entityConnection.GetMetadataWorkspace().TryGetItemCollection(DataSpace.CSpace, out itemCollection); 
                    }
                    catch (Exception) 
                    { 
                        // Never expecting a failure because we have already initialized the workspace when the metadata was loaded,
                        // and any errors would have been trapped then. Just ignore any errors that might occur here to prevent a crash. 
                    }

                    return itemCollection as EdmItemCollection; // not guaranteed not to be null, caller must check anyway before using
                } 

                return null; 
            } 
        }
 
        // The default DesignerDataSourceView
        private EntityDesignerDataSourceView View
        {
            get 
            {
                return _view; 
            } 
            set
            { 
                _view = value;
            }
        }
 
        /// 
        /// The status of loading the web.config file for named connections. 
        /// This helps to determine if we've already tried to load the web.config file and if it failed 
        /// we do not continue to load it again.
        ///  
        internal bool CanLoadWebConfig
        {
            get
            { 
                return _canLoadWebConfig;
            } 
            set 
            {
                _canLoadWebConfig = value; 
            }
        }

        // Whether or not a schema retrieval is being forced (used in RefreshSchema) 
        private bool ForceSchemaRetrieval
        { 
            get 
            {
                return _forceSchemaRetrieval; 
            }
            set
            {
                _forceSchemaRetrieval = value; 
            }
        } 
 
        // Loads metadata for the current connection string on the data source control
        private bool LoadMetadata() 
        {
            EntityConnectionStringBuilder connStrBuilder = VerifyConnectionString(this.EntityDataSource.ConnectionString, true /*allowNamedConnections*/);
            if (connStrBuilder != null)
            { 
                return LoadMetadata(connStrBuilder);
            } 
            // else the connection string could not be verified, and any errors are already displayed during the failed verification, so nothing more to do 

            return false; 
        }

        internal bool LoadMetadata(EntityConnectionStringBuilder connStrBuilder)
        { 
            Debug.Assert(connStrBuilder != null, "expected non-null connStrBuilder");
 
            // if these services are not available for some reason, we will not be able to do anything useful, so don't try to load metadata 
            if (_webApplication != null)
            { 
                // _assemblies could already be loaded if this call is coming from the wizard, because metadata could be loaded
                // multiple times if the connection string is changed, so don't load it again if we already have it. It can't have
                // changed since the last load, because the wizard dialog is modal and there is no way to have changed the project between loads.
                if (_assemblies == null) 
                {
                    LoadAssemblies(); 
                } 

                return LoadMetadataFromBuilder(connStrBuilder); 
            }

            return false;
        } 

        // Loads C-Space metadata from the specified connection string builder. 
        // Expects that the specified builder has already been verified and has minimum required properties 
        private bool LoadMetadataFromBuilder(EntityConnectionStringBuilder connStrBuilder)
        { 
            Debug.Assert(connStrBuilder != null, "expected non-null connStrBuilder");

            // We will be replacing the metadata with a new collection, and if something fails to load we want to make sure to clear out any existing data
            ClearMetadata(); 

            if (String.IsNullOrEmpty(connStrBuilder.ConnectionString)) 
            { 
                // Although we can't load metadata here, this is not an error because the user should not expect an empty connection string
                // to produce any metadata, so it will not be confusing when no values are available in the dropdowns. This is different from 
                // an invalid connection string because in that case they have entered a value and are expecting to get metadata from it.
                return false;
            }
 
            // If this is a named connection, load the contents of the named connection from the web.config and verify itet
            if (!String.IsNullOrEmpty(connStrBuilder.Name)) 
            { 
                connStrBuilder = GetBuilderForNamedConnection(connStrBuilder);
                if (connStrBuilder == null) 
                {
                    // some verification failed when getting the connection string builder,
                    // so we have nothing to load metadata from, just return
                    return false; 
                }
            } 
 
            string originalMetadata = connStrBuilder.Metadata;
            Debug.Assert(!String.IsNullOrEmpty(originalMetadata), "originalMetadata should have aleady been verified to be non-null or empty"); 

            List metadataWarnings = new List(); // keeps track of all warnings that happen during the parsing of the connection string
            List metadataPaths = new List();    // collection of resolved paths
 
            // We need to use the | separator to split the metadata value into individual paths, so first remove and process any paths
            // containing the macro |DataDirectory|. These will get combined again with the rest of the paths once they have been processed. 
            List dataDirectoryPaths = new List(); 
            string metadataWithoutDataDirectory = ResolveDataDirectory(originalMetadata, dataDirectoryPaths, metadataWarnings);
 
            foreach (string path in metadataWithoutDataDirectory.Split(new string[] { s_metadataPathSeparator }, StringSplitOptions.RemoveEmptyEntries))
            {
                string trimmedPath = path.Trim();
                if (!String.IsNullOrEmpty(trimmedPath)) 
                {
                    if (trimmedPath.StartsWith(s_virtualRoot, StringComparison.OrdinalIgnoreCase)) 
                    { 
                        // ~/
                        ResolveVirtualRootPath(trimmedPath, metadataPaths, metadataWarnings); 
                    }
                    else if (trimmedPath.StartsWith(s_relativeCurrentFolder, StringComparison.OrdinalIgnoreCase) ||
                        trimmedPath.StartsWith(s_altRelativeCurrentFolder, StringComparison.OrdinalIgnoreCase) ||
                        trimmedPath.StartsWith(s_relativeParentFolder, StringComparison.OrdinalIgnoreCase) || 
                        trimmedPath.StartsWith(s_altRelativeParentFolder, StringComparison.OrdinalIgnoreCase))
                    { 
                        // ../, ..\, ./, or ..\ 
                        ResolveRelativePath(trimmedPath, metadataPaths, metadataWarnings);
                    } 
                    else
                    {
                        // We are not trying to resolve any other types of paths, so just pass it along directly.
                        // If the format of the path is unrecognized, or if the path is not valid, metadata will throw an exception that will 
                        // be displayed to the user at that time.
                        metadataPaths.Add(trimmedPath); 
                    } 
                }
            } 

            // Add the paths with |DataDirectory| back to the list
            if (dataDirectoryPaths.Count > 0)
            { 
                metadataPaths.AddRange(dataDirectoryPaths);
            } 
 
            if (metadataWarnings.Count > 0)
            { 
                ShowWarning(BuildWarningMessage(Strings.Warning_ConnectionStringMessageHeader, metadataWarnings));
            }

            return SetEntityConnection(metadataPaths, connStrBuilder); 
        }
 
        private bool SetEntityConnection(List metadataPaths, EntityConnectionStringBuilder connStrBuilder) 
        {
            // It's possible the metadata was specified in the original connection string, but we filtered out everything due to not being able to resolve it to anything. 
            // In that case, warnings have already been displayed to indicate which paths were removed, so no need to display another message.
            if (metadataPaths.Count > 0)
            {
                try 
                {
                    // Get the connection first, because it might be needed to gather provider services information 
                    DbConnection dbConnection = GetDbConnection(connStrBuilder); 

                    MetadataWorkspace metadataWorkspace = new MetadataWorkspace(metadataPaths, _assemblies); 

                    // Ensure that we have all of the item collections registered. If some of them are missing this will cause problems eventually if we need to
                    // execute a query to get detailed schema information, but that will be handled later. For now just register everything to prevent errors in the
                    // stack that would not be understood by the user in the designer at this point. 
                    ItemCollection edmItemCollection;
                    ItemCollection storeItemCollection; 
                    ItemCollection csItemCollection; 
                    if (!metadataWorkspace.TryGetItemCollection(DataSpace.CSpace, out edmItemCollection))
                    { 
                        edmItemCollection = new EdmItemCollection();
                        metadataWorkspace.RegisterItemCollection(edmItemCollection);
                    }
 
                    if (!metadataWorkspace.TryGetItemCollection(DataSpace.SSpace, out storeItemCollection))
                    { 
                        return false; 
                    }
 
                    if (!metadataWorkspace.TryGetItemCollection(DataSpace.CSSpace, out csItemCollection))
                    {
                        Debug.Assert(edmItemCollection != null && storeItemCollection != null, "edm and store ItemCollection should be populated already");
                        metadataWorkspace.RegisterItemCollection(new StorageMappingItemCollection(edmItemCollection as EdmItemCollection, storeItemCollection as StoreItemCollection)); 
                    }
 
                    // Load OSpace metadata from all of the assemblies we know about 
                    ObjectItemCollection objectItemCollection = new ObjectItemCollection();
                    foreach (Assembly assembly in _assemblies) 
                    {
                        objectItemCollection.LoadFromAssembly(assembly);
                    }
                    metadataWorkspace.RegisterItemCollection(objectItemCollection); 

 
                    if (dbConnection != null) 
                    {
                        _entityConnection = new EntityConnection(metadataWorkspace, dbConnection); 
                        return true;
                    }
                    // else the DbConnection could not be created and the error should have already been displayed
                } 
                catch (Exception ex)
                { 
                    StringBuilder exceptionMessage = new StringBuilder(); 
                    exceptionMessage.AppendLine(Strings.Error_MetadataLoadError);
                    exceptionMessage.AppendLine(); 
                    exceptionMessage.Append(ex.Message);
                    ShowError(exceptionMessage.ToString());
                }
            } 

            return false; 
        } 

        // Clears out the existing metadata 
        internal void ClearMetadata()
        {
            _entityConnection = null;
        } 

        ///  
        /// Finds and caches all non system assemblies that are found using the TypeDiscoveryService 
        /// This searches places like the ~/bin folder, app_code, and the 'assemblies' section of web.config, among others
        ///  
        private void LoadAssemblies()
        {
            _assemblies = new HashSet();
 
            // Find the assemblies using the ITypeDiscoveryService
            ITypeDiscoveryService typeDiscoverySvc = this.EntityDataSource.Site.GetService(typeof(ITypeDiscoveryService)) as ITypeDiscoveryService; 
            if (typeDiscoverySvc != null) 
            {
                foreach (Type type in typeDiscoverySvc.GetTypes(typeof(object), false /*excludeGlobalTypes*/)) 
                {
                    if (!_assemblies.Contains(type.Assembly) && !IsSystemAssembly(type.Assembly.FullName))
                    {
                        _assemblies.Add(type.Assembly); 
                    }
                } 
            } 
        }
 
        // Explicitly rebuild the known assembly cache. This is done when launching the wizard and allows the wizard to pick up the latest
        // assemblies in the project, without having to reload them everytime the connection string changes while the wizard is running
        internal void ReloadResources()
        { 
            Debug.Assert(_interactiveMode == true, "resource cache should only explicitly be loaded in interactive mode");
            LoadAssemblies(); 
        } 

        // Is the assembly and its referenced assemblies not expected to have any metadata 
        // This does not detect all possible system assemblies, but just those we can detect as system for sure
        private static bool IsSystemAssembly(string fullName)
        {
            return (String.Equals(fullName, "*", StringComparison.OrdinalIgnoreCase) || 
                fullName.EndsWith(s_ecmPublicKeyToken, StringComparison.OrdinalIgnoreCase));
        } 
 
        // Combines all warnings into one message
        private string BuildWarningMessage(string headerMessage, List warnings) 
        {
            Debug.Assert(warnings != null && warnings.Count > 0, "expected non-null and non-empty warnings");

            StringBuilder warningMessage = new StringBuilder(); 
            warningMessage.AppendLine(headerMessage);
            warningMessage.AppendLine(); 
            foreach (string warning in warnings) 
            {
                warningMessage.AppendLine(warning); 
            }

            return warningMessage.ToString();
        } 

        // Get a connection string builder for the specified connection string, and do some basic verification 
        // namedConnStrBuilder should be based on a named connection and should already have been verified to be structurally valid 
        private EntityConnectionStringBuilder GetBuilderForNamedConnection(EntityConnectionStringBuilder namedConnStrBuilder)
        { 
            Debug.Assert(namedConnStrBuilder != null && !String.IsNullOrEmpty(namedConnStrBuilder.Name), "expected non-null connStrBuilder for a named connection");

            // Need to get the actual string from the web.config
            EntityConnectionStringBuilder connStrBuilder = null; 

            if (CanLoadWebConfig) 
            { 
                try
                { 
                    System.Configuration.Configuration webConfig = _webApplication.OpenWebConfiguration(true /*isReadOnly*/);
                    if (webConfig != null)
                    {
                        ConnectionStringSettings connStrSettings = webConfig.ConnectionStrings.ConnectionStrings[namedConnStrBuilder.Name]; 
                        if (connStrSettings != null && !String.IsNullOrEmpty(connStrSettings.ConnectionString) && connStrSettings.ProviderName == s_entityClientProviderName)
                        { 
                            // Verify the contents of the named connection and create a new builder from it 
                            // It can't reference another named connection, and must have both the provider and metadata keywords
                            connStrBuilder = VerifyConnectionString(connStrSettings.ConnectionString, false /*allowNamedConnections*/); 
                        }
                        else
                        {
                            ShowError(Strings.Error_NamedConnectionNotFound); 
                        }
                    } 
                    else 
                    {
                        ShowError(Strings.Error_CannotOpenWebConfig_SpecificConnection); 
                    }
                }
                catch (ConfigurationException ce)
                { 
                    StringBuilder error = new StringBuilder();
                    error.AppendLine(Strings.Error_CannotOpenWebConfig_SpecificConnection); 
                    error.AppendLine(); 
                    error.AppendLine(ce.Message);
                    ShowError(error.ToString()); 
                }
            }

            // could be null if verification failed 
            return connStrBuilder;
        } 
 
        // Make sure we have at least some basic keywords.This method does not attempt to do as much verification as EntityClient would do.
        // We are just looking for a named connection, or both the provider and metadata keywords. 
        /// 
        /// Make sure we have at least some basic keywords.This method does not attempt to do as much verification as EntityClient would do.
        /// We are just looking for a named connection, or both the provider and metadata keywords.        ///
        ///  
        /// Connection string to be verified. Can be empty or null.
        ///  
        /// Indicates if the specified string can be a named connection in the form "name=ConnectionName". 
        /// If this method is being called with a connection string that came from a named connection entry in the web.config, this should be false
        /// because we do not support nested named connections. 
        /// 
        /// 
        /// A new EntityConnectionStringBuilder if the basic verification succeeded, otherwise null. Can return a builder for an empty string.
        ///  
        private EntityConnectionStringBuilder VerifyConnectionString(string connectionString, bool allowNamedConnections)
        { 
            // Verify if we have a structurally valid connection string with both "provider" and "metadata" keywords 
            EntityConnectionStringBuilder connStrBuilder = null;
 
            try
            {
                // Verify that it can be loaded into the builder to ensure basic valid structure and keywords
                connStrBuilder = new EntityConnectionStringBuilder(connectionString); 
            }
            catch (ArgumentException ex) 
            { 
                // The message thrown from the connection string builder is not always useful to the user in this context, so add our own error text as well
                ShowError(Strings.Error_CreatingConnectionStringBuilder(ex.Message)); 
                return null;
            }
            Debug.Assert(connStrBuilder != null, "expected non-null connStrBuilder");
 
            // If the connection string is not empty, do some validation on it
            //     (a) If this is not supposed to be a named connection, make sure it isn't 
            //     (b) Then it's not a named connection, then verify the keywords 
            //     (c) Otherwise the connection string is a named connection, no further validation is needed
 
            // devnote: Using the ConnectionString property on the builder in the check for empty, because the original connection string
            //          could have been something like "name=", which produces an empty ConnectionString in the builder, although the original was not empty
            if (!String.IsNullOrEmpty(connStrBuilder.ConnectionString))
            { 
                // If named connection is not allowed, make sure it is not specified
                if (!allowNamedConnections && !String.IsNullOrEmpty(connStrBuilder.Name)) 
                { 
                    ShowError(Strings.Error_NestedNamedConnection);
                    return null; 
                }

                // If the connection string is not a named connection, verify the keywords
                if (String.IsNullOrEmpty(connStrBuilder.Name)) 
                {
                    if (String.IsNullOrEmpty(connStrBuilder.Metadata)) 
                    { 
                        ShowError(Strings.Error_MissingMetadataKeyword);
                        return null; 
                    }
                }
                // else it's a named connection and we don't need to validate it further
            } 

            return connStrBuilder; 
        } 

        internal void ShowError(string message) 
        {
            if (_interactiveMode)
            {
                UIHelper.ShowError(EntityDataSource.Site, message); 
            }
            // else we are in a mode where we just want to ignore errors (typically this happens when called from the property grid) 
        } 

        internal void ShowWarning(string message) 
        {
            if (_interactiveMode)
            {
                UIHelper.ShowWarning(EntityDataSource.Site, message); 
            }
            // else we are in a mode where we just want to ignore warnings (typically this happens when called from the property grid) 
        } 

        // Removes any paths containing |DataDirectory| from a string of metadata locations, adds them to a separate list and expands 
        // the macro to the full path to ~/ for any paths that start with the macro
        private string ResolveDataDirectory(string metadataPaths, List dataDirectoryPaths, List warnings)
        {
            Debug.Assert(dataDirectoryPaths != null, "null dataDirectoryPaths"); 

            // 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. 
            //
            int indexStart = metadataPaths.IndexOf(s_dataDirectory, StringComparison.OrdinalIgnoreCase); 
            while (indexStart != -1) 
            {
                int prevSeparatorIndex = indexStart == 0 ? -1 : metadataPaths.LastIndexOf( 
                                                                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 = metadataPaths.IndexOf(s_metadataPathSeparator, 
                                             indexStart + s_dataDirectory.Length,
                                             StringComparison.Ordinal); 
                string resolvedPath; 
                if (indexEnd == -1)
                { 
                    resolvedPath = ExpandDataDirectory(metadataPaths.Substring(macroPathBeginIndex), warnings);
                    if (resolvedPath != null)
                    {
                        // only add to the list if no warning occurred 
                        dataDirectoryPaths.Add(resolvedPath);
                    } 
                    metadataPaths = metadataPaths.Remove(macroPathBeginIndex);   // update the concatenated list of paths 
                    break;
                } 

                resolvedPath = ExpandDataDirectory(metadataPaths.Substring(macroPathBeginIndex, indexEnd - macroPathBeginIndex), warnings);
                if (resolvedPath != null)
                { 
                    // only add to the list if no warning occurred
                    dataDirectoryPaths.Add(resolvedPath); 
                } 

                // Update the concatenated list of paths by removing the one containing the macro. 
                //
                metadataPaths = metadataPaths.Remove(macroPathBeginIndex, indexEnd - macroPathBeginIndex);
                indexStart = metadataPaths.IndexOf(s_dataDirectory, StringComparison.OrdinalIgnoreCase);
            } 

            return metadataPaths; 
        } 

        // If the specified string starts with |DataDirectory|, replace that macro with the full path for ~/app_data in the application 
        private string ExpandDataDirectory(string pathWithMacro, List warnings)
        {
            string trimmedPath = pathWithMacro.Trim();
            if (trimmedPath.StartsWith(s_dataDirectory, StringComparison.OrdinalIgnoreCase)) 
            {
                string dataDirectoryPath = GetDataDirectory(); 
                if (dataDirectoryPath != null) 
                {
                    return String.Concat(dataDirectoryPath, trimmedPath.Substring(s_dataDirectory.Length)); 
                }
                else
                {
                    warnings.Add(Strings.Warning_DataDirectoryNotFound(trimmedPath)); 
                    return null;
                } 
            } 
            // else the macro is somewhere in the middle of the string which is not valid anyway, so just pass it along and let the metadata failure occur
 
            return trimmedPath;
        }

        ///  
        /// Resolves the |DataDirecotry| macro from the current web application
        ///  
        /// The physical path for the macro expansion, or null if the data directory could not be found 
        private string GetDataDirectory()
        { 
            IProjectItem dataDirectoryPath = _webApplication.GetProjectItemFromUrl(s_dataDirectoryPath);
            if (dataDirectoryPath != null)
            {
                return dataDirectoryPath.PhysicalPath; 
            }
            else 
            { 
                return null;
            } 
        }

        private void ResolveVirtualRootPath(string resourcePath, List metadataPaths, List warnings)
        { 
            IProjectItem rootItem = _webApplication.GetProjectItemFromUrl(s_virtualRoot);
            if (rootItem != null) 
            { 
                metadataPaths.Add(String.Concat(rootItem.PhysicalPath, resourcePath.Substring(s_virtualRoot.Length)));
            } 
            else
            {
                warnings.Add(Strings.Warning_VirtualRootNotFound(resourcePath));
            } 
        }
 
        private void ResolveRelativePath(string resourcePath, List metadataPaths, List warnings) 
        {
            IProjectItem rootItem = _webApplication.GetProjectItemFromUrl(s_virtualRoot); 
            if (rootItem != null)
            {
                metadataPaths.Add(String.Concat(rootItem.PhysicalPath, resourcePath));
            } 
            else
            { 
                warnings.Add(Strings.Warning_VirtualRootNotFound(resourcePath)); 
            }
        } 

        // Create a DbConnection for the specified connection string
        private DbConnection GetDbConnection(EntityConnectionStringBuilder connStrBuilder)
        { 
            DbProviderFactory factory = null;
            if (!string.IsNullOrEmpty(connStrBuilder.Provider)) 
            { 
                try
                { 
                    // Get the correct provider factory
                    factory = DbProviderFactories.GetFactory(connStrBuilder.Provider);
                }
                catch (Exception ex) 
                {
                    ShowError(Strings.Error_CannotCreateDbProviderFactory(ex.Message)); 
                } 
            }
            else 
            {
                ShowError(Strings.Error_CannotCreateDbProviderFactory(Strings.Error_MissingProviderKeyword));
            }
 
            if (factory != null)
            { 
                try 
                {
 
                    // Create the underlying provider specific connection and give it the specified provider connection string
                    DbConnection storeConnection = factory.CreateConnection();
                    if (storeConnection != null)
                    { 
                        storeConnection.ConnectionString = connStrBuilder.ProviderConnectionString;
                        return storeConnection; 
                    } 
                }
                catch (Exception) 
                {
                    // eat any exceptions and just show the general error below
                }
 
                ShowError(Strings.Error_ReturnedNullOnProviderMethod(factory.GetType().Name));
            } 
            return null; 
        }
 
        internal void RefreshSchema(bool preferSilent)
        {
            string originalDataDirectory = null;
            try 
            {
                _owner.SuppressDataSourceEvents(); 
                Cursor originalCursor = Cursor.Current; 

                // Make sure we have set the |DataDirectory| field in the AppDomain so that the underlying providers 
                // can make use of this macro
                originalDataDirectory = AppDomain.CurrentDomain.GetData(s_dataDirectoryNoPipes) as string;
                AppDomain.CurrentDomain.SetData(s_dataDirectoryNoPipes, GetDataDirectory());
 
                // Verify that we can get the current schema
                DataTable currentSchema = GetCurrentSchema(preferSilent); 
                if (currentSchema == null) 
                {
                    // error occurred when getting current schema 
                    return;
                }

                try 
                {
                    Cursor.Current = Cursors.WaitCursor; 
 
                    EntityDesignerDataSourceView view = GetView(DefaultViewName);
                    IDataSourceViewSchema oldViewSchema = view.Schema; 
                    bool wasForceUsed = false;
                    if (oldViewSchema == null)
                    {
                        ForceSchemaRetrieval = true; 
                        oldViewSchema = view.Schema;
                        ForceSchemaRetrieval = false; 
                        wasForceUsed = true; 
                    }
 
                    SaveSchema(this.ConnectionString, this.DefaultContainerName, this.EntitySetName, this.Select, this.CommandText, currentSchema);

                    // Compare new schema to old schema and if it changed, raise the SchemaRefreshed event
                    bool viewSchemaEquivalent = _owner.InternalViewSchemasEquivalent(oldViewSchema, view.Schema); 
                    if (!viewSchemaEquivalent)
                    { 
                        _owner.FireOnSchemaRefreshed(EventArgs.Empty); 
                    }
                    else if (wasForceUsed) 
                    {
                        // if the schemas were equivalent but the schema retrieval was forced, still raise the data source changed event
                        _owner.FireOnDataSourceChanged(EventArgs.Empty);
                    } 
                }
                finally 
                { 
                    Cursor.Current = originalCursor;
                } 
            }
            finally
            {
                // Reset the AppDomain to its original |DataDirectory| value 
                AppDomain.CurrentDomain.SetData(s_dataDirectoryNoPipes, originalDataDirectory);
                _owner.ResumeDataSourceEvents(); 
            } 
        }
 
        private DataTable GetCurrentSchema(bool preferSilent)
        {
            // Verify that we have values for a minimum set of properties that will be required to get schema
            if (String.IsNullOrEmpty(this.EntityDataSource.ConnectionString) || 
                String.IsNullOrEmpty(this.EntityDataSource.DefaultContainerName) ||
                String.IsNullOrEmpty(this.EntityDataSource.CommandText) && String.IsNullOrEmpty(this.EntityDataSource.EntitySetName)) 
            { 
                if (!preferSilent)
                { 
                    ShowError(Strings.Error_CannotRefreshSchema_MissingProperties);
                }

                return null; 
            }
 
            bool originalMode = _interactiveMode; 
            try
            { 
                // Suppress error messages while loading metadata if we are in silent mode
                _interactiveMode = !preferSilent;

                // In interactive mode, always clear any cached information so we are sure to get the latest schema 
                // This is necessary in case the metadata or entity classes in referenced assemblies has changed
                // or in case the metadata files have changed without changing any of the properties on the control 
                if (_interactiveMode) 
                {
                    ReloadResources(); 
                    ClearMetadata();
                }

                // Try to load metadata if we don't have it yet 
                if (_entityConnection == null)
                { 
                    if (!LoadMetadata()) 
                    {
                        return null; 
                    }
                    // else metadata was successfully loaded, so continue refreshing schema
                }
            } 
            finally
            { 
                _interactiveMode = originalMode; 
            }
 
            // Either _entityConnection was already set, or we should have successfully loaded it
            Debug.Assert(_entityConnection != null, "_entityConnection should have been initialized");

            try 
            {
                // Create a temporary data source based on the EntityConnection we have built with 
                // the right metadata from the design-time environment 
                EntityDataSource entityDataSource = new EntityDataSource(_entityConnection);
 
                // Copy only the properties that can affect the schema
                entityDataSource.CommandText = this.EntityDataSource.CommandText;
                CopyParameters(this.EntityDataSource.CommandParameters, entityDataSource.CommandParameters);
                entityDataSource.DefaultContainerName = this.EntityDataSource.DefaultContainerName; 
                entityDataSource.EntitySetName = this.EntityDataSource.EntitySetName;
                entityDataSource.EntityTypeFilter = this.EntityDataSource.EntityTypeFilter; 
                entityDataSource.GroupBy = this.EntityDataSource.GroupBy; 
                entityDataSource.Select = this.EntityDataSource.Select;
                CopyParameters(this.EntityDataSource.SelectParameters, entityDataSource.SelectParameters); 

                EntityDataSourceView view = (EntityDataSourceView)(((IDataSource)entityDataSource).GetView(DefaultViewName));
                DataTable viewTable = view.GetViewSchema();
                viewTable.TableName = DefaultViewName; 
                return viewTable;
            } 
            catch (Exception ex) 
            {
                if (!preferSilent) 
                {
                    StringBuilder errorMessage = new StringBuilder();
                    errorMessage.AppendLine(Strings.Error_CannotRefreshSchema_RuntimeException(ex.Message));
                    if (ex.InnerException != null) 
                    {
                        errorMessage.AppendLine(Strings.Error_CannotRefreshSchema_RuntimeException_InnerException(ex.InnerException.Message)); 
                    } 

                    ShowError(errorMessage.ToString()); 
                }
            }

            return null; 
        }
 
        private void CopyParameters(ParameterCollection originalParameters, ParameterCollection newParameters) 
        {
            Debug.Assert(originalParameters != null && newParameters != null, "parameter collections on the data source should never be null"); 
            Debug.Assert(newParameters.Count == 0, "new parameter collection should not contain any parameters yet");

            _owner.CloneParameters(originalParameters, newParameters);
        } 

        // Loads the schema 
        internal DataTable LoadSchema() 
        {
            if (!ForceSchemaRetrieval) 
            {
                // Only check for consistency if we are not forcing the retrieval
                string connectionString = _owner.LoadFromDesignerState(DesignerStateDataSourceConnectionStringKey) as string;
                string defaultContainerName = _owner.LoadFromDesignerState(DesignerStateDataSourceDefaultContainerNameKey) as string; 
                string entitySetName = _owner.LoadFromDesignerState(DesignerStateDataSourceEntitySetNameKey) as string;
                string select = _owner.LoadFromDesignerState(DesignerStateDataSourceSelectKey) as string; 
                string commandText = _owner.LoadFromDesignerState(DesignerStateDataSourceCommandTextKey) as string; 

                if (!String.Equals(connectionString, this.ConnectionString, StringComparison.OrdinalIgnoreCase) || 
                    !String.Equals(defaultContainerName, this.DefaultContainerName, StringComparison.OrdinalIgnoreCase) ||
                    !String.Equals(entitySetName, this.EntitySetName, StringComparison.OrdinalIgnoreCase) ||
                    !String.Equals(select, this.Select, StringComparison.OrdinalIgnoreCase) ||
                    !String.Equals(commandText, this.CommandText, StringComparison.OrdinalIgnoreCase)) 
                {
                    return null; 
                } 
            }
 
            // Either we are forcing schema retrieval, or we're not forcing but we're consistent, so get the schema
            DataTable schema = _owner.LoadFromDesignerState(DesignerStateDataSourceSchemaKey) as DataTable;
            return schema;
        } 

        private void SaveSchema(string connectionString, string defaultContainerName, string entitySetName, 
            string select, string commandText, DataTable currentSchema) 
        {
            // Save the schema to DesignerState 
            _owner.SaveDesignerState(DesignerStateDataSourceConnectionStringKey, connectionString);
            _owner.SaveDesignerState(DesignerStateDataSourceDefaultContainerNameKey, defaultContainerName);
            _owner.SaveDesignerState(DesignerStateDataSourceEntitySetNameKey, entitySetName);
            _owner.SaveDesignerState(DesignerStateDataSourceSelectKey, select); 
            _owner.SaveDesignerState(DesignerStateDataSourceCommandTextKey, commandText);
            _owner.SaveDesignerState(DesignerStateDataSourceSchemaKey, currentSchema); 
        } 

        // Gets a view (can only get the default view) 
        internal EntityDesignerDataSourceView GetView(string viewName)
        {
            if (String.IsNullOrEmpty(viewName) ||
                String.Equals(viewName, DefaultViewName, StringComparison.OrdinalIgnoreCase)) 
            {
                if (View == null) 
                { 
                    View = new EntityDesignerDataSourceView(_owner);
                } 
                return View;
            }
            return null;
        } 

        // Gets a list of view names 
        internal string[] GetViewNames() 
        {
            return new string[] { DefaultViewName }; 
        }

        // Caller can specify that the results should not be sorted if they may add something to the list and sort themselves
        internal List GetContainerNames(bool sortResults) 
        {
            List entityContainerItems = new List(); 
            if (this.EdmItemCollection != null) 
            {
                ReadOnlyCollection entityContainers = this.EdmItemCollection.GetItems(); 
                foreach (EntityContainer entityContainer in entityContainers)
                {
                    entityContainerItems.Add(new EntityDataSourceContainerNameItem(entityContainer));
                } 

                if (sortResults) 
                { 
                    entityContainerItems.Sort();
                } 
            }
            return entityContainerItems;
        }
 
        internal EntityDataSourceContainerNameItem GetEntityContainerItem(string entityContainerName)
        { 
            if (String.IsNullOrEmpty(entityContainerName)) 
            {
                return null; // can't make a valid wrapper with an empty container name 
            }

            EntityContainer container = null;
            if (this.EdmItemCollection != null && 
                this.EdmItemCollection.TryGetEntityContainer(entityContainerName, true /*ignoreCase*/, out container) &&
                container != null) 
            { 
                return new EntityDataSourceContainerNameItem(container);
            } 
            else
            {
                return new EntityDataSourceContainerNameItem(entityContainerName);
            } 
        }
 
        internal List GetEntitySets(string entityContainerName) 
        {
            EntityContainer container = null; 
            if (this.EdmItemCollection != null)
            {
                this.EdmItemCollection.TryGetEntityContainer(entityContainerName, true /*ignoreCase*/, out container);
            } 
            return GetEntitySets(container, true /*sortResults*/);
        } 
 
        // Caller can specify that the results should not be sorted if they may add something to the list and sort themselves
        internal List GetEntitySets(EntityContainer entityContainer, bool sortResults) 
        {
            List entitySetNameItems = new List();
            if (entityContainer != null)
            { 
                foreach (EntitySetBase entitySetBase in entityContainer.BaseEntitySets)
                { 
                    // BaseEntitySets returns RelationshipSets too, but we only want EntitySets 
                    if (entitySetBase.BuiltInTypeKind == BuiltInTypeKind.EntitySet)
                    { 
                        entitySetNameItems.Add(new EntityDataSourceEntitySetNameItem(entitySetBase as EntitySet));
                    }
                }
 
                if (sortResults)
                { 
                    entitySetNameItems.Sort(); 
                }
            } 
            return entitySetNameItems;
        }

        // Caller can specify that the results should not be sorted if they may add something to the list and sort themselves 
        internal List GetNamedEntityClientConnections(bool sortResults)
        { 
            List namedEntityClientConnections = new List(); 

            System.Configuration.Configuration webConfig = _webApplication.OpenWebConfiguration(true /*isReadOnly*/); 
            if (webConfig != null)
            {
                try
                { 
                    foreach (ConnectionStringSettings connStrSettings in webConfig.ConnectionStrings.ConnectionStrings)
                    { 
                        if (connStrSettings.ProviderName == s_entityClientProviderName) 
                        {
                            EntityConnectionStringBuilder connStrBuilder = new EntityConnectionStringBuilder(); 
                            connStrBuilder.Name = connStrSettings.Name;
                            namedEntityClientConnections.Add(new EntityConnectionStringBuilderItem(connStrBuilder));
                        }
                    } 

                    if (sortResults) 
                    { 
                        namedEntityClientConnections.Sort();
                    } 
                }
                catch (ConfigurationException ce)
                {
                    CanLoadWebConfig = false; 
                    namedEntityClientConnections.Clear();
                    StringBuilder error = new StringBuilder(); 
                    error.AppendLine(Strings.Warning_CannotOpenWebConfig_AllConnections); 
                    error.AppendLine();
                    error.AppendLine(ce.Message); 
                    ShowWarning(error.ToString());
                }
            }
            else 
            {
                ShowWarning(Strings.Warning_CannotOpenWebConfig_AllConnections); 
             } 

            return namedEntityClientConnections; 
        }

        internal EntityConnectionStringBuilderItem GetEntityConnectionStringBuilderItem(string connectionString)
        { 
            EntityConnectionStringBuilder connStrBuilder = VerifyConnectionString(connectionString, true /*allowNamedConnections*/);
            if (connStrBuilder != null) 
            { 
                return new EntityConnectionStringBuilderItem(connStrBuilder);
            } 
            else
            {
                return new EntityConnectionStringBuilderItem(connectionString);
            } 
        }
 
        internal List GetEntityTypeProperties(EntityType entityType) 
        {
            List properties = new List(); 
            foreach (EdmProperty property in entityType.Properties)
            {
                properties.Add(property.Name);
            } 

            Debug.Assert(properties.Count > 0, "expected entity to have at least one property"); 
 
            // don't sort the properties here because it will cause them to be displayed to the user in a non-intuitive order
 
            return properties;
        }

        internal List GetEntityTypeFilters(string entityContainerName, string entitySetName) 
        {
            EntityType baseEntitySetType = null; 
            if (this.EdmItemCollection != null) 
            {
                EntityContainer container; 
                if (this.EdmItemCollection.TryGetEntityContainer(entityContainerName, true /*ignoreCase*/, out container) && (container != null))
                {
                    EntitySet entitySet;
                    if (container.TryGetEntitySetByName(entitySetName, true /*ignoreCase*/, out entitySet) && entitySet != null) 
                    {
                        baseEntitySetType = entitySet.ElementType; 
                    } 
                }
            } 
            return GetEntityTypeFilters(baseEntitySetType, true /*sortResults*/);
        }

        internal List GetEntityTypeFilters(EntityType baseEntitySetType, bool sortResults) 
        {
            List derivedTypes = new List(); 
 
            if (baseEntitySetType != null && this.EdmItemCollection != null)
            { 
                foreach (EntityType entityType in GetTypeAndSubtypesOf(baseEntitySetType, this.EdmItemCollection))
                {
                    derivedTypes.Add(new EntityDataSourceEntityTypeFilterItem(entityType));
                } 

                if (sortResults) 
                { 
                    derivedTypes.Sort();
                } 
            }
            return derivedTypes;
        }
 
        #region Helper methods for finding possible types for EntityTypeFilter
        private static IEnumerable GetTypeAndSubtypesOf(EntityType entityType, EdmItemCollection itemCollection) 
        { 
            // Always include the specified type, even if it's abstract
            yield return entityType; 

            // Get the subtypes of the type from the item collection
            IEnumerable entityTypesInCollection = itemCollection.OfType();
            foreach (EntityType typeInCollection in entityTypesInCollection) 
            {
                if (entityType.Equals(typeInCollection) == false && IsStrictSubtypeOf(typeInCollection, entityType)) 
                { 
                    yield return typeInCollection;
                } 
            }

            yield break;
        } 

        // requires: firstType is not null 
        // effects: if otherType is among the base types, return true, 
        // otherwise returns false.
        // when othertype is same as the current type, return false. 
        private static bool IsStrictSubtypeOf(EntityType firstType, EntityType secondType)
        {
            Debug.Assert(firstType != null, "firstType should not be not null");
            if (secondType == null) 
            {
                return false; 
            } 

            // walk up my type hierarchy list 
            for (EntityType t = (EntityType)firstType.BaseType; t != null; t = (EntityType)t.BaseType)
            {
                if (t == secondType)
                    return true; 
            }
            return false; 
        } 
        #endregion
 
        // Copy properties from temporary state to the data source
        internal void SaveEntityDataSourceProperties(EntityDataSourceState state)
        {
            this.EntityDataSource.ConnectionString = state.ConnectionString; 
            this.EntityDataSource.DefaultContainerName = state.DefaultContainerName;
            this.EntityDataSource.EnableDelete = state.EnableDelete; 
            this.EntityDataSource.EnableInsert = state.EnableInsert; 
            this.EntityDataSource.EnableUpdate = state.EnableUpdate;
            this.EntityDataSource.EntitySetName = state.EntitySetName; 
            this.EntityDataSource.EntityTypeFilter = state.EntityTypeFilter;
            this.EntityDataSource.Select = state.Select;
        }
 
        // Copy  properties from the data source to temporary state
        internal EntityDataSourceState LoadEntityDataSourceState() 
        { 
            EntityDataSourceState state = new EntityDataSourceState();
            state.ConnectionString = this.EntityDataSource.ConnectionString; 
            state.DefaultContainerName = this.EntityDataSource.DefaultContainerName;
            state.EnableDelete = this.EntityDataSource.EnableDelete;
            state.EnableInsert = this.EntityDataSource.EnableInsert;
            state.EnableUpdate = this.EntityDataSource.EnableUpdate; 
            state.EntitySetName = this.EntityDataSource.EntitySetName;
            state.EntityTypeFilter = this.EntityDataSource.EntityTypeFilter; 
            state.Select = this.EntityDataSource.Select; 
            return state;
        } 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//----------------------------------------------------------------------------- 

using System.Collections.Generic; 
using System.Collections.ObjectModel;
using System.Configuration;
using System.ComponentModel.Design;
using System.Data; 
using System.Data.Common;
using System.Data.EntityClient; 
using System.Data.Mapping; 
using System.Data.Metadata.Edm;
using System.Web.UI.Design.WebControls.Util; 
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq; 
using System.Reflection;
using System.Text; 
using System.Web.Configuration; 
using System.Web.UI;
using System.Web.UI.Design; 
using System.Web.UI.WebControls;
using System.Windows.Forms;
using System.Xml;
 
namespace System.Web.UI.Design.WebControls
{ 
    internal class EntityDataSourceDesignerHelper 
    {
        #region Private and Internal static constants 
        private static readonly string s_virtualRoot = "~/";
        private static readonly string s_ecmPublicKeyToken = "PublicKeyToken=" + AssemblyRef.EcmaPublicKey;
        private static readonly string s_entityClientProviderName = "System.Data.EntityClient";
        private static readonly string s_metadataPathSeparator = "|"; 
        private static readonly string s_resPathPrefix = "res://";
        private static readonly string s_relativeParentFolder = "../"; 
        private static readonly string s_relativeCurrentFolder = "./"; 
        private static readonly string s_altRelativeParentFolder = @"..\";
        private static readonly string s_altRelativeCurrentFolder = @".\"; 
        private static readonly string s_dataDirectoryNoPipes = "DataDirectory";
        private static readonly string s_dataDirectory = "|DataDirectory|";
        private static readonly string s_dataDirectoryPath = String.Concat(s_virtualRoot, "app_data");
        private static readonly string s_resolvedResPathFormat = String.Concat(s_resPathPrefix, "{0}/{1}"); 
        private static readonly string DesignerStateDataSourceSchemaKey = "EntityDataSourceSchema";
        private static readonly string DesignerStateDataSourceConnectionStringKey = "EntityDataSourceConnectionString"; 
        private static readonly string DesignerStateDataSourceDefaultContainerNameKey = "EntityDataSourceDefaultContainerName"; 
        private static readonly string DesignerStateDataSourceEntitySetNameKey = "EntityDataSourceEntitySetNameKey";
        private static readonly string DesignerStateDataSourceSelectKey = "EntityDataSourceSelectKey"; 
        private static readonly string DesignerStateDataSourceCommandTextKey = "EntityDataSourceCommandTextKey";

        internal static readonly string DefaultViewName = "DefaultView";
        #endregion 

        #region Private instance fields 
        private readonly EntityDataSource _entityDataSource; 
        private EntityConnection _entityConnection;
        private readonly IWebApplication _webApplication; 
        // determines if any errors or warnings are displayed and if the EntityConnection and metadata are automatically loaded when accessed
        private bool _interactiveMode;
        private HashSet _assemblies;
        private EntityDesignerDataSourceView _view; 
        private bool _forceSchemaRetrieval;
        private readonly EntityDataSourceDesigner _owner; 
        private bool _canLoadWebConfig; 
        #endregion
 
        internal EntityDataSourceDesignerHelper(EntityDataSource entityDataSource, bool interactiveMode)
        {
            Debug.Assert(entityDataSource != null, "null entityDataSource");
 
            _entityDataSource = entityDataSource;
            _interactiveMode = interactiveMode; 
 
            _canLoadWebConfig = true;
 
            IServiceProvider serviceProvider = _entityDataSource.Site;
            if (serviceProvider != null)
            {
                // Get the designer instance associated with the specified data source control 
                IDesignerHost designerHost = (IDesignerHost)serviceProvider.GetService(typeof(IDesignerHost));
                if (designerHost != null) 
                { 
                    _owner = designerHost.GetDesigner(this.EntityDataSource) as EntityDataSourceDesigner;
                } 

                // Get other services used to determine design-time information
                _webApplication = serviceProvider.GetService(typeof(IWebApplication)) as IWebApplication;
 
            }
            Debug.Assert(_owner != null, "expected non-null owner"); 
            Debug.Assert(_webApplication != null, "expected non-null web application service"); 
        }
 
        internal void AddSystemWebEntityReference()
        {
            IServiceProvider serviceProvider = _entityDataSource.Site;
            if (serviceProvider != null) 
            {
                ITypeResolutionService typeResProvider = (ITypeResolutionService)serviceProvider.GetService(typeof(ITypeResolutionService)); 
                if (typeResProvider != null) 
                {
                    try 
                    {
                        // Adding the reference using just the name and public key since we don't want to be
                        // tied to a particular version here.
                        typeResProvider.ReferenceAssembly( 
                            new AssemblyName("System.Web.Entity,PublicKeyToken=" + AssemblyRef.EcmaPublicKey));
                    } 
                    catch (FileNotFoundException) 
                    {
                        Debug.Fail("Failed to find System.Web.Entity assembly."); 
                        // Intentionally ignored exception - the assembly should always be
                        // found, but if it isn't, then we don't want to stop the rest of the
                        // control from working, especially since the assembly may not always
                        // be required. 
                    }
                } 
            } 
        }
 
        #region Helpers for EntityDataSource properties
        internal bool AutoGenerateWhereClause
        {
            get 
            {
                return _entityDataSource.AutoGenerateWhereClause; 
            } 
        }
 
        internal bool AutoGenerateOrderByClause
        {
            get
            { 
                return _entityDataSource.AutoGenerateOrderByClause;
            } 
        } 

        internal bool CanPage 
        {
            get
            {
                DataSourceView view = ((IDataSource)_entityDataSource).GetView(DefaultViewName); 
                if (view != null)
                { 
                    return view.CanPage; 
                }
 
                return false;
            }
        }
 
        internal bool CanSort
        { 
            get 
            {
                DataSourceView view = ((IDataSource)_entityDataSource).GetView(DefaultViewName); 
                if (view != null)
                {
                    return view.CanSort;
                } 

                return false; 
            } 
        }
 
        internal string ConnectionString
        {
            get
            { 
                return _entityDataSource.ConnectionString;
            } 
            set 
            {
                if (value != ConnectionString) 
                {
                    _entityDataSource.ConnectionString = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                } 
            }
        } 
 
        internal string CommandText
        { 
            get
            {
                return _entityDataSource.CommandText;
            } 
            set
            { 
                if (value != CommandText) 
                {
                    _entityDataSource.CommandText = value; 
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                }
            }
        } 

        internal ParameterCollection CommandParameters 
        { 
            get
            { 
                return _entityDataSource.CommandParameters;
            }
        }
 
        internal string DefaultContainerName
        { 
            get 
            {
                return _entityDataSource.DefaultContainerName; 
            }
            set
            {
                if (value != DefaultContainerName) 
                {
                    _entityDataSource.DefaultContainerName = value; 
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                }
            } 
        }

        internal bool EnableDelete
        { 
            get
            { 
                return _entityDataSource.EnableDelete; 
            }
        } 

        internal bool EnableInsert
        {
            get 
            {
                return _entityDataSource.EnableInsert; 
            } 
        }
 
        internal bool EnableUpdate
        {
            get
            { 
                return _entityDataSource.EnableUpdate;
            } 
        } 

        internal string EntitySetName 
        {
            get
            {
                return _entityDataSource.EntitySetName; 
            }
            set 
            { 
                if (value != EntitySetName)
                { 
                    _entityDataSource.EntitySetName = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                }
            } 
        }
 
        internal string EntityTypeFilter 
        {
            get 
            {
                return _entityDataSource.EntityTypeFilter;
            }
            set 
            {
                if (value != EntityTypeFilter) 
                { 
                    _entityDataSource.EntityTypeFilter = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                }
            }
        }
 
        internal string GroupBy
        { 
            get 
            {
                return _entityDataSource.GroupBy; 
            }
        }

        internal string OrderBy 
        {
            get 
            { 
                return _entityDataSource.OrderBy;
            } 
            set
            {
                if (value != OrderBy)
                { 
                    _entityDataSource.OrderBy = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                } 
            }
        } 

        internal ParameterCollection OrderByParameters
        {
            get 
            {
                return _entityDataSource.OrderByParameters; 
            } 
        }
 
        internal string Select
        {
            get
            { 
                return _entityDataSource.Select;
            } 
            set 
            {
                if (value != Select) 
                {
                    _entityDataSource.Select = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty);
                } 
            }
        } 
 
        internal ParameterCollection SelectParameters
        { 
            get
            {
                return _entityDataSource.SelectParameters;
            } 
        }
 
        internal string Where 
        {
            get 
            {
                return _entityDataSource.Where;
            }
            set 
            {
                if (value != Where) 
                { 
                    _entityDataSource.Where = value;
                    _owner.FireOnDataSourceChanged(EventArgs.Empty); 
                }
            }
        }
 
        internal ParameterCollection WhereParameters
        { 
            get 
            {
                return _entityDataSource.WhereParameters; 
            }
        }
        #endregion
 
        private EntityDataSource EntityDataSource
        { 
            get 
            {
                return _entityDataSource; 
            }
        }

        private EdmItemCollection EdmItemCollection 
        {
            get 
            { 
                // In interactive mode, we will explicitly load metadata when needed, so never load it here
                // When not in interactive mode, we only need to load metadata once, which is determined by the presence of an EntityConnection 
                if (!_interactiveMode && _entityConnection == null)
                {
                    LoadMetadata();
                } 

                // _entityConnection may still be null if the load failed or if we are in interactive mode and the metadata has not been explicitly loaded 
                if (_entityConnection != null) 
                {
                    ItemCollection itemCollection = null; 

                    try
                    {
                        _entityConnection.GetMetadataWorkspace().TryGetItemCollection(DataSpace.CSpace, out itemCollection); 
                    }
                    catch (Exception) 
                    { 
                        // Never expecting a failure because we have already initialized the workspace when the metadata was loaded,
                        // and any errors would have been trapped then. Just ignore any errors that might occur here to prevent a crash. 
                    }

                    return itemCollection as EdmItemCollection; // not guaranteed not to be null, caller must check anyway before using
                } 

                return null; 
            } 
        }
 
        // The default DesignerDataSourceView
        private EntityDesignerDataSourceView View
        {
            get 
            {
                return _view; 
            } 
            set
            { 
                _view = value;
            }
        }
 
        /// 
        /// The status of loading the web.config file for named connections. 
        /// This helps to determine if we've already tried to load the web.config file and if it failed 
        /// we do not continue to load it again.
        ///  
        internal bool CanLoadWebConfig
        {
            get
            { 
                return _canLoadWebConfig;
            } 
            set 
            {
                _canLoadWebConfig = value; 
            }
        }

        // Whether or not a schema retrieval is being forced (used in RefreshSchema) 
        private bool ForceSchemaRetrieval
        { 
            get 
            {
                return _forceSchemaRetrieval; 
            }
            set
            {
                _forceSchemaRetrieval = value; 
            }
        } 
 
        // Loads metadata for the current connection string on the data source control
        private bool LoadMetadata() 
        {
            EntityConnectionStringBuilder connStrBuilder = VerifyConnectionString(this.EntityDataSource.ConnectionString, true /*allowNamedConnections*/);
            if (connStrBuilder != null)
            { 
                return LoadMetadata(connStrBuilder);
            } 
            // else the connection string could not be verified, and any errors are already displayed during the failed verification, so nothing more to do 

            return false; 
        }

        internal bool LoadMetadata(EntityConnectionStringBuilder connStrBuilder)
        { 
            Debug.Assert(connStrBuilder != null, "expected non-null connStrBuilder");
 
            // if these services are not available for some reason, we will not be able to do anything useful, so don't try to load metadata 
            if (_webApplication != null)
            { 
                // _assemblies could already be loaded if this call is coming from the wizard, because metadata could be loaded
                // multiple times if the connection string is changed, so don't load it again if we already have it. It can't have
                // changed since the last load, because the wizard dialog is modal and there is no way to have changed the project between loads.
                if (_assemblies == null) 
                {
                    LoadAssemblies(); 
                } 

                return LoadMetadataFromBuilder(connStrBuilder); 
            }

            return false;
        } 

        // Loads C-Space metadata from the specified connection string builder. 
        // Expects that the specified builder has already been verified and has minimum required properties 
        private bool LoadMetadataFromBuilder(EntityConnectionStringBuilder connStrBuilder)
        { 
            Debug.Assert(connStrBuilder != null, "expected non-null connStrBuilder");

            // We will be replacing the metadata with a new collection, and if something fails to load we want to make sure to clear out any existing data
            ClearMetadata(); 

            if (String.IsNullOrEmpty(connStrBuilder.ConnectionString)) 
            { 
                // Although we can't load metadata here, this is not an error because the user should not expect an empty connection string
                // to produce any metadata, so it will not be confusing when no values are available in the dropdowns. This is different from 
                // an invalid connection string because in that case they have entered a value and are expecting to get metadata from it.
                return false;
            }
 
            // If this is a named connection, load the contents of the named connection from the web.config and verify itet
            if (!String.IsNullOrEmpty(connStrBuilder.Name)) 
            { 
                connStrBuilder = GetBuilderForNamedConnection(connStrBuilder);
                if (connStrBuilder == null) 
                {
                    // some verification failed when getting the connection string builder,
                    // so we have nothing to load metadata from, just return
                    return false; 
                }
            } 
 
            string originalMetadata = connStrBuilder.Metadata;
            Debug.Assert(!String.IsNullOrEmpty(originalMetadata), "originalMetadata should have aleady been verified to be non-null or empty"); 

            List metadataWarnings = new List(); // keeps track of all warnings that happen during the parsing of the connection string
            List metadataPaths = new List();    // collection of resolved paths
 
            // We need to use the | separator to split the metadata value into individual paths, so first remove and process any paths
            // containing the macro |DataDirectory|. These will get combined again with the rest of the paths once they have been processed. 
            List dataDirectoryPaths = new List(); 
            string metadataWithoutDataDirectory = ResolveDataDirectory(originalMetadata, dataDirectoryPaths, metadataWarnings);
 
            foreach (string path in metadataWithoutDataDirectory.Split(new string[] { s_metadataPathSeparator }, StringSplitOptions.RemoveEmptyEntries))
            {
                string trimmedPath = path.Trim();
                if (!String.IsNullOrEmpty(trimmedPath)) 
                {
                    if (trimmedPath.StartsWith(s_virtualRoot, StringComparison.OrdinalIgnoreCase)) 
                    { 
                        // ~/
                        ResolveVirtualRootPath(trimmedPath, metadataPaths, metadataWarnings); 
                    }
                    else if (trimmedPath.StartsWith(s_relativeCurrentFolder, StringComparison.OrdinalIgnoreCase) ||
                        trimmedPath.StartsWith(s_altRelativeCurrentFolder, StringComparison.OrdinalIgnoreCase) ||
                        trimmedPath.StartsWith(s_relativeParentFolder, StringComparison.OrdinalIgnoreCase) || 
                        trimmedPath.StartsWith(s_altRelativeParentFolder, StringComparison.OrdinalIgnoreCase))
                    { 
                        // ../, ..\, ./, or ..\ 
                        ResolveRelativePath(trimmedPath, metadataPaths, metadataWarnings);
                    } 
                    else
                    {
                        // We are not trying to resolve any other types of paths, so just pass it along directly.
                        // If the format of the path is unrecognized, or if the path is not valid, metadata will throw an exception that will 
                        // be displayed to the user at that time.
                        metadataPaths.Add(trimmedPath); 
                    } 
                }
            } 

            // Add the paths with |DataDirectory| back to the list
            if (dataDirectoryPaths.Count > 0)
            { 
                metadataPaths.AddRange(dataDirectoryPaths);
            } 
 
            if (metadataWarnings.Count > 0)
            { 
                ShowWarning(BuildWarningMessage(Strings.Warning_ConnectionStringMessageHeader, metadataWarnings));
            }

            return SetEntityConnection(metadataPaths, connStrBuilder); 
        }
 
        private bool SetEntityConnection(List metadataPaths, EntityConnectionStringBuilder connStrBuilder) 
        {
            // It's possible the metadata was specified in the original connection string, but we filtered out everything due to not being able to resolve it to anything. 
            // In that case, warnings have already been displayed to indicate which paths were removed, so no need to display another message.
            if (metadataPaths.Count > 0)
            {
                try 
                {
                    // Get the connection first, because it might be needed to gather provider services information 
                    DbConnection dbConnection = GetDbConnection(connStrBuilder); 

                    MetadataWorkspace metadataWorkspace = new MetadataWorkspace(metadataPaths, _assemblies); 

                    // Ensure that we have all of the item collections registered. If some of them are missing this will cause problems eventually if we need to
                    // execute a query to get detailed schema information, but that will be handled later. For now just register everything to prevent errors in the
                    // stack that would not be understood by the user in the designer at this point. 
                    ItemCollection edmItemCollection;
                    ItemCollection storeItemCollection; 
                    ItemCollection csItemCollection; 
                    if (!metadataWorkspace.TryGetItemCollection(DataSpace.CSpace, out edmItemCollection))
                    { 
                        edmItemCollection = new EdmItemCollection();
                        metadataWorkspace.RegisterItemCollection(edmItemCollection);
                    }
 
                    if (!metadataWorkspace.TryGetItemCollection(DataSpace.SSpace, out storeItemCollection))
                    { 
                        return false; 
                    }
 
                    if (!metadataWorkspace.TryGetItemCollection(DataSpace.CSSpace, out csItemCollection))
                    {
                        Debug.Assert(edmItemCollection != null && storeItemCollection != null, "edm and store ItemCollection should be populated already");
                        metadataWorkspace.RegisterItemCollection(new StorageMappingItemCollection(edmItemCollection as EdmItemCollection, storeItemCollection as StoreItemCollection)); 
                    }
 
                    // Load OSpace metadata from all of the assemblies we know about 
                    ObjectItemCollection objectItemCollection = new ObjectItemCollection();
                    foreach (Assembly assembly in _assemblies) 
                    {
                        objectItemCollection.LoadFromAssembly(assembly);
                    }
                    metadataWorkspace.RegisterItemCollection(objectItemCollection); 

 
                    if (dbConnection != null) 
                    {
                        _entityConnection = new EntityConnection(metadataWorkspace, dbConnection); 
                        return true;
                    }
                    // else the DbConnection could not be created and the error should have already been displayed
                } 
                catch (Exception ex)
                { 
                    StringBuilder exceptionMessage = new StringBuilder(); 
                    exceptionMessage.AppendLine(Strings.Error_MetadataLoadError);
                    exceptionMessage.AppendLine(); 
                    exceptionMessage.Append(ex.Message);
                    ShowError(exceptionMessage.ToString());
                }
            } 

            return false; 
        } 

        // Clears out the existing metadata 
        internal void ClearMetadata()
        {
            _entityConnection = null;
        } 

        ///  
        /// Finds and caches all non system assemblies that are found using the TypeDiscoveryService 
        /// This searches places like the ~/bin folder, app_code, and the 'assemblies' section of web.config, among others
        ///  
        private void LoadAssemblies()
        {
            _assemblies = new HashSet();
 
            // Find the assemblies using the ITypeDiscoveryService
            ITypeDiscoveryService typeDiscoverySvc = this.EntityDataSource.Site.GetService(typeof(ITypeDiscoveryService)) as ITypeDiscoveryService; 
            if (typeDiscoverySvc != null) 
            {
                foreach (Type type in typeDiscoverySvc.GetTypes(typeof(object), false /*excludeGlobalTypes*/)) 
                {
                    if (!_assemblies.Contains(type.Assembly) && !IsSystemAssembly(type.Assembly.FullName))
                    {
                        _assemblies.Add(type.Assembly); 
                    }
                } 
            } 
        }
 
        // Explicitly rebuild the known assembly cache. This is done when launching the wizard and allows the wizard to pick up the latest
        // assemblies in the project, without having to reload them everytime the connection string changes while the wizard is running
        internal void ReloadResources()
        { 
            Debug.Assert(_interactiveMode == true, "resource cache should only explicitly be loaded in interactive mode");
            LoadAssemblies(); 
        } 

        // Is the assembly and its referenced assemblies not expected to have any metadata 
        // This does not detect all possible system assemblies, but just those we can detect as system for sure
        private static bool IsSystemAssembly(string fullName)
        {
            return (String.Equals(fullName, "*", StringComparison.OrdinalIgnoreCase) || 
                fullName.EndsWith(s_ecmPublicKeyToken, StringComparison.OrdinalIgnoreCase));
        } 
 
        // Combines all warnings into one message
        private string BuildWarningMessage(string headerMessage, List warnings) 
        {
            Debug.Assert(warnings != null && warnings.Count > 0, "expected non-null and non-empty warnings");

            StringBuilder warningMessage = new StringBuilder(); 
            warningMessage.AppendLine(headerMessage);
            warningMessage.AppendLine(); 
            foreach (string warning in warnings) 
            {
                warningMessage.AppendLine(warning); 
            }

            return warningMessage.ToString();
        } 

        // Get a connection string builder for the specified connection string, and do some basic verification 
        // namedConnStrBuilder should be based on a named connection and should already have been verified to be structurally valid 
        private EntityConnectionStringBuilder GetBuilderForNamedConnection(EntityConnectionStringBuilder namedConnStrBuilder)
        { 
            Debug.Assert(namedConnStrBuilder != null && !String.IsNullOrEmpty(namedConnStrBuilder.Name), "expected non-null connStrBuilder for a named connection");

            // Need to get the actual string from the web.config
            EntityConnectionStringBuilder connStrBuilder = null; 

            if (CanLoadWebConfig) 
            { 
                try
                { 
                    System.Configuration.Configuration webConfig = _webApplication.OpenWebConfiguration(true /*isReadOnly*/);
                    if (webConfig != null)
                    {
                        ConnectionStringSettings connStrSettings = webConfig.ConnectionStrings.ConnectionStrings[namedConnStrBuilder.Name]; 
                        if (connStrSettings != null && !String.IsNullOrEmpty(connStrSettings.ConnectionString) && connStrSettings.ProviderName == s_entityClientProviderName)
                        { 
                            // Verify the contents of the named connection and create a new builder from it 
                            // It can't reference another named connection, and must have both the provider and metadata keywords
                            connStrBuilder = VerifyConnectionString(connStrSettings.ConnectionString, false /*allowNamedConnections*/); 
                        }
                        else
                        {
                            ShowError(Strings.Error_NamedConnectionNotFound); 
                        }
                    } 
                    else 
                    {
                        ShowError(Strings.Error_CannotOpenWebConfig_SpecificConnection); 
                    }
                }
                catch (ConfigurationException ce)
                { 
                    StringBuilder error = new StringBuilder();
                    error.AppendLine(Strings.Error_CannotOpenWebConfig_SpecificConnection); 
                    error.AppendLine(); 
                    error.AppendLine(ce.Message);
                    ShowError(error.ToString()); 
                }
            }

            // could be null if verification failed 
            return connStrBuilder;
        } 
 
        // Make sure we have at least some basic keywords.This method does not attempt to do as much verification as EntityClient would do.
        // We are just looking for a named connection, or both the provider and metadata keywords. 
        /// 
        /// Make sure we have at least some basic keywords.This method does not attempt to do as much verification as EntityClient would do.
        /// We are just looking for a named connection, or both the provider and metadata keywords.        ///
        ///  
        /// Connection string to be verified. Can be empty or null.
        ///  
        /// Indicates if the specified string can be a named connection in the form "name=ConnectionName". 
        /// If this method is being called with a connection string that came from a named connection entry in the web.config, this should be false
        /// because we do not support nested named connections. 
        /// 
        /// 
        /// A new EntityConnectionStringBuilder if the basic verification succeeded, otherwise null. Can return a builder for an empty string.
        ///  
        private EntityConnectionStringBuilder VerifyConnectionString(string connectionString, bool allowNamedConnections)
        { 
            // Verify if we have a structurally valid connection string with both "provider" and "metadata" keywords 
            EntityConnectionStringBuilder connStrBuilder = null;
 
            try
            {
                // Verify that it can be loaded into the builder to ensure basic valid structure and keywords
                connStrBuilder = new EntityConnectionStringBuilder(connectionString); 
            }
            catch (ArgumentException ex) 
            { 
                // The message thrown from the connection string builder is not always useful to the user in this context, so add our own error text as well
                ShowError(Strings.Error_CreatingConnectionStringBuilder(ex.Message)); 
                return null;
            }
            Debug.Assert(connStrBuilder != null, "expected non-null connStrBuilder");
 
            // If the connection string is not empty, do some validation on it
            //     (a) If this is not supposed to be a named connection, make sure it isn't 
            //     (b) Then it's not a named connection, then verify the keywords 
            //     (c) Otherwise the connection string is a named connection, no further validation is needed
 
            // devnote: Using the ConnectionString property on the builder in the check for empty, because the original connection string
            //          could have been something like "name=", which produces an empty ConnectionString in the builder, although the original was not empty
            if (!String.IsNullOrEmpty(connStrBuilder.ConnectionString))
            { 
                // If named connection is not allowed, make sure it is not specified
                if (!allowNamedConnections && !String.IsNullOrEmpty(connStrBuilder.Name)) 
                { 
                    ShowError(Strings.Error_NestedNamedConnection);
                    return null; 
                }

                // If the connection string is not a named connection, verify the keywords
                if (String.IsNullOrEmpty(connStrBuilder.Name)) 
                {
                    if (String.IsNullOrEmpty(connStrBuilder.Metadata)) 
                    { 
                        ShowError(Strings.Error_MissingMetadataKeyword);
                        return null; 
                    }
                }
                // else it's a named connection and we don't need to validate it further
            } 

            return connStrBuilder; 
        } 

        internal void ShowError(string message) 
        {
            if (_interactiveMode)
            {
                UIHelper.ShowError(EntityDataSource.Site, message); 
            }
            // else we are in a mode where we just want to ignore errors (typically this happens when called from the property grid) 
        } 

        internal void ShowWarning(string message) 
        {
            if (_interactiveMode)
            {
                UIHelper.ShowWarning(EntityDataSource.Site, message); 
            }
            // else we are in a mode where we just want to ignore warnings (typically this happens when called from the property grid) 
        } 

        // Removes any paths containing |DataDirectory| from a string of metadata locations, adds them to a separate list and expands 
        // the macro to the full path to ~/ for any paths that start with the macro
        private string ResolveDataDirectory(string metadataPaths, List dataDirectoryPaths, List warnings)
        {
            Debug.Assert(dataDirectoryPaths != null, "null dataDirectoryPaths"); 

            // 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. 
            //
            int indexStart = metadataPaths.IndexOf(s_dataDirectory, StringComparison.OrdinalIgnoreCase); 
            while (indexStart != -1) 
            {
                int prevSeparatorIndex = indexStart == 0 ? -1 : metadataPaths.LastIndexOf( 
                                                                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 = metadataPaths.IndexOf(s_metadataPathSeparator, 
                                             indexStart + s_dataDirectory.Length,
                                             StringComparison.Ordinal); 
                string resolvedPath; 
                if (indexEnd == -1)
                { 
                    resolvedPath = ExpandDataDirectory(metadataPaths.Substring(macroPathBeginIndex), warnings);
                    if (resolvedPath != null)
                    {
                        // only add to the list if no warning occurred 
                        dataDirectoryPaths.Add(resolvedPath);
                    } 
                    metadataPaths = metadataPaths.Remove(macroPathBeginIndex);   // update the concatenated list of paths 
                    break;
                } 

                resolvedPath = ExpandDataDirectory(metadataPaths.Substring(macroPathBeginIndex, indexEnd - macroPathBeginIndex), warnings);
                if (resolvedPath != null)
                { 
                    // only add to the list if no warning occurred
                    dataDirectoryPaths.Add(resolvedPath); 
                } 

                // Update the concatenated list of paths by removing the one containing the macro. 
                //
                metadataPaths = metadataPaths.Remove(macroPathBeginIndex, indexEnd - macroPathBeginIndex);
                indexStart = metadataPaths.IndexOf(s_dataDirectory, StringComparison.OrdinalIgnoreCase);
            } 

            return metadataPaths; 
        } 

        // If the specified string starts with |DataDirectory|, replace that macro with the full path for ~/app_data in the application 
        private string ExpandDataDirectory(string pathWithMacro, List warnings)
        {
            string trimmedPath = pathWithMacro.Trim();
            if (trimmedPath.StartsWith(s_dataDirectory, StringComparison.OrdinalIgnoreCase)) 
            {
                string dataDirectoryPath = GetDataDirectory(); 
                if (dataDirectoryPath != null) 
                {
                    return String.Concat(dataDirectoryPath, trimmedPath.Substring(s_dataDirectory.Length)); 
                }
                else
                {
                    warnings.Add(Strings.Warning_DataDirectoryNotFound(trimmedPath)); 
                    return null;
                } 
            } 
            // else the macro is somewhere in the middle of the string which is not valid anyway, so just pass it along and let the metadata failure occur
 
            return trimmedPath;
        }

        ///  
        /// Resolves the |DataDirecotry| macro from the current web application
        ///  
        /// The physical path for the macro expansion, or null if the data directory could not be found 
        private string GetDataDirectory()
        { 
            IProjectItem dataDirectoryPath = _webApplication.GetProjectItemFromUrl(s_dataDirectoryPath);
            if (dataDirectoryPath != null)
            {
                return dataDirectoryPath.PhysicalPath; 
            }
            else 
            { 
                return null;
            } 
        }

        private void ResolveVirtualRootPath(string resourcePath, List metadataPaths, List warnings)
        { 
            IProjectItem rootItem = _webApplication.GetProjectItemFromUrl(s_virtualRoot);
            if (rootItem != null) 
            { 
                metadataPaths.Add(String.Concat(rootItem.PhysicalPath, resourcePath.Substring(s_virtualRoot.Length)));
            } 
            else
            {
                warnings.Add(Strings.Warning_VirtualRootNotFound(resourcePath));
            } 
        }
 
        private void ResolveRelativePath(string resourcePath, List metadataPaths, List warnings) 
        {
            IProjectItem rootItem = _webApplication.GetProjectItemFromUrl(s_virtualRoot); 
            if (rootItem != null)
            {
                metadataPaths.Add(String.Concat(rootItem.PhysicalPath, resourcePath));
            } 
            else
            { 
                warnings.Add(Strings.Warning_VirtualRootNotFound(resourcePath)); 
            }
        } 

        // Create a DbConnection for the specified connection string
        private DbConnection GetDbConnection(EntityConnectionStringBuilder connStrBuilder)
        { 
            DbProviderFactory factory = null;
            if (!string.IsNullOrEmpty(connStrBuilder.Provider)) 
            { 
                try
                { 
                    // Get the correct provider factory
                    factory = DbProviderFactories.GetFactory(connStrBuilder.Provider);
                }
                catch (Exception ex) 
                {
                    ShowError(Strings.Error_CannotCreateDbProviderFactory(ex.Message)); 
                } 
            }
            else 
            {
                ShowError(Strings.Error_CannotCreateDbProviderFactory(Strings.Error_MissingProviderKeyword));
            }
 
            if (factory != null)
            { 
                try 
                {
 
                    // Create the underlying provider specific connection and give it the specified provider connection string
                    DbConnection storeConnection = factory.CreateConnection();
                    if (storeConnection != null)
                    { 
                        storeConnection.ConnectionString = connStrBuilder.ProviderConnectionString;
                        return storeConnection; 
                    } 
                }
                catch (Exception) 
                {
                    // eat any exceptions and just show the general error below
                }
 
                ShowError(Strings.Error_ReturnedNullOnProviderMethod(factory.GetType().Name));
            } 
            return null; 
        }
 
        internal void RefreshSchema(bool preferSilent)
        {
            string originalDataDirectory = null;
            try 
            {
                _owner.SuppressDataSourceEvents(); 
                Cursor originalCursor = Cursor.Current; 

                // Make sure we have set the |DataDirectory| field in the AppDomain so that the underlying providers 
                // can make use of this macro
                originalDataDirectory = AppDomain.CurrentDomain.GetData(s_dataDirectoryNoPipes) as string;
                AppDomain.CurrentDomain.SetData(s_dataDirectoryNoPipes, GetDataDirectory());
 
                // Verify that we can get the current schema
                DataTable currentSchema = GetCurrentSchema(preferSilent); 
                if (currentSchema == null) 
                {
                    // error occurred when getting current schema 
                    return;
                }

                try 
                {
                    Cursor.Current = Cursors.WaitCursor; 
 
                    EntityDesignerDataSourceView view = GetView(DefaultViewName);
                    IDataSourceViewSchema oldViewSchema = view.Schema; 
                    bool wasForceUsed = false;
                    if (oldViewSchema == null)
                    {
                        ForceSchemaRetrieval = true; 
                        oldViewSchema = view.Schema;
                        ForceSchemaRetrieval = false; 
                        wasForceUsed = true; 
                    }
 
                    SaveSchema(this.ConnectionString, this.DefaultContainerName, this.EntitySetName, this.Select, this.CommandText, currentSchema);

                    // Compare new schema to old schema and if it changed, raise the SchemaRefreshed event
                    bool viewSchemaEquivalent = _owner.InternalViewSchemasEquivalent(oldViewSchema, view.Schema); 
                    if (!viewSchemaEquivalent)
                    { 
                        _owner.FireOnSchemaRefreshed(EventArgs.Empty); 
                    }
                    else if (wasForceUsed) 
                    {
                        // if the schemas were equivalent but the schema retrieval was forced, still raise the data source changed event
                        _owner.FireOnDataSourceChanged(EventArgs.Empty);
                    } 
                }
                finally 
                { 
                    Cursor.Current = originalCursor;
                } 
            }
            finally
            {
                // Reset the AppDomain to its original |DataDirectory| value 
                AppDomain.CurrentDomain.SetData(s_dataDirectoryNoPipes, originalDataDirectory);
                _owner.ResumeDataSourceEvents(); 
            } 
        }
 
        private DataTable GetCurrentSchema(bool preferSilent)
        {
            // Verify that we have values for a minimum set of properties that will be required to get schema
            if (String.IsNullOrEmpty(this.EntityDataSource.ConnectionString) || 
                String.IsNullOrEmpty(this.EntityDataSource.DefaultContainerName) ||
                String.IsNullOrEmpty(this.EntityDataSource.CommandText) && String.IsNullOrEmpty(this.EntityDataSource.EntitySetName)) 
            { 
                if (!preferSilent)
                { 
                    ShowError(Strings.Error_CannotRefreshSchema_MissingProperties);
                }

                return null; 
            }
 
            bool originalMode = _interactiveMode; 
            try
            { 
                // Suppress error messages while loading metadata if we are in silent mode
                _interactiveMode = !preferSilent;

                // In interactive mode, always clear any cached information so we are sure to get the latest schema 
                // This is necessary in case the metadata or entity classes in referenced assemblies has changed
                // or in case the metadata files have changed without changing any of the properties on the control 
                if (_interactiveMode) 
                {
                    ReloadResources(); 
                    ClearMetadata();
                }

                // Try to load metadata if we don't have it yet 
                if (_entityConnection == null)
                { 
                    if (!LoadMetadata()) 
                    {
                        return null; 
                    }
                    // else metadata was successfully loaded, so continue refreshing schema
                }
            } 
            finally
            { 
                _interactiveMode = originalMode; 
            }
 
            // Either _entityConnection was already set, or we should have successfully loaded it
            Debug.Assert(_entityConnection != null, "_entityConnection should have been initialized");

            try 
            {
                // Create a temporary data source based on the EntityConnection we have built with 
                // the right metadata from the design-time environment 
                EntityDataSource entityDataSource = new EntityDataSource(_entityConnection);
 
                // Copy only the properties that can affect the schema
                entityDataSource.CommandText = this.EntityDataSource.CommandText;
                CopyParameters(this.EntityDataSource.CommandParameters, entityDataSource.CommandParameters);
                entityDataSource.DefaultContainerName = this.EntityDataSource.DefaultContainerName; 
                entityDataSource.EntitySetName = this.EntityDataSource.EntitySetName;
                entityDataSource.EntityTypeFilter = this.EntityDataSource.EntityTypeFilter; 
                entityDataSource.GroupBy = this.EntityDataSource.GroupBy; 
                entityDataSource.Select = this.EntityDataSource.Select;
                CopyParameters(this.EntityDataSource.SelectParameters, entityDataSource.SelectParameters); 

                EntityDataSourceView view = (EntityDataSourceView)(((IDataSource)entityDataSource).GetView(DefaultViewName));
                DataTable viewTable = view.GetViewSchema();
                viewTable.TableName = DefaultViewName; 
                return viewTable;
            } 
            catch (Exception ex) 
            {
                if (!preferSilent) 
                {
                    StringBuilder errorMessage = new StringBuilder();
                    errorMessage.AppendLine(Strings.Error_CannotRefreshSchema_RuntimeException(ex.Message));
                    if (ex.InnerException != null) 
                    {
                        errorMessage.AppendLine(Strings.Error_CannotRefreshSchema_RuntimeException_InnerException(ex.InnerException.Message)); 
                    } 

                    ShowError(errorMessage.ToString()); 
                }
            }

            return null; 
        }
 
        private void CopyParameters(ParameterCollection originalParameters, ParameterCollection newParameters) 
        {
            Debug.Assert(originalParameters != null && newParameters != null, "parameter collections on the data source should never be null"); 
            Debug.Assert(newParameters.Count == 0, "new parameter collection should not contain any parameters yet");

            _owner.CloneParameters(originalParameters, newParameters);
        } 

        // Loads the schema 
        internal DataTable LoadSchema() 
        {
            if (!ForceSchemaRetrieval) 
            {
                // Only check for consistency if we are not forcing the retrieval
                string connectionString = _owner.LoadFromDesignerState(DesignerStateDataSourceConnectionStringKey) as string;
                string defaultContainerName = _owner.LoadFromDesignerState(DesignerStateDataSourceDefaultContainerNameKey) as string; 
                string entitySetName = _owner.LoadFromDesignerState(DesignerStateDataSourceEntitySetNameKey) as string;
                string select = _owner.LoadFromDesignerState(DesignerStateDataSourceSelectKey) as string; 
                string commandText = _owner.LoadFromDesignerState(DesignerStateDataSourceCommandTextKey) as string; 

                if (!String.Equals(connectionString, this.ConnectionString, StringComparison.OrdinalIgnoreCase) || 
                    !String.Equals(defaultContainerName, this.DefaultContainerName, StringComparison.OrdinalIgnoreCase) ||
                    !String.Equals(entitySetName, this.EntitySetName, StringComparison.OrdinalIgnoreCase) ||
                    !String.Equals(select, this.Select, StringComparison.OrdinalIgnoreCase) ||
                    !String.Equals(commandText, this.CommandText, StringComparison.OrdinalIgnoreCase)) 
                {
                    return null; 
                } 
            }
 
            // Either we are forcing schema retrieval, or we're not forcing but we're consistent, so get the schema
            DataTable schema = _owner.LoadFromDesignerState(DesignerStateDataSourceSchemaKey) as DataTable;
            return schema;
        } 

        private void SaveSchema(string connectionString, string defaultContainerName, string entitySetName, 
            string select, string commandText, DataTable currentSchema) 
        {
            // Save the schema to DesignerState 
            _owner.SaveDesignerState(DesignerStateDataSourceConnectionStringKey, connectionString);
            _owner.SaveDesignerState(DesignerStateDataSourceDefaultContainerNameKey, defaultContainerName);
            _owner.SaveDesignerState(DesignerStateDataSourceEntitySetNameKey, entitySetName);
            _owner.SaveDesignerState(DesignerStateDataSourceSelectKey, select); 
            _owner.SaveDesignerState(DesignerStateDataSourceCommandTextKey, commandText);
            _owner.SaveDesignerState(DesignerStateDataSourceSchemaKey, currentSchema); 
        } 

        // Gets a view (can only get the default view) 
        internal EntityDesignerDataSourceView GetView(string viewName)
        {
            if (String.IsNullOrEmpty(viewName) ||
                String.Equals(viewName, DefaultViewName, StringComparison.OrdinalIgnoreCase)) 
            {
                if (View == null) 
                { 
                    View = new EntityDesignerDataSourceView(_owner);
                } 
                return View;
            }
            return null;
        } 

        // Gets a list of view names 
        internal string[] GetViewNames() 
        {
            return new string[] { DefaultViewName }; 
        }

        // Caller can specify that the results should not be sorted if they may add something to the list and sort themselves
        internal List GetContainerNames(bool sortResults) 
        {
            List entityContainerItems = new List(); 
            if (this.EdmItemCollection != null) 
            {
                ReadOnlyCollection entityContainers = this.EdmItemCollection.GetItems(); 
                foreach (EntityContainer entityContainer in entityContainers)
                {
                    entityContainerItems.Add(new EntityDataSourceContainerNameItem(entityContainer));
                } 

                if (sortResults) 
                { 
                    entityContainerItems.Sort();
                } 
            }
            return entityContainerItems;
        }
 
        internal EntityDataSourceContainerNameItem GetEntityContainerItem(string entityContainerName)
        { 
            if (String.IsNullOrEmpty(entityContainerName)) 
            {
                return null; // can't make a valid wrapper with an empty container name 
            }

            EntityContainer container = null;
            if (this.EdmItemCollection != null && 
                this.EdmItemCollection.TryGetEntityContainer(entityContainerName, true /*ignoreCase*/, out container) &&
                container != null) 
            { 
                return new EntityDataSourceContainerNameItem(container);
            } 
            else
            {
                return new EntityDataSourceContainerNameItem(entityContainerName);
            } 
        }
 
        internal List GetEntitySets(string entityContainerName) 
        {
            EntityContainer container = null; 
            if (this.EdmItemCollection != null)
            {
                this.EdmItemCollection.TryGetEntityContainer(entityContainerName, true /*ignoreCase*/, out container);
            } 
            return GetEntitySets(container, true /*sortResults*/);
        } 
 
        // Caller can specify that the results should not be sorted if they may add something to the list and sort themselves
        internal List GetEntitySets(EntityContainer entityContainer, bool sortResults) 
        {
            List entitySetNameItems = new List();
            if (entityContainer != null)
            { 
                foreach (EntitySetBase entitySetBase in entityContainer.BaseEntitySets)
                { 
                    // BaseEntitySets returns RelationshipSets too, but we only want EntitySets 
                    if (entitySetBase.BuiltInTypeKind == BuiltInTypeKind.EntitySet)
                    { 
                        entitySetNameItems.Add(new EntityDataSourceEntitySetNameItem(entitySetBase as EntitySet));
                    }
                }
 
                if (sortResults)
                { 
                    entitySetNameItems.Sort(); 
                }
            } 
            return entitySetNameItems;
        }

        // Caller can specify that the results should not be sorted if they may add something to the list and sort themselves 
        internal List GetNamedEntityClientConnections(bool sortResults)
        { 
            List namedEntityClientConnections = new List(); 

            System.Configuration.Configuration webConfig = _webApplication.OpenWebConfiguration(true /*isReadOnly*/); 
            if (webConfig != null)
            {
                try
                { 
                    foreach (ConnectionStringSettings connStrSettings in webConfig.ConnectionStrings.ConnectionStrings)
                    { 
                        if (connStrSettings.ProviderName == s_entityClientProviderName) 
                        {
                            EntityConnectionStringBuilder connStrBuilder = new EntityConnectionStringBuilder(); 
                            connStrBuilder.Name = connStrSettings.Name;
                            namedEntityClientConnections.Add(new EntityConnectionStringBuilderItem(connStrBuilder));
                        }
                    } 

                    if (sortResults) 
                    { 
                        namedEntityClientConnections.Sort();
                    } 
                }
                catch (ConfigurationException ce)
                {
                    CanLoadWebConfig = false; 
                    namedEntityClientConnections.Clear();
                    StringBuilder error = new StringBuilder(); 
                    error.AppendLine(Strings.Warning_CannotOpenWebConfig_AllConnections); 
                    error.AppendLine();
                    error.AppendLine(ce.Message); 
                    ShowWarning(error.ToString());
                }
            }
            else 
            {
                ShowWarning(Strings.Warning_CannotOpenWebConfig_AllConnections); 
             } 

            return namedEntityClientConnections; 
        }

        internal EntityConnectionStringBuilderItem GetEntityConnectionStringBuilderItem(string connectionString)
        { 
            EntityConnectionStringBuilder connStrBuilder = VerifyConnectionString(connectionString, true /*allowNamedConnections*/);
            if (connStrBuilder != null) 
            { 
                return new EntityConnectionStringBuilderItem(connStrBuilder);
            } 
            else
            {
                return new EntityConnectionStringBuilderItem(connectionString);
            } 
        }
 
        internal List GetEntityTypeProperties(EntityType entityType) 
        {
            List properties = new List(); 
            foreach (EdmProperty property in entityType.Properties)
            {
                properties.Add(property.Name);
            } 

            Debug.Assert(properties.Count > 0, "expected entity to have at least one property"); 
 
            // don't sort the properties here because it will cause them to be displayed to the user in a non-intuitive order
 
            return properties;
        }

        internal List GetEntityTypeFilters(string entityContainerName, string entitySetName) 
        {
            EntityType baseEntitySetType = null; 
            if (this.EdmItemCollection != null) 
            {
                EntityContainer container; 
                if (this.EdmItemCollection.TryGetEntityContainer(entityContainerName, true /*ignoreCase*/, out container) && (container != null))
                {
                    EntitySet entitySet;
                    if (container.TryGetEntitySetByName(entitySetName, true /*ignoreCase*/, out entitySet) && entitySet != null) 
                    {
                        baseEntitySetType = entitySet.ElementType; 
                    } 
                }
            } 
            return GetEntityTypeFilters(baseEntitySetType, true /*sortResults*/);
        }

        internal List GetEntityTypeFilters(EntityType baseEntitySetType, bool sortResults) 
        {
            List derivedTypes = new List(); 
 
            if (baseEntitySetType != null && this.EdmItemCollection != null)
            { 
                foreach (EntityType entityType in GetTypeAndSubtypesOf(baseEntitySetType, this.EdmItemCollection))
                {
                    derivedTypes.Add(new EntityDataSourceEntityTypeFilterItem(entityType));
                } 

                if (sortResults) 
                { 
                    derivedTypes.Sort();
                } 
            }
            return derivedTypes;
        }
 
        #region Helper methods for finding possible types for EntityTypeFilter
        private static IEnumerable GetTypeAndSubtypesOf(EntityType entityType, EdmItemCollection itemCollection) 
        { 
            // Always include the specified type, even if it's abstract
            yield return entityType; 

            // Get the subtypes of the type from the item collection
            IEnumerable entityTypesInCollection = itemCollection.OfType();
            foreach (EntityType typeInCollection in entityTypesInCollection) 
            {
                if (entityType.Equals(typeInCollection) == false && IsStrictSubtypeOf(typeInCollection, entityType)) 
                { 
                    yield return typeInCollection;
                } 
            }

            yield break;
        } 

        // requires: firstType is not null 
        // effects: if otherType is among the base types, return true, 
        // otherwise returns false.
        // when othertype is same as the current type, return false. 
        private static bool IsStrictSubtypeOf(EntityType firstType, EntityType secondType)
        {
            Debug.Assert(firstType != null, "firstType should not be not null");
            if (secondType == null) 
            {
                return false; 
            } 

            // walk up my type hierarchy list 
            for (EntityType t = (EntityType)firstType.BaseType; t != null; t = (EntityType)t.BaseType)
            {
                if (t == secondType)
                    return true; 
            }
            return false; 
        } 
        #endregion
 
        // Copy properties from temporary state to the data source
        internal void SaveEntityDataSourceProperties(EntityDataSourceState state)
        {
            this.EntityDataSource.ConnectionString = state.ConnectionString; 
            this.EntityDataSource.DefaultContainerName = state.DefaultContainerName;
            this.EntityDataSource.EnableDelete = state.EnableDelete; 
            this.EntityDataSource.EnableInsert = state.EnableInsert; 
            this.EntityDataSource.EnableUpdate = state.EnableUpdate;
            this.EntityDataSource.EntitySetName = state.EntitySetName; 
            this.EntityDataSource.EntityTypeFilter = state.EntityTypeFilter;
            this.EntityDataSource.Select = state.Select;
        }
 
        // Copy  properties from the data source to temporary state
        internal EntityDataSourceState LoadEntityDataSourceState() 
        { 
            EntityDataSourceState state = new EntityDataSourceState();
            state.ConnectionString = this.EntityDataSource.ConnectionString; 
            state.DefaultContainerName = this.EntityDataSource.DefaultContainerName;
            state.EnableDelete = this.EntityDataSource.EnableDelete;
            state.EnableInsert = this.EntityDataSource.EnableInsert;
            state.EnableUpdate = this.EntityDataSource.EnableUpdate; 
            state.EntitySetName = this.EntityDataSource.EntitySetName;
            state.EntityTypeFilter = this.EntityDataSource.EntityTypeFilter; 
            state.Select = this.EntityDataSource.Select; 
            return state;
        } 
    }
}

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

Link Menu

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