2009-08-20 53 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的最佳途徑。所以你不需要任何跨域策略問題。

相關問題