using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Text; using System.Xml; using System.Xml.Schema; using System.IO; using System.Reflection; using System.Diagnostics; using System.Runtime.Serialization; using System.Security.Permissions; using System.Globalization; //using System.Workflow.Activities; using System.Workflow.ComponentModel; using System.Workflow.Runtime; using System.Workflow.Runtime.Hosting; using Hosting = System.Workflow.Runtime.Hosting; namespace System.Workflow.Runtime.Tracking { /// /// Used for xml serializing a TrackProfile. /// [Obsolete("The System.Workflow.* types are deprecated. Instead, please use the new types from System.Activities.*")] public class TrackingProfileSerializer { public TrackingProfileSerializer() { _schema = XmlSchema.Read(new StringReader(_xsd), null); _schema.Namespaces.Add("", _ns); } public XmlSchema Schema { get { return _schema; } } #region Deserialization List _vArgs = new List(); bool _vex = false; /// /// Deserialize TrackingProfile in xml form to a TrackingProfile object. /// /// TextReader containing TrackingProfile in xml form /// TrackingProfile /// XmlSchemaException /// XmlException /// ArgumentNullException /// ArgumentException /// ArgumentOutOfRangeException /// FormatException /// OverflowException /// InvalidOperationException /// TrackingProfileDeserializationException public TrackingProfile Deserialize(TextReader reader) { TrackingProfile profile = null; _vArgs = new List(); _vex = false; if (null == reader) throw new ArgumentNullException("reader"); // // Specify that if no namespace is declare the default should be interpreted as ours NameTable nt = new NameTable(); XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt); nsmgr.AddNamespace(String.Empty, _ns); XmlParserContext ctx = new XmlParserContext(nt, nsmgr, null, XmlSpace.None); XmlReader pReader = XmlReader.Create(reader, GetSchemaReaderSettings(), ctx); try { profile = new TrackingProfile(); // // Schema validation will catch if element is missing if (!pReader.ReadToDescendant("TrackingProfile")) { // // Will throw exception with validation errors CheckSchemaErrors(); return null; } string version = pReader.GetAttribute("version"); if ((null == version) || (0 == version.Trim().Length)) throw new TrackingProfileDeserializationException(ExecutionStringManager.InvalidProfileVersion); profile.Version = new Version(version); if (!pReader.ReadToDescendant("TrackPoints")) { // // Will throw exception with validation errors CheckSchemaErrors(); return null; } CreateTrackPoints(pReader, profile); CheckSchemaErrors(); } catch (Exception) { profile = null; throw; } finally { _vArgs = new List(); _vex = false; pReader.Close(); } return profile; } private void CheckSchemaErrors() { // // If the parsing hit an error->throw // Clients can check ValidationEventArgs to get // all errors & warnings that were caught. if (_vex) { TrackingProfileDeserializationException tpde = new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationSchemaError); if (null != _vArgs) { foreach (ValidationEventArgs arg in _vArgs) tpde.ValidationEventArgs.Add(arg); } throw tpde; } } private void CreateTrackPoints(XmlReader reader, TrackingProfile profile) { if (null == reader) throw new ArgumentNullException("reader"); if (null == profile) throw new ArgumentNullException("profile"); if (0 != string.Compare(reader.Name, "TrackPoints", StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "TrackPoints."); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "ActivityTrackPoint", StringComparison.Ordinal)) CreateActivityTrackPoint(reader, profile); else if (0 == string.Compare(reader.Name, "UserTrackPoint", StringComparison.Ordinal)) CreateUserTrackPoint(reader, profile); else if (0 == string.Compare(reader.Name, "WorkflowTrackPoint", StringComparison.Ordinal)) CreateWorkflowTrackPoint(reader, profile); break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "TrackPoints", StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "TrackPoints."); } private void CreateActivityTrackPoint(XmlReader reader, TrackingProfile profile) { if (null == reader) throw new ArgumentNullException("reader"); if (null == profile) throw new ArgumentNullException("profile"); if (0 != string.Compare(reader.Name, "ActivityTrackPoint", StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "ActivityTrackPoint."); if (reader.IsEmptyElement) return; ActivityTrackPoint point = new ActivityTrackPoint(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "Annotations", StringComparison.Ordinal)) CreateAnnotations(reader, point.Annotations); else if (0 == string.Compare(reader.Name, "MatchingLocations", StringComparison.Ordinal)) CreateActivityTrackingLocations(reader, point.MatchingLocations); else if (0 == string.Compare(reader.Name, "ExcludedLocations", StringComparison.Ordinal)) CreateActivityTrackingLocations(reader, point.ExcludedLocations); else if (0 == string.Compare(reader.Name, "Extracts", StringComparison.Ordinal)) CreateExtracts(reader, point.Extracts); // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "ActivityTrackPoint", StringComparison.Ordinal)) { profile.ActivityTrackPoints.Add(point); return; } break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "ActivityTrackPoint."); } private void CreateActivityTrackingLocation(XmlReader reader, ActivityTrackingLocation location) { if (null == reader) throw new ArgumentNullException("reader"); if (null == location) throw new ArgumentNullException("location"); if (0 != string.Compare(reader.Name, "ActivityTrackingLocation", StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "ActivityTrackingLocation."); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "TypeName", StringComparison.Ordinal)) { if (null != location.ActivityType) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidType); location.ActivityTypeName = reader.ReadString(); } else if (0 == string.Compare(reader.Name, "Type", StringComparison.Ordinal)) { if (null != location.ActivityTypeName) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidType); if (!reader.IsEmptyElement) { // // Schema validation will catch empty elements, just make sure // we don't pass GetType a null or empty string and continue. string type = reader.ReadString(); if ((null != type) && (type.Trim().Length > 0)) location.ActivityType = Type.GetType(type, true); } } else if (0 == string.Compare(reader.Name, "MatchDerivedTypes", StringComparison.Ordinal)) location.MatchDerivedTypes = reader.ReadElementContentAsBoolean(); else if (0 == string.Compare(reader.Name, "ExecutionStatusEvents", StringComparison.Ordinal)) CreateStatusEvents(reader, location.ExecutionStatusEvents); else if (0 == string.Compare(reader.Name, "Conditions", StringComparison.Ordinal)) CreateConditions(reader, location.Conditions); break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "ActivityTrackingLocation", StringComparison.Ordinal)) { // // If we don't have a type or name create the Activity type to track all activities if ((null == location.ActivityType) && (null == location.ActivityTypeName)) { location.ActivityType = typeof(Activity); location.MatchDerivedTypes = true; } return; } break; } } // // Something bad happened throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "ActivityTrackingLocation."); } private void CreateUserTrackPoint(XmlReader reader, TrackingProfile profile) { if (null == reader) throw new ArgumentNullException("reader"); if (null == profile) throw new ArgumentNullException("profile"); if (0 != string.Compare(reader.Name, "UserTrackPoint", StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "UserTrackPoint."); if (reader.IsEmptyElement) return; UserTrackPoint point = new UserTrackPoint(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "Annotations", StringComparison.Ordinal)) CreateAnnotations(reader, point.Annotations); else if (0 == string.Compare(reader.Name, "MatchingLocations", StringComparison.Ordinal)) CreateUserTrackingLocations(reader, point.MatchingLocations); else if (0 == string.Compare(reader.Name, "ExcludedLocations", StringComparison.Ordinal)) CreateUserTrackingLocations(reader, point.ExcludedLocations); else if (0 == string.Compare(reader.Name, "Extracts", StringComparison.Ordinal)) CreateExtracts(reader, point.Extracts); // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "UserTrackPoint", StringComparison.Ordinal)) { profile.UserTrackPoints.Add(point); return; } break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "UserTrackPoint."); } private void CreateUserTrackingLocation(XmlReader reader, UserTrackingLocation location) { if (null == reader) throw new ArgumentNullException("reader"); if (null == location) throw new ArgumentNullException("location"); if (0 != string.Compare(reader.Name, "UserTrackingLocation", StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "UserTrackingLocation."); if (reader.IsEmptyElement) return; string name = null, type = null; bool derived = false, seenAct = false, seenArg = false; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "Activity", StringComparison.Ordinal)) seenAct = true; else if (0 == string.Compare(reader.Name, "KeyName", StringComparison.Ordinal)) location.KeyName = reader.ReadString(); else if (0 == string.Compare(reader.Name, "Argument", StringComparison.Ordinal)) seenArg = true; else if (0 == string.Compare(reader.Name, "TypeName", StringComparison.Ordinal)) name = reader.ReadString(); else if (0 == string.Compare(reader.Name, "Type", StringComparison.Ordinal)) type = reader.ReadString(); else if (0 == string.Compare(reader.Name, "MatchDerivedTypes", StringComparison.Ordinal)) derived = reader.ReadElementContentAsBoolean(); else if (0 == string.Compare(reader.Name, "Conditions", StringComparison.Ordinal)) CreateConditions(reader, location.Conditions); break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "UserTrackingLocation", StringComparison.Ordinal)) { if (!seenAct) { location.ActivityType = typeof(Activity); location.MatchDerivedActivityTypes = true; } if (!seenArg) { location.ArgumentType = typeof(object); location.MatchDerivedArgumentTypes = true; } if ((null == location.ActivityType) && ((null == location.ActivityTypeName) || (0 == location.ActivityTypeName.Trim().Length)) && (null == location.ArgumentType) && ((null == location.ArgumentTypeName) || (0 == location.ArgumentTypeName.Trim().Length))) throw new TrackingProfileDeserializationException(ExecutionStringManager.MissingActivityType); return; } else if (0 == string.Compare(reader.Name, "Activity", StringComparison.Ordinal)) { if (!seenAct) { location.ActivityType = typeof(Activity); location.MatchDerivedActivityTypes = true; } else { if ((null != type) && (type.Trim().Length > 0)) location.ActivityType = Type.GetType(type, true); else location.ActivityTypeName = name; location.MatchDerivedActivityTypes = derived; } name = null; type = null; derived = false; } else if (0 == string.Compare(reader.Name, "Argument", StringComparison.Ordinal)) { if (!seenArg) { location.ArgumentType = typeof(object); location.MatchDerivedArgumentTypes = true; } else { if ((null != type) && (type.Trim().Length > 0)) location.ArgumentType = Type.GetType(type, true); else location.ArgumentTypeName = name; location.MatchDerivedArgumentTypes = derived; } name = null; type = null; derived = false; } break; } } // // Something bad happened throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "UserTrackingLocation."); } private void CreateWorkflowTrackPoint(XmlReader reader, TrackingProfile profile) { if (null == reader) throw new ArgumentNullException("reader"); if (null == profile) throw new ArgumentNullException("profile"); if (0 != string.Compare(reader.Name, "WorkflowTrackPoint", StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "WorkflowTrackPoint."); if (reader.IsEmptyElement) return; WorkflowTrackPoint point = new WorkflowTrackPoint(); point.MatchingLocation = new WorkflowTrackingLocation(); while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "Annotations", StringComparison.Ordinal)) CreateAnnotations(reader, point.Annotations); else if (0 == string.Compare(reader.Name, "TrackingWorkflowEvent", StringComparison.Ordinal)) point.MatchingLocation.Events.Add((TrackingWorkflowEvent)Enum.Parse(typeof(TrackingWorkflowEvent), reader.ReadString())); // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "WorkflowTrackPoint", StringComparison.Ordinal)) { profile.WorkflowTrackPoints.Add(point); return; } break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "WorkflowTrackPoint."); } private void CreateStatusEvents(XmlReader reader, IList events) { if (null == reader) throw new ArgumentNullException("reader"); if (null == events) throw new ArgumentNullException("events"); if (0 != string.Compare("ExecutionStatusEvents", reader.Name, StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "ExecutionStatusEvents."); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "ExecutionStatus", StringComparison.Ordinal)) { string status = reader.ReadString(); if ((null != status) && (status.Trim().Length > 0)) { string[] names = Enum.GetNames(typeof(ActivityExecutionStatus)); foreach (string s in names) { if (0 == string.Compare(s, status, StringComparison.Ordinal)) events.Add((ActivityExecutionStatus)Enum.Parse(typeof(ActivityExecutionStatus), status)); } } } // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "ExecutionStatusEvents", StringComparison.Ordinal)) return; break; } } // // Something is funky throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "ExecutionStatusEvents."); } private void CreateConditions(XmlReader reader, TrackingConditionCollection conditions) { if (null == reader) throw new ArgumentNullException("reader"); if (null == conditions) throw new ArgumentNullException("conditions"); if (0 != string.Compare("Conditions", reader.Name, StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "Conditions."); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "ActivityTrackingCondition", StringComparison.Ordinal)) { ActivityTrackingCondition condition = new ActivityTrackingCondition(); CreateCondition(reader, condition); conditions.Add(condition); } // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "Conditions", StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "Conditions."); } private void CreateCondition(XmlReader reader, TrackingCondition condition) { if (null == reader) throw new ArgumentNullException("reader"); if (null == condition) throw new ArgumentNullException("condition"); if (0 != string.Compare(condition.GetType().Name, reader.Name, StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + condition.GetType().Name); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "Member", StringComparison.Ordinal)) { condition.Member = reader.ReadString(); } else if (0 == string.Compare(reader.Name, "Operator", StringComparison.Ordinal)) { string op = reader.ReadString(); if ((null != op) && (op.Trim().Length > 0)) { string[] names = Enum.GetNames(typeof(ComparisonOperator)); foreach (string s in names) { if (0 == string.Compare(s, op, StringComparison.Ordinal)) condition.Operator = (ComparisonOperator)Enum.Parse(typeof(ComparisonOperator), op); } } } else if (0 == string.Compare(reader.Name, "Value", StringComparison.Ordinal)) { if (!reader.IsEmptyElement) condition.Value = reader.ReadString(); } // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, condition.GetType().Name, StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + condition.GetType().Name); } private void CreateExtracts(XmlReader reader, ExtractCollection extracts) { if (null == reader) throw new ArgumentNullException("reader"); if (null == extracts) throw new ArgumentNullException("extracts"); if (0 != string.Compare("Extracts", reader.Name, StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "Extracts"); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "ActivityDataTrackingExtract", StringComparison.Ordinal)) { ActivityDataTrackingExtract e = new ActivityDataTrackingExtract(); CreateExtract(reader, e); extracts.Add(e); } else if (0 == string.Compare(reader.Name, "WorkflowDataTrackingExtract", StringComparison.Ordinal)) { WorkflowDataTrackingExtract e = new WorkflowDataTrackingExtract(); CreateExtract(reader, e); extracts.Add(e); } // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "Extracts", StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "Extracts."); } private void CreateExtract(XmlReader reader, TrackingExtract extract) { if (null == reader) throw new ArgumentNullException("reader"); if (null == extract) throw new ArgumentNullException("extract"); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "Member", StringComparison.Ordinal)) extract.Member = reader.ReadString(); else if (0 == string.Compare(reader.Name, "Annotations", StringComparison.Ordinal)) CreateAnnotations(reader, extract.Annotations); // // Xsd validation will catch unknown elements break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, extract.GetType().Name, StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + extract.GetType().Name); } private void CreateAnnotations(XmlReader reader, TrackingAnnotationCollection annotations) { if (null == reader) throw new ArgumentNullException("reader"); if (null == annotations) throw new ArgumentNullException("annotations"); if (0 != string.Compare(reader.Name, "Annotations", StringComparison.Ordinal)) throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationInvalidPosition + "Annotations."); if (reader.IsEmptyElement) return; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "Annotation", StringComparison.Ordinal)) { // // Preserve null and empty as distinct values // null == empty string = if (!reader.IsEmptyElement) annotations.Add(reader.ReadString()); else annotations.Add(null); } break; case XmlNodeType.EndElement: if (0 == string.Compare(reader.Name, "Annotations", StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + "Annotations."); } private void CreateActivityTrackingLocations(XmlReader reader, ActivityTrackingLocationCollection activities) { if (null == reader) throw new ArgumentNullException("reader"); if (null == activities) throw new ArgumentNullException("activities"); if (reader.IsEmptyElement) return; string startName = reader.Name; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "ActivityTrackingLocation", StringComparison.Ordinal)) { ActivityTrackingLocation location = new ActivityTrackingLocation(); CreateActivityTrackingLocation(reader, location); activities.Add(location); } break; case XmlNodeType.EndElement: if (0 == string.Compare(startName, reader.Name, StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + startName + "."); } private void CreateUserTrackingLocations(XmlReader reader, UserTrackingLocationCollection user) { if (null == reader) throw new ArgumentNullException("reader"); if (null == user) throw new ArgumentNullException("user"); if (reader.IsEmptyElement) return; string startName = reader.Name; while (reader.Read()) { switch (reader.NodeType) { case XmlNodeType.Element: if (0 == string.Compare(reader.Name, "UserTrackingLocation", StringComparison.Ordinal)) { UserTrackingLocation location = new UserTrackingLocation(); CreateUserTrackingLocation(reader, location); user.Add(location); } break; case XmlNodeType.EndElement: if (0 == string.Compare(startName, reader.Name, StringComparison.Ordinal)) return; break; } } // // Only valid exit is on an EndElement that matches the element that is passed in. throw new TrackingProfileDeserializationException(ExecutionStringManager.TrackingDeserializationCloseElementNotFound + startName + "."); } private XmlReaderSettings GetSchemaReaderSettings() { XmlReaderSettings profileSettings = new XmlReaderSettings(); profileSettings.Schemas.Add(_schema); profileSettings.ValidationType = ValidationType.Schema; profileSettings.ConformanceLevel = ConformanceLevel.Document; profileSettings.CloseInput = false; profileSettings.IgnoreComments = true; profileSettings.IgnoreProcessingInstructions = true; profileSettings.DtdProcessing = DtdProcessing.Prohibit; profileSettings.ValidationEventHandler += new ValidationEventHandler(ValidationCallBack); return profileSettings; } private void ValidationCallBack(object sender, ValidationEventArgs e) { _vArgs.Add(e); if (e.Severity == XmlSeverityType.Error) _vex = true; } #endregion #region Serialization /// /// Xml serialize a TrackingProfile. /// /// TrackingProfile to serialize. /// TextWriter to store xml text. public void Serialize(TextWriter writer, TrackingProfile profile) { if (null == profile) throw new ArgumentNullException("profile"); if (null == writer) throw new ArgumentNullException("writer"); XmlTextWriter xmlWriter = new XmlTextWriter(writer); InitWriter(xmlWriter); Write(profile, xmlWriter); xmlWriter.Flush(); xmlWriter.Close(); } private void Write(TrackingProfile profile, XmlTextWriter writer) { writer.WriteStartDocument(true); writer.WriteStartElement("TrackingProfile"); // Write the namespace declaration. writer.WriteAttributeString("xmlns", _ns); if (null == profile.Version) throw new ArgumentException(ExecutionStringManager.InvalidProfileVersion); string version = null; if (profile.Version.Revision >= 0) version = string.Format(NumberFormatInfo.InvariantInfo, "{0}.{1}.{2}.{3}", profile.Version.Major, profile.Version.Minor, profile.Version.Build, profile.Version.Revision); else if (profile.Version.Build >= 0) version = string.Format(NumberFormatInfo.InvariantInfo, "{0}.{1}.{2}", profile.Version.Major, profile.Version.Minor, profile.Version.Build); else if (profile.Version.Minor >= 0) version = string.Format(NumberFormatInfo.InvariantInfo, "{0}.{1}", profile.Version.Major, profile.Version.Minor); writer.WriteAttributeString("version", version); WriteTrackPoints(profile, writer); writer.WriteEndElement(); writer.WriteEndDocument(); } #region TrackPoints private void WriteTrackPoints(TrackingProfile profile, XmlTextWriter writer) { // // We must have at least 1 trackpoint or the profile won't be valid if (((null == profile.WorkflowTrackPoints) || (0 == profile.WorkflowTrackPoints.Count)) && ((null == profile.ActivityTrackPoints) || (0 == profile.ActivityTrackPoints.Count)) && ((null == profile.UserTrackPoints) || (0 == profile.UserTrackPoints.Count))) throw new ArgumentException(ExecutionStringManager.TrackingSerializationNoTrackPoints); int count = 0; writer.WriteStartElement("TrackPoints"); foreach (WorkflowTrackPoint point in profile.WorkflowTrackPoints) { if (null != point) { WriteWorkflowTrackPoint(point, writer); count++; } } foreach (ActivityTrackPoint point in profile.ActivityTrackPoints) { if (null != point) { WriteActivityTrackPoint(point, writer); count++; } } foreach (UserTrackPoint point in profile.UserTrackPoints) { if (null != point) { WriteUserTrackPoint(point, writer); count++; } } // // We must have at least 1 trackpoint or the profile isn't valid if (0 == count) throw new ArgumentException(ExecutionStringManager.TrackingSerializationNoTrackPoints); writer.WriteEndElement(); } private void WriteActivityTrackPoint(ActivityTrackPoint point, XmlTextWriter writer) { if (null == point) throw new ArgumentNullException("point"); // // Validate this element's required fields if ((null == point.MatchingLocations) || (0 == point.MatchingLocations.Count)) throw new ArgumentException(ExecutionStringManager.NoMatchingLocations); writer.WriteStartElement("ActivityTrackPoint"); writer.WriteStartElement("MatchingLocations"); // // Write the locations that should be matched // At least one non null location is required. int count = 0; foreach (ActivityTrackingLocation location in point.MatchingLocations) { if (null != location) { WriteActivityTrackingLocation(location, writer); count++; } } if (0 == count) throw new ArgumentException(ExecutionStringManager.NoMatchingLocations); writer.WriteEndElement(); // // Write the locations that should not be matched (these override the locations to match) // Excludes are not required. if ((null != point.ExcludedLocations) && (point.ExcludedLocations.Count > 0)) { writer.WriteStartElement("ExcludedLocations"); foreach (ActivityTrackingLocation location in point.ExcludedLocations) { if (null != location) WriteActivityTrackingLocation(location, writer); } writer.WriteEndElement(); } // // Write annotations, not a required field WriteAnnotations(point.Annotations, writer); // // Write extracts, not a required field WriteExtracts(point.Extracts, writer); writer.WriteEndElement(); } private void WriteWorkflowTrackPoint(WorkflowTrackPoint point, XmlTextWriter writer) { // // Validate this element's required fields if (null == point.MatchingLocation) throw new ArgumentException(ExecutionStringManager.NoMatchingLocation); writer.WriteStartElement("WorkflowTrackPoint"); WriteWorkflowTrackingLocation(point.MatchingLocation, writer); // // Write annotations, not a required field WriteAnnotations(point.Annotations, writer); writer.WriteEndElement(); } private void WriteUserTrackPoint(UserTrackPoint point, XmlTextWriter writer) { // // Validate this element's required fields if ((null == point.MatchingLocations) || (0 == point.MatchingLocations.Count)) throw new ArgumentException(ExecutionStringManager.NoMatchingLocations); writer.WriteStartElement("UserTrackPoint"); writer.WriteStartElement("MatchingLocations"); // // Write the locations that should be matched // At least one non null location is required. int count = 0; foreach (UserTrackingLocation location in point.MatchingLocations) { if (null != location) { WriteUserTrackingLocation(location, writer); count++; } } if (0 == count) throw new ArgumentException(ExecutionStringManager.NoMatchingLocations); writer.WriteEndElement(); // // Write the locations that should not be matched (these override the locations to match) // Excludes are not required. if ((null != point.ExcludedLocations) && (point.ExcludedLocations.Count > 0)) { writer.WriteStartElement("ExcludedLocations"); foreach (UserTrackingLocation location in point.ExcludedLocations) { if (null != location) WriteUserTrackingLocation(location, writer); } writer.WriteEndElement(); } // // Write annotations, not a required field WriteAnnotations(point.Annotations, writer); // // Write extracts, not a required field WriteExtracts(point.Extracts, writer); writer.WriteEndElement(); } #endregion #region Location private void WriteActivityTrackingLocation(ActivityTrackingLocation loc, XmlTextWriter writer) { // // Validate this element's required fields if ((null == loc.ActivityType) && ((null == loc.ActivityTypeName) || (0 == loc.ActivityTypeName.Trim().Length))) throw new ArgumentException(ExecutionStringManager.MissingActivityType); writer.WriteStartElement("ActivityTrackingLocation"); writer.WriteStartElement("Activity"); if (null != loc.ActivityType) writer.WriteElementString("Type", loc.ActivityType.AssemblyQualifiedName); else writer.WriteElementString("TypeName", loc.ActivityTypeName); writer.WriteElementString("MatchDerivedTypes", loc.MatchDerivedTypes.ToString().ToLower(CultureInfo.InvariantCulture)); writer.WriteEndElement(); WriteEvents(loc.ExecutionStatusEvents, writer); if ((null != loc.Conditions) && (loc.Conditions.Count > 0)) WriteConditions(loc.Conditions, writer); writer.WriteEndElement(); } private void WriteUserTrackingLocation(UserTrackingLocation loc, XmlTextWriter writer) { // // Validate this element's required fields if ((null == loc.ActivityType) && ((null == loc.ActivityTypeName) || (0 == loc.ActivityTypeName.Trim().Length))) throw new ArgumentException(ExecutionStringManager.MissingActivityType); if ((null == loc.ArgumentType) && ((null == loc.ArgumentTypeName) || (0 == loc.ArgumentTypeName.Trim().Length))) throw new ArgumentException(ExecutionStringManager.MissingArgumentType); writer.WriteStartElement("UserTrackingLocation"); // // Write the Acctivity node writer.WriteStartElement("Activity"); if (null != loc.ActivityType) writer.WriteElementString("Type", loc.ActivityType.AssemblyQualifiedName); else writer.WriteElementString("TypeName", loc.ActivityTypeName); writer.WriteElementString("MatchDerivedTypes", loc.MatchDerivedActivityTypes.ToString().ToLower(CultureInfo.InvariantCulture)); writer.WriteEndElement(); // // Write the key name node if it is non null if (null != loc.KeyName) writer.WriteElementString("KeyName", loc.KeyName); // // Write the Argument node writer.WriteStartElement("Argument"); if (null != loc.ArgumentType) writer.WriteElementString("Type", loc.ArgumentType.AssemblyQualifiedName); else writer.WriteElementString("TypeName", loc.ArgumentTypeName); writer.WriteElementString("MatchDerivedTypes", loc.MatchDerivedArgumentTypes.ToString().ToLower(CultureInfo.InvariantCulture)); writer.WriteEndElement(); if ((null != loc.Conditions) && (loc.Conditions.Count > 0)) WriteConditions(loc.Conditions, writer); writer.WriteEndElement(); } private void WriteWorkflowTrackingLocation(WorkflowTrackingLocation loc, XmlTextWriter writer) { if ((null == loc.Events) || (0 == loc.Events.Count)) throw new ArgumentException(ExecutionStringManager.MissingWorkflowEvents); writer.WriteStartElement("MatchingLocation"); writer.WriteStartElement("WorkflowTrackingLocation"); WriteWorkflowEvents(loc.Events, writer); writer.WriteEndElement(); writer.WriteEndElement(); } #endregion #region TrackingExtract private void WriteExtracts(ExtractCollection extracts, XmlTextWriter writer) { if ((null == extracts) || (0 == extracts.Count)) return; writer.WriteStartElement("Extracts"); foreach (TrackingExtract e in extracts) { if (null != e) WriteExtract(e, writer); } writer.WriteEndElement(); } private void WriteExtract(TrackingExtract extract, XmlTextWriter writer) { Type t = extract.GetType(); if ((extract is ActivityDataTrackingExtract) || (extract is WorkflowDataTrackingExtract)) { writer.WriteStartElement(extract.GetType().Name); writer.WriteElementString("Member", (null == extract.Member ? string.Empty : extract.Member)); WriteAnnotations(extract.Annotations, writer); writer.WriteEndElement(); } else throw new ArgumentException(ExecutionStringManager.TrackingSerializationInvalidExtract); } #endregion #region Shared private void WriteConditions(TrackingConditionCollection conditions, XmlTextWriter writer) { if ((null == conditions) || (0 == conditions.Count)) return; writer.WriteStartElement("Conditions"); foreach (TrackingCondition c in conditions) { if (null != c) WriteCondition(c, writer); } writer.WriteEndElement(); } private void WriteCondition(TrackingCondition condition, XmlTextWriter writer) { if (null == condition) return; writer.WriteStartElement(condition.GetType().Name); writer.WriteElementString("Operator", condition.Operator.ToString()); if ((null == condition.Member) || (0 == condition.Member.Trim().Length)) throw new ArgumentException(ExecutionStringManager.MissingMemberName); writer.WriteElementString("Member", condition.Member); if (null != condition.Value) { if (string.Empty == condition.Value) { writer.WriteStartElement("Value"); writer.WriteRaw(string.Empty); writer.WriteEndElement(); } else writer.WriteElementString("Value", condition.Value); } writer.WriteEndElement(); } private void WriteAnnotations(TrackingAnnotationCollection annotations, XmlTextWriter writer) { if ((null == annotations) || (0 == annotations.Count)) return; writer.WriteStartElement("Annotations"); foreach (string s in annotations) { // // Preserve null and empty as distinct values // null == empty string = writer.WriteStartElement("Annotation"); if ((null == s) || (s.Length > 0)) { writer.WriteValue(null == s ? String.Empty : s); writer.WriteEndElement(); } else writer.WriteFullEndElement(); } writer.WriteEndElement(); } private void WriteEvents(IList events, XmlTextWriter writer) { if ((null == events) || (0 == events.Count)) throw new ArgumentException(ExecutionStringManager.MissingActivityEvents); writer.WriteStartElement("ExecutionStatusEvents"); foreach (ActivityExecutionStatus s in events) { if (!IsStatus((int)s)) throw new ArgumentException(ExecutionStringManager.InvalidStatus); writer.WriteStartElement("ExecutionStatus"); writer.WriteValue(s.ToString()); writer.WriteEndElement(); } writer.WriteEndElement(); } private bool IsStatus(int val) { foreach (ActivityExecutionStatus s in Enum.GetValues(typeof(ActivityExecutionStatus))) { if ((int)s == val) return true; } return false; } private void WriteWorkflowEvents(IList events, XmlTextWriter writer) { if ((null == events) || (0 == events.Count)) return; writer.WriteStartElement("TrackingWorkflowEvents"); foreach (TrackingWorkflowEvent s in events) { if (!IsWorkflowEvent((int)s)) throw new ArgumentException(ExecutionStringManager.InvalidWorkflowEvent); writer.WriteStartElement("TrackingWorkflowEvent"); writer.WriteValue(s.ToString()); writer.WriteEndElement(); } writer.WriteEndElement(); } private bool IsWorkflowEvent(int val) { foreach (TrackingWorkflowEvent s in Enum.GetValues(typeof(TrackingWorkflowEvent))) { if ((int)s == val) return true; } return false; } #endregion private void InitWriter(XmlTextWriter writer) { writer.Formatting = Formatting.Indented; writer.Indentation = 4; } #endregion #region Schema private const string _ns = "http://schemas.microsoft.com/winfx/2006/workflow/trackingprofile"; private XmlSchema _schema = null; internal const string _xsd = @" "; #endregion Schema } }