【问题标题】:Visual Studio serialization error when T4 uses DTE to open generated fileT4 使用 DTE 打开生成的文件时的 Visual Studio 序列化错误
【发布时间】:2016-12-06 16:44:12
【问题描述】:

我们有一个名为 GenerateProxies.tt 的 C# T4 文件,它调用了几个命令行代码生成实用程序。使用 System.Diagnostics Process 类,我们将标准输出重定向到 T4 输出文本文件 (GenerateProxies.txt),以便我们可以查看命令行输出是否有错误。

我在 T4 的末尾添加了以下简单代码,以便 Visual Studio 将打开生成的文本文件作为该过程的最后一步(workingDirectory 变量在模板的前面声明和填充)。这确实有效,但会引发序列化错误。这个错误可以避免吗?

<#@ assembly name="EnvDTE" #>
<#@ import namespace="EnvDTE" #>
<#
    IServiceProvider vssp = (IServiceProvider)this.Host;
    DTE dte = vssp.GetService(typeof(DTE)) as DTE;
    dte.ItemOperations.OpenFile(
        string.Format(@"{0}\GenerateProxies.txt", workingDirectory),
        Constants.vsViewKindTextView
    );
#>

同样,这确实工作,它打开了文本文件,但它产生了这个错误:

Running transformation: System.Runtime.Serialization.SerializationException:
Type 'Microsoft.VisualStudio.Platform.WindowManagement.DTE.WindowBase' in
Assembly 'Microsoft.VisualStudio.Platform.WindowManagement'
is not marked as serializable.

【问题讨论】:

  • 调用堆栈可能会有所帮助。
  • 是的,但不幸的是,它来自一个完全没有外部访问权限的开发虚拟机(这就是为什么我没有费心重新输入所有程序集信息、密钥 GUID 等的原因)。调用堆栈很大,但看起来像是某种 PInvoke 编组问题。显然 DTE 是 COM。我隐约怀疑这是线程问题。
  • 在我看来,有些东西被意外拉过 AppDomain 边界。调用堆栈可以识别来源,并且您可以在堆栈中的代码底部调查谁引用了该类型的实例。
  • 我有类似的问题,请参阅我的回答,评论不允许有那么多字符

标签: c# visual-studio-2015 t4 envdte


【解决方案1】:

EnvDTE 程序集是 COM 互操作程序集。您可以通过创建Runtime Callable Wrapper 来避免您的错误,该Runtime Callable Wrapper 根据互操作程序集中的信息编组对COM 对象的调用。 Microsoft 在 Microsoft.VisualStudio.TextTemplating命名空间:

<#@ template hostspecific="true" language="C#" #>
<#@ assembly name="EnvDTE" #>
<#@ import namespace="Microsoft.VisualStudio.TextTemplating" #>
<#
  IServiceProvider serviceProvider = (IServiceProvider)this.Host;
  EnvDTE.DTE dte = (EnvDTE.DTE) serviceProvider.GetCOMService(typeof(EnvDTE.DTE));
 #>

T4 模板在单独的 AppDomain 中运行,我相信这就是您的代码在异常情况下仍能正常工作的原因。 IServiceProvider.GetService(typeof(DTE)) 返回一个透明的Proxy Object。此异常是因为代理要求使用 Serializable 属性修饰跨应用程序域的对象。您可以像这样确认代码中的 DTE 对象是“透明代理”:

bool isProxy = RemotingServices.IsTransparentProxy(dte); 

【讨论】:

  • 开始在 Visual Studio 2019 中收到错误 Running transformation: System.Runtime.Serialization.SerializationException: Type 'Microsoft.VisualStudio.ProjectSystem.VS.Implementation.Package.Automation.OAProjectItem' in Assembly 'Microsoft.VisualStudio.ProjectSystem.VS.Implementation, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' is not marked as serializable,因为 T4 模板在 VS 2017 中运行良好。更新它以使用此处提到的 GetCOMService 扩展方法修复了它!
  • 和邓肯一样的经历。升级到 VS2019 后,我不得不调整 T4 模板。奇怪的是,它在调试时一切正常,所以这有点难以排除故障。我想知道他们为什么保留 .GetService() 方法。这有点暗示在某些情况下 GetCOMService() 不起作用。
【解决方案2】:

这不是答案,但是 OP 无法按照 cmets 中的要求提供堆栈跟踪。

当我尝试在我的 tt 文件中执行一个函数以写入输出窗口时抛出了类似的异常(ST 太长,无法评论)

private void WriteToOutput(string output)
{
      if (_host == null)
        throw new Exception("Host property returned unexpected value (null)");

      EnvDTE.DTE dte = (EnvDTE.DTE)_host.GetService(typeof(EnvDTE.DTE));

      if (dte == null)
        throw new Exception("Unable to retrieve DTE");

      Window window = dte.Windows.Item(EnvDTE.Constants.vsWindowKindOutput);
      window.Activate();

      var outputWindow = (EnvDTE.OutputWindow) window.Object;
      outputWindow.ActivePane.Activate();

      outputWindow.ActivePane.OutputString(output);
      outputWindow.ActivePane.OutputString("\n");
    }

严重性代码描述项目文件行抑制状态 错误运行转换: System.Runtime.Serialization.SerializationException:类型 'Microsoft.VisualStudio.Platform.WindowManagement.DTE.Windows' 在 程序集 'Microsoft.VisualStudio.Platform.WindowManagement, 版本=15.0.0.0,文化=中性,PublicKeyToken=b03f5f7f11d50a3a' 是 未标记为可序列化。

服务器堆栈跟踪:在 System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType 类型)在 System.Runtime.Serialization.FormatterServices.GetSerializableMembers(类型 类型,StreamingContext 上下文)在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(对象 obj,ISurrogateSelector surrogateSelector,StreamingContext 上下文, SerObjectInfoInit serObjectInfoInit,IFormatterConverter 转换器, ObjectWriter objectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(对象 obj,ISurrogateSelector surrogateSelector,StreamingContext 上下文, SerObjectInfoInit serObjectInfoInit,IFormatterConverter 转换器, ObjectWriter objectWriter, SerializationBinder binder) 在 System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(对象 图,Header[] inHeaders,__BinaryWriter serWriter,布尔 fCheck)
在 System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(流 序列化流、对象图、Header[] 标头、布尔 fCheck)
在 System.Runtime.Remoting.Channels.CrossAppDomainSerializer.SerializeMessageParts(ArrayList argsToSerialize) 在 System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage..ctor(IMethodReturnMessage 先生)在 System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage.SmuggleIfPossible(IMessage 味精)在 System.Runtime.Remoting.Channels.CrossAppDomainSink.DoDispatch(字节 [] reqStmBuff, SmuggledMethodCallMessage smuggledMcm, SmuggledMethodReturnMessage& smuggledMrm) 在 System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatchCallback(Object[] 参数)

在 [0] 处重新抛出异常:在 System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg,IMessage retMsg)在 System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(消息数据& msgData,Int32 类型)在 EnvDTE._DTE.get_Windows() 在 Microsoft.VisualStudio.TextTemplating8CBB5A87F4A34D52835396F51C533E1D8E9F22BC6977A9510B46C012D01E08C8AD263AC5BA030600D92BC0F39E7F1C3B6AA67D8CE545627E10A7F993E06C0D0。 输出)在 C:\ViewModels\BaseGridViewModels\BaseViewModels.tt:line 581 在 Microsoft.VisualStudio.TextTemplating8CBB5A87F4A34D52835396F51C533E1D8E9F22BC6977A9510B46C012D01E08C8AD263AC5BA030600D92BC0F39E7F1C3B6AA67D8CE545627E10A7F993E06C0D02.GeneratedTextTransformation.TypeMapper.GetItemsToGenerate [T](IEnumerable`1 itemCollection) 在 C:\ViewModels\BaseGridViewModels\BaseViewModels.tt:第 566 行 Microsoft.VisualStudio.TextTemplating8CBB5A87F4A34D52835396F51C533E1D8E9F22BC6977A9510B46C012D01E08C8AD263AC5BA030600D92BC0F39E7F1C3B6AA67D8CE545627E10A7F993E06C0D0 在 C:\ViewModels\BaseGridViewModels\BaseViewModels.tt:line 33 C:\ViewModels\BaseGridViewModels\BaseViewModels.tt 581

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-26
    • 2011-03-22
    • 1970-01-01
    • 2011-10-06
    相关资源
    最近更新 更多