如何判断库代码中是否允许代码访问安全性

时间:2010-03-26 16:50:43

标签: c# .net-4.0 code-access-security

在.NET 4中不推荐使用代码访问安全性(CAS)。每当您调用隐式使用它的方法时,它都会失败并显示NotSupportedException,可以使用configuration switch来解决该问题,使其回归旧行为。

我们有一个在.NET 3.5和.NET 4中都使用的公共库,所以我们需要能够判断我们是否应该使用CAS方法。

例如,在.NET 3.5中我应该调用:

Assembly.Load(string, Evidence);

而在.NET 4中,我想调用

Assembly.Load(string);

致电Load(string, Evidence)会引发NotSupportedException

当然这有效,但我想知道是否有更好的方法:

try
{
    asm = Assembly.Load(someString, someEvidence);
}
catch(NotSupportedException)
{
    asm = Assembly.Load(someString);
}

3 个答案:

答案 0 :(得分:2)

HI, 使用Environment.Version.MajorEnvironment.Version.Minor可以解决问题。

Version v = Environment.Version;
if (Environment.Version.Major <= 3)
{
    //DO 3.5 here
}
else if (Environment.Version.Major >= 4)
{
     //DO 4 here
}

希望这有帮助。

编辑:更改条件以假设将在未来版本的.NET上实现相同的CAS。

答案 1 :(得分:1)

这直接针对该功能进行编码。

    public static Assembly LoadAssembly(string assembly, Evidence evidence)
    {
        Assembly asm;
        MethodInfo load = 
            typeof(Assembly).GetMethod("Load", 
                                        new Type[] {typeof(string), typeof(Evidence)});

        if (Attribute.IsDefined(load, typeof(ObsoleteAttribute)))
        {
            asm = Assembly.Load(assembly);
        }
        else
        {
            asm = Assembly.Load(assembly, evidence);
        }
        return asm;
    }

此代码假定以下使用语句。

using System;
using System.Reflection;
using System.Security.Policy;

如果经常调用它,你可以避免这样的反射性能。

private static bool? _isEvidenceObsolete = null;
public static Assembly AssemblyLoader(string assembly, Evidence evidence)
{
    Assembly asm;
    if (!_isEvidenceObsolete.HasValue)
    {
        MethodInfo load =
           typeof(Assembly).GetMethod("Load",
                                       new Type[] { typeof(string), typeof(Evidence) });
        _isEvidenceObsolete = Attribute.IsDefined(load, typeof(ObsoleteAttribute));
    }

    if (_isEvidenceObsolete.Value)
    {
        asm = Assembly.Load(assembly);
    }
    else
    {
        asm = Assembly.Load(assembly, evidence);
    }
    return asm;
}

编辑:我必须亲自看看性能统计数据是什么,这就是我得到的。

经过的时间(以毫秒为单位):

Catch Exception: 45331
Reflection: 58
Static Reflection: 1

以下是我用于进行基准测试的代码:

public static void BenchmarkLoaders()
{
    Stopwatch timer = new Stopwatch();

    // Benchmark catching Exceptions
    timer.Start();
    for (int i = 0; i < 10000; i++)
    {
        NotSupported notSupported = new NotSupported();
        try
        {
            notSupported.ThrowException("Obsoleted Method Call");
        }
        catch (NotSupportedException nse)
        {
            //Do something
        }
    }
    timer.Stop();
    Console.WriteLine("Catch Exception: {0}", timer.ElapsedMilliseconds);
    timer.Reset();

    // Benchmark Reflection
    timer.Start();
    for (int i = 0; i < 10000; i++)
    {
        NotSupported notSupported = new NotSupported();

        notSupported.ReflectAssembly();
    }
    timer.Stop();
    Console.WriteLine("Reflection: {0}", timer.ElapsedMilliseconds);
    timer.Reset();


    // Benchmark Static Reflection
    timer.Start();
    for (int i = 0; i < 10000; i++)
    {
        NotSupported.ReflectAssemblyStatic();
    }
    timer.Stop();
    Console.WriteLine("Static Reflection: {0}", timer.ElapsedMilliseconds);
    timer.Reset();

}

这是 NotSupported 类。

public class NotSupported
{
    public void ThrowException(string message)
    {
        throw new NotSupportedException(message);
    }

    public void ReflectAssembly()
    {
        MethodInfo load = 
            typeof(Assembly).GetMethod("Load", 
                                        new Type[] { typeof(string), typeof(Evidence) });

        if (Attribute.IsDefined(load, typeof(ObsoleteAttribute)))
        {
            // Do something
        }
    }

    private static bool? _isEvidenceObsolete = null;
    public static void ReflectAssemblyStatic()
    {
        Assembly asm;
        if (!_isEvidenceObsolete.HasValue)
        {
            MethodInfo load =
               typeof(Assembly).GetMethod("Load",
                                           new Type[] { typeof(string), typeof(Evidence) });
            _isEvidenceObsolete = Attribute.IsDefined(load, typeof(ObsoleteAttribute));
        }

        if (_isEvidenceObsolete.Value)
        {
            //Do Stuff
        }
    }
}

我意识到这些不是真实世界的数字,但它确实为使用反映异常提供了一个非常有说服力的论据。

答案 2 :(得分:0)

System.Security.HostSecurityManager.DomainPolicy属性的getter是一种公共的轻量级方法,如果未应用旧版CAS策略开关,它将在.NET 4.0中快速失败。您可能需要考虑设置一个帮助程序类,以避免不止一次地产生潜在异常的成本。 e.g

internal static class CasPolicyHelper
{
    private static bool? _isCasPolicyEnabled;

    internal static bool IsCasPolicyEnabled
    {
        get
        {
            if (_isCasPolicyEnabled == null)
            {
                HostSecurityManager hostSecurityManager = new HostSecurityManager();
                try
                {
                    PolicyLevel level = hostSecurityManager.DomainPolicy;
                    _isCasPolicyEnabled = true;
                }
                catch (NotSupportedException)
                {
                    _isCasPolicyEnabled = false;
                }
            }

            return _isCasPolicyEnabled.Value;
        }
    }
}