如何使用PostSharp将所有调用包装到程序集中?

时间:2014-03-12 11:24:44

标签: postsharp

我的C#项目是指外部.NET程序集。我想在从项目到该程序集的每次调用周围插入锁定语句。我一直试图用PostSharp建立这个,但无法找到办法。我有外部组件的源代码,我可能通过在那里插入方面来实现我最简单的目标,但我更喜欢非侵入式解决方案,我可以保持外部组件不受影响。

方法1

我发现我可以将调用包装到外部程序集中。遗憾的是,PostSharp无法包含对抽象方法的调用,而接口成员也是抽象方法。因此,这种方法不能通过接口类型覆盖调用。

[assembly: WrappingAspect(
    AttributeTargetAssemblies = "Library",
    AttributeTargetExternalMemberAttributes = MulticastAttributes.NonAbstract)]

[Serializable]
internal class WrappingAspect : OnMethodBoundaryAspect {
    public override void OnEntry(MethodExecutionArgs args) {
        Monitor.Enter(SyncRoot);
    }

    public override void OnExit(MethodExecutionArgs args) {
        Monitor.Exit(SyncRoot);
    }
}

方法2

也许我可以在项目中包含所有引用外部程序集中类型的方法。我按照以下思路思考。但是,我无法尝试这一点,因为ReflectionSearch需要一个我目前没有的PostSharp许可证。

[assembly: WrappingAspect]

[Serializable]
internal class WrappingAspect : OnMethodBoundaryAspect {
    public override void OnEntry(MethodExecutionArgs args) {
        Monitor.Enter(SyncRoot);
    }

    public override void OnExit(MethodExecutionArgs args) {
        Monitor.Exit(SyncRoot);
    }

    public override bool CompileTimeValidate(MethodBase method) {
        return ReflectionSearch.GetDeclarationsUsedByMethod(method)
            .Any(r => r.UsedType.Assembly.FullName.StartsWith("Library"));
    }
}

问题

  1. 是否有一种非侵入性方式将所有调用包装到外部程序集,包括通过接口类型调用方法?
  2. 我的第二种方法是否有效;检测哪些方法引用外部组件并包装它们?
  3. 还有其他方法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:2)

您是否尝试过通过XML方法添加它们?直接从PostSharp(稍微过时)docs

  

通过XML添加方面提供了在不修改源代码的情况下应用方面的优势,这在某些遗留项目中可能是一个优势。

答案 1 :(得分:1)

回答我自己的问题1;就在这里。这是我如何使用@Mikee建议的PostSharp配置文件。我使用了PostSharp 3.1.39。

简而言之,您可以运行PostSharp将代码编织到DLL中,而无需更改该DLL的源代码。该命令可能看起来像这样(为了便于阅读,分成多行)

postsharp.4.0-x64.exe temp\mylib.dll /P:Output=mylib.dll /NoLogo
    /X:myconfig.psproj
   "/P:ReferenceDirectory=$(ProjectDir) "
   "/P:SearchPath=$(OutDir) "
   "/P:Configuration=$(Configuration)"
   "/P:Platform=$(Platform)"
   "/P:MSBuildProjectFullPath=$(ProjectPath) "
    /P:TargetFrameworkIdentifier=.NETFramework

此命令中的$(变量)直接来自Visual Studio,例如如果你在后期构建活动中运行它。注意Visual Studio变量中的尾部反斜杠;在结束报价之前添加额外空格是必要的预防措施。

mylib.dll是编织将完成的目标程序集。输入和输出DLL必须是两个不同的文件,因此输入位于临时文件夹中。

在我的情况下,配置文件myconfig.psproj看起来像这样:

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="http://schemas.postsharp.org/1.0/configuration">
  <Multicast xmlns:my="clr-namespace:MyApp.Aspects;assembly:MyApp">
    <my:MyAspect AttributeTargetMemberAttributes="Public"/>
  </Multicast>
</Project>

此配置会将MyApp程序集中的方面MyApp.Aspects.MyAspect应用于目标程序集中的所有公共成员。可以从documentation of MulticastAttribute

中找到更多配置属性

要在更复杂的场景中运行PostSharp,可能需要更多配置参数。运行postsharp.4.0-x64.exe /?会给你一个有点无用的命令行参数列表。要了解PostSharp作为Visual Studio项目的一部分运行时真正使用的参数类型,您可以这样做:

  1. 将PostSharp添加到您的C#项目(作为NuGet)。
  2. 为方法添加一些虚拟方面。
  3. 使用详细输出运行构建(在Visual Studio 2012中:工具 - &gt;选项 - &gt;项目和解决方案 - &gt;构建和运行 - &gt; MSBuild项目构建输出详细程度 - &gt;诊断)。
  4. 构建后,在构建输出窗口中搜索包含Task "PostSharp30"的行,然后向下浏览以查找以"Connected to the pipe after XXX ms. Requesting with XX arguments"开头的行。
  5. 该行的内容是postharp.4.0-x64.exe的参数列表。注意,参数用分号分隔;删除分号并引用参数以保留有意义的空格。
  6. 我为测试项目获得的参数列表比上面的最终命令要长得多。许多参数都没有必要。

    警告:PostSharp的免费Express版本不支持编织迭代器方法(使用return yield的方法)。你会收到警告。