Как я могу предоставить .Net 2.0 Webservice клиенту Silverlight? - PullRequest
2 голосов
/ 20 августа 2009

У меня есть тривиальный веб-сервис .Net 2.0 SOAP. Я хочу получить к нему доступ из приложения Silverlight, которое размещено на том же сервере, но с другим портом. Я знаю, что для этого мне нужно предоставить файл политики clientaccesspolicy.xml или crossdomain.xml (услуга доступна на http://example:8085/RemoteObject.rem?wsdl, поэтому файл политики должен присутствовать на http://example:8085/crossdomain.xml). Что я должен добавить к следующему простому веб-сервису, чтобы самостоятельно обслуживал файл политики, как это делает пример WCF ?

Веб-служба работает на Mono, хотя это ничего не должно изменить - IIS не задействован.

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Http;

namespace ConsoleApplication1
{
    class RemoteObject : MarshalByRefObject
    {
        static void Main()
        {
            var channel = new HttpChannel(8085);
            ChannelServices.RegisterChannel(channel, false);

            RemotingConfiguration.RegisterWellKnownServiceType(
                typeof(RemoteObject), "RemoteObject.rem",
                WellKnownObjectMode.Singleton);

            Console.WriteLine("Press ENTER to exit the server.");
            Console.ReadLine();
        }

        public DateTime Now()
        {
            return DateTime.Now;
        }
    }
}

РЕДАКТИРОВАТЬ: из-за всех непригодных ответов, позвольте мне повторить себя: мне нужно сделать это с .Net 2.0, а не 3.0 или 3.5. WCF недоступен .

Ответы [ 4 ]

2 голосов
/ 25 августа 2009

Я мало что знаю о deploymnets в MONO. Я бы предложил другой подход, если вы не нашли более подходящих подходов к вашему вопросу.

Вместо прямого вызова веб-службы из приложения silverlight .. вы можете вызвать метод javascript из управляемого кода Silverlight, используя

string sJson = HtmlPage.Window.Invoke("JSMethod", new string[] { strInParam }) as string;

и отправляет запрос AJAX (из метода JS) на ваш сервер, а также выполняет внутренний вызов веб-службы, развернутой в MONO (с сервера), и возвращает результат в формате JSON.

Я реализовал этот подход в своих проектах и ​​он работает нормально.

просто альтернатива ..

1 голос
/ 27 августа 2009

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-сервера.

1 голос
/ 26 августа 2009

Хорошо, я могу сказать, что ответ не является легким шагом. Пожалуйста, посмотрите на веб-сервер с открытым исходным кодом Cassini, и вам придется внедрить небольшой веб-сервер в ваше приложение и запустить собственную службу на своем пользовательском веб-сервере.

И лучший способ открыть этот silverlight - создать IFrame и позволить ему загружать html / aspx с вашего пользовательского веб-сервера с самого вашего собственного порта. Таким образом, вам не нужно никаких проблем междоменной политики.

0 голосов
/ 22 августа 2009
...