簡體   English   中英

使用DataContractSerializer進行序列化時出現SecurityException

[英]SecurityException when serializing with DataContractSerializer

我試圖在Windows Phone 7上序列化我的游戲狀態,因此制作了一個“保存”結構,這樣我就可以使用DataContractSerializer輕松地將所有狀態轉換為XML文檔。

當我單獨序列化Gamestate的每個數據成員時,Save()代碼工作正常。 然而,這導致了多個xml根錯誤,因此我將“保存”類作為唯一的根。 現在,每當我嘗試在任何東西上調用DataContractSerializer.WriteObject()時,我都會遇到安全性異常。

我一直在比較我的舊代碼和新代碼,但卻找不到任何錯誤。
我已經粘貼了下面的所有代碼,以防問題出現在Save()方法之外。
首先看一下Save()方法


例外細節:
在此輸入圖像描述

堆棧跟蹤:

   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.CreateDataContract(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.DataContractCriticalHelper.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.GetDataContractSkipValidation(Int32 id, RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type, SerializationMode mode)
   at System.Runtime.Serialization.DataContract.GetDataContract(RuntimeTypeHandle typeHandle, Type type)
   at System.Runtime.Serialization.DataContract.GetDataContract(Type type)
   at System.Runtime.Serialization.DataContractSerializer.get_RootContract()
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteStartObject(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(Stream stream, Object graph)
   at GameState_test.GameState.Save(String filename)
   at GameState_test.MainPage.SaveButton_Click(Object sender, RoutedEventArgs e)
   at System.Windows.Controls.Primitives.ButtonBase.OnClick()
   at System.Windows.Controls.Button.OnClick()
   at System.Windows.Controls.Primitives.ButtonBase.OnMouseLeftButtonUp(MouseButtonEventArgs e)
   at System.Windows.Controls.Control.OnMouseLeftButtonUp(Control ctrl, EventArgs e)
   at MS.Internal.JoltHelper.FireEvent(IntPtr unmanagedObj, IntPtr unmanagedObjArgs, Int32 argsTypeIndex, Int32 actualArgsTypeIndex, String eventName)

新代碼:

    namespace GameState_test
    {                                       //TODO: Find a way to not have this ignored
        [DataContract] public class Hazard { [IgnoreDataMember] public Planet CurrentPlanet;} 

        public class Connections
        {
            public Connections(List<List<int>> connections = null) { this.cons = connections; }

            public bool AreConnected(int Planet1, int Planet2)
            {
                for (int i = 0; i < cons[Planet1].Count; i++)
                    if (cons[Planet1][i] == Planet2) return true;

                return false;
            }

            public List<int> this [int index] { get { return cons[index]; } }

            internal readonly List<List<int>> cons; //internal so it can be read by serializer
        }

        [DataContract]
        public class GameState
        {
            public GameState(List<List<int>> connections) { this.Connections = new Connections(connections); }
            public GameState(Position pos, List<List<int>> con) { Position = pos; Connections = new Connections(con); }
            public GameState(string filename) //load a game
            {   
                using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");

                    using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.Open, System.IO.FileAccess.Read))
                    {
                        DataContractSerializer serializer = new DataContractSerializer(typeof(GameStateSave), new List<Type> {typeof(Hazard), typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet) });
                        GameStateSave Save = (GameStateSave)serializer.ReadObject(stream);

                        Position position = new Position(Save.planets, Save.connections, Save.playerPosition);

                        this.Position = position;
                        this.PlayerInventory = Save.playerInventory;
                        this.Connections = new Connections(Save.connections);
                    }
                }
            }

            [DataMember] public readonly Connections Connections;
            [DataMember] public Position Position;
            [DataMember] public Inventory PlayerInventory;

            public void Save(string filename) 
            {
                using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");

                    using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))
                    {
                        DataContractSerializer serializer = new DataContractSerializer(typeof (GameStateSave), new List<Type> {typeof(Hazard), typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet)} );

                        GameStateSave Save = GenerateSave();
                        serializer.WriteObject(stream, Save);

                        //NOTE: Even when I comment everything out but this, I still get an exception:
                        //serializer.WriteObject(stream, this.Position.Player); 
                    }
                }
            }

            private GameStateSave GenerateSave()
            {
                GameStateSave Save = new GameStateSave();

                Save.connections = this.Connections.cons;
                Save.playerInventory = this.PlayerInventory;
                Save.planets = this.Position.Planets;
                Save.playerPosition = this.Position.Player;

                return Save;
            }

        }

        [DataContract]
        internal struct GameStateSave //only to be used here
        {
            [DataMember]
            public List<List<int>> connections;
            [DataMember]
            public Inventory playerInventory;
            [DataMember]
            public List<Planet> planets;
            [DataMember]
            public int playerPosition;
        }

    }

舊代碼:

namespace GameState_test
{
    [DataContract] public class Hazard { [IgnoreDataMember] public Planet CurrentPlanet;}

    public class Connections
    {
        public Connections(List<List<int>> connections = null) { this.cons = connections; }

        public bool AreConnected(int Planet1, int Planet2)
        {
            for (int i = 0; i < cons[Planet1].Count; i++)
                if (cons[Planet1][i] == Planet2) return true;

            return false;
        }

        public List<int> this [int index] { get { return cons[index]; } }

        internal readonly List<List<int>> cons; //internal so it can be read by serializer
    }

    [DataContract]
    public class GameState
    {
        public GameState(List<List<int>> connections) { this.Connections = new Connections(connections); }
        public GameState(Position pos, List<List<int>> con) { Position = pos; Connections = new Connections(con); }
        public GameState(string filename) 
        {   //load a game
            using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");

                using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.Open, System.IO.FileAccess.Read))
                {
                    DataContractSerializer serializer = new DataContractSerializer(typeof(Hazard), new List<Type> { typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet) });

                    List<List<int>> Connections = (List<List<int>>) serializer.ReadObject(stream);
                    Inventory PlayerInventory = (Inventory) serializer.ReadObject(stream);
                    List<Planet> Planets = (List<Planet>) serializer.ReadObject(stream);
                    int PlayerPosition = (int)serializer.ReadObject(stream);

                    Position position = new Position(Planets, Connections, PlayerPosition);

                    this.Position = position;
                    this.PlayerInventory = PlayerInventory;
                    this.Connections = new Connections(Connections);
                }
            }
        }

        [DataMember] public readonly Connections Connections;
        [DataMember] public Position Position;
        [DataMember] public Inventory PlayerInventory;

        public void Save(string filename) 
        {
            using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
            {
                if (!store.DirectoryExists("SavedGames")) store.CreateDirectory("SavedGames");

                using (IsolatedStorageFileStream stream = store.OpenFile("SavedGames/" + filename + ".xml", System.IO.FileMode.OpenOrCreate, System.IO.FileAccess.Write))
                {
                    DataContractSerializer serializer = new DataContractSerializer(typeof (Hazard), new List<Type> {typeof(Inventory), typeof(List<List<int>>), typeof(List<Planet>), typeof(Planet)} );
                    serializer.WriteObject(stream, this.Connections.cons);
                    serializer.WriteObject(stream, this.PlayerInventory);
                    serializer.WriteObject(stream, this.Position.Planets);
                    serializer.WriteObject(stream, this.Position.Player);
                }
            }
        }

        internal class SerializableGameState //only to be used here
        {
            public List<List<int>> connections;
            public Inventory playerInventory;
            public List<Planet> planets;
            public int playerPosition;
        }

    }
}

Silverlight代碼在部分信任上運行,這意味着它無法完全訪問系統中的對象,包括非公共類型和成員。 您正在嘗試序列化一個內部類,它不能正常工作。 這是我嘗試序列化內部類時遇到的異常:

Exception: System.Security.SecurityException: The data contract type 'SL_ButtonAndText.SerializableGameState' is not serializable because it is not public. Making the type public will fix this error. Alternatively, you can make it internal, and use the InternalsVisibleToAttribute attribute on your assembly in order to enable serialization of internal members - see documentation for more details. Be aware that doing so has certain security implications. ---> System.Security.SecurityException: Security error.
   at System.Runtime.Serialization.CodeGenerator.BeginMethod(Type returnType, String methodName, Type[] argTypes, Boolean allowPrivateMemberAccess)
   at System.Runtime.Serialization.CodeGenerator.BeginMethod(String methodName, Type delegateType, Boolean allowPrivateMemberAccess)
   at System.Runtime.Serialization.XmlFormatWriterGenerator.CriticalHelper.GenerateClassWriter(ClassDataContract classContract)
   --- End of inner exception stack trace ---
   at System.Runtime.Serialization.ClassDataContract.RequiresMemberAccessForWrite(SecurityException securityException, String[] serializationAssemblyPatterns)
   at System.Runtime.Serialization.XmlFormatWriterGenerator.CriticalHelper.GenerateClassWriter(ClassDataContract classContract)
   at System.Runtime.Serialization.ClassDataContract.get_XmlFormatWriterDelegate()
   at System.Runtime.Serialization.ClassDataContract.WriteXmlValue(XmlWriterDelegator xmlWriter, Object obj, XmlObjectSerializerWriteContext context)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.WriteDataContractValue(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.XmlObjectSerializerWriteContext.SerializeWithoutXsiType(DataContract dataContract, XmlWriterDelegator xmlWriter, Object obj, RuntimeTypeHandle declaredTypeHandle)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObjectContent(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.DataContractSerializer.InternalWriteObject(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObjectHandleExceptions(XmlWriterDelegator writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(XmlDictionaryWriter writer, Object graph)
   at System.Runtime.Serialization.XmlObjectSerializer.WriteObject(Stream stream, Object graph)
   at SL_ButtonAndText.MainPage.Button_Click(Object sender, RoutedEventArgs e)

異常消息准確地告訴我的問題是什么(你的異常消息是否相似?)。 解決這個問題的一種方法是將類公開,這將是最簡單的解決方案。 如錯誤消息所示,另一種替代方法是使用[InternalsVisibleTo]屬性顯式允許DataContractSerializer對內部類型具有可見性。 下面的代碼具有[IVT]屬性,並添加我不再看到錯誤。

using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using System.Text;
using System.Windows;
using System.Windows.Controls;

[assembly: InternalsVisibleTo("System.Runtime.Serialization")]

namespace SL_ButtonAndText
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            AddToDebug(typeof(DataContractSerializer).Assembly.FullName);
            MemoryStream ms = new MemoryStream();
            DataContractSerializer dcs = new DataContractSerializer(typeof(SerializableGameState));
            SerializableGameState sgs = new SerializableGameState
            {
                connections = new List<List<int>>
                {
                    new List<int> { 1, 2, 3 },
                    new List<int> { 4, 5 },
                },
                playerPosition = 0
            };
            try
            {
                dcs.WriteObject(ms, sgs);
                AddToDebug("Serialized: {0}", Encoding.UTF8.GetString(ms.GetBuffer(), 0, (int)ms.Position));
            }
            catch (Exception ex)
            {
                AddToDebug("Exception: {0}", ex);
            }
        }

        private void AddToDebug(string text, params object[] args)
        {
            if (args != null && args.Length > 0) text = string.Format(text, args);
            this.Dispatcher.BeginInvoke(() => this.txtDebug.Text = this.txtDebug.Text + text + Environment.NewLine);
        }
    }

    [DataContract]
    internal class SerializableGameState
    {
        [DataMember]
        public List<List<int>> connections;
        [DataMember]
        public int playerPosition;
    }
}

Carlosfigueira是對的,這是因為在Silverlight中看不到內部結構。 要解決此問題,請在AssemblyInfo.cs中添加以下內容:

[assembly: InternalsVisibleTo("System.Runtime.Serialization, PublicKey="
+ "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E86493"
+ "83049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E"
+ "9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4"
+ "BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B"
+ "37AB")]
[assembly: InternalsVisibleTo("System.ServiceModel.Web, PublicKey="
+ "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E86493"
+ "83049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E"
+ "9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4"
+ "BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B"
+ "37AB")]
[assembly: InternalsVisibleTo("System.Runtime.Serialization.Json, PublicKey="
+ "00240000048000009400000006020000002400005253413100040000010001008D56C76F9E86493"
+ "83049F383C44BE0EC204181822A6C31CF5EB7EF486944D032188EA1D3920763712CCB12D75FB77E"
+ "9811149E6148E5D32FBAAB37611C1878DDC19E20EF135D0CB2CFF2BFEC3D115810C3D9069638FE4"
+ "BE215DBF795861920E5AB6F7DB2E2CEEF136AC23D5DD2BF031700AEC232F6C6B1C785B4305C123B"
+ "37AB")]

資料來源: http//systemmetaphor.blogspot.fr/2010/04/silverlight-serialization-avoiding.html

檢查您要保存或讀取的文件的權限。 也許這是簡單的文件權限錯誤。 檢查文件夾權限和管理權限等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM