DYNPROXY-56 - workaround for CLR serialization bug, applied patch from Fabian Schmied
[castle.git] / Tools / Castle.DynamicProxy2 / Castle.DynamicProxy / Serialization / ProxyObjectReference.cs
blob8fbe8d7f8d8effc86cea0312c1b1972c31d6a14f
1 // Copyright 2004-2007 Castle Project - http://www.castleproject.org/
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
16 using Castle.DynamicProxy.Generators;
18 namespace Castle.DynamicProxy.Serialization
20 using System;
21 using System.Collections;
22 using System.Reflection;
23 using System.Runtime.Serialization;
24 using Castle.Core.Interceptor;
26 /// <summary>
27 /// Handles the deserialization of proxies.
28 /// See here for more details:
29 /// http://groups.google.com/group/castle-project-devel/msg/fb5ef9656d050ba5
30 /// </summary>
31 [Serializable]
32 public class ProxyObjectReference : IObjectReference, ISerializable, IDeserializationCallback
34 private static ModuleScope _scope = new ModuleScope();
36 private Type _baseType;
37 private Type[] _interfaces;
38 private IInterceptor[] _interceptors;
39 private ProxySerializer.Indirection _data;
40 private object _proxy;
42 /// <summary>
43 /// Usefull for test cases
44 /// </summary>
45 public static void ResetScope()
47 _scope = new ModuleScope();
50 protected ProxyObjectReference(SerializationInfo info, StreamingContext context)
52 _interceptors = (IInterceptor[])info.GetValue("__interceptors", typeof (IInterceptor[]));
53 _baseType = (Type)info.GetValue("__baseType", typeof(Type));
55 String[] _interfaceNames = (String[])info.GetValue("__interfaces", typeof(String[]));
57 _interfaces = new Type[_interfaceNames.Length];
59 for (int i = 0; i < _interfaceNames.Length; i++)
61 _interfaces[i] = Type.GetType(_interfaceNames[i]);
64 _proxy = RecreateProxy(info, context);
67 protected virtual object RecreateProxy(SerializationInfo info, StreamingContext context)
69 if (_baseType == typeof(object))
71 return RecreateInterfaceProxy(info, context);
73 else
75 return RecreateClassProxy(info, context);
79 public object RecreateInterfaceProxy(SerializationInfo info, StreamingContext context)
81 object proxy = null;
83 object target = info.GetValue("__target", typeof(object));
84 InterfaceGeneratorType generatorType = (InterfaceGeneratorType)info.GetInt32("__interface_generator_type");
85 string interfaceName = info.GetString("__theInterface");
86 Type theInterface = Type.GetType(interfaceName, true, false);
87 InterfaceProxyWithTargetGenerator generator;
88 switch (generatorType)
90 case InterfaceGeneratorType.WithTarget:
91 generator = new InterfaceProxyWithTargetGenerator(_scope,theInterface);
92 break;
93 case InterfaceGeneratorType.WithoutTarget:
94 generator = new InterfaceProxyGeneratorWithoutTarget(_scope, theInterface);
95 break;
96 case InterfaceGeneratorType.WithTargetInterface:
97 generator = new InterfaceProxyWithTargetInterfaceGenerator(_scope, theInterface);
98 break;
99 default:
100 throw new InvalidOperationException(string.Format("Got value {0} for the interface generator type, which is not known for the purpose of serialization.", generatorType));
103 Type proxy_type = generator.GenerateCode(target.GetType(), _interfaces , ProxyGenerationOptions.Default);
105 proxy = Activator.CreateInstance(proxy_type, new object[] { _interceptors, target });
107 return proxy;
110 public object RecreateClassProxy(SerializationInfo info, StreamingContext context)
112 bool delegateBaseSer = info.GetBoolean("__delegateToBase");
114 object proxy = null;
116 ClassProxyGenerator cpGen = new ClassProxyGenerator(_scope, _baseType);
118 Type proxy_type = cpGen.GenerateCode(_interfaces, ProxyGenerationOptions.Default);
121 if (delegateBaseSer)
123 proxy = Activator.CreateInstance(proxy_type, new object[] { info, context });
125 else
127 proxy = FormatterServices.GetSafeUninitializedObject(proxy_type);
128 _data = (ProxySerializer.Indirection) info.GetValue("__data", typeof (ProxySerializer.Indirection));
130 SetInterceptor(proxy, proxy_type);
133 return proxy;
136 private void SetInterceptor (object proxy, Type proxy_type)
138 FieldInfo interceptorField = proxy_type.GetField("__interceptors");
140 if (interceptorField == null)
142 throw new SerializationException(
143 "The SerializationInfo specifies an invalid proxy type, which has no __interceptors field.");
146 interceptorField.SetValue (proxy, _interceptors);
149 protected void InvokeCallback(object target)
151 if (target is IDeserializationCallback)
153 (target as IDeserializationCallback).OnDeserialization(this);
157 public object GetRealObject(StreamingContext context)
159 return _proxy;
162 public void GetObjectData(SerializationInfo info, StreamingContext context)
164 // There is no need to implement this method as
165 // this class would never be serialized.
168 // Class proxies must be populated in this method, since only at this point all members held by _data.IndirectedObject
169 // have been fixed up.
170 public void OnDeserialization (object sender)
172 if (_data != null)
174 object[] objectData = (object[]) _data.IndirectedObject;
176 MemberInfo[] members = FormatterServices.GetSerializableMembers (_baseType);
177 FormatterServices.PopulateObjectMembers (_proxy, members, objectData);
178 _data = null;
180 InvokeCallback (_proxy);