简体   繁体   English

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

[英]How can I expose a .Net 2.0 Webservice to a Silverlight client?

I have a trivial .Net 2.0 SOAP web service. 我有一个简单的.Net 2.0 SOAP Web服务。 I want to access it from Silverlight application that is hosted on the same server, but different port. 我想从托管在同一服务器但不同端口上的Silverlight应用程序访问它。 I know that for this to work I need to provide a clientaccesspolicy.xml or crossdomain.xml policy file (the service is available at http://example:8085/RemoteObject.rem?wsdl , so the policy file has to be present at http://example:8085/crossdomain.xml ). 我知道要使其正常工作,我需要提供一个clientaccesspolicy.xmlcrossdomain.xml策略文件(该服务位于http://example:8085/RemoteObject.rem?wsdl ,因此该策略文件必须位于http://example:8085/crossdomain.xml )。 What should I add to the following simple web service to self-serve the policy file like the WCF example does ? 与WCF示例一样,我应该在以下简单的Web服务中添加些什么以自助服务策略文件

The web service is being run on Mono, although that shouldn't change anything - there's just no IIS involved. 该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;
        }
    }
}

EDIT: because of all the unusable answers, let me repeat myself: I need to do this with .Net 2.0, not 3.0 or 3.5. 编辑:由于所有无法使用的答案,让我重复一遍:我需要使用.Net 2.0(而不是3.0或3.5)来进行此操作。 WCF is not available . WCF不可用

I dont know much about the deploymnets in MONO. 我对MONO中的deploymnets了解不多。 I would suggest a different approach if you didnt find any better approaches for your question. 如果您没有找到更好的方法来解决这个问题,我建议您使用其他方法。

Instead of directly calling the webservice from silverlight app.. you can invoke a javascript method from your managed silverlight code using 您可以从托管的Silverlight代码中使用以下方法来调用javascript方法:

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

and fire a AJAX request (from JS method) to your server and will internally make a call to the webservice deployed in MONO (from server) and return a JSON formatted result. 并将AJAX请求(来自JS方法)发送到您的服务器,并将在内部对MONO中部署的Web服务进行调用(来自服务器),并返回JSON格式的结果。

I have implemented this approach in my projects and its working fine.. 我已经在我的项目中实现了这种方法,并且效果很好。

just an alternative.. 只是一种选择。

Ok, I can say that answer is not an easy step. 好的,我可以说答案并非易事。 Please look at Cassini open source web server, and you will have to implement a small web server in your application and run your custom service in your custom web server. 请查看Cassini开源Web服务器,您将必须在应用程序中实现小型Web服务器,然后在自定义Web服务器中运行自定义服务。

And the best way to open this silverlight would be, create an IFrame and let it load the html/aspx from your custom web server from your custom port itself. 打开此Silverlight的最佳方法是创建一个IFrame,并使其从自定义端口本身的自定义Web服务器加载html / aspx。 So you would not need any cross domain policy problems. 因此,您将不需要任何跨域策略问题。

EDIT2 : my coworker has found a usable solution: Web Service Enhancements from Microsoft. EDIT2我的同事找到了一个可用的解决方案:Microsoft的Web服务增强 It does need IIS and it has been deprecated with the introduction of WCF, but works well with plain .Net Framework 2.0 and should be deployable with Mono XSP . 它确实需要IIS,并且已随着WCF的引入而弃用,但它与纯.Net Framework 2.0兼容,并且可以与Mono XSP一起部署。

EDIT : solution below is pointless, because .Net 2.0 exposes web services using SOAP 1.1 rpc/encoded model, and Silverlight requires SOAP 1.2 document/literal. 编辑下面的解决方案是没有意义的,因为.Net 2.0使用SOAP 1.1 rpc /编码模型公开了Web服务,而Silverlight需要SOAP 1.2文档/文字。 So while the workaround works for the problem indicated in the question, the web service still cannot be consumed. 因此,尽管解决方法可以解决问题中指出的问题,但仍无法使用Web服务。

I managed to make this work without resorting to extreme hacks. 我设法做到了这一点而不求助于极端的技巧。 The key to my solution was to insert an additional IServerChannelSink into the request processing queue. 我的解决方案的关键是在请求处理队列中插入一个额外的IServerChannelSink So, I changed 所以,我改变了

var channel = new HttpChannel(8085);

to register my custom IServerChannelSink before the normal pipeline: 在普通管道之前注册我的自定义IServerChannelSink

var provider = ChainProviders(
  new PolicyServerSinkProvider(),
  new SdlChannelSinkProvider(),
  new SoapServerFormatterSinkProvider(),
  new BinaryServerFormatterSinkProvider());
var channel = new HttpChannel(new Hashtable(1) {{"port", 8085}}, null, provider);

I use a helper method to chain the sink providers together: 我使用辅助方法将接收器提供程序链接在一起:

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 simply creates a PolicyServerSink : 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 delegates all messages down the chain, except when it gets a request for crossdomain.xml - then it writes the needed xml into the response stream. 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; }
}

This can also be used to serve other files together with the web service. 这也可以用于与Web服务一起提供其他文件。 I am currently using this method to host my Silverlight application (the consumer of the web service) without a separate http server. 我目前正在使用此方法来托管我的Silverlight应用程序(Web服务的使用者),而没有单独的http服务器。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM