1 // Copyright 2004-2008 Castle Project - http://www.castleproject.org/
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
7 // http://www.apache.org/licenses/LICENSE-2.0
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.
15 namespace Castle
.DynamicProxy
.Serialization
18 using System
.Reflection
;
19 using System
.Runtime
.Serialization
;
20 using Castle
.DynamicProxy
;
21 using Castle
.Core
.Interceptor
;
22 using Castle
.DynamicProxy
.Generators
;
25 /// Handles the deserialization of proxies.
28 public class ProxyObjectReference
: IObjectReference
, ISerializable
, IDeserializationCallback
30 private static ModuleScope _scope
= new ModuleScope();
32 private readonly SerializationInfo _info
;
33 private readonly StreamingContext _context
;
35 private readonly Type _baseType
;
36 private readonly Type
[] _interfaces
;
37 private readonly object _proxy
;
38 private readonly ProxyGenerationOptions _proxyGenerationOptions
;
40 private bool _isInterfaceProxy
;
41 private bool _delegateToBase
;
44 /// Resets the <see cref="ModuleScope"/> used for deserialization to a new scope.
46 /// <remarks>This is useful for test cases.</remarks>
47 public static void ResetScope()
49 SetScope (new ModuleScope());
53 /// Resets the <see cref="ModuleScope"/> used for deserialization to a given <paramref name="scope"/>.
55 /// <param name="scope">The scope to be used for deserialization.</param>
56 /// <remarks>By default, the deserialization process uses a different scope than the rest of the application, which can lead to multiple proxies
57 /// being generated for the same type. By explicitly setting the deserialization scope to the application's scope, this can be avoided.</remarks>
58 public static void SetScope (ModuleScope scope
)
61 throw new ArgumentNullException ("scope");
66 /// Gets the <see cref="DynamicProxy.ModuleScope"/> used for deserialization.
68 /// <value>As <see cref="ProxyObjectReference"/> has no way of automatically determining the scope used by the application (and the application
69 /// might use more than one scope at the same time), <see cref="ProxyObjectReference"/> uses a dedicated scope instance for deserializing proxy
70 /// types. This instance can be reset and set to a specific value via <see cref="ResetScope"/> and <see cref="SetScope"/>.</value>
71 public static ModuleScope ModuleScope
73 get { return _scope; }
76 protected ProxyObjectReference(SerializationInfo info
, StreamingContext context
)
81 _baseType
= DeserializeTypeFromString("__baseType");
83 String
[] _interfaceNames
= (String
[]) info
.GetValue("__interfaces", typeof(String
[]));
84 _interfaces
= new Type
[_interfaceNames
.Length
];
86 for(int i
= 0; i
< _interfaceNames
.Length
; i
++)
87 _interfaces
[i
] = Type
.GetType(_interfaceNames
[i
]);
89 _proxyGenerationOptions
= (ProxyGenerationOptions
) info
.GetValue ("__proxyGenerationOptions", typeof (ProxyGenerationOptions
));
90 _proxy
= RecreateProxy ();
93 private Type
DeserializeTypeFromString (string key
)
95 return Type
.GetType(_info
.GetString(key
), true, false);
98 protected virtual object RecreateProxy ()
100 if (_baseType
== typeof(object)) // TODO: replace this hack by serializing a flag or something
102 _isInterfaceProxy
= true;
103 return RecreateInterfaceProxy();
107 _isInterfaceProxy
= false;
108 return RecreateClassProxy();
112 public object RecreateInterfaceProxy()
114 InterfaceGeneratorType generatorType
= (InterfaceGeneratorType
) _info
.GetInt32("__interface_generator_type");
116 Type theInterface
= DeserializeTypeFromString ("__theInterface");
117 Type targetType
= DeserializeTypeFromString ("__targetFieldType");
119 InterfaceProxyWithTargetGenerator generator
;
120 switch(generatorType
)
122 case InterfaceGeneratorType
.WithTarget
:
123 generator
= new InterfaceProxyWithTargetGenerator(_scope
, theInterface
);
125 case InterfaceGeneratorType
.WithoutTarget
:
126 generator
= new InterfaceProxyWithoutTargetGenerator(_scope
, theInterface
);
128 case InterfaceGeneratorType
.WithTargetInterface
:
129 generator
= new InterfaceProxyWithTargetInterfaceGenerator(_scope
, theInterface
);
132 throw new InvalidOperationException(
134 "Got value {0} for the interface generator type, which is not known for the purpose of serialization.",
138 Type proxy_type
= generator
.GenerateCode(targetType
, _interfaces
, _proxyGenerationOptions
);
139 return FormatterServices
.GetSafeUninitializedObject (proxy_type
);
142 public object RecreateClassProxy()
144 _delegateToBase
= _info
.GetBoolean ("__delegateToBase");
146 ClassProxyGenerator cpGen
= new ClassProxyGenerator(_scope
, _baseType
);
148 Type proxy_type
= cpGen
.GenerateCode(_interfaces
, _proxyGenerationOptions
);
153 return Activator
.CreateInstance(proxy_type
, new object[] {_info, _context}
);
157 return FormatterServices
.GetSafeUninitializedObject(proxy_type
);
161 protected void InvokeCallback(object target
)
163 if (target
is IDeserializationCallback
)
165 (target
as IDeserializationCallback
).OnDeserialization(this);
169 public object GetRealObject(StreamingContext context
)
174 public void GetObjectData(SerializationInfo info
, StreamingContext context
)
176 // There is no need to implement this method as
177 // this class would never be serialized.
180 public void OnDeserialization (object sender
)
182 IInterceptor
[] _interceptors
= (IInterceptor
[]) _info
.GetValue ("__interceptors", typeof (IInterceptor
[]));
183 SetInterceptors (_interceptors
);
185 if (_isInterfaceProxy
)
187 object target
= _info
.GetValue ("__target", typeof (object));
190 else if (!_delegateToBase
)
192 object[] baseMemberData
= (object[]) _info
.GetValue ("__data", typeof (object[]));
193 MemberInfo
[] members
= FormatterServices
.GetSerializableMembers (_baseType
);
194 FormatterServices
.PopulateObjectMembers (_proxy
, members
, baseMemberData
);
197 InvokeCallback (_proxy
);
200 private void SetTarget (object target
)
202 FieldInfo targetField
= _proxy
.GetType ().GetField ("__target");
203 if (targetField
== null)
205 throw new SerializationException (
206 "The SerializationInfo specifies an invalid interface proxy type, which has no __target field.");
209 targetField
.SetValue (_proxy
, target
);
212 private void SetInterceptors (IInterceptor
[] interceptors
)
214 FieldInfo interceptorField
= _proxy
.GetType ().GetField ("__interceptors");
215 if (interceptorField
== null)
217 throw new SerializationException (
218 "The SerializationInfo specifies an invalid proxy type, which has no __interceptors field.");
221 interceptorField
.SetValue (_proxy
, interceptors
);