模拟IIS向Silverlight输出策略文件

模拟IIS向Silverlight输出策略文件,第1张

概述问题 最近的Silverlight开发中,由于部分需求对实时性和数据量下载速度有要求,部分WCF服务配置成了netTcpBinding,这种方式跟普通的service.svc寄宿IIS不同的是,Silverlight需要的策略文件需要放置在本机IIS的根下,也就是wwwroot文件夹下,以满足Silverlight在以TCP协议调用本机WCF服务时请求策略文件。 (注:Silverlight通过T 问题

最近的Silverlight开发中,由于部分需求对实时性和数据量下载速度有要求,部分WCF服务配置成了netTcpBinding,这种方式跟普通的service.svc寄宿IIS不同的是,Silverlight需要的策略文件需要放置在本机IIS的根下,也就是wwwroot文件夹下,以满足Silverlight在以TCP协议调用本机WCF服务时请求策略文件。

(注:Silverlight通过TCP协议调用WCF服务时,会以http方式请求主机的一个策略文件,地址是http://localhost/clientaccesspolicy.xml)

这其实是个不太好的选择,程序运行的所需的环境被分成了两部分,同事的机器上并未安装IIS,为了大家开发简便,不用在额外安装IIS,也为了让程序更加独立,我就想能不能写代码监控80端口模拟IIS向Silverlight输出这个策略文件。

解决方法

有了这个想法之后,首先想到的是通过Socket进行监听,因为此前在MSDN上看到过这种方式,但很无奈,将代码转移过来之后,并未成功。相信做过Silverlight在Socket方面应用的朋友对下面这个PolicyServer类很熟悉吧。

          

代码@H_419_28@ using@H_419_28@  System;
@H_419_28@ using@H_419_28@  System.IO;
@H_419_28@ using@H_419_28@  System.Net;
@H_419_28@ using@H_419_28@  System.Net.sockets;

@H_419_28@ namespace@H_419_28@  PolicyServer
{
@H_419_28@ //@H_419_28@  Encapsulate and manage state for a single connection from a clIEnt@H_419_28@
@H_419_28@ class@H_419_28@  PolicyConnection
{
    @H_419_28@ private@H_419_28@  Socket m_connection;

    @H_419_28@ //@H_419_28@  buffer to receive the request from the clIEnt@H_419_28@
@H_419_28@     @H_419_28@ private@H_419_28@  @H_419_28@ byte@H_419_28@ [] m_buffer;
    @H_419_28@ private@H_419_28@  @H_419_28@ int@H_419_28@  m_received;

    @H_419_28@ //@H_419_28@  the policy to return to the clIEnt@H_419_28@
@H_419_28@     @H_419_28@ private@H_419_28@  @H_419_28@ byte@H_419_28@ [] m_policy;

    @H_419_28@ //@H_419_28@  the request that we're expecting from the clIEnt@H_419_28@
@H_419_28@     @H_419_28@ private@H_419_28@  @H_419_28@ static@H_419_28@  @H_419_28@ string@H_419_28@  s_policyRequestString @H_419_28@ =@H_419_28@  @H_419_28@ "@H_419_28@ <policy-file-request/>@H_419_28@ "@H_419_28@ ;



    @H_419_28@ public@H_419_28@  PolicyConnection(Socket clIEnt, @H_419_28@ byte@H_419_28@ [] policy)
    {
        m_connection @H_419_28@ =@H_419_28@  clIEnt;
        m_policy @H_419_28@ =@H_419_28@  policy;

        m_buffer @H_419_28@ =@H_419_28@  @H_419_28@ new@H_419_28@  @H_419_28@ byte@H_419_28@ [s_policyRequestString.Length];
        m_received @H_419_28@ =@H_419_28@  @H_419_28@ 0@H_419_28@ ;

        @H_419_28@ try@H_419_28@
        {
            @H_419_28@ //@H_419_28@  receive the request from the clIEnt@H_419_28@
@H_419_28@             m_connection.BeginReceive(m_buffer, @H_419_28@ 0@H_419_28@ , s_policyRequestString.Length, SocketFlags.None, @H_419_28@ new@H_419_28@  AsyncCallback(OnReceive), @H_419_28@ null@H_419_28@ );
        }
        @H_419_28@ catch@H_419_28@  (SocketException)
        {
            m_connection.Close();
        }
    }

    @H_419_28@ //@H_419_28@  Called when we receive data from the clIEnt@H_419_28@
@H_419_28@     @H_419_28@ private@H_419_28@  @H_419_28@ voID@H_419_28@  OnReceive(IAsyncResult res)
    {
        @H_419_28@ try@H_419_28@
        {
            m_received @H_419_28@ +=@H_419_28@  m_connection.EndReceive(res);

            @H_419_28@ //@H_419_28@  if we haven't gotten enough for a full request yet, receive again@H_419_28@
@H_419_28@             @H_419_28@ if@H_419_28@  (m_received @H_419_28@ <@H_419_28@  s_policyRequestString.Length)
            {
                m_connection.BeginReceive(m_buffer, m_received, s_policyRequestString.Length @H_419_28@ -@H_419_28@  m_received, @H_419_28@ null@H_419_28@ );
                @H_419_28@ return@H_419_28@ ;
            }

            @H_419_28@ //@H_419_28@  make sure the request is valID@H_419_28@
@H_419_28@             @H_419_28@ string@H_419_28@  request @H_419_28@ =@H_419_28@  System.Text.EnCoding.UTF8.GetString(m_buffer, m_received);
            @H_419_28@ if@H_419_28@  (StringComparer.InvariantCultureIgnoreCase.Compare(request, s_policyRequestString) @H_419_28@ !=@H_419_28@  @H_419_28@ 0@H_419_28@ )
            {
                m_connection.Close();
                @H_419_28@ return@H_419_28@ ;
            }

            @H_419_28@ //@H_419_28@  send the policy@H_419_28@
@H_419_28@             m_connection.BeginSend(m_policy, m_policy.Length, @H_419_28@ new@H_419_28@  AsyncCallback(OnSend), @H_419_28@ null@H_419_28@ );
        }
        @H_419_28@ catch@H_419_28@  (SocketException)
        {
            m_connection.Close();
        }
    }

    @H_419_28@ //@H_419_28@  called after sending the policy to the clIEnt; close the connection.@H_419_28@
@H_419_28@     @H_419_28@ public@H_419_28@  @H_419_28@ voID@H_419_28@  OnSend(IAsyncResult res)
    {
        @H_419_28@ try@H_419_28@
        {
            m_connection.EndSend(res);
        }
        @H_419_28@ finally@H_419_28@
        {
            m_connection.Close();
        }
    }
}

@H_419_28@ //@H_419_28@  Listens for connections on port 943 and dispatches requests to a PolicyConnection@H_419_28@
@H_419_28@ class@H_419_28@  PolicyServer
{
    @H_419_28@ private@H_419_28@  Socket m_Listener;
    @H_419_28@ private@H_419_28@  @H_419_28@ byte@H_419_28@ [] m_policy;

    @H_419_28@ //@H_419_28@  pass in the path of an XML file containing the socket policy@H_419_28@
@H_419_28@     @H_419_28@ public@H_419_28@  PolicyServer(@H_419_28@ string@H_419_28@  policyfile)
    {
        @H_419_28@ //@H_419_28@  Load the policy file@H_419_28@
@H_419_28@         fileStream policyStream @H_419_28@ =@H_419_28@  @H_419_28@ new@H_419_28@  fileStream(policyfile, fileMode.Open);

        m_policy @H_419_28@ =@H_419_28@  @H_419_28@ new@H_419_28@  @H_419_28@ byte@H_419_28@ [policyStream.Length];
        policyStream.Read(m_policy, m_policy.Length);

        policyStream.Close();

        m_Listener @H_419_28@ =@H_419_28@  @H_419_28@ new@H_419_28@  Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

        m_Listener.SetSocketoption(SocketoptionLevel.IPv6, (Socketoptionname)@H_419_28@ 27@H_419_28@ , @H_419_28@ 0@H_419_28@ );

        m_Listener.Bind(@H_419_28@ new@H_419_28@  IPEndPoint(IPAddress.IPv6Any, @H_419_28@ 943@H_419_28@ ));
        m_Listener.Listen(@H_419_28@ 10@H_419_28@ );

        m_Listener.BeginAccept(@H_419_28@ new@H_419_28@  AsyncCallback(OnConnection), @H_419_28@ null@H_419_28@ );
    }

     @H_419_28@ public@H_419_28@  @H_419_28@ voID@H_419_28@  OnConnection(IAsyncResult res)
    {
        Socket clIEnt @H_419_28@ =@H_419_28@  @H_419_28@ null@H_419_28@ ;

        @H_419_28@ try@H_419_28@
        {
            clIEnt @H_419_28@ =@H_419_28@  m_Listener.EndAccept(res);
        }
        @H_419_28@ catch@H_419_28@  (SocketException)
        {
            @H_419_28@ return@H_419_28@ ;
        }

        @H_419_28@ //@H_419_28@  handle this policy request with a PolicyConnection@H_419_28@
@H_419_28@         PolicyConnection pc @H_419_28@ =@H_419_28@  @H_419_28@ new@H_419_28@  PolicyConnection(clIEnt, m_policy);

        @H_419_28@ //@H_419_28@  look for more connections@H_419_28@
@H_419_28@         m_Listener.BeginAccept(@H_419_28@ new@H_419_28@  AsyncCallback(OnConnection), @H_419_28@ null@H_419_28@ );
    }

    @H_419_28@ public@H_419_28@  @H_419_28@ voID@H_419_28@  Close()
    {
        m_Listener.Close();
    }
}
@H_419_28@ public@H_419_28@  @H_419_28@ class@H_419_28@  Program
{
    @H_419_28@ static@H_419_28@  @H_419_28@ voID@H_419_28@  Main(@H_419_28@ string@H_419_28@ [] args)
    {
        @H_419_28@ if@H_419_28@  (args.Length @H_419_28@ ==@H_419_28@  @H_419_28@ 0@H_419_28@ )
        {
            Console.Writeline(@H_419_28@ "@H_419_28@ usage: PolicyServer.exe Policyfile.xml@H_419_28@ "@H_419_28@ );
            @H_419_28@ return@H_419_28@ ;
        }

        PolicyServer ps @H_419_28@ =@H_419_28@  @H_419_28@ new@H_419_28@  PolicyServer(args[@H_419_28@ 0@H_419_28@ ]);
        System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
    }
}
}
@H_419_28@

 

此路不通之后,又想起使用httpListener类,看看是否能够监听http请求,果然能够截获http的请求
httpListener @H_419_28@Listener = new @H_419_28@httpListener@H_419_28@();Listener.Prefixes.Add(http://localhost/@H_419_28@);
Listener.Start();Console@[email protected]("开始监听…"@H_419_28@);httpListenerContext @H_419_28@context = Listener.GetContext();httpListenerRequest @H_419_28@request = context.Request;httpListenerResponse @H_419_28@response = context.Response;但是这种方式有个明显的缺点,就是线程是阻塞的。于是,又想到使用线程池。
System.Threading.ThreadPool@[email protected](new @[email protected].WaitCallback@H_419_28@(Listen));

 

private static voID @H_419_28@Listen(object @H_419_28@state)        {            while @H_419_28@(httpListener.IsListening)            {                httpListener.BeginGetContext(new @H_419_28@AsyncCallback@H_419_28@(ListenerCallback),httpListener);                ListenForNextRequest.WaitOne();            }        }

这样的话,每接收一个请求便会异步处理这个请求。在请求的处理上,接收请求后需要向外输出策略文件流,供silverlight端接收验证。

using @H_419_28@(System.Net.httpListenerResponse @H_419_28@response = context.Response)            {                System.Threading.Thread@[email protected](1000);                string @H_419_28@responseString = "<?xml version=\"1.0\" enCoding=\"utf-8\"?> "                                        @H_419_28@+ " <access-policy> "                                        @H_419_28@+ "    <cross-domain-access> "                                           @H_419_28@+ "    <policy> "                                              @H_419_28@+ "    <allow-from http-request-headers=\"*\">"                                                 @H_419_28@+ "    <domain uri=\"*\" /> "                                                 @H_419_28@+ " </allow-from> "                                                 @H_419_28@+ " <grant-to> "                                                   @H_419_28@+ "  <socket-resource port=\"4502-4534\" protocol=\"tcp\" /> "                                                @H_419_28@+ "  </grant-to> "                                             @H_419_28@+ "  </policy> "                                        @H_419_28@+ "    </cross-domain-access>"                                        @H_419_28@+ " </access-policy>"@H_419_28@;                byte@H_419_28@[] buffer = System.Text.EnCoding@[email protected](responseString);                response.ContentLength64 = buffer.LongLength;                response.OutputStream.Write(buffer,buffer.Length);            } 

启动这个模拟服务,将clIEntaccesspolicy从wwwroot中移除后再运行一下程序,OK,我们不再需要将策略文件放到IIS下了。

提醒 

如果你的机器装了IIS,请还是放一个策略文件到wwwroot吧,否则就停掉IIS再使用这个类,因为IIS和这个类只能有一方监听80端口。

 

本文中的这个类参考了http://forums.silverlight.net/forums/p/113106/255614.aspx

总结

以上是内存溢出为你收集整理的模拟IIS向Silverlight输出策略文件全部内容,希望文章能够帮你解决模拟IIS向Silverlight输出策略文件所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1025270.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-23
下一篇 2022-05-23

发表评论

登录后才能评论

评论列表(0条)

保存