How can I open a .NET 2.0 web service for the Silverlight client?

I have a trivial SOAP.Net 2.0 web service. I want to access it from a Silverlight application hosted on the same server but with a different port. I know that for this I need to provide a policy file clientaccesspolicy.xml

or crossdomain.xml

(the service is available at http://example:8085/RemoteObject.rem?wsdl

, so the policy file must be present at http://example:8085/crossdomain.xml

). What should I add to the following simple web service to self serve policy file like WCF example ?

The web service runs in Mono, although that doesn't change anything - it doesn't involve 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 unused answers, let me repeat: I need to do this with .Net 2.0, not 3.0 or 3.5. WCF is not available .

+2


source to share


4 answers


EDIT2 : A colleague of mine found a helpful solution: "Web Services Enhancements" from Microsoft. It really needs IIS and is deprecated with the introduction of WCF, but works well with simple .NET Framework 2.0 and should be available for deployment with Mono XSP .

EDIT : The solution below is pointless as .Net 2.0 provides web services using SOAP 1.1 rpc / encoded model and Silverlight requires SOAP 1.2 / literal document. Therefore, while the workaround works for the problem mentioned in the question, the web service still cannot be used.

I managed to get this job done without resorting to extreme hacks. By the time of my decision, an additional one was added IServerChannelSink

to the request processing queue. So I changed

var channel = new HttpChannel(8085);

      

register your custom IServerChannelSink

to normal pipeline:

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

      

I am using a helper method to combine the receiver providers:



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

just creates 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 to the chain, except when it receives a request for crossdomain.xml

- then it writes the required xml to the response stream.

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; }
}

      

It can also be used to work with other files along with the web service. I am currently using this method to host my Silverlight application (web service consumer) without a separate http server.

+1


source


I don't know much about deployments in MONO. I would suggest a different approach if you haven't found a better approach to your question.

Instead of calling the webservice directly from the silverlight application, you can call the javascript method from the managed Silverlight code using

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

      



and fire an AJAX request (from the JS method) to your server and internally call the web service deployed to MONO (from the server) and return a JSON formatted result.

I have implemented this approach in my projects and it works great.

just an alternative ..

+2


source


Ok, I can say that the answer is not an easy step. Take a look at the open source Cassini web server and you need to implement a small web server in your application and run your own service on your web server.

And the best way to open this silverlight is to create an IFrame and let it load html / aspx from your custom webserver from your own port. So you don't need any cross power problems.

+1


source


0


source







All Articles