下面的代码实现了一个可以在客户端上使用的自定义 BinaryFormatterSink,而不是 BinaryClientFormatterSink。它基于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;
}
}
}