Code:
/ WCF / WCF / 3.5.30729.1 / untmp / Orcas / SP / ndp / cdf / src / NetFx35 / System.ServiceModel.Web / System / UriTemplateCompoundPathSegment.cs / 3 / UriTemplateCompoundPathSegment.cs
//---------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //--------------------------------------------------------------- namespace System { using System.Collections.Generic; using System.Collections.Specialized; using System.ServiceModel; using System.ServiceModel.Web; using System.Text; // Thin wrapper around formatted string; use type system to help ensure we // are doing canonicalization right/consistently - the literal sections are held in an // un-escaped format // We are assuming that the string will be always built as Lit{Var}Lit[{Var}Lit[{Var}Lit[...]]], // when the first and last literals may be empty class UriTemplateCompoundPathSegment : UriTemplatePathSegment, IComparable{ readonly string firstLiteral; readonly List varLitPairs; CompoundSegmentClass csClass; UriTemplateCompoundPathSegment(string originalSegment, bool endsWithSlash, string firstLiteral) : base(originalSegment, UriTemplatePartType.Compound, endsWithSlash) { this.firstLiteral = firstLiteral; this.varLitPairs = new List (); } public static new UriTemplateCompoundPathSegment CreateFromUriTemplate(string segment, UriTemplate template) { string origSegment = segment; bool endsWithSlash = segment.EndsWith("/", StringComparison.Ordinal); if (endsWithSlash) { segment = segment.Remove(segment.Length - 1); } int nextVarStart = segment.IndexOf("{", StringComparison.Ordinal); Fx.Assert(nextVarStart >= 0, "The method is only called after identifying a '{' character in the segment"); string firstLiteral = ((nextVarStart > 0) ? segment.Substring(0, nextVarStart) : string.Empty); if (firstLiteral.IndexOf(UriTemplate.WildcardPath, StringComparison.Ordinal) != -1) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException( SR2.GetString(SR2.UTInvalidWildcardInVariableOrLiteral, template.originalTemplate, UriTemplate.WildcardPath))); } UriTemplateCompoundPathSegment result = new UriTemplateCompoundPathSegment(origSegment, endsWithSlash, ((firstLiteral != string.Empty) ? Uri.UnescapeDataString(firstLiteral) : string.Empty)); do { int nextVarEnd = segment.IndexOf("}", nextVarStart + 1, StringComparison.Ordinal); if (nextVarEnd < nextVarStart + 2) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException( SR2.GetString(SR2.UTInvalidFormatSegmentOrQueryPart, segment))); } bool hasDefault; string varName = template.AddPathVariable(UriTemplatePartType.Compound, segment.Substring(nextVarStart + 1, nextVarEnd - nextVarStart - 1), out hasDefault); if (hasDefault) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( SR2.GetString(SR2.UTDefaultValueToCompoundSegmentVar, template, origSegment, varName))); } nextVarStart = segment.IndexOf("{", nextVarEnd + 1, StringComparison.Ordinal); string literal; if (nextVarStart > 0) { if (nextVarStart == nextVarEnd + 1) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("template", SR2.GetString(SR2.UTDoesNotSupportAdjacentVarsInCompoundSegment, template, segment)); } literal = segment.Substring(nextVarEnd + 1, nextVarStart - nextVarEnd - 1); } else if (nextVarEnd + 1 < segment.Length) { literal = segment.Substring(nextVarEnd + 1); } else { literal = string.Empty; } if (literal.IndexOf(UriTemplate.WildcardPath, StringComparison.Ordinal) != -1) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException( SR2.GetString(SR2.UTInvalidWildcardInVariableOrLiteral, template.originalTemplate, UriTemplate.WildcardPath))); } if (literal.IndexOf('}') != -1) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new FormatException( SR2.GetString(SR2.UTInvalidFormatSegmentOrQueryPart, segment))); } result.varLitPairs.Add(new VarAndLitPair(varName, ((literal == string.Empty) ? string.Empty : Uri.UnescapeDataString(literal)))); } while (nextVarStart > 0); if (string.IsNullOrEmpty(result.firstLiteral)) { if (string.IsNullOrEmpty(result.varLitPairs[result.varLitPairs.Count - 1].Literal)) { result.csClass = CompoundSegmentClass.HasNoPrefixNorSuffix; } else { result.csClass = CompoundSegmentClass.HasOnlySuffix; } } else { if (string.IsNullOrEmpty(result.varLitPairs[result.varLitPairs.Count - 1].Literal)) { result.csClass = CompoundSegmentClass.HasOnlyPrefix; } else { result.csClass = CompoundSegmentClass.HasPrefixAndSuffix; } } return result; } public override void Bind(string[] values, ref int valueIndex, StringBuilder path) { Fx.Assert(valueIndex + this.varLitPairs.Count <= values.Length, "Not enough values to bind"); path.Append(this.firstLiteral); for (int pairIndex = 0; pairIndex < this.varLitPairs.Count; pairIndex++) { path.Append(values[valueIndex++]); path.Append(this.varLitPairs[pairIndex].Literal); } if (this.EndsWithSlash) { path.Append("/"); } } public override bool IsEquivalentTo(UriTemplatePathSegment other, bool ignoreTrailingSlash) { if (other == null) { Fx.Assert("why would we ever call this?"); return false; } if (!ignoreTrailingSlash && (this.EndsWithSlash != other.EndsWithSlash)) { return false; } UriTemplateCompoundPathSegment otherAsCompound = other as UriTemplateCompoundPathSegment; Fx.Assert(otherAsCompound != null, "The nature requires that this will be OK"); if (this.varLitPairs.Count != otherAsCompound.varLitPairs.Count) { return false; } if (StringComparer.OrdinalIgnoreCase.Compare(this.firstLiteral, otherAsCompound.firstLiteral) != 0) { return false; } for (int pairIndex = 0; pairIndex < this.varLitPairs.Count; pairIndex++) { if (StringComparer.OrdinalIgnoreCase.Compare(this.varLitPairs[pairIndex].Literal, otherAsCompound.varLitPairs[pairIndex].Literal) != 0) { return false; } } return true; } public override bool IsMatch(UriTemplateLiteralPathSegment segment, bool ignoreTrailingSlash) { if (!ignoreTrailingSlash && (this.EndsWithSlash != segment.EndsWithSlash)) { return false; } return TryLookup(segment.AsUnescapedString(), null); } public override void Lookup(string segment, NameValueCollection boundParameters) { if (!TryLookup(segment, boundParameters)) { Fx.Assert("How can that be? Lookup is expected to be called after IsMatch"); throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException( SR2.GetString(SR2.UTCSRLookupBeforeMatch))); } } bool TryLookup(string segment, NameValueCollection boundParameters) { int segmentPosition = 0; if (!string.IsNullOrEmpty(this.firstLiteral)) { if (segment.StartsWith(this.firstLiteral, StringComparison.Ordinal)) { segmentPosition = this.firstLiteral.Length; } else { return false; } } for (int pairIndex = 0; pairIndex < this.varLitPairs.Count - 1; pairIndex++) { int nextLiteralPosition = segment.IndexOf(this.varLitPairs[pairIndex].Literal, segmentPosition, StringComparison.Ordinal); if (nextLiteralPosition < segmentPosition + 1) { return false; } if (boundParameters != null) { string varValue = segment.Substring(segmentPosition, nextLiteralPosition - segmentPosition); boundParameters.Add(this.varLitPairs[pairIndex].VarName, varValue); } segmentPosition = nextLiteralPosition + this.varLitPairs[pairIndex].Literal.Length; } if (segmentPosition < segment.Length) { if (string.IsNullOrEmpty(this.varLitPairs[varLitPairs.Count - 1].Literal)) { if (boundParameters != null) { boundParameters.Add(this.varLitPairs[varLitPairs.Count - 1].VarName, segment.Substring(segmentPosition)); } return true; } else if ((segmentPosition + this.varLitPairs[varLitPairs.Count - 1].Literal.Length < segment.Length) && segment.EndsWith(this.varLitPairs[varLitPairs.Count - 1].Literal, StringComparison.Ordinal)) { if (boundParameters != null) { boundParameters.Add(this.varLitPairs[varLitPairs.Count - 1].VarName, segment.Substring(segmentPosition, segment.Length - segmentPosition - this.varLitPairs[varLitPairs.Count - 1].Literal.Length)); } return true; } else { return false; } } else { return false; } } // A note about comparing compound segments: // We are using this for generating the sorted collections at the nodes of the UriTemplateTrieNode. // The idea is that we are sorting the segments based on preferred matching, when we have two // compound segments matching the same wire segment, we will give preference to the preceding one. // The order is based on the following concepts: // - We are defining four classes of compound segments: prefix+suffix, prefix-only, suffix-only // and none // - Whenever we are comparing segments from different class the preferred one is the segment with // the prefared class, based on the order we defined them (p+s \ p \ s \ n). // - Within each class the preference is based on the prefix\suffix, while prefix has precedence // over suffix if both exists. // - If after comparing the class, as well as the prefix\suffix, we didn't reach to a conclusion, // the preference is given to the segment with more variables parts. // This order mostly follows the intuitive common sense; the major issue comes from preferring the // prefix over the suffix in the case where both exist. This is derived from the problematic of any // other type of solution that don't prefere the prefix over the suffix or vice versa. To better // understanding lets considered the following example: // In comparing 'foo{x}bar' and 'food{x}ar', unless we are preferring prefix or suffix, we have // to state that they have the same order. So is the case with 'foo{x}babar' and 'food{x}ar', which // will lead us to claiming the 'foo{x}bar' and 'foo{x}babar' are from the same order, which they // clearly are not. // Taking other approaches to this problem results in similar cases. The only solution is preferring // either the prefix or the suffix over the other; since we already preferred prefix over suffix // implicitly (we preferred the prefix only class over the suffix only, we also prefared literal // over variable, if in the same path segment) that still maintain consistency. // Therefore: // - 'food{var}' should be before 'foo{var}'; '{x}.{y}.{z}' should be before '{x}.{y}'. // - the order between '{var}bar' and '{var}qux' is not important // - '{x}.{y}' and '{x}_{y}' should have the same order // - 'foo{x}bar' is less preferred than 'food{x}ar' // In the above third case - if we are opening the table with allowDuplicate=false, we will throw; // if we are opening it with allowDuplicate=true we will let it go and might match both templates // for certain wire candidates. int IComparable .CompareTo(UriTemplateCompoundPathSegment other) { Fx.Assert(other != null, "We are only expected to get here for comparing real compound segments"); switch (this.csClass) { case CompoundSegmentClass.HasPrefixAndSuffix: switch (other.csClass) { case CompoundSegmentClass.HasPrefixAndSuffix: return CompareToOtherThatHasPrefixAndSuffix(other); case CompoundSegmentClass.HasOnlyPrefix: case CompoundSegmentClass.HasOnlySuffix: case CompoundSegmentClass.HasNoPrefixNorSuffix: return -1; default: Fx.Assert("Invalid other.CompoundSegmentClass"); return 0; } case CompoundSegmentClass.HasOnlyPrefix: switch (other.csClass) { case CompoundSegmentClass.HasPrefixAndSuffix: return 1; case CompoundSegmentClass.HasOnlyPrefix: return CompareToOtherThatHasOnlyPrefix(other); case CompoundSegmentClass.HasOnlySuffix: case CompoundSegmentClass.HasNoPrefixNorSuffix: return -1; default: Fx.Assert("Invalid other.CompoundSegmentClass"); return 0; } case CompoundSegmentClass.HasOnlySuffix: switch (other.csClass) { case CompoundSegmentClass.HasPrefixAndSuffix: case CompoundSegmentClass.HasOnlyPrefix: return 1; case CompoundSegmentClass.HasOnlySuffix: return CompareToOtherThatHasOnlySuffix(other); case CompoundSegmentClass.HasNoPrefixNorSuffix: return -1; default: Fx.Assert("Invalid other.CompoundSegmentClass"); return 0; } case CompoundSegmentClass.HasNoPrefixNorSuffix: switch (other.csClass) { case CompoundSegmentClass.HasPrefixAndSuffix: case CompoundSegmentClass.HasOnlyPrefix: case CompoundSegmentClass.HasOnlySuffix: return 1; case CompoundSegmentClass.HasNoPrefixNorSuffix: return CompareToOtherThatHasNoPrefixNorSuffix(other); default: Fx.Assert("Invalid other.CompoundSegmentClass"); return 0; } default: Fx.Assert("Invalid this.CompoundSegmentClass"); return 0; } } int CompareToOtherThatHasPrefixAndSuffix(UriTemplateCompoundPathSegment other) { Fx.Assert(this.csClass == CompoundSegmentClass.HasPrefixAndSuffix, "Otherwise, how did we got here?"); Fx.Assert(other.csClass == CompoundSegmentClass.HasPrefixAndSuffix, "Otherwise, how did we got here?"); // In this case we are determining the order based on the prefix of the two segments, // then by their suffix and then based on the number of variables int prefixOrder = ComparePrefixToOtherPrefix(other); if (prefixOrder == 0) { int suffixOrder = CompareSuffixToOtherSuffix(other); if (suffixOrder == 0) { return (other.varLitPairs.Count - this.varLitPairs.Count); } else { return suffixOrder; } } else { return prefixOrder; } } int CompareToOtherThatHasOnlyPrefix(UriTemplateCompoundPathSegment other) { Fx.Assert(this.csClass == CompoundSegmentClass.HasOnlyPrefix, "Otherwise, how did we got here?"); Fx.Assert(other.csClass == CompoundSegmentClass.HasOnlyPrefix, "Otherwise, how did we got here?"); // In this case we are determining the order based on the prefix of the two segments, // then based on the number of variables int prefixOrder = ComparePrefixToOtherPrefix(other); if (prefixOrder == 0) { return (other.varLitPairs.Count - this.varLitPairs.Count); } else { return prefixOrder; } } int CompareToOtherThatHasOnlySuffix(UriTemplateCompoundPathSegment other) { Fx.Assert(this.csClass == CompoundSegmentClass.HasOnlySuffix, "Otherwise, how did we got here?"); Fx.Assert(other.csClass == CompoundSegmentClass.HasOnlySuffix, "Otherwise, how did we got here?"); // In this case we are determining the order based on the suffix of the two segments, // then based on the number of variables int suffixOrder = CompareSuffixToOtherSuffix(other); if (suffixOrder == 0) { return (other.varLitPairs.Count - this.varLitPairs.Count); } else { return suffixOrder; } } int CompareToOtherThatHasNoPrefixNorSuffix(UriTemplateCompoundPathSegment other) { Fx.Assert(this.csClass == CompoundSegmentClass.HasNoPrefixNorSuffix, "Otherwise, how did we got here?"); Fx.Assert(other.csClass == CompoundSegmentClass.HasNoPrefixNorSuffix, "Otherwise, how did we got here?"); // In this case the order is determined by the number of variables return (other.varLitPairs.Count - this.varLitPairs.Count); } int ComparePrefixToOtherPrefix(UriTemplateCompoundPathSegment other) { return string.Compare(other.firstLiteral, this.firstLiteral, StringComparison.OrdinalIgnoreCase); } int CompareSuffixToOtherSuffix(UriTemplateCompoundPathSegment other) { string reversedSuffix = ReverseString(this.varLitPairs[this.varLitPairs.Count - 1].Literal); string reversedOtherSuffix = ReverseString(other.varLitPairs[other.varLitPairs.Count - 1].Literal); return string.Compare(reversedOtherSuffix, reversedSuffix, StringComparison.OrdinalIgnoreCase); } static string ReverseString(string stringToReverse) { char[] reversedString = new char[stringToReverse.Length]; for (int i = 0; i < stringToReverse.Length; i++) { reversedString[i] = stringToReverse[stringToReverse.Length - i - 1]; } return new string(reversedString); } enum CompoundSegmentClass { Undefined, HasPrefixAndSuffix, HasOnlyPrefix, HasOnlySuffix, HasNoPrefixNorSuffix } struct VarAndLitPair { readonly string literal; readonly string varName; public VarAndLitPair(string varName, string literal) { this.varName = varName; this.literal = literal; } public string Literal { get { return this.literal; } } public string VarName { get { return this.varName; } } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- PageBorderless.cs
- ControlAdapter.cs
- MediaSystem.cs
- TreeView.cs
- ProfileSettingsCollection.cs
- StringExpressionSet.cs
- TraceEventCache.cs
- UIElementHelper.cs
- LogReserveAndAppendState.cs
- TemplateControlParser.cs
- PeerDuplexChannel.cs
- ImportException.cs
- ReversePositionQuery.cs
- UdpDiscoveryEndpointElement.cs
- TrackBar.cs
- EndpointDispatcher.cs
- Pointer.cs
- JsonWriterDelegator.cs
- MdImport.cs
- InvalidPrinterException.cs
- FactoryMaker.cs
- precedingsibling.cs
- ValidationVisibilityAttribute.cs
- SmtpTransport.cs
- httpstaticobjectscollection.cs
- XmlNamespaceDeclarationsAttribute.cs
- IntranetCredentialPolicy.cs
- SqlProviderManifest.cs
- ImpersonationContext.cs
- BamlReader.cs
- Logging.cs
- CodePrimitiveExpression.cs
- NetworkStream.cs
- ToolStrip.cs
- Activity.cs
- IPipelineRuntime.cs
- ControlUtil.cs
- TreeViewAutomationPeer.cs
- UnsafeNetInfoNativeMethods.cs
- Nullable.cs
- DataGridBoundColumn.cs
- GridItemCollection.cs
- XmlSchemaCompilationSettings.cs
- CodeGen.cs
- FormViewUpdateEventArgs.cs
- Marshal.cs
- TransformValueSerializer.cs
- HighContrastHelper.cs
- X509Chain.cs
- DoubleConverter.cs
- ColumnMapVisitor.cs
- HtmlTernaryTree.cs
- TimelineGroup.cs
- IPAddress.cs
- LicenseException.cs
- SqlRewriteScalarSubqueries.cs
- RC2CryptoServiceProvider.cs
- HttpGetProtocolReflector.cs
- DetailsViewDeletedEventArgs.cs
- Camera.cs
- OleDbSchemaGuid.cs
- VerbConverter.cs
- WindowInteropHelper.cs
- TargetInvocationException.cs
- WebPartZoneBase.cs
- XmlSchemaAll.cs
- XmlStringTable.cs
- EnumMember.cs
- InkCanvasInnerCanvas.cs
- CodeExporter.cs
- ResourceSetExpression.cs
- WebPartVerbCollection.cs
- CustomErrorsSection.cs
- ProgressBar.cs
- StandardToolWindows.cs
- DataControlCommands.cs
- WpfSharedBamlSchemaContext.cs
- StandardOleMarshalObject.cs
- List.cs
- HasActivatableWorkflowEvent.cs
- CollectionEditor.cs
- GAC.cs
- InlineObject.cs
- WorkflowControlClient.cs
- Parser.cs
- SoapAttributeOverrides.cs
- ClassHandlersStore.cs
- WebOperationContext.cs
- SingleStorage.cs
- EntityDataSourceWizardForm.cs
- Version.cs
- DbConnectionPoolOptions.cs
- Site.cs
- IndexOutOfRangeException.cs
- SchemaImporterExtension.cs
- CodeDirectionExpression.cs
- SrgsItemList.cs
- FileSystemInfo.cs
- LinearQuaternionKeyFrame.cs
- SweepDirectionValidation.cs