一起谈.NET技术,模拟IIS向Silverlight输出策略文件

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

  问题

  最近的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类很熟悉吧。

 
 
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;

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

// buffer to receive the request from the client
private byte [] m_buffer;
private int m_received;

// the policy to return to the client
private byte [] m_policy;

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



public PolicyConnection(Socket client, byte [] policy)
{
m_connection
= client;
m_policy
= policy;

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

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

// Called when we receive data from the client
private void OnReceive(IAsyncResult res)
{
try
{
m_received
+= m_connection.EndReceive(res);

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

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

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

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

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

// pass in the path of an XML file containing the socket policy
public PolicyServer( string policyFile)
{
// Load the policy file
FileStream policyStream = new FileStream(policyFile, FileMode.Open);

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

policyStream.Close();

m_listener
= new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

m_listener.SetSocketOption(SocketOptionLevel.IPv6, (SocketOptionName)
27 , 0 );

m_listener.Bind(
new IPEndPoint(IPAddress.IPv6Any, 943 ));
m_listener.Listen(
10 );

m_listener.BeginAccept(
new AsyncCallback(OnConnection), null );
}

public void OnConnection(IAsyncResult res)
{
Socket client
= null ;

try
{
client
= m_listener.EndAccept(res);
}
catch (SocketException)
{
return ;
}

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

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

public void Close()
{
m_listener.Close();
}
}
public class Program
{
static void Main( string [] args)
{
if (args.Length == 0 )
{
Console.WriteLine(
" usage: PolicyServer.exe PolicyFile.xml " );
return ;
}

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

  此路不通之后,又想起使用HttpListener类,看看是否能够监听http请求,果然能够截获HTTP的请求。

 
 
HttpListener listener = new HttpListener();
listener.Prefixes.Add(http:
// localhost/);

listener.Start();Console.WriteLine(
" 开始监听… " );

HttpListenerContext context
= listener.GetContext();
HttpListenerRequest request
= context.Request;
HttpListenerResponse response
= context.Response;

  但是这种方式有个明显的缺点,就是线程是阻塞的。于是,又想到使用线程池。

 
 
System.Threading.ThreadPool.QueueUserWorkItem( new System.Threading.WaitCallback(Listen));
private static void Listen( object state)
{
while (httpListener.IsListening)
{
httpListener.BeginGetContext(
new AsyncCallback(ListenerCallback), httpListener);
listenForNextRequest.WaitOne();
}
}

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

 
 
using (System.Net.HttpListenerResponse response = context.Response)
{
System.Threading.Thread.Sleep(
1000 );

string responseString = " <?xml version=\ " 1.0 \ " encoding=\ " utf - 8 \ " ?> "
+ " <access-policy> "
+ " <cross-domain-access> "
+ " <policy> "
+ " <allow-from http-request-headers=\ " * \ " > "
+ " <domain uri=\ " * \ " /> "
+ " </allow-from> "
+ " <grant-to> "
+ " <socket-resource port=\ " 4502 - 4534 \ " protocol=\ " tcp\ " /> "
+ " </grant-to> "
+ " </policy> "
+ " </cross-domain-access> "
+ " </access-policy> " ;
byte [] buffer = System.Text.Encoding.UTF8.GetBytes(responseString);
response.ContentLength64
= buffer.LongLength;
response.OutputStream.Write(buffer,
0 , buffer.Length);
}

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

  提醒 

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

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

目录
相关文章
|
监控 Cloud Native 测试技术
.NET技术深度解析:现代企业级开发指南
每日激励:“不要一直责怪过去的自己,他曾经站在雾里也很迷茫”。我是蒋星熠Jaxonic,一名在代码宇宙中探索的极客旅人。从.NET Framework到.NET 8,我深耕跨平台、高性能、云原生开发,践行领域驱动设计与微服务架构,用代码书写技术诗篇。分享架构演进、性能优化与AI融合前沿,助力开发者在二进制星河中逐光前行。关注我,共探技术无限可能!
.NET技术深度解析:现代企业级开发指南
|
SQL 小程序 API
如何运用C#.NET技术快速开发一套掌上医院系统?
本方案基于C#.NET技术快速构建掌上医院系统,结合模块化开发理念与医院信息化需求。核心功能涵盖用户端的预约挂号、在线问诊、报告查询等,以及管理端的排班管理和数据统计。采用.NET Core Web API与uni-app实现前后端分离,支持跨平台小程序开发。数据库选用SQL Server 2012,并通过读写分离与索引优化提升性能。部署方案包括Windows Server与负载均衡设计,确保高可用性。同时针对API差异、数据库老化及高并发等问题制定应对措施,保障系统稳定运行。推荐使用Postman、Redgate等工具辅助开发,提升效率与质量。
759 0
|
开发框架 算法 .NET
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
C#/.NET/.NET Core技术前沿周刊 | 第 15 期(2024年11.25-11.30)
390 6
|
开发框架 Cloud Native .NET
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
C#/.NET/.NET Core技术前沿周刊 | 第 16 期(2024年12.01-12.08)
449 6
|
机器学习/深度学习 人工智能 Cloud Native
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台
在数字化时代,.NET 技术凭借其跨平台兼容性、丰富的类库和工具集以及卓越的性能与效率,成为软件开发的重要平台。本文深入解析 .NET 的核心优势,探讨其在企业级应用、Web 开发及移动应用等领域的应用案例,并展望未来在人工智能、云原生等方面的发展趋势。
570 3
|
敏捷开发 缓存 中间件
.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素
本文深入探讨了.NET技术的高效开发模式,涵盖面向对象编程、良好架构设计及高效代码编写与管理三大关键要素,并通过企业级应用和Web应用开发的实践案例,展示了如何在实际项目中应用这些模式,旨在为开发者提供有益的参考和指导。
286 3
|
开发框架 安全 Java
.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力
本文深入探讨了.NET技术的独特魅力与优势,涵盖高效的开发体验、强大的性能表现、高度的可扩展性及丰富的生态系统等方面,展示了其在软件开发领域的核心竞争力。.NET不仅支持跨平台开发,具备出色的安全性和稳定性,还能与多种技术无缝集成,为企业级应用提供全面支持。
689 3
|
监控 前端开发 API
一款基于 .NET MVC 框架开发、功能全面的MES系统
一款基于 .NET MVC 框架开发、功能全面的MES系统
989 5
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
588 7