【问题标题】:How do I implement Exception.GetObjectData in .NET 4 in a library assembly that has the AllowPartiallyTrustedCallersAttribute?如何在具有 AllowPartiallyTrustedCallersAttribute 的库程序集中实现 .NET 4 中的 Exception.GetObjectData?
【发布时间】:2026-02-19 12:40:01
【问题描述】:

我有一个标有AllowPartiallyTrustedCallersAttribute 的程序集,其中包含一个自定义异常类。我想通过覆盖GetObjectData 使其可序列化。

在 .NET 4 中,GetObjectData 已成为 SecurityCritical 方法。这意味着覆盖也需要为SecurityCritical。由于我的程序集标有AllowPartiallyTrustedCallersAttribute,因此除非另有说明,否则其中的所有代码都自动为SecurityTransparent。因此,我将 SecurityCriticalAttribute 应用于 GetObjectData 覆盖:

using System;
using System.Runtime.Serialization;
using System.Security;

[assembly:AllowPartiallyTrustedCallers]

namespace Library
{
  [Serializable]
  public class MyException : Exception
  {
    public string String;

    public MyException ()
    {
    }

    protected MyException (SerializationInfo info, StreamingContext context)
        : base(info, context)
    {
      String = info.GetString ("String");
    }

    [SecurityCritical]
    public override void GetObjectData (System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
    {
      info.AddValue ("String", String);
      base.GetObjectData (info, context);
    }
  }
}

这在完全信任的情况下运行良好,例如,当我从桌面运行链接此程序集的代码时。

但是,当我从安全沙箱(见下文)使用这个类时,我得到一个TypeLoadException

覆盖成员时违反了继承安全规则: 'Library.MyException.GetObjectData(System.Runtime.Serialization.SerializationInfo, System.Runtime.Serialization.StreamingContext)'。安全 覆盖方法的可访问性必须与安全性相匹配 被覆盖的方法的可访问性。

我的问题:

  • 为什么会出现此异常?我确实将覆盖标记为SecurityCritical,那么问题出在哪里?
  • 由于SecurityCriticalAttribute 在我的沙箱中被忽略,此类在其他部分信任主机(例如 IIS/ASP.NET 或 SQL Server)中的行为如何?
  • 如何在 .NET 4 中实现可序列化的异常类?

沙盒代码:

var evidence = new Evidence();
evidence.AddHostEvidence (new Zone (SecurityZone.Internet));
var setupInfo = AppDomain.CurrentDomain.SetupInformation;
var permissionSet = SecurityManager.GetStandardSandbox (evidence);
permissionSet.AddPermission (new ReflectionPermission (ReflectionPermissionFlag.MemberAccess));
permissionSet.AddPermission (new SecurityPermission (SecurityPermissionFlag.ControlEvidence));
var sandbox = AppDomain.CreateDomain ("Sandbox", evidence, setupInfo, permissionSet);

【问题讨论】:

    标签: c# code-access-security


    【解决方案1】:

    您已经自己回答了问题的第一部分。您的程序集被加载为安全透明,因为它没有以完全信任的方式加载,因此SecurityCritical 属性被忽略。所以你得到了例外。

    您应该处理SerializeObjectState 事件并创建一个实现ISafeSerializationData 的类型来存储序列化的异常状态,而不是覆盖GetObjectData。这些存在于这个确切的场景中。

    【讨论】:

      【解决方案2】:

      好吧,我知道这篇文章比较陈旧,但从我最近的观察来看,如果你不给沙盒AppDomain 中的程序集FullTrust,则加载的程序集中的所有代码都将是SeurityTransparent。这意味着应用于MyException.GetObjectDataSecurityCriticalAttribute 将什么也不做。它将是 SeurityTransparent,并且肯定不会与其基本方法 SecurityCritical 兼容。

      希望这个提示会有所帮助。

      请参阅 https://docs.microsoft.com/en-us/dotnet/framework/misc/how-to-run-partially-trusted-code-in-a-sandbox,了解如何将沙盒化 AppDomain 中的某些程序集标记为完全可信。

      【讨论】:

        【解决方案3】:

        除了完全受信任的代码之外,您不能调用标有securitycriticalattribute 的代码:

        SecurityCriticalAttribute 相当于一个完整的链接需求 相信。标有 SecurityCriticalAttribute 的类型或成员可以 仅由完全受信任的代码调用;它不必要求 特定权限。它不能被部分受信任的代码调用。

        有一个相关的问题here讨论securitysafecriticalattribute的使用。

        【讨论】:

        • 其实我并没有调用SecurityCritical成员(GetObjectData),我只是想覆盖它而不违反“继承安全规则”。这在部分受信任的程序集中是不可能的吗?
        • 我不这么认为,因为您的覆盖仍然标有该属性。不过,看起来 securitysafecritical 属性会给你想要的东西。它会将您的覆盖标记为安全关键,并且可以通过透明代码安全访问。从上面的链接:“部分受信任的类型和成员可以访问使用 SecuritySafeCriticalAttribute 属性标记的类型或成员。”
        • 不,SecuritySafeCrititcal 不能用于覆盖 SecurityCritical 方法。 (我试过了;使用SecuritySafeCritical,即使完全信任,我也会得到“继承安全规则”例外。)