EDIT2 : мой коллега нашел полезное решение: Улучшения веб-службы от Microsoft. Он нуждается в IIS и устарел с появлением WCF, но хорошо работает с простым .Net Framework 2.0 и должен развертываться с Mono XSP .
EDIT : * Решение 1013 *, представленное ниже, не имеет смысла, поскольку .Net 2.0 предоставляет веб-сервисы, использующие модель SOAP 1.1 rpc / кодированный, а Silverlight требует документ / литерал SOAP 1.2. Таким образом, хотя обходной путь работает для проблемы, указанной в вопросе, веб-служба по-прежнему не может использоваться.
Мне удалось сделать эту работу, не прибегая к экстремальным взломам. Ключом к моему решению было вставить дополнительный 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; }
}
Это также можно использовать для обслуживания других файлов вместе с веб-сервисом. В настоящее время я использую этот метод для размещения своего приложения Silverlight (потребителя веб-службы) без отдельного http-сервера.