2009-08-20 51 views
2

我有一个简单的.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如何将.Net 2.0 Webservice公开到Silverlight客户端?

Web服务正在单声道上运行,尽管这不应该改变任何东西 - 只是没有涉及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不可用

+0

你曾经尝试在Windows机器上运行你的web服务..?是那个作品.. ?? – RameshVel 2009-08-25 10:59:08

+0

是的,它的确如此,这只是Silverlight的安全限制,可以防止我想到的情况。 – skolima 2009-08-25 12:35:08

回答

1

EDIT2我的同事发现了一个可用的解决方案:来自微软的Web Service Enhancements。它确实需要IIS,并且在引入WCF时已被弃用,但在纯净的.Net Framework 2.0中运行良好,并且应该可部署到Mono XSP

EDIT:下面溶液是没有意义的,因为净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简单的创建a 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应用程序(Web服务的使用者),而无需单独的http服务器。

+0

.NET 2.0也可以做文档/文字。 – 2009-09-05 02:18:35

2

我不知道很多关于单声道deploymnets。如果您没有为您的问题找到更好的方法,我会建议采用不同的方法。

而不是直接调用从Silverlight应用程序的Web服务..你可以使用

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

托管的Silverlight代码调用JavaScript方法,并触发一个AJAX请求(来自JS方法)到您的服务器和内部会调用MONO中部署的webservice(从服务器)并返回JSON格式的结果。

我已经实现了我的项目和它的做工精细这种方法..

只是一种替代..

+0

这看起来像一个很好的答案 – JustLoren 2009-08-26 12:58:17

+0

谢谢罗兰... – RameshVel 2009-08-27 04:54:32

1

好吧,我可以说,答案并不是一件容易的一步。请查看Cassini开源Web服务器,您将不得不在您的应用程序中实现小型Web服务器,并在您的自定义Web服务器中运行您的自定义服务。

而打开这个Silverlight的是,创建一个iframe,让它从你的自定义端口自身加载从您的自定义Web服务器的HTML/ASPX的最佳途径。所以你不需要任何跨域策略问题。

相关问题