如何将.Net 2.0 Web服务公开给Silverlight客户端?

时间:2009-08-20 15:05:59

标签: c# silverlight web-services .net-2.0 mono

我有一个简单的.Net 2.0 SOAP Web服务。我想从Silverlight应用程序访问它,该应用程序托管在同一台服务器上,但不同的端口。我知道要实现此目的,我需要提供clientaccesspolicy.xmlcrossdomain.xml政策文件(该服务位于http://example:8085/RemoteObject.rem?wsdl,因此政策文件必须出现在http://example:8085/crossdomain.xml })。我应该将以下简单的Web服务添加到self-serve the policy file like the WCF example does

Web服务正在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 个答案:

答案 0 :(得分:2)

我对MONO中的deploymnets了解不多。如果你没有为你的问题找到更好的方法,我建议采用不同的方法。

您可以使用

从您管理的Silverlight代码中调用javascript方法,而不是直接从silverlight应用程序调用web服务。
string sJson = HtmlPage.Window.Invoke("JSMethod", new string[] { strInParam }) as string;

并将AJAX请求(来自JS方法)发送到您的服务器,并在内部调用部署在MONO中的Web服务(来自服务器)并返回JSON格式的结果。

我已经在我的项目中实现了这种方法,并且工作正常......

只是另一种选择..

答案 1 :(得分:1)

好的,我可以说答案不是一个简单的步骤。请查看Cassini开源Web服务器,您必须在应用程序中实现一个小型Web服务器,并在自定义Web服务器中运行自定义服务。

打开这个Silverlight的最好方法是,创建一个IFrame,然后从自定义端口本身加载自定义Web服务器的html / aspx。因此,您不需要任何跨域策略问题。

答案 2 :(得分:1)

EDIT2 我的同事找到了一个可用的解决方案:来自Microsoft的Web Service Enhancements。它确实需要IIS,并且随着WCF的引入而被弃用,但与普通.Net Framework 2.0一起运行良好,并且可以与Mono XSP一起部署。

编辑:下面的解决方案毫无意义,因为.Net 2.0使用SOAP 1.1 rpc / encoded模型公开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服务器。

答案 3 :(得分:0)