storagemappingitemcollection.viewdictionary.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Mapping / storagemappingitemcollection.viewdictionary.cs / 3 / storagemappingitemcollection.viewdictionary.cs

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

using System.Data.Common.Utils; 
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Data.Common.CommandTrees; 
using System.Data.Metadata.Edm;
using System.Data.Mapping.ViewGeneration; 
using System.Reflection; 
using System.Data.Mapping.Update.Internal;
using System.Linq; 

// All methods prefixed with 'Serialized' have locked access through the shared Memoizer. Do not call it from outside the Memoizer's scope.
namespace System.Data.Mapping
{ 
    using OfTypeQVCacheKey = Pair>;
 
    public partial class StorageMappingItemCollection : MappingItemCollection 
    {
        internal delegate bool TryGetUserDefinedQueryView(EntitySetBase extent, out GeneratedView generatedView); 
        internal delegate bool TryGetUserDefinedQueryViewOfType(OfTypeQVCacheKey extent, out GeneratedView generatedView);

        internal class ViewDictionary
        { 

            readonly TryGetUserDefinedQueryView TryGetUserDefinedQueryView; 
            readonly TryGetUserDefinedQueryViewOfType TryGetUserDefinedQueryViewOfType; 

            private StorageMappingItemCollection m_storageMappingItemCollection; 

            private static ConfigViewGenerator m_config = new ConfigViewGenerator();

            // List of assemblies from which we have loaded views from 
            private List m_knownViewGenAssemblies = new List();
 
            // indicates whether the views are being fetched from a generated class or they are being generated at the runtime 
            private bool m_generatedViewsMode = true;
 
            //Caches computation of view generation (of all EntitySets) for a given EntityContainer
            private readonly Memoizer> m_generatedViewsMemoizer;

            //Caches computation of getting Type-specific Query Views - either by view gen or user-defined input 
            private readonly Memoizer m_generatedViewOfTypeMemoizer;
 
            internal ViewDictionary(StorageMappingItemCollection storageMappingItemCollection, 
                            out Dictionary userDefinedQueryViewsDict,
                            out Dictionary userDefinedQueryViewsOfTypeDict) 
            {
                this.m_storageMappingItemCollection = storageMappingItemCollection;
                this.m_generatedViewsMemoizer = new Memoizer>(SerializedGetGeneratedViews
                    , null); 
                this.m_generatedViewOfTypeMemoizer = new Memoizer(SerializedGeneratedViewOfType, OfTypeQVCacheKey.PairComparer.Instance);
 
                userDefinedQueryViewsDict = new Dictionary(EqualityComparer.Default); 
                userDefinedQueryViewsOfTypeDict = new Dictionary(OfTypeQVCacheKey.PairComparer.Instance);
 
                TryGetUserDefinedQueryView = userDefinedQueryViewsDict.TryGetValue;
                TryGetUserDefinedQueryViewOfType = userDefinedQueryViewsOfTypeDict.TryGetValue;
            }
 

            private Dictionary SerializedGetGeneratedViews(EntityContainer container) 
            { 
                Dictionary extentMappingViews = new Dictionary(); ;
 
                MetadataWorkspace workspace = new MetadataWorkspace();
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.StoreItemCollection);
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.EdmItemCollection);
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection); 

                //If we are in generated views mode 
                if (m_generatedViewsMode) 
                {
                    if(ObjectItemCollection.ViewGenerationAssemblies!=null && ObjectItemCollection.ViewGenerationAssemblies.Count>0) 
                    {
                        SerializedCollectViewsFromObjectCollection(workspace, this.m_storageMappingItemCollection, extentMappingViews);
                    }
                    else 
                    {
                        SerializedCollectViewsFromReferencedAssemblies(workspace, this.m_storageMappingItemCollection, extentMappingViews); 
                    } 

                    if (this.m_knownViewGenAssemblies.Count != 0) 
                    {
                        EntityBid.Trace(" The View generation Mode is Compile Time View Generation\n");
                    }
                } 

                if (extentMappingViews.Count==0) 
                { 
                    //We should change the mode to runtime generation of views.
                    this.m_generatedViewsMode = false; 
                    EntityBid.Trace(" The View generation Mode is Runtime View Generation\n");
                    this.SerializedGenerateViews(container, extentMappingViews);

                } 

                Debug.Assert(extentMappingViews.Count>0, "view should be generated at this point"); 
 
                return extentMappingViews;
            } 

            /// 
            /// Call the View Generator's Generate view method
            /// and collect the Views and store it in a local dictionary. 
            /// 
            ///  
            ///  
            private void SerializedGenerateViews(EntityContainer container, Dictionary resultDictionary)
            { 
                Debug.Assert(container != null);

                MetadataWorkspace metadataWorkspace = new MetadataWorkspace();
                metadataWorkspace.RegisterItemCollection(m_storageMappingItemCollection.EdmItemCollection); 
                metadataWorkspace.RegisterItemCollection(m_storageMappingItemCollection.StoreItemCollection);
                metadataWorkspace.RegisterItemCollection(m_storageMappingItemCollection); 
 
                //Get the mapping that has the entity container
                //mapped. 
                StorageEntityContainerMapping entityContainerMap = MappingMetadataHelper.GetEntityContainerMap(m_storageMappingItemCollection, container);
                //If there are no entity set maps, don't call the view generation process
                if (entityContainerMap.IsEmpty)
                { 
                    return;
                } 
                ViewGenResults viewGenResults = ViewGenerator.GenerateViewsForSchema(entityContainerMap, metadataWorkspace, m_config); 
                KeyToListMap extentMappingViews = viewGenResults.Views;
                if (viewGenResults.HasErrors) 
                {
                    // Can get the list of errors using viewGenResults.Errors

                    throw new MappingException(Helper.CombineErrorMessage(viewGenResults.Errors)); 
                }
 
                foreach (KeyValuePair> keyValuePair in extentMappingViews.KeyValuePairs) 
                {
                    //Multiple Views are returned for an extent but the first view 
                    //is the only one that we will use for now. In the future,
                    //we might start using the other views which are per type within an extent.
                    GeneratedView generatedView;
                    //Add the view to the local dictionary 

                    if (!resultDictionary.TryGetValue(keyValuePair.Key, out generatedView)) 
                    { 
                        generatedView = keyValuePair.Value[0];
                        resultDictionary.Add(keyValuePair.Key, generatedView); 
                    }
                }
            }
 
            /// 
            /// Generates a single query view for a given Extent and type. It is used to generate OfType and OfTypeOnly views. 
            ///  
            /// Whether the view should include extents that are subtypes of the given entity
            private bool TryGenerateQueryViewOfType(EntityContainer entityContainer, EntitySetBase entity, EntityTypeBase type, bool includeSubtypes, out GeneratedView generatedView) 
            {
                Debug.Assert(entityContainer != null);
                Debug.Assert(entity != null);
                Debug.Assert(type != null); 

                MetadataWorkspace workspace = new MetadataWorkspace(); 
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.EdmItemCollection); 
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.StoreItemCollection);
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection); 

                if (type.Abstract)
                {
                    generatedView = null; 
                    return false;
                } 
 
                //Get the mapping that has the entity container mapped.
                StorageEntityContainerMapping entityContainerMap = MappingMetadataHelper.GetEntityContainerMap(m_storageMappingItemCollection, entityContainer); 
                Debug.Assert(!entityContainerMap.IsEmpty, "There are no entity set maps");

                bool success;
                ViewGenResults viewGenResults = ViewGenerator.GenerateQueryViewOfType(entityContainerMap, workspace, m_config, entity, type, includeSubtypes, out success); 
                if (!success)
                { 
                    generatedView = null; 
                    return false; //could not generate view
                } 

                KeyToListMap extentMappingViews = viewGenResults.Views;

                if (viewGenResults.HasErrors) 
                {
                    throw new MappingException(Helper.CombineErrorMessage(viewGenResults.Errors)); 
                } 

                Debug.Assert(extentMappingViews.AllValues.Count() == 1, "Viewgen should have produced only one view"); 
                generatedView = extentMappingViews.AllValues.First();

                return true;
            } 

            ///  
            /// Tries to generate the Oftype or OfTypeOnly query view for a given entity set and type. 
            /// Returns false if the view could not be generated.
            /// Possible reasons for failing are 
            ///   1) Passing in OfTypeOnly on an abstract type
            ///   2) In user-specified query views mode a query for the given type is absent
            /// 
            internal bool TryGetGeneratedViewOfType(MetadataWorkspace workspace, EntitySetBase entity, EntityTypeBase type, bool includeSubtypes, out GeneratedView generatedView) 
            {
                OfTypeQVCacheKey key = new OfTypeQVCacheKey(entity, new Pair(type, includeSubtypes)); 
                generatedView = this.m_generatedViewOfTypeMemoizer.Evaluate(key); 
                return (generatedView != null);
            } 

            /// 
            /// Note: Null return value implies QV was not generated.
            ///  
            /// 
            private GeneratedView SerializedGeneratedViewOfType(OfTypeQVCacheKey arg) 
            { 
                GeneratedView generatedView;
                //See if we have collected user-defined QueryView 
                if(TryGetUserDefinedQueryViewOfType(arg, out generatedView))
                {
                    return generatedView;
                } 

                //Now we have to generate the type-specific view 
                EntitySetBase entity = arg.First; 
                EntityTypeBase type = arg.Second.First;
                bool includeSubtypes = arg.Second.Second; 

                if (!TryGenerateQueryViewOfType(entity.EntityContainer, entity, type, includeSubtypes, out generatedView))
                {
                    generatedView = null; 
                }
 
                return generatedView; 
            }
 
            /// 
            /// Returns the update or query view for an Extent as a
            /// string.
            /// There are a series of steps that we go through for discovering a view for an extent. 
            /// To start with we assume that we are working with Generated Views. To find out the
            /// generated view we go to the ObjectItemCollection and see if it is not-null. If the ObjectItemCollection 
            /// is non-null, we get the view generation assemblies that it might have cached during the 
            /// Object metadata discovery.If there are no view generation assemblies we switch to the
            /// runtime view generation strategy. If there are view generation assemblies, we get the list and 
            /// go through them and see if there are any assemblies that are there from which we have not already loaded
            /// the views. We collect the views from assemblies that we have not already collected from earlier.
            /// If the ObjectItemCollection is null and we are in the view generation mode, that means that
            /// the query or update is issued from the Value layer and this is the first time view has been asked for. 
            /// The compile time view gen for value layer queries will work for very simple scenarios.
            /// If the users wants to get the performance benefit, they should call MetadataWorkspace.LoadFromAssembly. 
            /// At this point we go through the referenced assemblies of the entry assembly( this wont work for Asp.net 
            /// or if the viewgen assembly was not referenced by the executing application).
            /// and try to see if there were any view gen assemblies. If there are, we collect the views for all extents. 
            /// Once we have all the generated views gathered, we try to get the view for the extent passed in.
            /// If we find one we will return it. If we can't find one an exception will be thrown.
            /// If there were no view gen assemblies either in the ObjectItemCollection or in the list of referenced
            /// assemblies of calling assembly, we change the mode to runtime view generation and will continue to 
            /// be in that mode for the rest of the lifetime of the mapping item collection.
            ///  
            internal GeneratedView GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection) 
            {
                //First check if we have collected a view from user-defined query views 
                //Dont need to worry whether to generate Query view or update viw, because that is relative to the extent.
                GeneratedView view;

                if (TryGetUserDefinedQueryView(extent, out view)) 
                {
                    return view; 
                } 

                //If no User-defined QV is found, call memoized View Generation procedure 
                Dictionary generatedViews = m_generatedViewsMemoizer.Evaluate(extent.EntityContainer);

                if (!generatedViews.TryGetValue(extent, out view))
                { 
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Mapping_Views_For_Extent_Not_Generated(
                        (extent.GetDataSpace()==DataSpace.SSpace)?"Table":"EntitySet",extent.Name)); 
                } 

                return view; 
            }

            /// 
            /// Collect the views from object collection's view gen assembly 
            /// 
            ///  
            ///  
            private void SerializedCollectViewsFromObjectCollection(MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection, Dictionary extentMappingViews)
            { 
                IList allViewGenAssemblies = ObjectItemCollection.ViewGenerationAssemblies;
                if (allViewGenAssemblies != null)
                {
                    foreach (Assembly assembly in allViewGenAssemblies) 
                    {
                        object[] viewGenAttributes = assembly.GetCustomAttributes(typeof(System.Data.Mapping.EntityViewGenerationAttribute), false /*inherit*/); 
                        if ((viewGenAttributes != null) && (viewGenAttributes.Length != 0)) 
                        {
                            foreach (EntityViewGenerationAttribute viewGenAttribute in viewGenAttributes) 
                            {
                                Type viewContainerType = viewGenAttribute.ViewGenerationType;
                                if (!viewContainerType.IsSubclassOf(typeof(EntityViewContainer)))
                                { 
                                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Generated_View_Type_Super_Class_1(StorageMslConstructs.EntityViewGenerationTypeName));
                                } 
                                EntityViewContainer viewContainer = (Activator.CreateInstance(viewContainerType) as EntityViewContainer); 
                                Debug.Assert(viewContainer != null, "Should be able to create the type");
 
                                if (SerializedAddGeneratedViewsInEntityViewContainer(workspace, viewContainer, storageMappingItemCollection, extentMappingViews))
                                {
                                    EntityBid.Trace(" Collected views from Assembly='%ls'\n", assembly.FullName);
                                } 
                            }
                        } 
                    } 
                }
            } 

            /// 
            /// this method do the following check on the generated views in the EntityViewContainer,
            /// then add those views all at once to the dicitionary 
            /// 1. there should be one storeageEntityContainerMapping that has the same h
            ///     C side and S side names as the EnittyViewcontainer 
            /// 2. Generate the hash for the storageEntityContainerMapping in the MM closure, 
            ///     and this hash should be the same in EntityViewContainer
            /// 3. Generate the hash for all of the view text in the EntityViewContainer and 
            ///     this hash should be the same as the stored on in the EntityViewContainer
            /// 
            /// 
            ///  
            private bool SerializedAddGeneratedViewsInEntityViewContainer(MetadataWorkspace workspace, EntityViewContainer entityViewContainer, StorageMappingItemCollection storageMappingItemCollection, Dictionary extentMappingViews)
            { 
                StorageEntityContainerMapping storageEntityContainerMapping; 
                // first check
                if (this.TryGetCorrespondingStorageEntityContainerMapping(entityViewContainer, 
                    storageMappingItemCollection.GetItems(), out storageEntityContainerMapping))
                {

                    // second check 
                    if (this.SerializedVerifyHashOverMmClosure(storageEntityContainerMapping, entityViewContainer, workspace.GetItemCollection(DataSpace.CSpace)))
                    { 
                        // third check, prior to the check, we collect all the views in the entity view container to the dictionary 
                        // if the views are changed then we will throw exception out
                        if (this.VerifyViewsHaveNotChanged(workspace, entityViewContainer)) 
                        {
                            this.SerializedAddGeneratedViews(workspace, entityViewContainer, extentMappingViews);
                            return true;
                        } 
                        else
                        { 
                            throw new InvalidOperationException(System.Data.Entity.Strings.Generated_Views_Changed); 
                        }
                    } 
                    else
                    {
                        throw new MappingException(Data.Entity.Strings.ViewGen_HashOnMappingClosure_Not_Matching(entityViewContainer.EdmEntityContainerName));
                    } 
                }
                return false; 
 
            }
 
            private bool TryGetCorrespondingStorageEntityContainerMapping(EntityViewContainer viewContainer,
                IEnumerable storageEntityContainerMappingList, out StorageEntityContainerMapping storageEntityContainerMapping)
            {
                storageEntityContainerMapping = null; 

                foreach (var entityContainerMapping in storageEntityContainerMappingList) 
                { 
                    // first check
                    if (entityContainerMapping.EdmEntityContainer.Name == viewContainer.EdmEntityContainerName && 
                        entityContainerMapping.StorageEntityContainer.Name == viewContainer.StoreEntityContainerName)
                    {
                        storageEntityContainerMapping = entityContainerMapping;
                        return true; 
                    }
                } 
                return false; 

            } 

            private bool SerializedVerifyHashOverMmClosure(StorageEntityContainerMapping entityContainerMapping, EntityViewContainer entityViewContainer, ItemCollection itemCollection)
            {
                if (MetadataMappingHasherVisitor.GetMappingClosureHash(entityContainerMapping, itemCollection) == 
                    entityViewContainer.HashOverMappingClosure)
                { 
                    return true; 
                }
                return false; 
            }

            private bool VerifyViewsHaveNotChanged(MetadataWorkspace workspace, EntityViewContainer viewContainer)
            { 
                //Now check whether the hash of the generated views match the one
                //we stored in the code file during design 
                //Produce the hash and add it to the code 
                string viewHash = MetadataHelper.GenerateHashForAllExtentViewsContent(viewContainer.ExtentViews);
                string storedViewHash = viewContainer.HashOverAllExtentViews; 
                if (viewHash != storedViewHash)
                {
                    return false;
                } 
                return true;
            } 
 

            //Collect the names of the entitysetbases and the generated views from 
            //the generated type into a string so that we can produce a hash over it.
            private void SerializedAddGeneratedViews(MetadataWorkspace workspace, EntityViewContainer viewContainer, Dictionary extentMappingViews)
            {
                foreach (KeyValuePair extentView in viewContainer.ExtentViews) 
                {
                    EntityContainer entityContainer = null; 
                    EntitySetBase extent = null; 

 
                    string extentFullName = extentView.Key;
                    int extentNameIndex = extentFullName.LastIndexOf('.');

                    if (extentNameIndex != -1) 
                    {
                        string entityContainerName = extentFullName.Substring(0, extentNameIndex); 
                        string extentName = extentFullName.Substring(extentFullName.LastIndexOf('.') + 1); 

                        if (!workspace.TryGetItem(entityContainerName, DataSpace.CSpace, out entityContainer)) 
                        {
                            workspace.TryGetItem(entityContainerName, DataSpace.SSpace, out entityContainer);
                        }
 
                        if (entityContainer != null)
                        { 
                            entityContainer.BaseEntitySets.TryGetValue(extentName, false, out extent); 
                        }
                    } 

                    if (extent == null)
                    {
                        throw new MappingException(System.Data.Entity.Strings.Generated_Views_Invalid_Extent_1(extentFullName)); 
                    }
 
                    //Create a Generated view and cache it 
                    GeneratedView generatedView;
                    //Add the view to the local dictionary 
                    if (!extentMappingViews.TryGetValue(extent, out generatedView))
                    {
                        generatedView = new GeneratedView(extent, null /*edmType*/, extentView.Value, workspace,
                                            new ConfigViewGenerator()); 
                        extentMappingViews.Add(extent, generatedView);
                    } 
                } 
            }
 

            /// 
            /// Tries to collect the views from the referenced assemblies of Entry assembly.
            ///  
            /// 
            private void SerializedCollectViewsFromReferencedAssemblies(MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection, Dictionary extentMappingViews) 
            { 
                ObjectItemCollection objectCollection;
                ItemCollection itemCollection; 
                if (!workspace.TryGetItemCollection(DataSpace.OSpace, out itemCollection))
                {
                    //Possible enhancement : Think about achieving the same thing without creating Object Item Collection.
                    objectCollection = new ObjectItemCollection(); 
                    itemCollection = objectCollection;
                    // The GetEntryAssembly method can return a null reference 
                    //when a managed assembly has been loaded from an unmanaged application. 
                    Assembly entryAssembly = Assembly.GetEntryAssembly();
                    if (entryAssembly != null) 
                    {
                        objectCollection.LoadAllReferencedAssemblies(entryAssembly, true);
                    }
                } 
                this.SerializedCollectViewsFromObjectCollection(workspace, storageMappingItemCollection, extentMappingViews);
            } 
 
            /// 
            /// This method collect all the user defined query views in MSL 
            /// Assumption: This method is called only from the StorageMappingItemCollection's constructor
            /// and no other thread can be calling ViewDictionary.GetGeneratedViews() at the same time.
            /// m_extentMappingViews and m_extentTypeQueryViews are not thread safe.
            ///  
            /// 
            ///  
            internal static void CollectViews(StorageEntityContainerMapping entityContainerMapping, StorageMappingItemCollection storageMappingItemCollection, 
                IList errors, Dictionary userDefinedQueryViewsDict, Dictionary userDefinedQueryViewsOfTypeDict)
            { 
                //Create a new MetadataWorkspace, since Query needs it to compile Query
                //Since the MetadataWorkspace really is a thin wrapper over item collections,
                //this should not pose a problem.
                MetadataWorkspace workspace = new MetadataWorkspace(); 
                workspace.RegisterItemCollection(storageMappingItemCollection.m_edmCollection);
                workspace.RegisterItemCollection(storageMappingItemCollection.m_storeItemCollection); 
                workspace.RegisterItemCollection(storageMappingItemCollection); 
                ConfigViewGenerator config = new ConfigViewGenerator();
 
                foreach (StorageSetMapping setMapping in entityContainerMapping.AllSetMaps)
                {
                    if (setMapping.QueryView != null)
                    { 
                        GeneratedView generatedView;
                        if (!userDefinedQueryViewsDict.TryGetValue(setMapping.Set, out generatedView)) 
                        { 
                            // Parse the view so that we will get back any errors in the view
                            // Catch the query exception and add it as a parser error 
                            try
                            {
                                //Add first QueryView
                                generatedView = new GeneratedView(setMapping.Set, 
                                                              setMapping.Set.ElementType, setMapping.QueryView.Trim(), workspace,
                                                              config); 
 
                                bool validationError = false;
                                foreach (EdmSchemaError error in generatedView.ParseUserSpecifiedView(workspace, 
                                    storageMappingItemCollection.StoreItemCollection, setMapping, setMapping.Set.ElementType, true /* includeSubtypes*/))
                                {
                                    validationError = true;
                                    errors.Add(error); 
                                }
                                if (!validationError) 
                                { 
                                    userDefinedQueryViewsDict.Add(setMapping.Set, generatedView);
                                } 

                                //Add all type-specific QueryViews
                                foreach (OfTypeQVCacheKey key in setMapping.GetTypeSpecificQVKeys())
                                { 
                                    Debug.Assert(key.First.Equals(setMapping.Set));
 
                                    generatedView = new GeneratedView(setMapping.Set, 
                                                              key.Second.First /*EntityType*/,
                                                              setMapping.GetTypeSpecificQueryView(key) /*QV*/, 
                                                              workspace, config);

                                    validationError = false;
                                    foreach (EdmSchemaError error in generatedView.ParseUserSpecifiedView(workspace, storageMappingItemCollection.StoreItemCollection, setMapping, key.Second.First, key.Second.Second)) 
                                    {
                                        validationError = true; 
                                        errors.Add(error); 
                                    }
 
                                    if (!validationError)
                                    {
                                        userDefinedQueryViewsOfTypeDict.Add(key, generatedView);
                                    } 

                                } 
                            } 
                            catch (Exception e)
                            { 
                                //catching all the exception types since Query parser seems to be throwing veriety of
                                //exceptions - EntityException, ArgumentException, ArgumentNullException etc.
                                if (EntityUtil.IsCatchableExceptionType(e))
                                { 
                                    EdmSchemaError error = new EdmSchemaError(System.Data.Entity.Strings.Mapping_Invalid_QueryView_2(setMapping.Set.Name, e.Message),
                                                               (int)StorageMappingErrorCode.InvalidQueryView, EdmSchemaErrorSeverity.Error, 
                                                               setMapping.EntityContainerMapping.SourceLocation, setMapping.StartLineNumber, setMapping.StartLinePosition, e); 
                                    errors.Add(error);
                                } 
                                else
                                {
                                    throw;
                                } 
                            }
                        } 
                    } 
                }
            } 
        }
    }
}

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

using System.Data.Common.Utils; 
using System.Diagnostics;
using System.Collections.Generic;
using System.Text;
using System.Data.Common.CommandTrees; 
using System.Data.Metadata.Edm;
using System.Data.Mapping.ViewGeneration; 
using System.Reflection; 
using System.Data.Mapping.Update.Internal;
using System.Linq; 

// All methods prefixed with 'Serialized' have locked access through the shared Memoizer. Do not call it from outside the Memoizer's scope.
namespace System.Data.Mapping
{ 
    using OfTypeQVCacheKey = Pair>;
 
    public partial class StorageMappingItemCollection : MappingItemCollection 
    {
        internal delegate bool TryGetUserDefinedQueryView(EntitySetBase extent, out GeneratedView generatedView); 
        internal delegate bool TryGetUserDefinedQueryViewOfType(OfTypeQVCacheKey extent, out GeneratedView generatedView);

        internal class ViewDictionary
        { 

            readonly TryGetUserDefinedQueryView TryGetUserDefinedQueryView; 
            readonly TryGetUserDefinedQueryViewOfType TryGetUserDefinedQueryViewOfType; 

            private StorageMappingItemCollection m_storageMappingItemCollection; 

            private static ConfigViewGenerator m_config = new ConfigViewGenerator();

            // List of assemblies from which we have loaded views from 
            private List m_knownViewGenAssemblies = new List();
 
            // indicates whether the views are being fetched from a generated class or they are being generated at the runtime 
            private bool m_generatedViewsMode = true;
 
            //Caches computation of view generation (of all EntitySets) for a given EntityContainer
            private readonly Memoizer> m_generatedViewsMemoizer;

            //Caches computation of getting Type-specific Query Views - either by view gen or user-defined input 
            private readonly Memoizer m_generatedViewOfTypeMemoizer;
 
            internal ViewDictionary(StorageMappingItemCollection storageMappingItemCollection, 
                            out Dictionary userDefinedQueryViewsDict,
                            out Dictionary userDefinedQueryViewsOfTypeDict) 
            {
                this.m_storageMappingItemCollection = storageMappingItemCollection;
                this.m_generatedViewsMemoizer = new Memoizer>(SerializedGetGeneratedViews
                    , null); 
                this.m_generatedViewOfTypeMemoizer = new Memoizer(SerializedGeneratedViewOfType, OfTypeQVCacheKey.PairComparer.Instance);
 
                userDefinedQueryViewsDict = new Dictionary(EqualityComparer.Default); 
                userDefinedQueryViewsOfTypeDict = new Dictionary(OfTypeQVCacheKey.PairComparer.Instance);
 
                TryGetUserDefinedQueryView = userDefinedQueryViewsDict.TryGetValue;
                TryGetUserDefinedQueryViewOfType = userDefinedQueryViewsOfTypeDict.TryGetValue;
            }
 

            private Dictionary SerializedGetGeneratedViews(EntityContainer container) 
            { 
                Dictionary extentMappingViews = new Dictionary(); ;
 
                MetadataWorkspace workspace = new MetadataWorkspace();
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.StoreItemCollection);
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.EdmItemCollection);
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection); 

                //If we are in generated views mode 
                if (m_generatedViewsMode) 
                {
                    if(ObjectItemCollection.ViewGenerationAssemblies!=null && ObjectItemCollection.ViewGenerationAssemblies.Count>0) 
                    {
                        SerializedCollectViewsFromObjectCollection(workspace, this.m_storageMappingItemCollection, extentMappingViews);
                    }
                    else 
                    {
                        SerializedCollectViewsFromReferencedAssemblies(workspace, this.m_storageMappingItemCollection, extentMappingViews); 
                    } 

                    if (this.m_knownViewGenAssemblies.Count != 0) 
                    {
                        EntityBid.Trace(" The View generation Mode is Compile Time View Generation\n");
                    }
                } 

                if (extentMappingViews.Count==0) 
                { 
                    //We should change the mode to runtime generation of views.
                    this.m_generatedViewsMode = false; 
                    EntityBid.Trace(" The View generation Mode is Runtime View Generation\n");
                    this.SerializedGenerateViews(container, extentMappingViews);

                } 

                Debug.Assert(extentMappingViews.Count>0, "view should be generated at this point"); 
 
                return extentMappingViews;
            } 

            /// 
            /// Call the View Generator's Generate view method
            /// and collect the Views and store it in a local dictionary. 
            /// 
            ///  
            ///  
            private void SerializedGenerateViews(EntityContainer container, Dictionary resultDictionary)
            { 
                Debug.Assert(container != null);

                MetadataWorkspace metadataWorkspace = new MetadataWorkspace();
                metadataWorkspace.RegisterItemCollection(m_storageMappingItemCollection.EdmItemCollection); 
                metadataWorkspace.RegisterItemCollection(m_storageMappingItemCollection.StoreItemCollection);
                metadataWorkspace.RegisterItemCollection(m_storageMappingItemCollection); 
 
                //Get the mapping that has the entity container
                //mapped. 
                StorageEntityContainerMapping entityContainerMap = MappingMetadataHelper.GetEntityContainerMap(m_storageMappingItemCollection, container);
                //If there are no entity set maps, don't call the view generation process
                if (entityContainerMap.IsEmpty)
                { 
                    return;
                } 
                ViewGenResults viewGenResults = ViewGenerator.GenerateViewsForSchema(entityContainerMap, metadataWorkspace, m_config); 
                KeyToListMap extentMappingViews = viewGenResults.Views;
                if (viewGenResults.HasErrors) 
                {
                    // Can get the list of errors using viewGenResults.Errors

                    throw new MappingException(Helper.CombineErrorMessage(viewGenResults.Errors)); 
                }
 
                foreach (KeyValuePair> keyValuePair in extentMappingViews.KeyValuePairs) 
                {
                    //Multiple Views are returned for an extent but the first view 
                    //is the only one that we will use for now. In the future,
                    //we might start using the other views which are per type within an extent.
                    GeneratedView generatedView;
                    //Add the view to the local dictionary 

                    if (!resultDictionary.TryGetValue(keyValuePair.Key, out generatedView)) 
                    { 
                        generatedView = keyValuePair.Value[0];
                        resultDictionary.Add(keyValuePair.Key, generatedView); 
                    }
                }
            }
 
            /// 
            /// Generates a single query view for a given Extent and type. It is used to generate OfType and OfTypeOnly views. 
            ///  
            /// Whether the view should include extents that are subtypes of the given entity
            private bool TryGenerateQueryViewOfType(EntityContainer entityContainer, EntitySetBase entity, EntityTypeBase type, bool includeSubtypes, out GeneratedView generatedView) 
            {
                Debug.Assert(entityContainer != null);
                Debug.Assert(entity != null);
                Debug.Assert(type != null); 

                MetadataWorkspace workspace = new MetadataWorkspace(); 
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.EdmItemCollection); 
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection.StoreItemCollection);
                workspace.RegisterItemCollection(this.m_storageMappingItemCollection); 

                if (type.Abstract)
                {
                    generatedView = null; 
                    return false;
                } 
 
                //Get the mapping that has the entity container mapped.
                StorageEntityContainerMapping entityContainerMap = MappingMetadataHelper.GetEntityContainerMap(m_storageMappingItemCollection, entityContainer); 
                Debug.Assert(!entityContainerMap.IsEmpty, "There are no entity set maps");

                bool success;
                ViewGenResults viewGenResults = ViewGenerator.GenerateQueryViewOfType(entityContainerMap, workspace, m_config, entity, type, includeSubtypes, out success); 
                if (!success)
                { 
                    generatedView = null; 
                    return false; //could not generate view
                } 

                KeyToListMap extentMappingViews = viewGenResults.Views;

                if (viewGenResults.HasErrors) 
                {
                    throw new MappingException(Helper.CombineErrorMessage(viewGenResults.Errors)); 
                } 

                Debug.Assert(extentMappingViews.AllValues.Count() == 1, "Viewgen should have produced only one view"); 
                generatedView = extentMappingViews.AllValues.First();

                return true;
            } 

            ///  
            /// Tries to generate the Oftype or OfTypeOnly query view for a given entity set and type. 
            /// Returns false if the view could not be generated.
            /// Possible reasons for failing are 
            ///   1) Passing in OfTypeOnly on an abstract type
            ///   2) In user-specified query views mode a query for the given type is absent
            /// 
            internal bool TryGetGeneratedViewOfType(MetadataWorkspace workspace, EntitySetBase entity, EntityTypeBase type, bool includeSubtypes, out GeneratedView generatedView) 
            {
                OfTypeQVCacheKey key = new OfTypeQVCacheKey(entity, new Pair(type, includeSubtypes)); 
                generatedView = this.m_generatedViewOfTypeMemoizer.Evaluate(key); 
                return (generatedView != null);
            } 

            /// 
            /// Note: Null return value implies QV was not generated.
            ///  
            /// 
            private GeneratedView SerializedGeneratedViewOfType(OfTypeQVCacheKey arg) 
            { 
                GeneratedView generatedView;
                //See if we have collected user-defined QueryView 
                if(TryGetUserDefinedQueryViewOfType(arg, out generatedView))
                {
                    return generatedView;
                } 

                //Now we have to generate the type-specific view 
                EntitySetBase entity = arg.First; 
                EntityTypeBase type = arg.Second.First;
                bool includeSubtypes = arg.Second.Second; 

                if (!TryGenerateQueryViewOfType(entity.EntityContainer, entity, type, includeSubtypes, out generatedView))
                {
                    generatedView = null; 
                }
 
                return generatedView; 
            }
 
            /// 
            /// Returns the update or query view for an Extent as a
            /// string.
            /// There are a series of steps that we go through for discovering a view for an extent. 
            /// To start with we assume that we are working with Generated Views. To find out the
            /// generated view we go to the ObjectItemCollection and see if it is not-null. If the ObjectItemCollection 
            /// is non-null, we get the view generation assemblies that it might have cached during the 
            /// Object metadata discovery.If there are no view generation assemblies we switch to the
            /// runtime view generation strategy. If there are view generation assemblies, we get the list and 
            /// go through them and see if there are any assemblies that are there from which we have not already loaded
            /// the views. We collect the views from assemblies that we have not already collected from earlier.
            /// If the ObjectItemCollection is null and we are in the view generation mode, that means that
            /// the query or update is issued from the Value layer and this is the first time view has been asked for. 
            /// The compile time view gen for value layer queries will work for very simple scenarios.
            /// If the users wants to get the performance benefit, they should call MetadataWorkspace.LoadFromAssembly. 
            /// At this point we go through the referenced assemblies of the entry assembly( this wont work for Asp.net 
            /// or if the viewgen assembly was not referenced by the executing application).
            /// and try to see if there were any view gen assemblies. If there are, we collect the views for all extents. 
            /// Once we have all the generated views gathered, we try to get the view for the extent passed in.
            /// If we find one we will return it. If we can't find one an exception will be thrown.
            /// If there were no view gen assemblies either in the ObjectItemCollection or in the list of referenced
            /// assemblies of calling assembly, we change the mode to runtime view generation and will continue to 
            /// be in that mode for the rest of the lifetime of the mapping item collection.
            ///  
            internal GeneratedView GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection) 
            {
                //First check if we have collected a view from user-defined query views 
                //Dont need to worry whether to generate Query view or update viw, because that is relative to the extent.
                GeneratedView view;

                if (TryGetUserDefinedQueryView(extent, out view)) 
                {
                    return view; 
                } 

                //If no User-defined QV is found, call memoized View Generation procedure 
                Dictionary generatedViews = m_generatedViewsMemoizer.Evaluate(extent.EntityContainer);

                if (!generatedViews.TryGetValue(extent, out view))
                { 
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Mapping_Views_For_Extent_Not_Generated(
                        (extent.GetDataSpace()==DataSpace.SSpace)?"Table":"EntitySet",extent.Name)); 
                } 

                return view; 
            }

            /// 
            /// Collect the views from object collection's view gen assembly 
            /// 
            ///  
            ///  
            private void SerializedCollectViewsFromObjectCollection(MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection, Dictionary extentMappingViews)
            { 
                IList allViewGenAssemblies = ObjectItemCollection.ViewGenerationAssemblies;
                if (allViewGenAssemblies != null)
                {
                    foreach (Assembly assembly in allViewGenAssemblies) 
                    {
                        object[] viewGenAttributes = assembly.GetCustomAttributes(typeof(System.Data.Mapping.EntityViewGenerationAttribute), false /*inherit*/); 
                        if ((viewGenAttributes != null) && (viewGenAttributes.Length != 0)) 
                        {
                            foreach (EntityViewGenerationAttribute viewGenAttribute in viewGenAttributes) 
                            {
                                Type viewContainerType = viewGenAttribute.ViewGenerationType;
                                if (!viewContainerType.IsSubclassOf(typeof(EntityViewContainer)))
                                { 
                                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.Generated_View_Type_Super_Class_1(StorageMslConstructs.EntityViewGenerationTypeName));
                                } 
                                EntityViewContainer viewContainer = (Activator.CreateInstance(viewContainerType) as EntityViewContainer); 
                                Debug.Assert(viewContainer != null, "Should be able to create the type");
 
                                if (SerializedAddGeneratedViewsInEntityViewContainer(workspace, viewContainer, storageMappingItemCollection, extentMappingViews))
                                {
                                    EntityBid.Trace(" Collected views from Assembly='%ls'\n", assembly.FullName);
                                } 
                            }
                        } 
                    } 
                }
            } 

            /// 
            /// this method do the following check on the generated views in the EntityViewContainer,
            /// then add those views all at once to the dicitionary 
            /// 1. there should be one storeageEntityContainerMapping that has the same h
            ///     C side and S side names as the EnittyViewcontainer 
            /// 2. Generate the hash for the storageEntityContainerMapping in the MM closure, 
            ///     and this hash should be the same in EntityViewContainer
            /// 3. Generate the hash for all of the view text in the EntityViewContainer and 
            ///     this hash should be the same as the stored on in the EntityViewContainer
            /// 
            /// 
            ///  
            private bool SerializedAddGeneratedViewsInEntityViewContainer(MetadataWorkspace workspace, EntityViewContainer entityViewContainer, StorageMappingItemCollection storageMappingItemCollection, Dictionary extentMappingViews)
            { 
                StorageEntityContainerMapping storageEntityContainerMapping; 
                // first check
                if (this.TryGetCorrespondingStorageEntityContainerMapping(entityViewContainer, 
                    storageMappingItemCollection.GetItems(), out storageEntityContainerMapping))
                {

                    // second check 
                    if (this.SerializedVerifyHashOverMmClosure(storageEntityContainerMapping, entityViewContainer, workspace.GetItemCollection(DataSpace.CSpace)))
                    { 
                        // third check, prior to the check, we collect all the views in the entity view container to the dictionary 
                        // if the views are changed then we will throw exception out
                        if (this.VerifyViewsHaveNotChanged(workspace, entityViewContainer)) 
                        {
                            this.SerializedAddGeneratedViews(workspace, entityViewContainer, extentMappingViews);
                            return true;
                        } 
                        else
                        { 
                            throw new InvalidOperationException(System.Data.Entity.Strings.Generated_Views_Changed); 
                        }
                    } 
                    else
                    {
                        throw new MappingException(Data.Entity.Strings.ViewGen_HashOnMappingClosure_Not_Matching(entityViewContainer.EdmEntityContainerName));
                    } 
                }
                return false; 
 
            }
 
            private bool TryGetCorrespondingStorageEntityContainerMapping(EntityViewContainer viewContainer,
                IEnumerable storageEntityContainerMappingList, out StorageEntityContainerMapping storageEntityContainerMapping)
            {
                storageEntityContainerMapping = null; 

                foreach (var entityContainerMapping in storageEntityContainerMappingList) 
                { 
                    // first check
                    if (entityContainerMapping.EdmEntityContainer.Name == viewContainer.EdmEntityContainerName && 
                        entityContainerMapping.StorageEntityContainer.Name == viewContainer.StoreEntityContainerName)
                    {
                        storageEntityContainerMapping = entityContainerMapping;
                        return true; 
                    }
                } 
                return false; 

            } 

            private bool SerializedVerifyHashOverMmClosure(StorageEntityContainerMapping entityContainerMapping, EntityViewContainer entityViewContainer, ItemCollection itemCollection)
            {
                if (MetadataMappingHasherVisitor.GetMappingClosureHash(entityContainerMapping, itemCollection) == 
                    entityViewContainer.HashOverMappingClosure)
                { 
                    return true; 
                }
                return false; 
            }

            private bool VerifyViewsHaveNotChanged(MetadataWorkspace workspace, EntityViewContainer viewContainer)
            { 
                //Now check whether the hash of the generated views match the one
                //we stored in the code file during design 
                //Produce the hash and add it to the code 
                string viewHash = MetadataHelper.GenerateHashForAllExtentViewsContent(viewContainer.ExtentViews);
                string storedViewHash = viewContainer.HashOverAllExtentViews; 
                if (viewHash != storedViewHash)
                {
                    return false;
                } 
                return true;
            } 
 

            //Collect the names of the entitysetbases and the generated views from 
            //the generated type into a string so that we can produce a hash over it.
            private void SerializedAddGeneratedViews(MetadataWorkspace workspace, EntityViewContainer viewContainer, Dictionary extentMappingViews)
            {
                foreach (KeyValuePair extentView in viewContainer.ExtentViews) 
                {
                    EntityContainer entityContainer = null; 
                    EntitySetBase extent = null; 

 
                    string extentFullName = extentView.Key;
                    int extentNameIndex = extentFullName.LastIndexOf('.');

                    if (extentNameIndex != -1) 
                    {
                        string entityContainerName = extentFullName.Substring(0, extentNameIndex); 
                        string extentName = extentFullName.Substring(extentFullName.LastIndexOf('.') + 1); 

                        if (!workspace.TryGetItem(entityContainerName, DataSpace.CSpace, out entityContainer)) 
                        {
                            workspace.TryGetItem(entityContainerName, DataSpace.SSpace, out entityContainer);
                        }
 
                        if (entityContainer != null)
                        { 
                            entityContainer.BaseEntitySets.TryGetValue(extentName, false, out extent); 
                        }
                    } 

                    if (extent == null)
                    {
                        throw new MappingException(System.Data.Entity.Strings.Generated_Views_Invalid_Extent_1(extentFullName)); 
                    }
 
                    //Create a Generated view and cache it 
                    GeneratedView generatedView;
                    //Add the view to the local dictionary 
                    if (!extentMappingViews.TryGetValue(extent, out generatedView))
                    {
                        generatedView = new GeneratedView(extent, null /*edmType*/, extentView.Value, workspace,
                                            new ConfigViewGenerator()); 
                        extentMappingViews.Add(extent, generatedView);
                    } 
                } 
            }
 

            /// 
            /// Tries to collect the views from the referenced assemblies of Entry assembly.
            ///  
            /// 
            private void SerializedCollectViewsFromReferencedAssemblies(MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection, Dictionary extentMappingViews) 
            { 
                ObjectItemCollection objectCollection;
                ItemCollection itemCollection; 
                if (!workspace.TryGetItemCollection(DataSpace.OSpace, out itemCollection))
                {
                    //Possible enhancement : Think about achieving the same thing without creating Object Item Collection.
                    objectCollection = new ObjectItemCollection(); 
                    itemCollection = objectCollection;
                    // The GetEntryAssembly method can return a null reference 
                    //when a managed assembly has been loaded from an unmanaged application. 
                    Assembly entryAssembly = Assembly.GetEntryAssembly();
                    if (entryAssembly != null) 
                    {
                        objectCollection.LoadAllReferencedAssemblies(entryAssembly, true);
                    }
                } 
                this.SerializedCollectViewsFromObjectCollection(workspace, storageMappingItemCollection, extentMappingViews);
            } 
 
            /// 
            /// This method collect all the user defined query views in MSL 
            /// Assumption: This method is called only from the StorageMappingItemCollection's constructor
            /// and no other thread can be calling ViewDictionary.GetGeneratedViews() at the same time.
            /// m_extentMappingViews and m_extentTypeQueryViews are not thread safe.
            ///  
            /// 
            ///  
            internal static void CollectViews(StorageEntityContainerMapping entityContainerMapping, StorageMappingItemCollection storageMappingItemCollection, 
                IList errors, Dictionary userDefinedQueryViewsDict, Dictionary userDefinedQueryViewsOfTypeDict)
            { 
                //Create a new MetadataWorkspace, since Query needs it to compile Query
                //Since the MetadataWorkspace really is a thin wrapper over item collections,
                //this should not pose a problem.
                MetadataWorkspace workspace = new MetadataWorkspace(); 
                workspace.RegisterItemCollection(storageMappingItemCollection.m_edmCollection);
                workspace.RegisterItemCollection(storageMappingItemCollection.m_storeItemCollection); 
                workspace.RegisterItemCollection(storageMappingItemCollection); 
                ConfigViewGenerator config = new ConfigViewGenerator();
 
                foreach (StorageSetMapping setMapping in entityContainerMapping.AllSetMaps)
                {
                    if (setMapping.QueryView != null)
                    { 
                        GeneratedView generatedView;
                        if (!userDefinedQueryViewsDict.TryGetValue(setMapping.Set, out generatedView)) 
                        { 
                            // Parse the view so that we will get back any errors in the view
                            // Catch the query exception and add it as a parser error 
                            try
                            {
                                //Add first QueryView
                                generatedView = new GeneratedView(setMapping.Set, 
                                                              setMapping.Set.ElementType, setMapping.QueryView.Trim(), workspace,
                                                              config); 
 
                                bool validationError = false;
                                foreach (EdmSchemaError error in generatedView.ParseUserSpecifiedView(workspace, 
                                    storageMappingItemCollection.StoreItemCollection, setMapping, setMapping.Set.ElementType, true /* includeSubtypes*/))
                                {
                                    validationError = true;
                                    errors.Add(error); 
                                }
                                if (!validationError) 
                                { 
                                    userDefinedQueryViewsDict.Add(setMapping.Set, generatedView);
                                } 

                                //Add all type-specific QueryViews
                                foreach (OfTypeQVCacheKey key in setMapping.GetTypeSpecificQVKeys())
                                { 
                                    Debug.Assert(key.First.Equals(setMapping.Set));
 
                                    generatedView = new GeneratedView(setMapping.Set, 
                                                              key.Second.First /*EntityType*/,
                                                              setMapping.GetTypeSpecificQueryView(key) /*QV*/, 
                                                              workspace, config);

                                    validationError = false;
                                    foreach (EdmSchemaError error in generatedView.ParseUserSpecifiedView(workspace, storageMappingItemCollection.StoreItemCollection, setMapping, key.Second.First, key.Second.Second)) 
                                    {
                                        validationError = true; 
                                        errors.Add(error); 
                                    }
 
                                    if (!validationError)
                                    {
                                        userDefinedQueryViewsOfTypeDict.Add(key, generatedView);
                                    } 

                                } 
                            } 
                            catch (Exception e)
                            { 
                                //catching all the exception types since Query parser seems to be throwing veriety of
                                //exceptions - EntityException, ArgumentException, ArgumentNullException etc.
                                if (EntityUtil.IsCatchableExceptionType(e))
                                { 
                                    EdmSchemaError error = new EdmSchemaError(System.Data.Entity.Strings.Mapping_Invalid_QueryView_2(setMapping.Set.Name, e.Message),
                                                               (int)StorageMappingErrorCode.InvalidQueryView, EdmSchemaErrorSeverity.Error, 
                                                               setMapping.EntityContainerMapping.SourceLocation, setMapping.StartLineNumber, setMapping.StartLinePosition, e); 
                                    errors.Add(error);
                                } 
                                else
                                {
                                    throw;
                                } 
                            }
                        } 
                    } 
                }
            } 
        }
    }
}

// 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