Serialization.cs
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license.
4 //
5 // Microsoft Bot Framework: http://botframework.com
6 //
7 // Bot Builder SDK GitHub:
8 // https://github.com/Microsoft/BotBuilder
9 //
10 // Copyright (c) Microsoft Corporation
11 // All rights reserved.
12 //
13 // MIT License:
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 //
33 
35 using Newtonsoft.Json.Linq;
36 using System;
37 using System.Collections;
38 using System.Collections.Generic;
39 using System.Diagnostics;
40 using System.Linq;
41 using System.Reflection;
42 using System.Runtime.CompilerServices;
43 using System.Runtime.Serialization;
44 
45 namespace Microsoft.Bot.Builder.Internals.Fibers
46 {
47  public static class Serialization
48  {
52  public interface ISurrogateProvider : ISerializationSurrogate
53  {
61  bool Handles(Type type, StreamingContext context, out int priority);
62  }
63 
65  {
66  [Serializable]
67  public sealed class ObjectReference : IObjectReference
68  {
69  public readonly Type Type = null;
70  object IObjectReference.GetRealObject(StreamingContext context)
71  {
72  var resolver = (IResolver)context.Context;
73  var real = resolver.Resolve(this.Type, tag: null);
74  return real;
75  }
76  }
77 
78  private readonly int priority;
79 
80  public StoreInstanceByTypeSurrogate(int priority)
81  {
82  this.priority = priority;
83  }
84 
85  bool ISurrogateProvider.Handles(Type type, StreamingContext context, out int priority)
86  {
87  var resolver = (IResolver)context.Context;
88  var handles = resolver.CanResolve(type, tag: null);
89  priority = handles ? this.priority : 0;
90  return handles;
91  }
92 
93  void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
94  {
95  var type = obj.GetType();
96  info.SetType(typeof(ObjectReference));
97  info.AddValue(nameof(ObjectReference.Type), type);
98  }
99 
100  object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
101  {
102  throw new NotImplementedException();
103  }
104  }
105 
107  {
108  public const BindingFlags Flags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
109  private readonly int priority;
110 
111  public StoreInstanceByFieldsSurrogate(int priority)
112  {
113  this.priority = priority;
114  }
115 
116  bool ISurrogateProvider.Handles(Type type, StreamingContext context, out int priority)
117  {
118  bool handles = !type.IsSerializable;
119  priority = handles ? this.priority : 0;
120  return handles;
121  }
122 
123  void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
124  {
125  var type = obj.GetType();
126  var fields = type.GetFields(Flags);
127  foreach (var field in fields)
128  {
129  var value = field.GetValue(obj);
130  info.AddValue(field.Name, value);
131  }
132  }
133 
134  object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
135  {
136  var type = obj.GetType();
137  var fields = type.GetFields(Flags);
138  foreach (var field in fields)
139  {
140  var value = info.GetValue(field.Name, field.FieldType);
141  field.SetValue(obj, value);
142  }
143 
144  return obj;
145  }
146  }
147 
149  {
150  private readonly int priority;
151  public ClosureCaptureErrorSurrogate(int priority)
152  {
153  this.priority = priority;
154  }
155 
156  bool ISurrogateProvider.Handles(Type type, StreamingContext context, out int priority)
157  {
158  bool generated = Attribute.IsDefined(type, typeof(CompilerGeneratedAttribute));
159  bool handles = generated && !type.IsSerializable;
160  priority = handles ? this.priority : 0;
161  return handles;
162  }
163 
164  void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
165  {
166  throw new ClosureCaptureException(obj);
167  }
168 
169  object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
170  {
171  throw new NotImplementedException();
172  }
173  }
174 
176  {
177  private readonly HashSet<Type> visited = new HashSet<Type>();
178  private readonly ISurrogateProvider inner;
179  // TOOD: better tracing interface
180  private readonly TraceListener trace;
181 
182  public SurrogateLogDecorator(ISurrogateProvider inner, TraceListener trace)
183  {
184  SetField.NotNull(out this.inner, nameof(inner), inner);
185  SetField.NotNull(out this.trace, nameof(trace), trace);
186  }
187  public override string ToString()
188  {
189  return $"{this.GetType().Name}({this.inner})";
190  }
191  bool ISurrogateProvider.Handles(Type type, StreamingContext context, out int priority)
192  {
193  return this.inner.Handles(type, context, out priority);
194  }
195 
196  void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
197  {
198  this.Visit(obj);
199  this.inner.GetObjectData(obj, info, context);
200  }
201 
202  object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
203  {
204  this.Visit(obj);
205  return this.inner.SetObjectData(obj, info, context, selector);
206  }
207 
208  private void Visit(object obj)
209  {
210  var type = obj.GetType();
211  bool added;
212  lock (this.visited)
213  {
214  added = this.visited.Add(type);
215  }
216  if (added)
217  {
218  var message = $"{this.inner.GetType().Name}: visiting {type}";
219  this.trace.WriteLine(message);
220  }
221  }
222  }
223 
224  public sealed class JObjectSurrogate : ISurrogateProvider
225  {
226  private readonly int priority;
227 
228  public JObjectSurrogate(int priority)
229  {
230  this.priority = priority;
231  }
232 
233  bool ISurrogateProvider.Handles(Type type, StreamingContext context, out int priority)
234  {
235  bool handles = type == typeof(JObject);
236  priority = handles ? this.priority : 0;
237  return handles;
238  }
239 
240  void ISerializationSurrogate.GetObjectData(object obj, SerializationInfo info, StreamingContext context)
241  {
242  var instance = (JObject)obj;
243  info.AddValue(typeof(JObject).Name, instance.ToString(Newtonsoft.Json.Formatting.None));
244  }
245 
246  object ISerializationSurrogate.SetObjectData(object obj, SerializationInfo info, StreamingContext context, ISurrogateSelector selector)
247  {
248  return obj = JObject.Parse((string)info.GetValue(typeof(JObject).Name, typeof(string)));
249  }
250  }
251 
252  public sealed class SurrogateSelector : ISurrogateSelector
253  {
254  private readonly IReadOnlyList<ISurrogateProvider> providers;
255  public SurrogateSelector(IReadOnlyList<ISurrogateProvider> providers)
256  {
257  SetField.NotNull(out this.providers, nameof(providers), providers);
258  }
259 
260  void ISurrogateSelector.ChainSelector(ISurrogateSelector selector)
261  {
262  throw new NotImplementedException();
263  }
264 
265  ISurrogateSelector ISurrogateSelector.GetNextSelector()
266  {
267  throw new NotImplementedException();
268  }
269 
270  ISerializationSurrogate ISurrogateSelector.GetSurrogate(Type type, StreamingContext context, out ISurrogateSelector selector)
271  {
272  int maximumPriority = -int.MaxValue;
273  ISurrogateProvider maximumProvider = null;
274  for (int index = 0; index < this.providers.Count; ++index)
275  {
276  var provider = this.providers[index];
277  int priority;
278  if (provider.Handles(type, context, out priority) && priority > maximumPriority)
279  {
280  maximumPriority = priority;
281  maximumProvider = provider;
282  }
283  }
284 
285  if (maximumProvider != null)
286  {
287  selector = this;
288  return maximumProvider;
289  }
290  else
291  {
292  selector = null;
293  return null;
294  }
295  }
296  }
297  }
298 }
SurrogateSelector(IReadOnlyList< ISurrogateProvider > providers)
Extend ISerializationSurrogate with a "tester" method used by SurrogateSelector.
Allow the resolution of values based on type and optionally tag.
Namespace for internal scorable implementation that is not useful for most developers and may change ...
Namespace for scorable interfaces, classes and compositions.
SurrogateLogDecorator(ISurrogateProvider inner, TraceListener trace)
bool Handles(Type type, StreamingContext context, out int priority)
Determine whether this surrogate provider handles this type.
Root namespace for the Microsoft Bot Builder SDK.