SourceLocationProvider.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / Debugger / SourceLocationProvider.cs / 1638171 / SourceLocationProvider.cs

                            //---------------------------------------------------------------- 
// Copyright (c) Microsoft Corporation.  All rights reserved.
//---------------------------------------------------------------

namespace System.Activities.Debugger 
{
    using System; 
    using System.Activities.Hosting; 
    using System.Activities.XamlIntegration;
    using System.Diagnostics; 
    using System.Collections.Generic;
    using System.Diagnostics.CodeAnalysis;
    using System.Runtime;
    using System.Reflection; 
    using System.Xaml;
    using System.Xml; 
    using System.IO; 
    using System.Activities.Validation;
    using System.Collections.ObjectModel; 

    // Provide SourceLocation information for activities in given root activity.
    // This is integration point with Workflow project system (TBD).
    // The current plan is to get SourceLocation from (in this order): 
    //  1. pdb (when available)
    //  2a. parse xaml files available in the same project (or metadata store) or 
    //  2b. ask user to point to the correct xaml source. 
    //  3.  Publish (serialize to tmp file) and deserialize it to collect SourceLocation (for loose xaml).
    // Current code cover only step 3. 

    [DebuggerNonUserCode]
    public static class SourceLocationProvider
    { 
        [Fx.Tag.Throws(typeof(Exception), "Calls Serialize/Deserialize to temporary file")]
        static internal Dictionary GetSourceLocations(Activity rootActivity, out string sourcePath, out bool isTemporaryFile) 
        { 
            sourcePath = XamlDebuggerXmlReader.GetFileName(rootActivity) as string;
            isTemporaryFile = false; 
            Dictionary mapping;
            Assembly localAssembly;

            // This may not be the local assembly since it may not be the real root for x:Class 
            localAssembly = rootActivity.GetType().Assembly;
 
            if (rootActivity.Parent != null) 
            {
                localAssembly = rootActivity.Parent.GetType().Assembly; 
            }

            if (rootActivity.Children != null && rootActivity.Children.Count > 0)
            { // In case of actual root is wrapped either in x:Class activity or CorrelationScope 
                Activity body = rootActivity.Children[0];
                string bodySourcePath = XamlDebuggerXmlReader.GetFileName(body) as string; 
                if (!string.IsNullOrEmpty(bodySourcePath)) 
                {
                    rootActivity = body; 
                    sourcePath = bodySourcePath;
                }
            }
 
            if (!string.IsNullOrEmpty(sourcePath))
            { 
                SourceLocation tempSourceLocation; 
                Activity tempRootActivity;
 
                if (TryGetSourceLocation(rootActivity, sourcePath, out tempSourceLocation)) // already has source location.
                {
                    tempRootActivity = rootActivity;
                } 
                else
                { 
                    // Need to store the file in memory temporary so don't have to re-read the file twice 
                    // for XamlDebugXmlReader's BracketLocator.
                    FileInfo fi = new FileInfo(sourcePath); 
                    byte[] buffer = new byte[fi.Length];

                    using (FileStream fs = new FileStream(sourcePath, FileMode.Open, FileAccess.Read))
                    { 
                        fs.Read(buffer, 0, buffer.Length);
                    } 
 
                    // Use two separate MemoryStreams so they're are not interfere to each other.
                    object deserializedObject = Deserialize(buffer, localAssembly); 
                    IDebuggableWorkflowTree debuggableWorkflowTree = deserializedObject as IDebuggableWorkflowTree;
                    if (debuggableWorkflowTree != null)
                    { // Declarative Service and x:Class case
                        tempRootActivity = debuggableWorkflowTree.GetWorkflowRoot(); 
                    }
                    else 
                    { // Loose XAML case. 
                        tempRootActivity = deserializedObject as Activity;
                    } 

                    Fx.Assert(tempRootActivity != null, "Unexpected workflow xaml file");
                }
 
                mapping = new Dictionary();
                if (tempRootActivity != null) 
                { 
                    CollectMapping(rootActivity, tempRootActivity, mapping, sourcePath);
                } 
            }
            else
            { // Publish the source file to temporary file.
                string tempFileName = Path.GetTempFileName(); 
                sourcePath = Path.ChangeExtension(tempFileName, ".xaml");
                File.Move(tempFileName, sourcePath); 
                isTemporaryFile = true; 
                mapping = PublishAndCollectMapping(rootActivity, sourcePath);
            } 

            return mapping;
        }
 
        static void Serialize(Stream writeStream, Activity activity)
        { 
 
            using (XmlWriter writer = XmlWriter.Create(writeStream,
                new XmlWriterSettings 
                {
                    Indent = true,
                    IndentChars = "    "
                })) 
            {
                XamlServices.Save(writer, activity); 
                writer.Flush(); 
            }
        } 

        static object Deserialize(byte[] buffer, Assembly localAssembly)
        {
            using (XmlReader xmlReader = XmlReader.Create(new MemoryStream(buffer))) 
            {
                using (XamlXmlReader xamlXmlReader = new XamlXmlReader(xmlReader, new XamlXmlReaderSettings { LocalAssembly = localAssembly, ProvideLineInfo = true })) 
                { 
                    using (XamlDebuggerXmlReader xamlDebuggerReader = new XamlDebuggerXmlReader(xamlXmlReader, new StreamReader(new MemoryStream(buffer))))
                    { 
                        using (XamlReader activityBuilderReader = ActivityXamlServices.CreateBuilderReader(xamlDebuggerReader))
                        {
                            return XamlServices.Load(activityBuilderReader);
                        } 
                    }
                } 
            } 
        }
 
        // Publish activity to a file, return the SourceLocation mapping of activities & expressions.
        static Dictionary PublishAndCollectMapping(Activity activity, string path)
        {
            Dictionary mapping = new Dictionary(); 
            using (MemoryStream stream = new MemoryStream())
            { 
                Serialize(stream, activity); 
                stream.Position = 0;
                Activity newActivity = Deserialize(stream.GetBuffer(), activity.GetType().Assembly) as Activity; 
                Fx.Assert(newActivity != null, "Cannot do roundtrip serialization");
                using (StreamWriter writer = new StreamWriter(path))
                {
                    stream.Position = 0; 
                    using (StreamReader reader = new StreamReader(stream))
                    { 
                        writer.Write(reader.ReadToEnd()); 
                    }
                } 

                CollectMapping(activity, newActivity, mapping, path);
            }
            return mapping; 
        }
 
        // Collect mapping for activity1 and its descendants to their corresponding source location. 
        // activity2 is the shadow of activity1 but with SourceLocation information.
        public static void CollectMapping(Activity rootActivity1, Activity rootActivity2, Dictionary mapping, string path) 
        {
            // For x:Class, the rootActivity here may not be the real root, but it's the first child of the x:Class activity.
            Activity realRoot1 = (rootActivity1.RootActivity != null) ? rootActivity1.RootActivity : rootActivity1;
            if (!realRoot1.IsRuntimeReady) 
            {
                IList validationErrors = null; 
                ActivityUtilities.CacheRootMetadata(realRoot1, new ActivityLocationReferenceEnvironment(), ProcessActivityTreeOptions.ValidationOptions, null, ref validationErrors); 
            }
 
            // Similarly for rootActivity2.
            Activity realRoot2 = (rootActivity2.RootActivity != null) ? rootActivity2.RootActivity : rootActivity2;
            if (!realRoot2.IsRuntimeReady)
            { 
                IList validationErrors = null;
                ActivityUtilities.CacheRootMetadata(realRoot2, new ActivityLocationReferenceEnvironment(), ProcessActivityTreeOptions.ValidationOptions, null, ref validationErrors); 
            } 

            Queue> pairsRemaining = new Queue>(); 

            pairsRemaining.Enqueue(new KeyValuePair(rootActivity1, rootActivity2));
            KeyValuePair currentPair;
            HashSet visited = new HashSet(); 

            while (pairsRemaining.Count > 0) 
            { 
                currentPair = pairsRemaining.Dequeue();
                Activity activity1 = currentPair.Key; 
                Activity activity2 = currentPair.Value;

                visited.Add(activity1);
 
                SourceLocation sourceLocation;
                if (TryGetSourceLocation(activity2, path, out sourceLocation)) 
                { 
                    mapping.Add(activity1, sourceLocation);
                } 
                else if (!((activity2 is IExpressionContainer) || (activity2 is IValueSerializableExpression))) // Expression is known not to have source location.
                {
                    //Some activities may not have corresponding Xaml node, e.g. ActivityFaultedOutput.
                    Debugger.Log(2, "Workflow", "WorkflowDebugger: Does not have corresponding Xaml node for: " + activity2.DisplayName + "\n"); 
                }
 
                // This to avoid comparing any value expression with DesignTimeValueExpression (in designer case). 
                if (!((activity1 is IExpressionContainer) || (activity2 is IExpressionContainer) ||
                      (activity1 is IValueSerializableExpression) || (activity2 is IValueSerializableExpression))) 
                {
                    IEnumerator enumerator1 = WorkflowInspectionServices.GetActivities(activity1).GetEnumerator();
                    IEnumerator enumerator2 = WorkflowInspectionServices.GetActivities(activity2).GetEnumerator();
                    bool hasNextItem1 = enumerator1.MoveNext(); 
                    bool hasNextItem2 = enumerator2.MoveNext();
                    while (hasNextItem1 && hasNextItem2) 
                    { 
                        if (!visited.Contains(enumerator1.Current))  // avoid adding the same activity (e.g. some default implementation).
                        { 
                            if (enumerator1.Current.GetType() != enumerator2.Current.GetType())
                            {
                                // Give debugger log instead of just asserting; to help user find out mismatch problem.
                                Debugger.Log(2, "Workflow", 
                                    "Unmatched type: " + enumerator1.Current.GetType().FullName +
                                    " vs " + enumerator2.Current.GetType().FullName + "\n"); 
                            } 
                            pairsRemaining.Enqueue(new KeyValuePair(enumerator1.Current, enumerator2.Current));
                        } 
                        hasNextItem1 = enumerator1.MoveNext();
                        hasNextItem2 = enumerator2.MoveNext();
                    }
 
                    // If enumerators do not finish at the same time, then they have unmatched number of activities.
                    // Give debugger log instead of just asserting; to help user find out mismatch problem. 
                    if (hasNextItem1 || hasNextItem2) 
                    {
                        Debugger.Log(2, "Workflow", "Unmatched number of children\n"); 
                    }
                }
            }
        } 

        // Get SourceLocation for object deserialized with XamlDebuggerXmlReader in deserializer stack. 
        static bool TryGetSourceLocation(object obj, string path, out SourceLocation sourceLocation) 
        {
            sourceLocation = null; 
            int startLine, startColumn, endLine, endColumn;

            if (AttachablePropertyServices.TryGetProperty(obj, XamlDebuggerXmlReader.StartLineName, out startLine) &&
                AttachablePropertyServices.TryGetProperty(obj, XamlDebuggerXmlReader.StartColumnName, out startColumn) && 
                AttachablePropertyServices.TryGetProperty(obj, XamlDebuggerXmlReader.EndLineName, out endLine) &&
                AttachablePropertyServices.TryGetProperty(obj, XamlDebuggerXmlReader.EndColumnName, out endColumn) && 
                SourceLocation.IsValidRange(startLine, startColumn, endLine, endColumn)) 
            {
                sourceLocation = new SourceLocation(path, startLine, startColumn, endLine, endColumn); 
                return true;
            }
            return false;
        } 
    }
} 

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