2

.NET 3.5を使用し、.NETリモーティングを介していくつかのメソッドを公開するサービスがあります。これらのメソッドの一部は、引数としてDataSetを想定しています。クライアントが.NET3.5も実行している場合は、すべて問題ありません。ただし、クライアントが.NET 4を実行している場合、(サーバー上で)次のリモート例外が発生します。

ファイルまたはアセンブリ'System.Data、Version = 4.0.0.0、Culture = neutral、PublicKeyToken=b77a5c561934e089'またはその依存関係の1つを読み込めませんでした。システムは、指定されたファイルを見つけることができません。

したがって、明らかにDataSetにはバージョン2とバージョン4の2つのバージョンがあります。DataSetが作成されてサーバーに送信される別の.NET3.5プロジェクトを作成しようとしました。ただし、他の.NET4アセンブリと一緒に.NET4ランタイムにロードされる場合でも、DataSetバージョン4が使用されます。

最も奇妙なことは、.net3.5でも実行されている別のサービスを使用することです。バージョン4のデータセットを問題なく送信できます。私はそこで何が違うのか理解できませんでした。

任意の洞察や解決策をいただければ幸いです。

更新: Microsoftは問題を認識しているようです:ここを参照してください。異なる.NETバージョン間で通信するためにそのようなハックが本当に必要な場合はかなり悲しいです...

4

1 に答える 1

1

次のコードは、BinaryClientFormatterSinkの代わりにクライアントで使用できるカスタムBinaryFormatterSinkを実装しています。これは、 MSDNのMicrosoftの例に基づいています

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;
        }
    }
}
于 2012-11-15T13:58:27.120 に答える