Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / NetFx40 / System.Activities / System / Activities / Validation / ActivityValidationServices.cs / 1305376 / ActivityValidationServices.cs
//------------------------------------------------------------------------------ // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.Activities.Validation { using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Runtime; using System.Text; using System.Threading; using System.Linq; public static class ActivityValidationServices { internal static readonly ReadOnlyCollectionEmptyChildren = new ReadOnlyCollection (new Activity[0]); static ValidationSettings defaultSettings = new ValidationSettings(); internal static ReadOnlyCollection EmptyValidationErrors = new ReadOnlyCollection (new List (0)); public static ValidationResults Validate(Activity toValidate) { return Validate(toValidate, defaultSettings); } public static ValidationResults Validate(Activity toValidate, ValidationSettings settings) { if (toValidate == null) { throw FxTrace.Exception.ArgumentNull("toValidate"); } if (settings == null) { throw FxTrace.Exception.ArgumentNull("settings"); } if (toValidate.HasBeenAssociatedWithAnInstance) { throw FxTrace.Exception.AsError(new InvalidOperationException(SR.RootActivityAlreadyAssociatedWithInstance(toValidate.DisplayName))); } InternalActivityValidationServices validator = new InternalActivityValidationServices(settings, toValidate); return validator.InternalValidate(); } public static Activity Resolve(Activity root, string id) { return WorkflowInspectionServices.Resolve(root, id); } internal static void ThrowIfViolationsExist(IList validationErrors) { Exception exception = CreateExceptionFromValidationErrors(validationErrors); if (exception != null) { throw FxTrace.Exception.AsError(exception); } } static Exception CreateExceptionFromValidationErrors(IList validationErrors) { if (validationErrors != null && validationErrors.Count > 0) { string exceptionString = GenerateExceptionString(validationErrors, ExceptionReason.InvalidTree); if (exceptionString != null) { return new InvalidWorkflowException(exceptionString); } else { return null; } } else { return null; } } internal static List GetChildren(ActivityUtilities.ChildActivity root, ActivityUtilities.ActivityCallStack parentChain, ProcessActivityTreeOptions options) { ActivityUtilities.FinishCachingSubtree(root, parentChain, options); List listOfChildren = new List (); foreach (Activity activity in WorkflowInspectionServices.GetActivities(root.Activity)) { listOfChildren.Add(activity); } int toProcessIndex = 0; while (toProcessIndex < listOfChildren.Count) { foreach (Activity activity in WorkflowInspectionServices.GetActivities(listOfChildren[toProcessIndex])) { listOfChildren.Add(activity); } toProcessIndex++; } return listOfChildren; } internal static void ValidateRootInputs(Activity rootActivity, IDictionary inputs) { IList validationErrors = null; ValidationHelper.ValidateArguments(rootActivity, rootActivity.EquivalenceInfo, rootActivity.OverloadGroups, rootActivity.RequiredArgumentsNotInOverloadGroups, inputs, ref validationErrors); // Validate if there are any extra arguments passed in the input dictionary if (inputs != null) { List unusedArguments = null; IEnumerable arguments = rootActivity.RuntimeArguments.Where((a) => ArgumentDirectionHelper.IsIn(a.Direction)); foreach (string key in inputs.Keys) { bool found = false; foreach (RuntimeArgument argument in arguments) { if (argument.Name == key) { found = true; // Validate if the input argument type matches the expected argument type. object inputArgumentValue = null; if (inputs.TryGetValue(key, out inputArgumentValue)) { if (!TypeHelper.AreTypesCompatible(inputArgumentValue, argument.Type)) { ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.InputParametersTypeMismatch(argument.Type, argument.Name), rootActivity)); } } // The ValidateArguments will validate Required in-args and hence not duplicating that validation if the key is not found. break; } } if (!found) { if (unusedArguments == null) { unusedArguments = new List (); } unusedArguments.Add(key); } } if (unusedArguments != null) { ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.UnusedInputArguments(unusedArguments.AsCommaSeparatedValues()), rootActivity)); } } if (validationErrors != null && validationErrors.Count > 0) { string parameterName = "rootArgumentValues"; ExceptionReason reason = ExceptionReason.InvalidNonNullInputs; if (inputs == null) { parameterName = "program"; reason = ExceptionReason.InvalidNullInputs; } string exceptionString = GenerateExceptionString(validationErrors, reason); if (exceptionString != null) { throw FxTrace.Exception.Argument(parameterName, exceptionString); } } } internal static void ValidateArguments(Activity activity, bool isRoot, ref IList validationErrors) { Fx.Assert(activity != null, "Activity to validate should not be null."); Dictionary > overloadGroups; List requiredArgumentsNotInOverloadGroups; ValidationHelper.OverloadGroupEquivalenceInfo equivalenceInfo; if (ValidationHelper.GatherAndValidateOverloads(activity, out overloadGroups, out requiredArgumentsNotInOverloadGroups, out equivalenceInfo, ref validationErrors)) { // If we're not the root and the overload groups are valid // then we validate the arguments if (!isRoot) { ValidationHelper.ValidateArguments(activity, equivalenceInfo, overloadGroups, requiredArgumentsNotInOverloadGroups, null, ref validationErrors); } } // If we are the root, regardless of whether the groups are // valid or not, we cache the group information if (isRoot) { activity.OverloadGroups = overloadGroups; activity.RequiredArgumentsNotInOverloadGroups = requiredArgumentsNotInOverloadGroups; activity.EquivalenceInfo = equivalenceInfo; } } static string GenerateExceptionString(IList validationErrors, ExceptionReason reason) { // 4096 is an arbitrary constant. Currently clipped by character count (not bytes). const int maxExceptionStringSize = 4096; StringBuilder exceptionMessageBuilder = null; for (int i = 0; i < validationErrors.Count; i++) { ValidationError validationError = validationErrors[i]; if (!validationError.IsWarning) { // create the common exception string if (exceptionMessageBuilder == null) { exceptionMessageBuilder = new StringBuilder(); switch (reason) { case ExceptionReason.InvalidTree: exceptionMessageBuilder.Append(SR.ErrorsEncounteredWhileProcessingTree); break; case ExceptionReason.InvalidNonNullInputs: exceptionMessageBuilder.Append(SR.RootArgumentViolationsFound); break; case ExceptionReason.InvalidNullInputs: exceptionMessageBuilder.Append(SR.RootArgumentViolationsFoundNoInputs); break; } } string activityName = null; if (validationError.Source != null) { activityName = validationError.Source.DisplayName; } else { activityName = " "; } exceptionMessageBuilder.AppendLine(); exceptionMessageBuilder.Append(string.Format(SR.Culture, "'{0}': {1}", activityName, validationError.Message)); if (exceptionMessageBuilder.Length > maxExceptionStringSize) { break; } } } string exceptionString = null; if (exceptionMessageBuilder != null) { exceptionString = exceptionMessageBuilder.ToString(); if (exceptionString.Length > maxExceptionStringSize) { string snipNotification = SR.TooManyViolationsForExceptionMessage; exceptionString = exceptionString.Substring(0, maxExceptionStringSize - snipNotification.Length); exceptionString += snipNotification; } } return exceptionString; } static internal string GenerateValidationErrorPrefix(Activity toValidate, ActivityUtilities.ActivityCallStack parentChain, out Activity source) { bool parentVisible = true; string prefix = ""; source = toValidate; // Find out if any of the parents of the activity are not publicly visible for (int i = 0; i < parentChain.Count; i++) { if (parentChain[i].Activity.MemberOf.Parent != null) { parentVisible = false; break; } } // Figure out the source of validation error: // - For hidden activity - source will be closest visible public parent // - For visible activity - source will be the activity itself // In current design an activity is visible only if it is in the root id space. // In future, if we provide a knob for the user to specify the // id spaces that are visible, then this check needs to be changed // to iterate over the parentChain and find the closest parent activity that // is in the visible id spaces. while (source.MemberOf.Parent != null) { source = source.Parent; } if (toValidate.MemberOf.Parent != null) { // Activity itself is hidden prefix = SR.ValidationErrorPrefixForHiddenActivity(source); } else { if (!parentVisible) { // Activity itself is public but has a private parent prefix = SR.ValidationErrorPrefixForPublicActivityWithHiddenParent(source.Parent, source); } } return prefix; } internal static void RunConstraints(ActivityUtilities.ChildActivity childActivity, ActivityUtilities.ActivityCallStack parentChain, IList constraints, ProcessActivityTreeOptions options, bool suppressGetChildrenViolations, ref IList validationErrors) { if (constraints != null) { Activity toValidate = childActivity.Activity; LocationReferenceEnvironment environment = toValidate.GetParentEnvironment(); Dictionary inputDictionary = new Dictionary (2); for (int constraintIndex = 0; constraintIndex < constraints.Count; constraintIndex++) { Constraint constraint = constraints[constraintIndex]; // there may be null entries here if (constraint == null) { continue; } inputDictionary[Constraint.ToValidateArgumentName] = toValidate; ValidationContext validationContext = new ValidationContext(childActivity, parentChain, options, environment); inputDictionary[Constraint.ToValidateContextArgumentName] = validationContext; IDictionary results = null; try { results = WorkflowInvoker.Invoke(constraint, inputDictionary); } catch (Exception e) { if (Fx.IsFatal(e)) { throw; } ValidationError constraintExceptionValidationError = new ValidationError(SR.InternalConstraintException(constraint.DisplayName, toValidate.GetType().FullName, toValidate.DisplayName, e.ToString()), false) { Source = toValidate, Id = toValidate.Id }; ActivityUtilities.Add(ref validationErrors, constraintExceptionValidationError); } if (results != null) { object resultValidationErrors; if (results.TryGetValue(Constraint.ValidationErrorListArgumentName, out resultValidationErrors)) { IList validationErrorList = (IList )resultValidationErrors; if (validationErrorList.Count > 0) { if (validationErrors == null) { validationErrors = new List (); } Activity source; string prefix = ActivityValidationServices.GenerateValidationErrorPrefix(childActivity.Activity, parentChain, out source); for (int validationErrorIndex = 0; validationErrorIndex < validationErrorList.Count; validationErrorIndex++) { ValidationError validationError = validationErrorList[validationErrorIndex]; validationError.Source = source; validationError.Id = source.Id; if (!string.IsNullOrEmpty(prefix)) { validationError.Message = prefix + validationError.Message; } validationErrors.Add(validationError); } } } } if (!suppressGetChildrenViolations) { validationContext.AddGetChildrenErrors(ref validationErrors); } } } } internal static bool HasErrors(IList validationErrors) { if (validationErrors != null && validationErrors.Count > 0) { for (int i = 0; i < validationErrors.Count; i++) { if (!validationErrors[i].IsWarning) { return true; } } } return false; } class InternalActivityValidationServices { ValidationSettings settings; Activity rootToValidate; IList errors; ProcessActivityTreeOptions options; Activity expressionRoot; internal InternalActivityValidationServices(ValidationSettings settings, Activity toValidate) { this.settings = settings; this.rootToValidate = toValidate; } internal ValidationResults InternalValidate() { this.options = ProcessActivityTreeOptions.GetValidationOptions(this.settings); if (this.settings.OnlyUseAdditionalConstraints) { // We don't want the errors from CacheMetadata so we send those to a "dummy" list. IList suppressedErrors = null; ActivityUtilities.CacheRootMetadata(this.rootToValidate, null, this.options, new ActivityUtilities.ProcessActivityCallback(ValidateElement), ref suppressedErrors); } else { // We want to add the CacheMetadata errors to our errors collection ActivityUtilities.CacheRootMetadata(this.rootToValidate, null, this.options, new ActivityUtilities.ProcessActivityCallback(ValidateElement), ref this.errors); } return new ValidationResults(this.errors); } void ValidateElement(ActivityUtilities.ChildActivity childActivity, ActivityUtilities.ActivityCallStack parentChain) { Activity toValidate = childActivity.Activity; if (!this.settings.SingleLevel || object.ReferenceEquals(toValidate, this.rootToValidate)) { // 0. Open time violations are captured by the CacheMetadata walk. // 1. Argument validations are done by the CacheMetadata walk. // 2. Build constraints are done by the CacheMetadata walk. // 3. Then do policy constraints if (this.settings.HasAdditionalConstraints) { bool suppressGetChildrenViolations = this.settings.OnlyUseAdditionalConstraints || this.settings.SingleLevel; Type currentType = toValidate.GetType(); while (currentType != null) { IList policyConstraints; if (this.settings.AdditionalConstraints.TryGetValue(currentType, out policyConstraints)) { RunConstraints(childActivity, parentChain, policyConstraints, this.options, suppressGetChildrenViolations, ref this.errors); } if (currentType.IsGenericType) { Type genericDefinitionType = currentType.GetGenericTypeDefinition(); if (genericDefinitionType != null) { IList genericTypePolicyConstraints; if (this.settings.AdditionalConstraints.TryGetValue(genericDefinitionType, out genericTypePolicyConstraints)) { RunConstraints(childActivity, parentChain, genericTypePolicyConstraints, this.options, suppressGetChildrenViolations, ref this.errors); } } } currentType = currentType.BaseType; } } //4. Validate if the argument expression subtree contains an activity that can induce idle. if (childActivity.Activity.IsExpressionRoot) { if (childActivity.Activity.HasNonEmptySubtree) { this.expressionRoot = childActivity.Activity; ActivityUtilities.FinishCachingSubtree(childActivity, parentChain, ProcessActivityTreeOptions.FullCachingOptions, ValidateExpressionSubtree); this.expressionRoot = null; } else if (childActivity.Activity.InternalCanInduceIdle) { Activity activity = childActivity.Activity; RuntimeArgument runtimeArgument = GetBoundRuntimeArgument(activity); ValidationError error = new ValidationError(SR.CanInduceIdleActivityInArgumentExpression(runtimeArgument.Name, activity.Parent.DisplayName, activity.DisplayName), true, runtimeArgument.Name, activity.Parent); ActivityUtilities.Add(ref this.errors, error); } } } } void ValidateExpressionSubtree(ActivityUtilities.ChildActivity childActivity, ActivityUtilities.ActivityCallStack parentChain) { Fx.Assert(this.expressionRoot != null, "This callback should be called activities in the expression subtree only."); if (childActivity.Activity.InternalCanInduceIdle) { Activity activity = childActivity.Activity; Activity expressionRoot = this.expressionRoot; RuntimeArgument runtimeArgument = GetBoundRuntimeArgument(expressionRoot); ValidationError error = new ValidationError(SR.CanInduceIdleActivityInArgumentExpression(runtimeArgument.Name, expressionRoot.Parent.DisplayName, activity.DisplayName), true, runtimeArgument.Name, expressionRoot.Parent); ActivityUtilities.Add(ref this.errors, error); } } } // Iterate through all runtime arguments on the configured activity // and find the one that binds to expressionActivity. static RuntimeArgument GetBoundRuntimeArgument(Activity expressionActivity) { Activity configuredActivity = expressionActivity.Parent; Fx.Assert(configuredActivity != null, "Configured activity should not be null."); RuntimeArgument boundRuntimeArgument = null; for (int i = 0; i < configuredActivity.RuntimeArguments.Count; i++) { boundRuntimeArgument = configuredActivity.RuntimeArguments[i]; if (object.ReferenceEquals(boundRuntimeArgument.BoundArgument.Expression, expressionActivity)) { break; } } Fx.Assert(boundRuntimeArgument != null, "We should always be able to find the runtime argument!"); return boundRuntimeArgument; } // This method checks for duplicate evaluation order entries in a collection that is // sorted in ascendng order of evaluation order values. internal static void ValidateEvaluationOrder(IList runtimeArguments, Activity referenceActivity, ref IList validationErrors) { for (int i = 0; i < runtimeArguments.Count-1; i++) { RuntimeArgument argument = runtimeArguments[i]; RuntimeArgument nextArgument = runtimeArguments[i + 1]; if (argument.IsEvaluationOrderSpecified && nextArgument.IsEvaluationOrderSpecified) { if (argument.BoundArgument.EvaluationOrder == nextArgument.BoundArgument.EvaluationOrder) { ActivityUtilities.Add(ref validationErrors, new ValidationError(SR.DuplicateEvaluationOrderValues(referenceActivity.DisplayName, argument.BoundArgument.EvaluationOrder), false, argument.Name, referenceActivity)); } } } } enum ExceptionReason { InvalidTree, InvalidNullInputs, InvalidNonNullInputs } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WebControlParameterProxy.cs
- ModelUIElement3D.cs
- XmlEventCache.cs
- ToolStripSettings.cs
- SourceChangedEventArgs.cs
- MemberAccessException.cs
- ElementMarkupObject.cs
- BamlLocalizabilityResolver.cs
- DefaultEvaluationContext.cs
- TextDpi.cs
- BoundColumn.cs
- HostProtectionException.cs
- ProfileBuildProvider.cs
- CodeDOMProvider.cs
- RightsManagementEncryptedStream.cs
- LinqMaximalSubtreeNominator.cs
- RoleManagerEventArgs.cs
- SplitterCancelEvent.cs
- OracleInternalConnection.cs
- DbParameterCollection.cs
- FocusWithinProperty.cs
- ScriptControlManager.cs
- MessageVersionConverter.cs
- ComMethodElement.cs
- DataServices.cs
- EntityRecordInfo.cs
- util.cs
- FileLogRecordStream.cs
- XmlUtf8RawTextWriter.cs
- ValueTable.cs
- WebPartEditVerb.cs
- PointUtil.cs
- DelegateSerializationHolder.cs
- ContractSearchPattern.cs
- TraceRecord.cs
- TextDecorationLocationValidation.cs
- VisualStyleInformation.cs
- DataBindEngine.cs
- UInt32Storage.cs
- AttributeProviderAttribute.cs
- TextElementCollectionHelper.cs
- _ChunkParse.cs
- ParallelDesigner.cs
- InnerItemCollectionView.cs
- SafeRightsManagementQueryHandle.cs
- Schema.cs
- MimeMapping.cs
- GiveFeedbackEventArgs.cs
- TabControl.cs
- DataGridViewTextBoxCell.cs
- DelegatingTypeDescriptionProvider.cs
- DesignerSerializationOptionsAttribute.cs
- HashHelpers.cs
- ContentPosition.cs
- FrameworkTemplate.cs
- PersonalizationProviderHelper.cs
- ZipIOBlockManager.cs
- DesignerVerbToolStripMenuItem.cs
- Section.cs
- EnumValAlphaComparer.cs
- ListViewGroupItemCollection.cs
- ResolveNameEventArgs.cs
- HandledEventArgs.cs
- XmlAttributeAttribute.cs
- XmlWriter.cs
- DetailsViewCommandEventArgs.cs
- UpdateTracker.cs
- Delay.cs
- StreamGeometryContext.cs
- MultiAsyncResult.cs
- StandardToolWindows.cs
- RuntimeVariableList.cs
- WebPartVerbsEventArgs.cs
- ProxySimple.cs
- NativeMethods.cs
- ContentHostHelper.cs
- BufferedStream.cs
- DynamicRenderer.cs
- PasswordTextContainer.cs
- ZoneIdentityPermission.cs
- XsdDataContractImporter.cs
- SqlUtils.cs
- WasNotInstalledException.cs
- Converter.cs
- FolderBrowserDialogDesigner.cs
- DBPropSet.cs
- DesignerExtenders.cs
- DocumentPage.cs
- LineBreak.cs
- HierarchicalDataSourceConverter.cs
- VBIdentifierName.cs
- ProxyManager.cs
- HostingPreferredMapPath.cs
- StylusTip.cs
- RawStylusInputReport.cs
- ItemsPanelTemplate.cs
- ColorConverter.cs
- DragStartedEventArgs.cs
- PropertySegmentSerializationProvider.cs
- CompilationLock.cs