EDIT2:我的同事找到了一个可用的解决方案:来自 Microsoft 的 Web Service Enhancements。它确实需要 IIS,并且随着 WCF 的引入而被弃用,但在普通的 .Net Framework 2.0 中运行良好,并且应该可以使用 Mono XSP 进行部署。
编辑:下面的解决方案毫无意义,因为 .Net 2.0 使用 SOAP 1.1 rpc/编码模型公开 Web 服务,而 Silverlight 需要 SOAP 1.2 文档/文字。因此,虽然解决方法适用于问题中指出的问题,但仍然无法使用 Web 服务。
我成功地完成了这项工作,而没有采取极端的黑客手段。我的解决方案的关键是在请求处理队列中插入一个额外的IServerChannelSink。所以,我改变了
var channel = new HttpChannel(8085);
在正常管道之前注册我的自定义IServerChannelSink:
var provider = ChainProviders(
new PolicyServerSinkProvider(),
new SdlChannelSinkProvider(),
new SoapServerFormatterSinkProvider(),
new BinaryServerFormatterSinkProvider());
var channel = new HttpChannel(new Hashtable(1) {{"port", 8085}}, null, provider);
我使用辅助方法将接收器提供者链接在一起:
private static IServerChannelSinkProvider ChainProviders(
params IServerChannelSinkProvider[] providers)
{
for (int i = 1; i < providers.Length; i++)
providers[i-1].Next = providers[i];
return providers[0];
}
PolicyServerSinkProvider 只是创建一个PolicyServerSink:
internal class PolicyServerSinkProvider : IServerChannelSinkProvider
{
public void GetChannelData(IChannelDataStore channelData){}
public IServerChannelSink CreateSink(IChannelReceiver channel)
{
IServerChannelSink nextSink = null;
if (Next != null)
nextSink = Next.CreateSink(channel);
return new PolicyServerSink(channel, nextSink);
}
public IServerChannelSinkProvider Next { get; set; }
}
PolicyServerSink 将所有消息委托到链中,除非它收到对 crossdomain.xml 的请求 - 然后它将所需的 xml 写入响应流。
internal class PolicyServerSink : IServerChannelSink
{
public PolicyServerSink(
IChannelReceiver receiver, IServerChannelSink nextSink)
{
NextChannelSink = nextSink;
}
public IDictionary Properties { get; private set; }
public ServerProcessing ProcessMessage(
IServerChannelSinkStack sinkStack, IMessage requestMsg,
ITransportHeaders requestHeaders, Stream requestStream,
out IMessage responseMsg, out ITransportHeaders responseHeaders,
out Stream responseStream)
{
if (requestMsg != null || ! ShouldIntercept(requestHeaders))
return NextChannelSink.ProcessMessage(
sinkStack, requestMsg, requestHeaders, requestStream,
out responseMsg, out responseHeaders, out responseStream);
responseHeaders = new TransportHeaders();
responseHeaders["Content-Type"] = "text/xml";
responseStream = new MemoryStream(Encoding.UTF8.GetBytes(
@"<?xml version=""1.0""?><!DOCTYPE cross-domain-policy SYSTEM "
+ @"""http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd"">"
+ @"<cross-domain-policy><allow-access-from domain=""*"" />"
+ @"</cross-domain-policy>")) {Position = 0};
responseMsg = null;
return ServerProcessing.Complete;
}
private static bool ShouldIntercept(ITransportHeaders headers)
{
return ((string) headers["__RequestUri"]).Equals(
"/crossdomain.xml", StringComparison.InvariantCultureIgnoreCase);
}
public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack,
object state, IMessage msg, ITransportHeaders headers, Stream stream)
{
}
public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack,
object state, IMessage msg, ITransportHeaders headers)
{
throw new NotSupportedException();
}
public IServerChannelSink NextChannelSink { get; private set; }
}
这也可用于与 Web 服务一起提供其他文件。我目前正在使用这种方法来托管我的 Silverlight 应用程序(Web 服务的使用者),而无需单独的 http 服务器。