File: CorrelationKey.cs

package info (click to toggle)
mono 4.6.2.7%2Bdfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 778,148 kB
  • ctags: 914,052
  • sloc: cs: 5,779,509; xml: 2,773,713; ansic: 432,645; sh: 14,749; makefile: 12,361; perl: 2,488; python: 1,434; cpp: 849; asm: 531; sql: 95; sed: 16; php: 1
file content (155 lines) | stat: -rw-r--r-- 5,902 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
//------------------------------------------------------------
// Copyright (c) Microsoft Corporation.  All rights reserved.
//------------------------------------------------------------

namespace System.ServiceModel.Channels
{
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Globalization;
    using System.Runtime;
    using System.Runtime.DurableInstancing;
    using System.Security.Cryptography;
    using System.Text;
    using System.Xml.Linq;

    using ReadOnlyStringDictionary = System.Runtime.ReadOnlyDictionaryInternal<string, string>;

    public sealed class CorrelationKey : InstanceKey
    {
        static readonly XNamespace CorrelationNamespace = XNamespace.Get("urn:microsoft-com:correlation");
        static readonly ReadOnlyStringDictionary emptyDictionary = new ReadOnlyStringDictionary(new Dictionary<string, string>(0));

        string name;

        CorrelationKey(string keyString, XNamespace provider)
            : base(GenerateKey(keyString), new Dictionary<XName, InstanceValue>(2)
            {
                { provider.GetName("KeyString"), new InstanceValue(keyString, InstanceValueOptions.Optional) },
                { WorkflowNamespace.KeyProvider, new InstanceValue(provider.NamespaceName, InstanceValueOptions.Optional) },
            })
        {
            KeyString = keyString;
        }

        // The public constructor normalizes the parameters and calls this constructor, which creates the key string and adds it to the data avaliable to the "real" constructor.
        CorrelationKey(ReadOnlyStringDictionary keyData, string scopeName, XNamespace provider)
            : this(GenerateKeyString(keyData, scopeName, provider.NamespaceName), provider)
        {
            KeyData = keyData;
            Provider = provider;
        }

        public CorrelationKey(IDictionary<string, string> keyData, XName scopeName, XNamespace provider)
            : this(keyData == null ? CorrelationKey.emptyDictionary : MakeReadonlyCopy(keyData), scopeName != null ? scopeName.ToString() : null, provider ?? CorrelationNamespace)
        {
            ScopeName = scopeName;
        }

        private static ReadOnlyStringDictionary MakeReadonlyCopy(IDictionary<string, string> dictionary)
        {
            IDictionary<string, string> copy;
            if (dictionary.IsReadOnly)
                copy = dictionary;
            else
                copy = new Dictionary<string, string>(dictionary);
            return new ReadOnlyStringDictionary(copy);
        }

        public IDictionary<string, string> KeyData { get; private set; }

        public XName ScopeName { get; private set; }

        public XNamespace Provider { get; private set; }

        public string KeyString { get; private set; }


        // This name is not an aspect of the key itself, it exists to allow keys to be locally disambiguated.
        public string Name
        {
            get
            {
                return this.name;
            }

            set
            {
                if (!IsValid)
                {
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(
                        new InvalidOperationException(SR.GetString(SR.CannotSetNameOnTheInvalidKey)));
                }
                this.name = value;
            }
        }

        static Guid GenerateKey(string keyString)
        {
            byte[] keyBytes = Encoding.Unicode.GetBytes(keyString);
            byte[] hashBytes = HashHelper.ComputeHash(keyBytes);

            return new Guid(hashBytes);
        }


        // The checksum ends up describing the structure of the key data, so we don't need to worry about
        // key collisions between maliciously-crafted key data even though we don't do any escaping.
        static string GenerateKeyString(ReadOnlyStringDictionary keyData, string scopeName, string provider)
        {
            if (string.IsNullOrEmpty(scopeName))
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(
                    "scopeName", SR.GetString(SR.ScopeNameMustBeSpecified));
            }

            if (provider.Length == 0)
            {
                throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(
                    "provider", SR.GetString(SR.ProviderCannotBeEmptyString));
            }

            StringBuilder key = new StringBuilder();
            StringBuilder checksum = new StringBuilder();
            SortedList<string, string> sortedKeyData = new SortedList<string, string>(keyData, StringComparer.Ordinal);

            checksum.Append(sortedKeyData.Count.ToString(NumberFormatInfo.InvariantInfo));
            checksum.Append('.');

            for (int i = 0; i < sortedKeyData.Count; i++)
            {
                if (i > 0)
                {
                    key.Append('&');
                }
                key.Append(sortedKeyData.Keys[i]);
                key.Append('=');
                key.Append(sortedKeyData.Values[i]);

                checksum.Append(sortedKeyData.Keys[i].Length.ToString(NumberFormatInfo.InvariantInfo));
                checksum.Append('.');
                checksum.Append(sortedKeyData.Values[i].Length.ToString(NumberFormatInfo.InvariantInfo));
                checksum.Append('.');
            }

            if (sortedKeyData.Count > 0)
            {
                key.Append(',');
            }

            key.Append(scopeName);
            key.Append(',');
            key.Append(provider);

            checksum.Append(scopeName.Length.ToString(NumberFormatInfo.InvariantInfo));
            checksum.Append('.');
            checksum.Append(provider.Length.ToString(NumberFormatInfo.InvariantInfo));

            key.Append('|');
            key.Append(checksum);

            return key.ToString();
        }
    }
}