Visual Studio serialization error when T4 uses DTE to open generated file

前端 未结 2 655
独厮守ぢ
独厮守ぢ 2021-01-12 08:26

We have a C# T4 file named GenerateProxies.tt which calls several command-line codegen utilities. Using the System.Diagnostics Process class, we redirect the standard output

相关标签:
2条回答
  • 2021-01-12 09:04

    This is not an answer however the OP could not provide the stack trace as requested in the comments.

    I have a similar exception being thrown when I try to execute a function in my tt file to write to the Output window (ST is too long for comment)

    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");
        }
    

    Severity Code Description Project File Line Suppression State Error Running transformation: System.Runtime.Serialization.SerializationException: Type 'Microsoft.VisualStudio.Platform.WindowManagement.DTE.Windows' in Assembly 'Microsoft.VisualStudio.Platform.WindowManagement, Version=15.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' is not marked as serializable.

    Server stack trace: at System.Runtime.Serialization.FormatterServices.InternalGetSerializableMembers(RuntimeType type) at System.Runtime.Serialization.FormatterServices.GetSerializableMembers(Type type, StreamingContext context) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitMemberInfo() at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.InitSerialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) at System.Runtime.Serialization.Formatters.Binary.WriteObjectInfo.Serialize(Object obj, ISurrogateSelector surrogateSelector, StreamingContext context, SerObjectInfoInit serObjectInfoInit, IFormatterConverter converter, ObjectWriter objectWriter, SerializationBinder binder) at System.Runtime.Serialization.Formatters.Binary.ObjectWriter.Serialize(Object graph, Header[] inHeaders, __BinaryWriter serWriter, Boolean fCheck)
    at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Serialize(Stream serializationStream, Object graph, Header[] headers, Boolean fCheck)
    at System.Runtime.Remoting.Channels.CrossAppDomainSerializer.SerializeMessageParts(ArrayList argsToSerialize) at System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage..ctor(IMethodReturnMessage mrm) at System.Runtime.Remoting.Messaging.SmuggledMethodReturnMessage.SmuggleIfPossible(IMessage msg) at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoDispatch(Byte[] reqStmBuff, SmuggledMethodCallMessage smuggledMcm, SmuggledMethodReturnMessage& smuggledMrm) at System.Runtime.Remoting.Channels.CrossAppDomainSink.DoTransitionDispatchCallback(Object[] args)

    Exception rethrown at [0]: at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg) at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type) at EnvDTE._DTE.get_Windows() at Microsoft.VisualStudio.TextTemplating8CBB5A87F4A34D52835396F51C533E1D8E9F22BC6977A9510B46C012D01E08C8AD263AC5BA030600D92BC0F39E7F1C3B6AA67D8CE545627E10A7F993E06C0D02.GeneratedTextTransformation.TypeMapper.WriteToOutput(String output) in C:\ViewModels\BaseGridViewModels\BaseViewModels.tt:line 581 at Microsoft.VisualStudio.TextTemplating8CBB5A87F4A34D52835396F51C533E1D8E9F22BC6977A9510B46C012D01E08C8AD263AC5BA030600D92BC0F39E7F1C3B6AA67D8CE545627E10A7F993E06C0D02.GeneratedTextTransformation.TypeMapper.GetItemsToGenerate[T](IEnumerable`1 itemCollection) in C:\ViewModels\BaseGridViewModels\BaseViewModels.tt:line 566 at Microsoft.VisualStudio.TextTemplating8CBB5A87F4A34D52835396F51C533E1D8E9F22BC6977A9510B46C012D01E08C8AD263AC5BA030600D92BC0F39E7F1C3B6AA67D8CE545627E10A7F993E06C0D02.GeneratedTextTransformation.TransformText() in C:\ViewModels\BaseGridViewModels\BaseViewModels.tt:line 33 C:\ViewModels\BaseGridViewModels\BaseViewModels.tt 581

    0 讨论(0)
  • 2021-01-12 09:23

    The EnvDTE assemblies are COM interop assemblies. Your error can be avoided by creating a Runtime Callable Wrapper, which marshals calls to the COM object based off information in the interop-assembly. Microsoft has provided an extension method within the Microsoft.VisualStudio.TextTemplating namespace:

    <#@ 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 templates run in a separate AppDomain, and I believe that is the reason your code is working despite the exception. IServiceProvider.GetService(typeof(DTE)) returns a transparent Proxy Object. This exception is because the proxy requires objects crossing an app domain be decorated with the Serializable attribute. You can confirm the DTE object in your code is a "transparent proxy" like this:

    bool isProxy = RemotingServices.IsTransparentProxy(dte); 
    
    0 讨论(0)
提交回复
热议问题