示例#1
0
        private void SerializeObject(Queue <SerializeOperation> serializeOperations, string url, object obj, bool publicReference, Type storageType = null)
        {
            // Don't create context in case we don't want to serialize referenced objects
            //if (!SerializeReferencedObjects && obj != RootObject)
            //    return null;

            // Already saved?
            // TODO: Ref counting? Should we change it on save? Probably depends if we cache or not.
            if (LoadedAssetReferences.ContainsKey(obj))
            {
                return;
            }

            var serializer = Serializer.GetSerializer(storageType, obj.GetType());

            if (serializer == null)
            {
                throw new InvalidOperationException($"Content serializer for {obj.GetType()} could not be found.");
            }

            var contentSerializerContext = new ContentSerializerContext(url, ArchiveMode.Serialize, this);

            using (var stream = FileProvider.OpenStream(url, VirtualFileMode.Create, VirtualFileAccess.Write))
            {
                var streamWriter = new BinarySerializationWriter(stream);
                PrepareSerializerContext(contentSerializerContext, streamWriter.Context);

                ChunkHeader header = null;

                // Allocate space in the stream, and also include header version in the hash computation, which is better
                // If serialization type is null, it means there should be no header.
                var serializationType = serializer.SerializationType;
                if (serializationType != null)
                {
                    header = new ChunkHeader {
                        Type = serializer.SerializationType.AssemblyQualifiedName
                    };
                    header.Write(streamWriter);
                    header.OffsetToObject = (int)streamWriter.NativeStream.Position;
                }

                contentSerializerContext.SerializeContent(streamWriter, serializer, obj);

                // Write references and updated header
                if (header != null)
                {
                    header.OffsetToReferences = (int)streamWriter.NativeStream.Position;
                    contentSerializerContext.SerializeReferences(streamWriter);

                    // Move back to the pre-allocated header position in the steam
                    stream.Seek(0, SeekOrigin.Begin);

                    // Write actual header.
                    header.Write(new BinarySerializationWriter(stream));
                }
            }

            var assetReference = new Reference(url, publicReference);

            SetAssetObject(assetReference, obj);

            // Process content references
            // TODO: Should we work at ChunkReference level?
            foreach (var contentReference in contentSerializerContext.ContentReferences)
            {
                if (contentReference.ObjectValue != null)
                {
                    var attachedReference = AttachedReferenceManager.GetAttachedReference(contentReference.ObjectValue);
                    if (attachedReference == null || attachedReference.IsProxy)
                    {
                        continue;
                    }

                    serializeOperations.Enqueue(new SerializeOperation(contentReference.Location, contentReference.ObjectValue, false));
                }
            }
        }
示例#2
0
        private object DeserializeObject(Queue <DeserializeOperation> serializeOperations, Reference parentReference, string url, Type objType, object obj, ContentManagerLoaderSettings settings)
        {
            // Try to find already loaded object
            Reference reference = FindDeserializedObject(url, objType);

            if (reference != null && reference.Deserialized)
            {
                // Add reference
                bool isRoot = parentReference == null;
                if (isRoot || parentReference.References.Add(reference))
                {
                    IncrementReference(reference, isRoot);
                }

                // Check if need to fully stream resource
                if (!settings.AllowContentStreaming)
                {
                    var streamingManager = services.GetService <IStreamingManager>();
                    streamingManager?.FullyLoadResource(reference.Object);
                }

                return(reference.Object);
            }

            if (!FileProvider.FileExists(url))
            {
                HandleAssetNotFound(url);
                return(null);
            }

            ContentSerializerContext contentSerializerContext;
            object result;

            // Open asset binary stream
            try
            {
                using (var stream = FileProvider.OpenStream(url, VirtualFileMode.Open, VirtualFileAccess.Read))
                {
                    // File does not exist
                    // TODO/Benlitz: Add a log entry for that, it's not expected to happen
                    if (stream == null)
                    {
                        return(null);
                    }

                    Type headerObjType = null;

                    // Read header
                    var streamReader = new BinarySerializationReader(stream);
                    var chunkHeader  = ChunkHeader.Read(streamReader);
                    if (chunkHeader != null)
                    {
                        headerObjType = AssemblyRegistry.GetType(chunkHeader.Type);
                    }

                    // Find serializer
                    var serializer = Serializer.GetSerializer(headerObjType, objType);
                    if (serializer == null)
                    {
                        throw new InvalidOperationException($"Content serializer for {headerObjType}/{objType} could not be found.");
                    }
                    contentSerializerContext = new ContentSerializerContext(url, ArchiveMode.Deserialize, this)
                    {
                        LoadContentReferences = settings.LoadContentReferences,
                        AllowContentStreaming = settings.AllowContentStreaming,
                    };

                    // Read chunk references
                    if (chunkHeader != null && chunkHeader.OffsetToReferences != -1)
                    {
                        // Seek to where references are stored and deserialize them
                        streamReader.NativeStream.Seek(chunkHeader.OffsetToReferences, SeekOrigin.Begin);
                        contentSerializerContext.SerializeReferences(streamReader);
                        streamReader.NativeStream.Seek(chunkHeader.OffsetToObject, SeekOrigin.Begin);
                    }

                    if (reference == null)
                    {
                        // Create Reference
                        reference = new Reference(url, parentReference == null);
                        result    = obj ?? serializer.Construct(contentSerializerContext);
                        SetAssetObject(reference, result);
                    }
                    else
                    {
                        result = reference.Object;
                    }

                    reference.Deserialized = true;

                    PrepareSerializerContext(contentSerializerContext, streamReader.Context);

                    contentSerializerContext.SerializeContent(streamReader, serializer, result);

                    // Add reference
                    parentReference?.References.Add(reference);
                }
            }
            catch (Exception exception)
            {
                throw new ContentManagerException($"Unexpected exception while loading asset [{url}]. Reason: {exception.Message}. Check inner-exception for details.", exception);
            }

            if (settings.LoadContentReferences)
            {
                // Process content references
                // TODO: Should we work at ChunkReference level?
                foreach (var contentReference in contentSerializerContext.ContentReferences)
                {
                    bool shouldBeLoaded = true;

                    //Reference childReference;

                    settings.ContentFilter?.Invoke(contentReference, ref shouldBeLoaded);

                    if (shouldBeLoaded)
                    {
                        serializeOperations.Enqueue(new DeserializeOperation(reference, contentReference.Location, contentReference.Type, contentReference.ObjectValue));
                    }
                }
            }

            return(result);
        }