< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.UriTemplateTable
Assembly: CoreWCF.WebHttp
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.WebHttp/src/CoreWCF/UriTemplateTable.cs
Line coverage
61%
Covered lines: 141
Uncovered lines: 88
Coverable lines: 229
Total lines: 606
Line coverage: 61.5%
Branch coverage
57%
Covered branches: 74
Total branches: 128
Branch coverage: 57.8%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Cyclomatic complexity NPath complexity Sequence coverage
.ctor()100%110%
.ctor(...)100%110%
.ctor(...)100%11100%
.ctor(...)100%110%
.ctor(...)100%110%
.ctor(...)66.66%6683.33%
MakeReadOnly(...)100%22100%
Match(...)52.94%343456.52%
MatchSingle(...)75%4483.33%
AllEquivalent(...)0%660%
AtLeastOneCandidateHasQueryPart(...)100%44100%
NoCandidateHasQueryLiteralRequirementsAndThereIsAnEmptyFallback(...)66.66%6671.42%
None()100%11100%
NotAllCandidatesArePathFullyEquivalent(...)12.5%8822.22%
ComputeRelativeSegmentsAndLookup(...)100%44100%
ConstructFastPathTable()100%1414100%
FastComputeRelativeSegmentsAndLookup(...)100%44100%
NormalizeBaseAddress()100%66100%
SlowComputeRelativeSegmentsAndLookup(...)60%101057.14%
Validate(...)50%4471.42%
VerifyThatFastPathAndSlowPathHaveSameResults(...)0%440%
.ctor()100%11100%
Freeze()100%11100%
.ctor()100%11100%
.ctor(...)0%220%
InsertItem(...)100%11100%
SetItem(...)100%110%
ThrowIfInvalid(...)50%4442.85%

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.WebHttp/src/CoreWCF/UriTemplateTable.cs

#LineLine coverage
 1// Licensed to the .NET Foundation under one or more agreements.
 2// The .NET Foundation licenses this file to you under the MIT license.
 3
 4using System;
 5using System.Collections.Generic;
 6using System.Collections.ObjectModel;
 7using System.Collections.Specialized;
 8using System.Diagnostics;
 9using CoreWCF.Runtime;
 10
 11namespace CoreWCF
 12{
 13    public class UriTemplateTable
 14    {
 15        private Uri _baseAddress;
 16        private string _basePath;
 17        private Dictionary<string, FastPathInfo> _fastPathTable; // key is uri.PathAndQuery, fastPathTable may be null
 18        private bool _noTemplateHasQueryPart;
 19        private int _numSegmentsInBaseAddress;
 20        private UriTemplateTrieNode _rootNode;
 21        private readonly UriTemplatesCollection _templates;
 22        private readonly object _thisLock;
 23        private readonly bool _addTrailingSlashToBaseAddress;
 24
 25        public UriTemplateTable()
 026            : this(null, null, true)
 27        {
 028        }
 29
 30        public UriTemplateTable(IEnumerable<KeyValuePair<UriTemplate, object>> keyValuePairs)
 031            : this(null, keyValuePairs, true)
 32        {
 033        }
 34
 35        public UriTemplateTable(Uri baseAddress)
 4736            : this(baseAddress, null, true)
 37        {
 4738        }
 39
 40        internal UriTemplateTable(Uri baseAddress, bool addTrailingSlashToBaseAddress)
 041            : this(baseAddress, null, addTrailingSlashToBaseAddress)
 42        {
 043        }
 44
 45        public UriTemplateTable(Uri baseAddress, IEnumerable<KeyValuePair<UriTemplate, object>> keyValuePairs)
 046            : this(baseAddress, keyValuePairs, true)
 47        {
 048        }
 49
 4750        internal UriTemplateTable(Uri baseAddress, IEnumerable<KeyValuePair<UriTemplate, object>> keyValuePairs, bool ad
 51        {
 4752            if (baseAddress != null && !baseAddress.IsAbsoluteUri)
 53            {
 054                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(baseAddress), SR.UTTMustBeAbsolute);
 55            }
 56
 4757            _addTrailingSlashToBaseAddress = addTrailingSlashToBaseAddress;
 4758            OriginalBaseAddress = baseAddress;
 59
 4760            if (keyValuePairs != null)
 61            {
 062                _templates = new UriTemplatesCollection(keyValuePairs);
 63            }
 64            else
 65            {
 4766                _templates = new UriTemplatesCollection();
 67            }
 68
 4769            _thisLock = new object();
 4770            _baseAddress = baseAddress;
 4771            NormalizeBaseAddress();
 4772        }
 73
 74        public Uri BaseAddress
 75        {
 76            get
 77            {
 078                return _baseAddress;
 79            }
 80            set
 81            {
 082                if (value == null)
 83                {
 084                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(value));
 85                }
 86
 087                lock (_thisLock)
 88                {
 089                    if (IsReadOnly)
 90                    {
 091                        throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(
 092                            SR.UTTCannotChangeBaseAddress));
 93                    }
 94                    else
 95                    {
 096                        if (!value.IsAbsoluteUri)
 97                        {
 098                            throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(nameof(value), SR.UTTBaseAddres
 99                        }
 100                        else
 101                        {
 0102                            OriginalBaseAddress = value;
 0103                            _baseAddress = value;
 0104                            NormalizeBaseAddress();
 105                        }
 106                    }
 0107                }
 0108            }
 109        }
 110
 197111        public Uri OriginalBaseAddress { get; private set; }
 112
 83113        public bool IsReadOnly => _templates.IsFrozen;
 114
 163115        public IList<KeyValuePair<UriTemplate, object>> KeyValuePairs => _templates;
 116
 117        public void MakeReadOnly(bool allowDuplicateEquivalentUriTemplates)
 118        {
 119            // idempotent
 83120            lock (_thisLock)
 121            {
 83122                if (!IsReadOnly)
 123                {
 47124                    _templates.Freeze();
 47125                    Validate(allowDuplicateEquivalentUriTemplates);
 47126                    ConstructFastPathTable();
 127                }
 83128            }
 83129        }
 130
 131        public Collection<UriTemplateMatch> Match(Uri uri)
 132        {
 36133            if (uri == null)
 134            {
 0135                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(uri));
 136            }
 137
 36138            if (!uri.IsAbsoluteUri)
 139            {
 0140                return None();
 141            }
 142
 36143            MakeReadOnly(true);
 144
 145            // Matching path :
 36146            if (!FastComputeRelativeSegmentsAndLookup(uri, out Collection<string> relativeSegments, out IList<UriTemplat
 147            {
 1148                return None();
 149            }
 150
 151            // Matching query :
 35152            NameValueCollection queryParameters = null;
 35153            if (!_noTemplateHasQueryPart && AtLeastOneCandidateHasQueryPart(candidates))
 154            {
 1155                Collection<UriTemplateTableMatchCandidate> nextCandidates = new Collection<UriTemplateTableMatchCandidat
 156                Fx.Assert(nextCandidates.Count == 0, "nextCandidates should be empty");
 157
 158                // then deal with query
 1159                queryParameters = UriTemplateHelpers.ParseQueryString(uri.Query);
 1160                bool mustBeEspeciallyInteresting = NoCandidateHasQueryLiteralRequirementsAndThereIsAnEmptyFallback(candi
 4161                for (int i = 0; i < candidates.Count; i++)
 162                {
 1163                    if (UriTemplateHelpers.CanMatchQueryInterestingly(candidates[i].Template, queryParameters, mustBeEsp
 164                    {
 1165                        nextCandidates.Add(candidates[i]);
 166                    }
 167                }
 168
 1169                if (nextCandidates.Count > 1)
 170                {
 171                    Fx.Assert(AllEquivalent(nextCandidates, 0, nextCandidates.Count), "demux algorithm problem, multiple
 172                }
 173
 1174                if (nextCandidates.Count == 0)
 175                {
 0176                    for (int i = 0; i < candidates.Count; i++)
 177                    {
 0178                        if (UriTemplateHelpers.CanMatchQueryTrivially(candidates[i].Template))
 179                        {
 0180                            nextCandidates.Add(candidates[i]);
 181                        }
 182                    }
 183                }
 184
 1185                if (nextCandidates.Count == 0)
 186                {
 0187                    return None();
 188                }
 189
 1190                if (nextCandidates.Count > 1)
 191                {
 192                    Fx.Assert(AllEquivalent(nextCandidates, 0, nextCandidates.Count), "demux algorithm problem, multiple
 193                }
 194
 1195                candidates = nextCandidates;
 196            }
 197
 198            // Verifying that we have not broken the allowDuplicates settings because of terminal defaults
 199            //  This situation can be caused when we are hosting ".../" and ".../{foo=xyz}" in the same
 200            //  table. They are not equivalent; yet they reside together in the same path partially-equivalent
 201            //  set. If we hit a uri that ends up in that particular end-of-path set, we want to provide the
 202            //  user only the 'best' match and not both; thus preventing inconsistancy between the MakeReadonly
 203            //  settings and the matching results. We will assume that the 'best' matches will be the ones with
 204            //  the smallest number of segments - this will prefer ".../" over ".../{x=1}[/...]".
 35205            if (NotAllCandidatesArePathFullyEquivalent(candidates))
 206            {
 0207                Collection<UriTemplateTableMatchCandidate> nextCandidates = new Collection<UriTemplateTableMatchCandidat
 0208                int minSegmentsCount = -1;
 0209                for (int i = 0; i < candidates.Count; i++)
 210                {
 0211                    UriTemplateTableMatchCandidate candidate = candidates[i];
 0212                    if (minSegmentsCount == -1)
 213                    {
 0214                        minSegmentsCount = candidate.Template._segments.Count;
 0215                        nextCandidates.Add(candidate);
 216                    }
 0217                    else if (candidate.Template._segments.Count < minSegmentsCount)
 218                    {
 0219                        minSegmentsCount = candidate.Template._segments.Count;
 0220                        nextCandidates.Clear();
 0221                        nextCandidates.Add(candidate);
 222                    }
 0223                    else if (candidate.Template._segments.Count == minSegmentsCount)
 224                    {
 0225                        nextCandidates.Add(candidate);
 226                    }
 227                }
 228
 229                Fx.Assert(minSegmentsCount != -1, "At least the first entry in the list should be kept");
 230                Fx.Assert(nextCandidates.Count >= 1, "At least the first entry in the list should be kept");
 231                Fx.Assert(nextCandidates[0].Template._segments.Count == minSegmentsCount, "Trivial");
 232
 0233                candidates = nextCandidates;
 234            }
 235
 236            // Building the actual result
 35237            Collection<UriTemplateMatch> actualResults = new Collection<UriTemplateMatch>();
 140238            for (int i = 0; i < candidates.Count; i++)
 239            {
 35240                UriTemplateTableMatchCandidate candidate = candidates[i];
 35241                UriTemplateMatch match = candidate.Template.CreateUriTemplateMatch(OriginalBaseAddress,
 35242                    uri, candidate.Data, candidate.SegmentsCount, relativeSegments, queryParameters);
 35243                actualResults.Add(match);
 244            }
 245
 35246            return actualResults;
 247        }
 248
 249        public UriTemplateMatch MatchSingle(Uri uri)
 250        {
 36251            Collection<UriTemplateMatch> c = Match(uri);
 36252            if (c.Count == 0)
 253            {
 1254                return null;
 255            }
 256
 35257            if (c.Count == 1)
 258            {
 35259                return c[0];
 260            }
 261
 0262            throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new UriTemplateMatchException(SR.UTTMultipleMatche
 263        }
 264
 265        private static bool AllEquivalent(IList<UriTemplateTableMatchCandidate> list, int a, int b)
 266        {
 0267            for (int i = a; i < b - 1; ++i)
 268            {
 0269                if (!list[i].Template.IsPathPartiallyEquivalentAt(list[i + 1].Template, list[i].SegmentsCount))
 270                {
 0271                    return false;
 272                }
 273
 0274                if (!list[i].Template.IsQueryEquivalent(list[i + 1].Template))
 275                {
 0276                    return false;
 277                }
 278            }
 279
 0280            return true;
 281        }
 282
 283        private static bool AtLeastOneCandidateHasQueryPart(IList<UriTemplateTableMatchCandidate> candidates)
 284        {
 26285            for (int i = 0; i < candidates.Count; i++)
 286            {
 7287                if (!UriTemplateHelpers.CanMatchQueryTrivially(candidates[i].Template))
 288                {
 1289                    return true;
 290                }
 291            }
 292
 6293            return false;
 294        }
 295
 296        private static bool NoCandidateHasQueryLiteralRequirementsAndThereIsAnEmptyFallback(
 297            IList<UriTemplateTableMatchCandidate> candidates)
 298        {
 1299            bool thereIsAmEmptyFallback = false;
 4300            for (int i = 0; i < candidates.Count; i++)
 301            {
 1302                if (UriTemplateHelpers.HasQueryLiteralRequirements(candidates[i].Template))
 303                {
 0304                    return false;
 305                }
 306
 1307                if (candidates[i].Template._queries.Count == 0)
 308                {
 0309                    thereIsAmEmptyFallback = true;
 310                }
 311            }
 312
 1313            return thereIsAmEmptyFallback;
 314        }
 315
 316        private static Collection<UriTemplateMatch> None()
 317        {
 1318            return new Collection<UriTemplateMatch>();
 319        }
 320
 321        private static bool NotAllCandidatesArePathFullyEquivalent(IList<UriTemplateTableMatchCandidate> candidates)
 322        {
 35323            if (candidates.Count <= 1)
 324            {
 35325                return false;
 326            }
 327
 0328            int segmentsCount = -1;
 0329            for (int i = 0; i < candidates.Count; i++)
 330            {
 0331                if (segmentsCount == -1)
 332                {
 0333                    segmentsCount = candidates[i].Template._segments.Count;
 334                }
 0335                else if (segmentsCount != candidates[i].Template._segments.Count)
 336                {
 0337                    return true;
 338                }
 339            }
 340
 0341            return false;
 342        }
 343
 344        private bool ComputeRelativeSegmentsAndLookup(Uri uri,
 345            ICollection<string> relativePathSegments, // add to this
 346            ICollection<UriTemplateTableMatchCandidate> candidates) // matched candidates
 347        {
 122348            string[] uriSegments = uri.Segments;
 122349            int numRelativeSegments = uriSegments.Length - _numSegmentsInBaseAddress;
 350            Fx.Assert(numRelativeSegments >= 0, "bad num segments");
 122351            UriTemplateLiteralPathSegment[] uSegments = new UriTemplateLiteralPathSegment[numRelativeSegments];
 504352            for (int i = 0; i < numRelativeSegments; ++i)
 353            {
 130354                string seg = uriSegments[i + _numSegmentsInBaseAddress];
 355                // compute representation for matching
 130356                UriTemplateLiteralPathSegment lps = UriTemplateLiteralPathSegment.CreateFromWireData(seg);
 130357                uSegments[i] = lps;
 358                // compute representation to project out into results
 130359                string relPathSeg = Uri.UnescapeDataString(seg);
 130360                if (lps.EndsWithSlash)
 361                {
 362                    Fx.Assert(relPathSeg.EndsWith("/", StringComparison.Ordinal), "problem with relative path segment");
 9363                    relPathSeg = relPathSeg.Substring(0, relPathSeg.Length - 1); // trim slash
 364                }
 365
 130366                relativePathSegments.Add(relPathSeg);
 367            }
 368
 122369            return _rootNode.Match(uSegments, candidates);
 370        }
 371
 372        private void ConstructFastPathTable()
 373        {
 47374            _noTemplateHasQueryPart = true;
 420375            foreach (KeyValuePair<UriTemplate, object> kvp in _templates)
 376            {
 163377                UriTemplate ut = kvp.Key;
 163378                if (!UriTemplateHelpers.CanMatchQueryTrivially(ut))
 379                {
 8380                    _noTemplateHasQueryPart = false;
 381                }
 382
 163383                if (ut.HasNoVariables && !ut.HasWildcard)
 384                {
 385                    // eligible for fast path
 115386                    if (_fastPathTable == null)
 387                    {
 39388                        _fastPathTable = new Dictionary<string, FastPathInfo>();
 389                    }
 390
 115391                    Uri uri = ut.BindByPosition(OriginalBaseAddress);
 115392                    string uriPath = UriTemplateHelpers.GetUriPath(uri);
 115393                    if (_fastPathTable.ContainsKey(uriPath))
 394                    {
 395                        // nothing to do, we've already seen it
 396                    }
 397                    else
 398                    {
 115399                        FastPathInfo fpInfo = new FastPathInfo();
 115400                        if (ComputeRelativeSegmentsAndLookup(uri, fpInfo.RelativePathSegments,
 115401                            fpInfo.Candidates))
 402                        {
 115403                            fpInfo.Freeze();
 115404                            _fastPathTable.Add(uriPath, fpInfo);
 405                        }
 406                    }
 407                }
 408            }
 47409        }
 410
 411        // this method checks the literal cache for a match if none, goes through the slower path of cracking the segmen
 412        private bool FastComputeRelativeSegmentsAndLookup(Uri uri, out Collection<string> relativePathSegments,
 413            out IList<UriTemplateTableMatchCandidate> candidates)
 414        {
 415            // Consider fast-path and lookup
 416            // return false if not under base uri
 36417            string uriPath = UriTemplateHelpers.GetUriPath(uri);
 36418            if ((_fastPathTable != null) && _fastPathTable.TryGetValue(uriPath, out FastPathInfo fpInfo))
 419            {
 29420                relativePathSegments = fpInfo.RelativePathSegments;
 29421                candidates = fpInfo.Candidates;
 422                VerifyThatFastPathAndSlowPathHaveSameResults(uri, relativePathSegments, candidates);
 29423                return true;
 424            }
 425            else
 426            {
 7427                relativePathSegments = new Collection<string>();
 7428                candidates = new Collection<UriTemplateTableMatchCandidate>();
 7429                return SlowComputeRelativeSegmentsAndLookup(uri, uriPath, relativePathSegments, candidates);
 430            }
 431        }
 432
 433        private void NormalizeBaseAddress()
 434        {
 47435            if (_baseAddress != null)
 436            {
 437                // ensure trailing slash on baseAddress, so that IsBaseOf will work later
 47438                UriBuilder ub = new UriBuilder(_baseAddress);
 47439                if (_addTrailingSlashToBaseAddress && !ub.Path.EndsWith("/", StringComparison.Ordinal))
 440                {
 45441                    ub.Path = ub.Path + "/";
 442                }
 443
 47444                ub.Host = "localhost"; // always normalize to localhost
 47445                ub.Port = -1;
 47446                ub.UserName = null;
 47447                ub.Password = null;
 47448                ub.Path = ub.Path.ToUpperInvariant();
 47449                ub.Scheme = Uri.UriSchemeHttp;
 47450                _baseAddress = ub.Uri;
 47451                _basePath = UriTemplateHelpers.GetUriPath(_baseAddress);
 452            }
 47453        }
 454
 455        private bool SlowComputeRelativeSegmentsAndLookup(Uri uri, string uriPath, Collection<string> relativePathSegmen
 456            ICollection<UriTemplateTableMatchCandidate> candidates)
 457        {
 458            // ensure 'under' the base address
 7459            if (uriPath.Length < _basePath.Length)
 460            {
 0461                return false;
 462            }
 463
 7464            if (!uriPath.StartsWith(_basePath, StringComparison.OrdinalIgnoreCase))
 465            {
 0466                return false;
 467            }
 468            else
 469            {
 470                // uriPath StartsWith basePath, but this check is not enough - basePath 'service1' should not match with
 471                // make sure that after the match the next character is /, this is to avoid a uriPath of the form /servi
 7472                if (uriPath.Length > _basePath.Length && !_basePath.EndsWith("/", StringComparison.Ordinal) && uriPath[_
 473                {
 0474                    return false;
 475                }
 476            }
 477
 7478            return ComputeRelativeSegmentsAndLookup(uri, relativePathSegments, candidates);
 479        }
 480
 481        private void Validate(bool allowDuplicateEquivalentUriTemplates)
 482        {
 47483            if (_baseAddress == null)
 484            {
 0485                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.UTTBaseAddres
 486            }
 487
 47488            _numSegmentsInBaseAddress = _baseAddress.Segments.Length;
 47489            if (_templates.Count == 0)
 490            {
 0491                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.UTTEmptyKeyVa
 492            }
 493
 494            // build the trie and
 495            // validate that forall Uri u, at most one UriTemplate is a best match for u
 47496            _rootNode = UriTemplateTrieNode.Make(_templates, allowDuplicateEquivalentUriTemplates);
 47497        }
 498
 499        [Conditional("DEBUG")]
 500        private void VerifyThatFastPathAndSlowPathHaveSameResults(Uri uri, Collection<string> fastPathRelativePathSegmen
 501            IList<UriTemplateTableMatchCandidate> fastPathCandidates)
 502        {
 0503            Collection<string> slowPathRelativePathSegments = new Collection<string>();
 0504            List<UriTemplateTableMatchCandidate> slowPathCandidates = new List<UriTemplateTableMatchCandidate>();
 0505            if (!SlowComputeRelativeSegmentsAndLookup(uri, UriTemplateHelpers.GetUriPath(uri),
 0506                slowPathRelativePathSegments, slowPathCandidates))
 507            {
 508                Fx.Assert("fast path yielded a result but slow path yielded no result");
 509            }
 510
 511            // compare results
 0512            if (fastPathRelativePathSegments.Count != slowPathRelativePathSegments.Count)
 513            {
 514                Fx.Assert("fast path yielded different number of segments from slow path");
 515            }
 516
 0517            for (int i = 0; i < fastPathRelativePathSegments.Count; ++i)
 518            {
 0519                if (fastPathRelativePathSegments[i] != slowPathRelativePathSegments[i])
 520                {
 521                    Fx.Assert("fast path yielded different segments from slow path");
 522                }
 523            }
 524
 0525            if (fastPathCandidates.Count != slowPathCandidates.Count)
 526            {
 527                Fx.Assert("fast path yielded different number of candidates from slow path");
 528            }
 529
 0530            for (int i = 0; i < fastPathCandidates.Count; i++)
 531            {
 0532                if (!slowPathCandidates.Contains(fastPathCandidates[i]))
 533                {
 534                    Fx.Assert("fast path yielded different candidates from slow path");
 535                }
 536            }
 0537        }
 538
 539        internal class FastPathInfo
 540        {
 541            private readonly FreezableCollection<UriTemplateTableMatchCandidate> _candidates;
 542            private readonly FreezableCollection<string> _relativePathSegments;
 543
 115544            public FastPathInfo()
 545            {
 115546                _relativePathSegments = new FreezableCollection<string>();
 115547                _candidates = new FreezableCollection<UriTemplateTableMatchCandidate>();
 115548            }
 549
 144550            public Collection<UriTemplateTableMatchCandidate> Candidates => _candidates;
 551
 144552            public Collection<string> RelativePathSegments => _relativePathSegments;
 553
 554            public void Freeze()
 555            {
 115556                _relativePathSegments.Freeze();
 115557                _candidates.Freeze();
 115558            }
 559        }
 560
 561        internal class UriTemplatesCollection : FreezableCollection<KeyValuePair<UriTemplate, object>>
 562        {
 563            public UriTemplatesCollection()
 47564                : base()
 565            {
 47566            }
 567
 568            public UriTemplatesCollection(IEnumerable<KeyValuePair<UriTemplate, object>> keyValuePairs)
 0569                : base()
 570            {
 0571                foreach (KeyValuePair<UriTemplate, object> kvp in keyValuePairs)
 572                {
 0573                    ThrowIfInvalid(kvp.Key, "keyValuePairs");
 0574                    Add(kvp);
 575                }
 0576            }
 577
 578            protected override void InsertItem(int index, KeyValuePair<UriTemplate, object> item)
 579            {
 163580                ThrowIfInvalid(item.Key, "item");
 163581                base.InsertItem(index, item);
 163582            }
 583
 584            protected override void SetItem(int index, KeyValuePair<UriTemplate, object> item)
 585            {
 0586                ThrowIfInvalid(item.Key, "item");
 0587                base.SetItem(index, item);
 0588            }
 589
 590            private static void ThrowIfInvalid(UriTemplate template, string argName)
 591            {
 163592                if (template == null)
 593                {
 0594                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(argName,
 0595                        SR.UTTNullTemplateKey);
 596                }
 597
 163598                if (template.IgnoreTrailingSlash)
 599                {
 0600                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(argName,
 0601                        SR.Format(SR.UTTInvalidTemplateKey, template));
 602                }
 163603            }
 604        }
 605    }
 606}

Methods/Properties

.ctor()
.ctor(System.Collections.Generic.IEnumerable`1<System.Collections.Generic.KeyValuePair`2<CoreWCF.UriTemplate,System.Object>>)
.ctor(System.Uri)
.ctor(System.Uri,System.Boolean)
.ctor(System.Uri,System.Collections.Generic.IEnumerable`1<System.Collections.Generic.KeyValuePair`2<CoreWCF.UriTemplate,System.Object>>)
.ctor(System.Uri,System.Collections.Generic.IEnumerable`1<System.Collections.Generic.KeyValuePair`2<CoreWCF.UriTemplate,System.Object>>,System.Boolean)
BaseAddress()
BaseAddress(System.Uri)
OriginalBaseAddress()
IsReadOnly()
KeyValuePairs()
MakeReadOnly(System.Boolean)
Match(System.Uri)
MatchSingle(System.Uri)
AllEquivalent(System.Collections.Generic.IList`1<CoreWCF.UriTemplateTableMatchCandidate>,System.Int32,System.Int32)
AtLeastOneCandidateHasQueryPart(System.Collections.Generic.IList`1<CoreWCF.UriTemplateTableMatchCandidate>)
NoCandidateHasQueryLiteralRequirementsAndThereIsAnEmptyFallback(System.Collections.Generic.IList`1<CoreWCF.UriTemplateTableMatchCandidate>)
None()
NotAllCandidatesArePathFullyEquivalent(System.Collections.Generic.IList`1<CoreWCF.UriTemplateTableMatchCandidate>)
ComputeRelativeSegmentsAndLookup(System.Uri,System.Collections.Generic.ICollection`1<System.String>,System.Collections.Generic.ICollection`1<CoreWCF.UriTemplateTableMatchCandidate>)
ConstructFastPathTable()
FastComputeRelativeSegmentsAndLookup(System.Uri,System.Collections.ObjectModel.Collection`1<System.String>&,System.Collections.Generic.IList`1<CoreWCF.UriTemplateTableMatchCandidate>&)
NormalizeBaseAddress()
SlowComputeRelativeSegmentsAndLookup(System.Uri,System.String,System.Collections.ObjectModel.Collection`1<System.String>,System.Collections.Generic.ICollection`1<CoreWCF.UriTemplateTableMatchCandidate>)
Validate(System.Boolean)
VerifyThatFastPathAndSlowPathHaveSameResults(System.Uri,System.Collections.ObjectModel.Collection`1<System.String>,System.Collections.Generic.IList`1<CoreWCF.UriTemplateTableMatchCandidate>)
.ctor()
Candidates()
RelativePathSegments()
Freeze()
.ctor()
.ctor(System.Collections.Generic.IEnumerable`1<System.Collections.Generic.KeyValuePair`2<CoreWCF.UriTemplate,System.Object>>)
InsertItem(System.Int32,System.Collections.Generic.KeyValuePair`2<CoreWCF.UriTemplate,System.Object>)
SetItem(System.Int32,System.Collections.Generic.KeyValuePair`2<CoreWCF.UriTemplate,System.Object>)
ThrowIfInvalid(CoreWCF.UriTemplate,System.String)