[英]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.xml
或crossdomain.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.