WPF中通过本地简易Web服务器托管Silverlight解决权限问题
解决WPF托管Silverlight本地加载时的网络图片权限问题
我帮你梳理下这个问题的核心:直接用WebBrowser加载本地XAP文件时,Silverlight处于本地文件权限上下文,哪怕签名了也会限制网络资源访问;而部署到服务器后是Web上下文,权限就正常了。所以在WPF里内置一个轻量Web服务器托管XAP,是完美的离线解决方案,不用依赖外部服务。
下面是具体的实现步骤和代码:
1. 准备资源文件
- 把你的Silverlight XAP文件放到WPF项目中,右键属性设置为「复制到输出目录:始终复制」,确保程序运行时能在输出目录找到它。
- 如果不想依赖CDN的Silverlight.js,也可以下载该文件到本地项目,同样设置复制到输出目录,后续在HTML里改成本地路径即可。
2. 实现内置HttpListener服务
我们用.NET自带的HttpListener来搭建本地服务器,不需要额外安装任何库,完全离线可用。
在WPF的主窗口里添加以下代码:
using System; using System.IO; using System.Net; using System.Text; using System.Windows; namespace WpfSilverlightHost { public partial class MainWindow : Window { private HttpListener _localWebServer; private const string ServerBaseUrl = "http://localhost:8080/"; // 可以自定义端口 public MainWindow() { InitializeComponent(); Loaded += MainWindow_Loaded; Closed += MainWindow_Closed; } private void MainWindow_Loaded(object sender, RoutedEventArgs e) { StartLocalWebServer(); // 让WebBrowser加载本地服务器的首页 silverlightWebBrowser.Navigate(new Uri(ServerBaseUrl)); } private void StartLocalWebServer() { _localWebServer = new HttpListener(); _localWebServer.Prefixes.Add(ServerBaseUrl); _localWebServer.Start(); // 异步处理请求,避免阻塞UI _localWebServer.BeginGetContext(ProcessRequest, null); } private void ProcessRequest(IAsyncResult result) { var context = _localWebServer.EndGetContext(result); // 继续监听下一个请求 _localWebServer.BeginGetContext(ProcessRequest, null); var requestPath = context.Request.Url.AbsolutePath; var response = context.Response; try { byte[] responseData; if (requestPath == "/" || requestPath == "/index.html") { // 返回Silverlight的宿主HTML页面 var hostHtml = @" <!DOCTYPE html> <html> <head> <meta charset='utf-8' /> <title>Silverlight Local Host</title> <!-- 如果用本地的Silverlight.js,改成http://localhost:8080/Silverlight.js --> <script type='text/javascript' src='https://ajax.aspnetcdn.com/ajax/silverlight/5.0.61118.0/Silverlight.js'></script> </head> <body style='margin:0'> <div id='silverlightContainer' style='width:100vw; height:100vh'> <object data='data:application/x-silverlight-2,' type='application/x-silverlight-2' width='100%' height='100%'> <param name='source' value='YourSilverlightApp.xap' /> <!-- 替换成你的XAP文件名 --> <param name='background' value='white' /> <param name='minRuntimeVersion' value='5.0.61118.0' /> <param name='autoUpgrade' value='true' /> <a href='https://go.microsoft.com/fwlink/?LinkID=149156&v=5.0.61118.0' style='text-decoration:none'> <img src='https://go.microsoft.com/fwlink/?LinkId=161376' alt='安装Silverlight' style='border:none'/> </a> </object> <iframe id='_sl_historyFrame' style='visibility:hidden; height:0; width:0; border:0'></iframe> </div> </body> </html>"; responseData = Encoding.UTF8.GetBytes(hostHtml); response.ContentType = "text/html"; } else if (requestPath.EndsWith(".xap")) { // 返回XAP文件内容 var xapFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, requestPath.TrimStart('/')); responseData = File.ReadAllBytes(xapFilePath); response.ContentType = "application/x-silverlight-app"; } else if (requestPath.EndsWith(".js")) { // 如果托管本地Silverlight.js,处理这个请求 var jsFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, requestPath.TrimStart('/')); responseData = File.ReadAllBytes(jsFilePath); response.ContentType = "application/javascript"; } else { // 404处理 response.StatusCode = (int)HttpStatusCode.NotFound; responseData = Encoding.UTF8.GetBytes("资源未找到"); } response.ContentLength64 = responseData.Length; using (var outputStream = response.OutputStream) { outputStream.Write(responseData, 0, responseData.Length); } } catch (Exception ex) { // 简单错误处理 response.StatusCode = (int)HttpStatusCode.InternalServerError; var errorData = Encoding.UTF8.GetBytes($"服务器错误: {ex.Message}"); response.ContentLength64 = errorData.Length; using (var outputStream = response.OutputStream) { outputStream.Write(errorData, 0, errorData.Length); } } } private void MainWindow_Closed(object sender, EventArgs e) { // 关闭窗口时停止服务器,释放资源 _localWebServer?.Stop(); _localWebServer?.Close(); } } }
3. 关键注意事项
- 端口选择:如果8080端口被占用,可以换成其他未被使用的端口(比如8081、9000等),确保ServerBaseUrl和HTML里的路径对应。
- 权限问题:
HttpListener绑定localhost时,普通用户权限即可运行;如果要绑定其他IP,可能需要管理员权限(不过localhost完全满足离线需求)。 - 跨域图片:因为现在Silverlight是从本地Web服务器加载的,和部署到外部服务器的权限上下文一致,只要目标图片服务器支持跨域(你之前部署到服务器能正常显示,说明已经满足),就能正常加载网络图片。
- XAP签名:这个方案里不需要再对XAP签名,因为Silverlight运行在Web上下文,而非本地文件上下文,权限限制自动解除。
这个方案完全满足离线使用需求,启动WPF时自动开启本地服务器,关闭窗口时自动停止,不会残留进程。
内容的提问来源于stack exchange,提问作者Sandeep
相关产品推荐
相关产品推荐

