XDocument.Save(string)错误处理

时间:2014-05-13 20:22:10

标签: c# .net linq-to-xml

处理XDocument.Save(string)执行期间可能抛出的异常的最佳做法是什么?

我发现可以抛出XmlExceptions - 我是否还要检查IOExceptions

这适用于高可用性应用程序,我希望观察并捕获与磁盘空间相关的错误。我应该为IOExceptionXMLException执行多次捕获吗? Stack Overflow推荐什么?

2 个答案:

答案 0 :(得分:2)

这取决于。由于IOExceptionXmlException意味着两个完全不同的东西,我会单独处理它们,只要您正在执行其他操作,然后记录并通知用户

通过其他我的意思是,例如,捕获IOException并尝试写入其他位置,如备份接收器。对于XMLException,触发向XML供应商发出的XML无效的通知。

如果你只需要记录和忽略,就没有必要单独捕捉它们。如果没有完成日志记录,只需让它在调用链上运行。

答案 1 :(得分:1)

这可能是一项艰巨的任务。考虑一下您正在执行的代码流:

public void Save(string fileName, SaveOptions options)
{
  XmlWriterSettings xmlWriterSettings = XNode.GetXmlWriterSettings(options);
  if (this.declaration != null)
  {
    if (!string.IsNullOrEmpty(this.declaration.Encoding))
    {
      try
      {
        xmlWriterSettings.Encoding = Encoding.GetEncoding(this.declaration.Encoding);
      }
      catch (ArgumentException ex)
      {
      }
    }
  }
  using (XmlWriter writer = XmlWriter.Create(fileName, xmlWriterSettings))
    this.Save(writer);
}

在其中,XmlWriter.Create(fileName, xmlWriterSettings) 单独会引发以下异常:

  • ArgumentNullException
  • ArgumentOutOfRangeException
  • 的ArgumentException
  • NotSupportedException异常
  • IOException的

有无数原因。此外,此代码(明确抛出这些异常):

private unsafe void Init(string path, FileMode mode, FileAccess access, int rights, bool useRights, FileShare share, int bufferSize, FileOptions options, Win32Native.SECURITY_ATTRIBUTES secAttrs, string msgPath, bool bFromProxy, bool useLongPath, bool checkHost)
{
  if (path == null)
    throw new ArgumentNullException("path", Environment.GetResourceString("ArgumentNull_Path"));
  if (path.Length == 0)
    throw new ArgumentException(Environment.GetResourceString("Argument_EmptyPath"));
  FileSystemRights fileSystemRights = (FileSystemRights) rights;
  this._fileName = msgPath;
  this._exposedHandle = false;
  FileShare fileShare = share & ~FileShare.Inheritable;
  string paramName = (string) null;
  if (mode < FileMode.CreateNew || mode > FileMode.Append)
    paramName = "mode";
  else if (!useRights && (access < FileAccess.Read || access > FileAccess.ReadWrite))
    paramName = "access";
  else if (useRights && (fileSystemRights < FileSystemRights.ReadData || fileSystemRights > FileSystemRights.FullControl))
    paramName = "rights";
  else if (fileShare < FileShare.None || fileShare > (FileShare.ReadWrite | FileShare.Delete))
    paramName = "share";
  if (paramName != null)
    throw new ArgumentOutOfRangeException(paramName, Environment.GetResourceString("ArgumentOutOfRange_Enum"));
  if (options != FileOptions.None && (options & (FileOptions) 67092479) != FileOptions.None)
    throw new ArgumentOutOfRangeException("options", Environment.GetResourceString("ArgumentOutOfRange_Enum"));
  if (bufferSize <= 0)
    throw new ArgumentOutOfRangeException("bufferSize", Environment.GetResourceString("ArgumentOutOfRange_NeedPosNum"));
  if ((!useRights && (access & FileAccess.Write) == (FileAccess) 0 || useRights && (fileSystemRights & FileSystemRights.Write) == (FileSystemRights) 0) && (mode == FileMode.Truncate || mode == FileMode.CreateNew || (mode == FileMode.Create || mode == FileMode.Append)))
  {
    if (!useRights)
      throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&AccessCombo", (object) mode, (object) access));
    else
      throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileMode&RightsCombo", (object) mode, (object) fileSystemRights));
  }
  else
  {
    if (useRights && mode == FileMode.Truncate)
    {
      if (fileSystemRights == FileSystemRights.Write)
      {
        useRights = false;
        access = FileAccess.Write;
      }
      else
        throw new ArgumentException(Environment.GetResourceString("Argument_InvalidFileModeTruncate&RightsCombo", (object) mode, (object) fileSystemRights));
    }
    int dwDesiredAccess = useRights ? rights : (access == FileAccess.Read ? int.MinValue : (access == FileAccess.Write ? 1073741824 : -1073741824));
    int maxPathLength = useLongPath ? Path.MaxLongPath : Path.MaxPath;
    string path1 = Path.NormalizePath(path, true, maxPathLength);
    this._fileName = path1;
    if (path1.StartsWith("\\\\.\\", StringComparison.Ordinal))
      throw new ArgumentException(Environment.GetResourceString("Arg_DevicesNotSupported"));
    Path.CheckInvalidPathChars(path1, true);
    if (path1.IndexOf(':', 2) != -1)
      throw new NotSupportedException(Environment.GetResourceString("Argument_PathFormatNotSupported"));
    bool flag1 = false;
    if (!useRights && (access & FileAccess.Read) != (FileAccess) 0 || useRights && (fileSystemRights & FileSystemRights.ReadAndExecute) != (FileSystemRights) 0)
    {
      if (mode == FileMode.Append)
        throw new ArgumentException(Environment.GetResourceString("Argument_InvalidAppendMode"));
      flag1 = true;
    }
    if (!CodeAccessSecurityEngine.QuickCheckForAllDemands())
    {
      FileIOPermissionAccess access1 = FileIOPermissionAccess.NoAccess;
      if (flag1)
        access1 |= FileIOPermissionAccess.Read;
      if (!useRights && (access & FileAccess.Write) != (FileAccess) 0 || useRights && (fileSystemRights & (FileSystemRights.Write | FileSystemRights.DeleteSubdirectoriesAndFiles | FileSystemRights.Delete | FileSystemRights.ChangePermissions | FileSystemRights.TakeOwnership)) != (FileSystemRights) 0 || useRights && (fileSystemRights & FileSystemRights.Synchronize) != (FileSystemRights) 0 && mode == FileMode.OpenOrCreate)
      {
        if (mode == FileMode.Append)
          access1 |= FileIOPermissionAccess.Append;
        else
          access1 |= FileIOPermissionAccess.Write;
      }
      AccessControlActions control = secAttrs != null && (IntPtr) secAttrs.pSecurityDescriptor != IntPtr.Zero ? AccessControlActions.Change : AccessControlActions.None;
      new FileIOPermission(access1, control, new string[1]
      {
        path1
      }, 0 != 0, 0 != 0).Demand();
    }
    share &= ~FileShare.Inheritable;
    bool flag2 = mode == FileMode.Append;
    if (mode == FileMode.Append)
      mode = FileMode.OpenOrCreate;
    if (FileStream._canUseAsync && (options & FileOptions.Asynchronous) != FileOptions.None)
      this._isAsync = true;
    else
      options &= ~FileOptions.Asynchronous;
    int dwFlagsAndAttributes = (int) (options | (FileOptions) 1048576);
    int newMode = Win32Native.SetErrorMode(1);
    try
    {
      string str = path1;
      if (useLongPath)
        str = Path.AddLongPathPrefix(str);
      this._handle = Win32Native.SafeCreateFile(str, dwDesiredAccess, share, secAttrs, mode, dwFlagsAndAttributes, IntPtr.Zero);
      if (this._handle.IsInvalid)
      {
        int errorCode = Marshal.GetLastWin32Error();
        if (errorCode == 3 && path1.Equals(Directory.InternalGetDirectoryRoot(path1)))
          errorCode = 5;
        bool flag3 = false;
        if (!bFromProxy)
        {
          try
          {
            new FileIOPermission(FileIOPermissionAccess.PathDiscovery, new string[1]
            {
              this._fileName
            }, 0 != 0, 0 != 0).Demand();
            flag3 = true;
          }
          catch (SecurityException ex)
          {
          }
        }
        if (flag3)
          __Error.WinIOError(errorCode, this._fileName);
        else
          __Error.WinIOError(errorCode, msgPath);
      }
    }
    finally
    {
      Win32Native.SetErrorMode(newMode);
    }
    if (Win32Native.GetFileType(this._handle) != 1)
    {
      this._handle.Close();
      throw new NotSupportedException(Environment.GetResourceString("NotSupported_FileStreamOnNonFiles"));
    }
    else
    {
      if (this._isAsync)
      {
        bool flag3 = false;
        new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Assert();
        try
        {
          flag3 = ThreadPool.BindHandle((SafeHandle) this._handle);
        }
        finally
        {
          CodeAccessPermission.RevertAssert();
          if (!flag3)
            this._handle.Close();
        }
        if (!flag3)
          throw new IOException(Environment.GetResourceString("IO.IO_BindHandleFailed"));
      }
      if (!useRights)
      {
        this._canRead = (access & FileAccess.Read) != (FileAccess) 0;
        this._canWrite = (access & FileAccess.Write) != (FileAccess) 0;
      }
      else
      {
        this._canRead = (fileSystemRights & FileSystemRights.ReadData) != (FileSystemRights) 0;
        this._canWrite = (fileSystemRights & FileSystemRights.WriteData) != (FileSystemRights) 0 || (fileSystemRights & FileSystemRights.AppendData) != (FileSystemRights) 0;
      }
      this._canSeek = true;
      this._isPipe = false;
      this._pos = 0L;
      this._bufferSize = bufferSize;
      this._readPos = 0;
      this._readLen = 0;
      this._writePos = 0;
      if (flag2)
        this._appendStart = this.SeekCore(0L, SeekOrigin.End);
      else
        this._appendStart = -1L;
    }
  }
}

使用大量依赖项,这些依赖项可能会抛出自己的异常。

我的建议,首先要确保真的需要知道可能引发的每个可能的异常。正如约翰和我的谈话所述,在99%以上的情况下抛出什么异常并不重要,可以用同样的方式处理。

有关何时的更多信息,您可能 需要知道所有异常类型,请仔细阅读评论。

最后,如果你需要知道每个异常,请获取JetBrains dotPeek的副本并使用.NET Framework代码。