// Copyright 2004-2008 Castle Project - http://www.castleproject.org/ // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. namespace Castle.DynamicProxy.Serialization { using System; using System.Reflection; using System.Runtime.Serialization; using Castle.DynamicProxy; using Castle.Core.Interceptor; using Castle.DynamicProxy.Generators; /// /// Handles the deserialization of proxies. /// [Serializable] public class ProxyObjectReference : IObjectReference, ISerializable, IDeserializationCallback { private static ModuleScope _scope = new ModuleScope(); private readonly SerializationInfo _info; private readonly StreamingContext _context; private readonly Type _baseType; private readonly Type[] _interfaces; private readonly object _proxy; private readonly ProxyGenerationOptions _proxyGenerationOptions; private bool _isInterfaceProxy; private bool _delegateToBase; /// /// Resets the used for deserialization to a new scope. /// /// This is useful for test cases. public static void ResetScope() { SetScope(new ModuleScope()); } /// /// Resets the used for deserialization to a given . /// /// The scope to be used for deserialization. /// By default, the deserialization process uses a different scope than the rest of the application, which can lead to multiple proxies /// being generated for the same type. By explicitly setting the deserialization scope to the application's scope, this can be avoided. public static void SetScope(ModuleScope scope) { if (scope == null) throw new ArgumentNullException("scope"); _scope = scope; } /// /// Gets the used for deserialization. /// /// As has no way of automatically determining the scope used by the application (and the application /// might use more than one scope at the same time), uses a dedicated scope instance for deserializing proxy /// types. This instance can be reset and set to a specific value via and . public static ModuleScope ModuleScope { get { return _scope; } } protected ProxyObjectReference(SerializationInfo info, StreamingContext context) { _info = info; _context = context; _baseType = DeserializeTypeFromString("__baseType"); String[] _interfaceNames = (String[]) info.GetValue("__interfaces", typeof (String[])); _interfaces = new Type[_interfaceNames.Length]; for (int i = 0; i < _interfaceNames.Length; i++) _interfaces[i] = Type.GetType(_interfaceNames[i]); _proxyGenerationOptions = (ProxyGenerationOptions) info.GetValue("__proxyGenerationOptions", typeof (ProxyGenerationOptions)); _proxy = RecreateProxy(); // We'll try to deserialize as much of the proxy state as possible here. This is just best effort; due to deserialization dependency reasons, // we need to repeat this in OnDeserialization to guarantee correct state deserialization. DeserializeProxyState(); } private Type DeserializeTypeFromString(string key) { return Type.GetType(_info.GetString(key), true, false); } protected virtual object RecreateProxy() { if (_baseType == typeof (object)) // TODO: replace this hack by serializing a flag or something { _isInterfaceProxy = true; return RecreateInterfaceProxy(); } else { _isInterfaceProxy = false; return RecreateClassProxy(); } } public object RecreateInterfaceProxy() { InterfaceGeneratorType generatorType = (InterfaceGeneratorType) _info.GetInt32("__interface_generator_type"); Type theInterface = DeserializeTypeFromString("__theInterface"); Type targetType = DeserializeTypeFromString("__targetFieldType"); InterfaceProxyWithTargetGenerator generator; switch (generatorType) { case InterfaceGeneratorType.WithTarget: generator = new InterfaceProxyWithTargetGenerator(_scope, theInterface); break; case InterfaceGeneratorType.WithoutTarget: generator = new InterfaceProxyWithoutTargetGenerator(_scope, theInterface); break; case InterfaceGeneratorType.WithTargetInterface: generator = new InterfaceProxyWithTargetInterfaceGenerator(_scope, theInterface); break; default: throw new InvalidOperationException( string.Format( "Got value {0} for the interface generator type, which is not known for the purpose of serialization.", generatorType)); } Type proxy_type = generator.GenerateCode(targetType, _interfaces, _proxyGenerationOptions); return FormatterServices.GetSafeUninitializedObject(proxy_type); } public object RecreateClassProxy() { _delegateToBase = _info.GetBoolean("__delegateToBase"); ClassProxyGenerator cpGen = new ClassProxyGenerator(_scope, _baseType); Type proxy_type = cpGen.GenerateCode(_interfaces, _proxyGenerationOptions); if (_delegateToBase) { return Activator.CreateInstance(proxy_type, new object[] {_info, _context}); } else { return FormatterServices.GetSafeUninitializedObject(proxy_type); } } protected void InvokeCallback(object target) { if (target is IDeserializationCallback) { (target as IDeserializationCallback).OnDeserialization(this); } } public object GetRealObject(StreamingContext context) { return _proxy; } public void GetObjectData(SerializationInfo info, StreamingContext context) { // There is no need to implement this method as // this class would never be serialized. } public void OnDeserialization(object sender) { IInterceptor[] _interceptors = (IInterceptor[]) _info.GetValue("__interceptors", typeof (IInterceptor[])); SetInterceptors(_interceptors); // mixins if (_proxyGenerationOptions.HasMixins) { foreach (Type type in _proxyGenerationOptions.MixinData.MixinInterfacesAndPositions.Keys) { string mixinFieldName = "__mixin_" + type.FullName.Replace(".", "_"); FieldInfo mixinField = _proxy.GetType().GetField(mixinFieldName); if (mixinField == null) { throw new SerializationException( "The SerializationInfo specifies an invalid proxy type, which has no " + mixinFieldName + " field."); } mixinField.SetValue(_proxy, _info.GetValue(mixinFieldName, type)); } } // Get the proxy state again, to get all those members we couldn't get in the constructor due to deserialization ordering. DeserializeProxyState(); InvokeCallback(_proxy); } private void DeserializeProxyState() { if (_isInterfaceProxy) { object target = _info.GetValue("__target", typeof (object)); SetTarget(target); } else if (!_delegateToBase) { object[] baseMemberData = (object[]) _info.GetValue("__data", typeof (object[])); MemberInfo[] members = FormatterServices.GetSerializableMembers(_baseType); FormatterServices.PopulateObjectMembers(_proxy, members, baseMemberData); } } private void SetTarget(object target) { FieldInfo targetField = _proxy.GetType().GetField("__target"); if (targetField == null) { throw new SerializationException( "The SerializationInfo specifies an invalid interface proxy type, which has no __target field."); } targetField.SetValue(_proxy, target); } private void SetInterceptors(IInterceptor[] interceptors) { FieldInfo interceptorField = _proxy.GetType().GetField("__interceptors"); if (interceptorField == null) { throw new SerializationException( "The SerializationInfo specifies an invalid proxy type, which has no __interceptors field."); } interceptorField.SetValue(_proxy, interceptors); } } }