2009-10-28 3 views
1

J'ai une application .NET régulière. Dans ce cas, j'ai une pièce importée par MEF. Il importe bien, mais à un certain point, je veux enregistrer une liste d'objets dans un fichier. Dans ce cas, il économise juste une liste des meilleurs scores:System.Security.SecurityException lors de la création d'un nouveau FileStream

class HighScores 
{ 
    static HighScores() 
    { 
     CheckTrust(); 
    } 

    [ImportingConstructor] 
    public HighScores(
     [Import("/Services/LoggingService", typeof(ILoggingService))] 
     ILoggingService l 
     ) 
    { 
     logger = l; 

    } 

    private ILoggingService logger { get; set; } 

    public IEnumerable<HighScore> Scores 
    { 
     get 
     { 
      return m_Scores; 
     } 
    } 
    private List<HighScore> m_ScoresUnsorted = new List<HighScore>(); 
    private readonly ObservableCollection<HighScore> m_Scores = 
     new ObservableCollection<HighScore>(); 

    public void LogNewHighScore(string name, int score, int level) 
    { 
     m_ScoresUnsorted.Add(new HighScore(name, score, level)); 
     CreateObservable(); 

     if (IsFullTrust) 
     { 
      Stream stream = null; 
      try 
      { 
       // this line causes exception 
       stream = new FileStream("HighScores.dat", 
         System.IO.FileMode.Create, FileAccess.Write); 
       BinaryFormatter b = new BinaryFormatter(); 
       b.Serialize(stream, m_ScoresUnsorted); 
      } 
      catch (Exception e) 
      { 
       logger.Error("Error writing high scores:", e); 
      } 
      finally 
      { 
       if (stream != null) 
       { 
        stream.Close(); 
       } 
      } 
     } 
    } 

    private void CreateObservable() 
    { 
     m_ScoresUnsorted.Sort(); 
     m_Scores.Clear(); 
     for(int i = m_ScoresUnsorted.Count-1; i >= 0; i--) 
     { 
      m_Scores.Add(m_ScoresUnsorted[i]); 
     } 
    } 

    static private void CheckTrust() 
    { 
     try 
     { 
      FileIOPermission permission = 
       new FileIOPermission(PermissionState.Unrestricted); 
      s_FullTrust = SecurityManager.IsGranted(permission); 
     } 
     catch (Exception) 
     { 
      // ignore 
     } 
    } 

    static private bool s_FullTrust; 
    static public bool IsFullTrust 
    { 
     get 
     { 
      return s_FullTrust; 
     } 
    } 

} 

Je reçois System.Security.SecurityException sur la nouvelle ligne FileStream. La chose étrange est que si je remplace juste ceci avec un TextWriter, cela fonctionne. Je ne comprends pas ce que je fais mal.

EDIT: En savoir plus ... quand je mets ce code dans le constructeur, il s'exécute. Si vous suivez la pile d'appels (lors de la rupture dans l'exemple ci-dessus), il semble être en cours d'exécution sur le thread graphique. Plus précisément, le répartiteur WPF exécute une opération get sur une propriété basée sur le fait qu'un événement PropertyChanged a été déclenché. Alors peut-être que cela a à voir avec un rafraîchissement de l'interface graphique dans WPF ne pas être autorisé à faire des E/S de fichiers? Ce genre de sens ... vous ne voudriez pas verrouiller l'interface graphique pour quelque chose comme un fichier d'écriture ...

Répondre

0

J'ai été en mesure de l'exécuter en prenant la fonctionnalité de flux et de le mettre sur un " dangereux » fil ThreadPool, comme ceci:

 ThreadPool.UnsafeQueueUserWorkItem(ignoredState => 
     { 
      Stream stream = null; 
      try 
      { 
       stream = new FileStream("HighScores.dat", System.IO.FileMode.Create, FileAccess.Write); 
       BinaryFormatter b = new BinaryFormatter(); 
       b.Serialize(stream, "Test String"); 
      } 
      catch (Exception e) 
      { 
       logger.Error("Error writing high scores:", e); 
      } 
      finally 
      { 
       if (stream != null) 
       { 
        stream.Close(); 
       } 
      } 
     }, null); 

Bien sûr, cela a un tas de problèmes de synchronisation vraiment mauvais que je dois nettoyer, mais cela fonctionne. Je pense que ce que je ferai est de verrouiller à l'intérieur du fil et lui faire faire une copie de la liste, puis écrire la copie sur le disque. Je vais devoir me débarrasser de l'enregistreur aussi, car vous ne pouvez pas y accéder en toute sécurité sur plusieurs threads.

J'aimerais vraiment savoir pourquoi je devais faire ça.

Questions connexes