2012-08-13 4 views
2

.NET 3.5를 사용하고 .NET Remoting을 통해 일부 메서드를 제공하는 서비스가 있습니다. 이러한 메소드 중 일부는 DataSet을 인수로 기대합니다. 클라이언트가 .NET 3.5를 실행할 때 모든 것이 잘됩니다. 클라이언트가 .NET 4를 실행하는 경우 그러나, 나는 (서버)에 다음과 같은 원격 예외를 얻을 :Remoting을 통해 .net 4에서 .net 3.5로 DataSet 보내기

파일 또는 어셈블리를로드 할 수 없습니다 '를 System.Data, 버전 = 4.0.0.0, 중립 문화 = PublicKeyToken = b77a5c561934e089 '또는 해당 종속성 중 하나를 선택하십시오. 시스템에서 파일을 찾을 수 없습니다. 버전 2와 버전 4. 데이터 집합이 생성되고 서버로 전송되는 별도의 .NET 3.5 프로젝트를 만드는 시도 -

그래서 분명히 데이터 집합의 두 가지 버전이 있습니다. 그러나 .NET 4 런타임에서 다른 .NET 4 어셈블리와 함께로드되면 DataSet 버전 4를 계속 사용합니다.

이상한 점은 .net 3.5에서 실행되는 다른 서비스와 관련이 있습니다. 버전 4 DataSets 아무 문제 없어. 나는 거기에 다른 것이 무엇인지 알아낼 수 없었다.

모든 통찰력이나 해결책은 크게 감사하겠습니다.

는 업데이트 : here를 참조하십시오 Microsoft는 문제를 인식 될 것으로 보인다. 같은 해킹이 다른 .NET 버전간에 실제로 통신해야하는 경우 꽤 슬프지만 ...

답변

1

아래 코드는 BinaryClientFormatterSink 대신 클라이언트에서 사용할 수있는 사용자 지정 BinaryFormatterSink를 구현합니다. Microsoft 예제를 기반으로합니다. 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