2012-08-13 93 views
2

我有一個使用.NET 3.5並通過.NET遠程處理公開某些方法的服務。其中一些方法需要DataSet作爲參數。當客戶端也運行.NET 3.5時,一切都很好。然而,當客戶端運行.NET 4中得到以下遠程異常(在服務器上):通過遠程發送從.net 4到.net 3.5的數據集

無法加載文件或程序集「System.Data,版本= 4.0.0.0,文化=中立, PublicKeyToken = b77a5c561934e089'或它的一個依賴關係。系統找不到指定的文件 。

所以顯然有兩個版本的DataSets - 版本2和版本4.我已經嘗試創建一個單獨的.NET 3.5項目,其中DataSet被創建併發送到服務器。但是,當它在.NET 4運行時加載其他.NET 4程序集時,它仍然使用DataSet版本4.

最奇怪的事情是在.net 3.5中運行不同的服務我可以發送版本4 DataSet沒有問題。我一直無法弄清楚那裏有什麼不同。

任何洞察力或解決方案將不勝感激。

更新: 微軟似乎意識到了這個問題:請參閱here。非常難過,但如果真的需要這種黑客之間的通信不同的.NET版本...

回答

1

下面的代碼實現了可以在客戶端而不是BinaryClientFormatterSink使用自定義BinaryFormatterSink。它基於微軟的例子MSDN

using System; 
using System.Collections; 
using System.Collections.Generic; 
using System.IO; 
using System.Linq; 
using System.Reflection; 
using System.Runtime.Remoting.Channels; 
using System.Runtime.Remoting.Messaging; 
using System.Runtime.Serialization; 
using System.Runtime.Serialization.Formatters; 
using System.Runtime.Serialization.Formatters.Binary; 
using System.Text; 

namespace bla 
{ 
    class VersionConversionClientSinkProvider : IClientChannelSinkProvider 
    { 
     public IClientChannelSink CreateSink(IChannelSender channel, string url, object remoteChannelData) 
     { 
      if (Next != null) 
      { 
       var nextSink = Next.CreateSink(channel, url, remoteChannelData); 
       if (nextSink != null) 
       { 
        return new VersionConversionClientSink(nextSink); 
       } 
      } 
      return null; 
     } 

     public IClientChannelSinkProvider Next { get; set; } 
    } 

    class VersionConversionClientSink : IClientChannelSink, IMessageSink 
    { 
     public VersionConversionClientSink(IClientChannelSink channel) 
     { 
      _next = channel; 
     } 

     readonly IClientChannelSink _next; 

     public IDictionary Properties 
     { 
      get { return NextChannelSink.Properties; } 
     } 

     public void ProcessMessage(IMessage msg, ITransportHeaders requestHeaders, Stream requestStream, out ITransportHeaders responseHeaders, out Stream responseStream) 
     { 
      throw new NotSupportedException(); 
     } 

     private void SerializeMessage(IMessage msg, out ITransportHeaders headers, out Stream stream) 
     { 
      var binaryFormatter = new BinaryFormatter 
       { 
        Binder = new VersionConversionSerializationBinder() 
       }; 

      stream = new MemoryStream(); 
      binaryFormatter.Serialize(stream, msg); 
      stream.Position = 0; 

      headers = new TransportHeaders(); 
     } 

     private IMessage DeserializeMessage(Stream stream) 
     { 
      var binaryFormatter = new BinaryFormatter 
       { 
        AssemblyFormat = FormatterAssemblyStyle.Simple 
       }; 

      var msg = (IMessage) binaryFormatter.Deserialize(stream); 
      stream.Close(); 
      return msg; 
     } 

     public void AsyncProcessRequest(IClientChannelSinkStack sinkStack, IMessage msg, ITransportHeaders headers, Stream stream) 
     { 
      throw new NotSupportedException(); 
     } 

     public void AsyncProcessResponse(IClientResponseChannelSinkStack sinkStack, object state, ITransportHeaders headers, Stream stream) 
     { 
      sinkStack.AsyncProcessResponse(headers, stream); 
     } 

     public Stream GetRequestStream(IMessage msg, ITransportHeaders headers) 
     { 
      return _next.GetRequestStream(msg, headers); 
     } 

     public IClientChannelSink NextChannelSink 
     { 
      get { return _next; } 
     } 

     public IMessage SyncProcessMessage(IMessage msg) 
     { 
      IMethodCallMessage mcm = msg as IMethodCallMessage; 
      try 
      { 
       ITransportHeaders headers; 
       Stream stream; 
       SerializeMessage(msg, out headers, out stream); 
       ITransportHeaders responseHeaders; 
       Stream responseStream; 
       NextChannelSink.ProcessMessage(msg, headers, stream, out responseHeaders, out responseStream); 
       if (responseHeaders == null) 
        throw new ArgumentNullException("returnHeaders"); 
       else 
        return DeserializeMessage(responseStream); 
      } 
      catch (Exception ex) 
      { 
       return new ReturnMessage(ex, mcm); 
      } 
     } 

     public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink) 
     { 
      var mcm = (IMethodCallMessage)msg; 
      try 
      { 
       ITransportHeaders headers; 
       Stream stream; 
       SerializeMessage(msg, out headers, out stream); 
       var channelSinkStack = new ClientChannelSinkStack(replySink); 
       channelSinkStack.Push(this, msg); 
       NextChannelSink.AsyncProcessRequest(channelSinkStack, msg, headers, stream); 
      } 
      catch (Exception ex) 
      { 
       IMessage msg1 = new ReturnMessage(ex, mcm); 
       if (replySink != null) 
        replySink.SyncProcessMessage(msg1); 
      } 
      return null; 
     } 

     public IMessageSink NextSink 
     { 
      get { throw new NotSupportedException(); } 
     } 
    } 

    class VersionConversionSerializationBinder : SerializationBinder 
    { 
     string[] frameworkPublicKeyTokens = new string[] { 
       "B7-7A-5C-56-19-34-E0-89", 
       "B0-3F-5F-7F-11-D5-0A-3A", 
       "31-BF-38-56-AD-36-4E-35", 
       "89-84-5D-CD-80-80-CC-91" 
      }; 

     bool IsFrameworkAssembly(Assembly assembly) 
     { 
      foreach (string frameworkToken in frameworkPublicKeyTokens) 
      { 
       if (frameworkToken == BitConverter.ToString(assembly.GetName().GetPublicKeyToken())) 
       { 
        return true; 
       } 
      } 
      return false; 
     } 

     public override void BindToName(Type serializedType, out string assemblyName, out string typeName) 
     { 
      // To handle arrays 
      if (serializedType.IsArray) 
      { 
       string elementTypeName; 
       Type elementType = serializedType.GetElementType(); 
       BindToName(elementType, out assemblyName, out elementTypeName); 
       StringBuilder typeNameBuilder = new StringBuilder(elementTypeName); 
       typeNameBuilder.Append("["); 
       int arrayRank = serializedType.GetArrayRank(); 
       for (int i = 1; i < arrayRank; i++) 
       { 
        typeNameBuilder.Append(","); 
       } 
       if (arrayRank == 1 && serializedType == elementType.MakeArrayType(1)) 
       { 
        typeNameBuilder.Append("*"); 
       } 
       typeNameBuilder.Append("]"); 
       typeName = typeNameBuilder.ToString(); 
      } 
      // To handle generic types 
      else if (serializedType.IsGenericType && !serializedType.IsGenericTypeDefinition) 
      { 
       string definitionTypeName; 
       Type[] genericParameters = serializedType.GetGenericArguments(); 
       BindToName(serializedType.GetGenericTypeDefinition(), out assemblyName, out definitionTypeName); 
       StringBuilder typeNameBuilder = new StringBuilder(definitionTypeName); 
       typeNameBuilder.Append("["); 
       for (int i = 0; i < genericParameters.Length; i++) 
       { 
        if (i > 0) 
        { 
         typeNameBuilder.Append(","); 
        } 
        string parameterTypeName, parameterAssemblyName; 
        BindToName(genericParameters[i], out parameterAssemblyName, out parameterTypeName); 
        typeNameBuilder.AppendFormat("[{0}, {1}]", parameterTypeName, parameterAssemblyName); 
       } 
       typeNameBuilder.Append("]"); 
       typeName = typeNameBuilder.ToString(); 
      } 
      // To handle the rest of types 
      else 
      { 
       assemblyName = serializedType.Assembly.FullName; 
       if (IsFrameworkAssembly(serializedType.Assembly)) 
       { 
        assemblyName = assemblyName.Replace("Version=4.0.0.0", "Version=2.0.0.0"); 
       } 
       typeName = serializedType.FullName; 
      } 
     } 

     public override Type BindToType(string assemblyName, string typeName) 
     { 
      return null; 
     } 
    } 
} 
+0

不幸的是,上面的代碼並沒有真正解決問題。轉移到WCF更容易 – user1596059 2013-04-26 15:38:17

相關問題