目录

介绍

背景

解决方案的说明

A  C#类来控制Chrome浏览器

将Chrome与.Net Core控制台应用程序(静态Web应用程序)一起使用

将Chrome与AspNet Core MVC应用程序结合使用

Chrome类的Launch()方法

“普通” HTML演示应用程序

AspNet Core演示应用程序

发布AspNet Core演示应用程序

结论


  • 下载最新的存储库存档

一种使用C#和Chrome开发跨平台桌面GUI应用程序的方法,它是Electron和Electron.NET库的非常轻巧的替代方案。

源代码可以在github上找到

介绍

该项目使用现有的Chrome安装程序将AspNet Core应用程序或由静态文件(html,javascript和css)组成的纯HTML应用程序呈现为桌面应用程序。

不需要Chromium或NodeJS,也不需要Chromium嵌入式框架(CEF)或CefSharp。

背景

这个想法很古老:为什么不使用html,javascript和css构建可被浏览器执行从而跨平台的桌面应用程序?

这个问题有很多答案。其中一些如下:

  • Electron
  • Electron.NET
  • Chromely
  • Ooui
  • Apache Cordova (mobile)
  • Ionic (mobile)
  • SpiderEye
  • Steve Sanderson's WebWindow
  • WebView
  • WebView-cs
  • Google's Carlo
  • CarloSharp
  • Positron

解决方案的说明

此解决方案基于以下想法:在运行MS Windows或Linux或MacOS的计算机中,有很大一部分安装了Google的Chrome浏览器。同时,.Net Core和AspNet Core在所有这些OS上运行。

所需要的是一种首先创建Chrome浏览器实例,然后指示其导航到“主页” URL的方法。

已经有一个使用NodeJS的方式做以上说的内容:是 Mathias Bynens的优秀 Puppeteer的NodeJS库。Google提供了一个有关Puppeteer 的门户,其中包含许多有价值的信息和示例。

再有是Puppeteer的C#端口,Darío Kondratiuk的 Puppeteer-Sharp。

这是来自github的Puppeteer的描述。

Puppeteer是一个Node库,它提供了高级API来通过DevTools协议控制Chrome或Chromium 。Puppeteer 默认情况下headless运行,但可以配置为运行完整(non-headless)的Chrome或Chromium。

此解决方案不是基于Headless Chrome浏览器的。相反,它使用的是普通的Chrome窗口,其中只有一个标签页,根本没有地址栏。Puppeteer,当然还有Puppeteer-Sharp都可以通过这种方式运行Chrome浏览器。

A  C#类来控制Chrome浏览器

该项目包含一个名为Chrome的静态类,其中包含不到400行代码,该类用于启动Chrome并导航到第一个HTML页面。为此,Chrome 类提供Launch()方法

static public void Launch(ChromeStartOptions Options, Action Closed = null)

当浏览器关闭时,它接受一个Options对象和一个回调来调用。这是ChromeStartOptions类。

public class ChromeStartOptions
{public ChromeStartOptions(bool IsAspNetCoreApp = true){this.IsAspNetCoreApp = IsAspNetCoreApp;}public bool IsAspNetCoreApp { get; set; } = true;public string ChromePath { get; set; } = "";public string HomeUrl { get; set; } = @"Index.html";public string ContentFolder { get; set; } = "wwwroot";public int Left { get; set; } = 300;public int Top { get; set; } = 150;public int Width { get; set; } = 1024;public int Height { get; set; } = 768;
}

HomeUrl和ContentFolder特性用于静态HTML应用程序,而不是ASPNET Core应用程序。

将Chrome与.Net Core控制台应用程序(静态Web应用程序)一起使用

这是在.Net Core控制台应用程序中使用它的方法,以便将纯HTML应用程序呈现为桌面应用程序。

static void Main(string[] args)
{ManualResetEvent CloseEvent = new ManualResetEvent(false);            Chrome.Launch(new ChromeStartOptions(false), () => {CloseEvent.Set();});            CloseEvent.WaitOne();
}

将Chrome与AspNet Core MVC应用程序结合使用

这里是如何从AspNet Core Startup类的Configure()方法内部调用它的方法,以便将AspNet Core MVC应用程序呈现为桌面应用程序。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{// code here ....// call Chrome as the last thing in the Configure methodChrome.Launch(new ChromeStartOptions(true), () => {IHostApplicationLifetime LifeTime = app.ApplicationServices.GetService(typeof(IHostApplicationLifetime)) as IHostApplicationLifetime;LifeTime.StopApplication();});
}

Chrome类的Launch()方法

通过ChromeStartOptions实例传递给Launch()方法的标志指示应用程序的类型。True表示AspNet Core,而false表示纯静态HTML应用程序。

调用者可以通过ChromeStartOptions类的实例将更多信息传递给Launch()方法。ChromePath就是这样一点信息,表示可以找到Chrome的路径。

目前,该Crome类已尽力寻找在Windows和Linux上安装Chrome浏览器的位置。我计划研究Chrome启动器项目的代码,并尝试更好地解决此问题。

该Chrome.Launch()方法调用Chrome.LaunchAsync()执行以下操作的方法:

  • 处理传入的选项
  • 准备一个Puppeteer-Sharp的LaunchOptions实例。
  • 调用Puppeteer.LaunchAsync(options)方法并返回一个Browser实例。
  • 如果这是AspNet Core应用程序,则该选项实例已准备好并且已经包含初始Url。否则,此步骤将推迟。
  • 现在Chrome已启动并运行,并显示一个标签Page。
  • 该代码获得对此Page的引用。
  • 如果这不是 AspNet Core应用程序,请将事件处理程序链接到该Page以满足传如请求,因为没有web服务器。紧接着调用Page.GoToAsync(url)传递应用程序的“主页” URL。
  • 在下一步中,在两种情况下,都将另一个事件处理程序链接到Page,以处理浏览器的关闭。

这是Chrome.LaunchAsync()方法的完整代码。

static public async Task LaunchAsync(ChromeStartOptions Options, Action Closed = null)
{if (Browser == null){// prepare optionsIsAspNetCoreApp = Options.IsAspNetCoreApp;if (!string.IsNullOrWhiteSpace(Options.ContentFolder)){ContentFolder = Path.GetFullPath(Options.ContentFolder);} HomeUrl = !IsAspNetCoreApp ? $@"http://{SStaticApp}/{Options.HomeUrl}" : $"http://localhost:{Port}"; List<string> ArgList = new List<string>(DefaultArgs);string AppValue = !IsAspNetCoreApp ? "data:text/html, loading..." : Chrome.HomeUrl;ArgList.Add($"--app={AppValue}");   // The --app= argument opens Chrome in app mode that is no fullscreen, no url bar, just the windowArgList.Add($"--window-size={Options.Width},{Options.Height}");ArgList.Add($"--window-position={Options.Left},{Options.Top}");LaunchOptions LaunchOptions = new LaunchOptions{Devtools = false,Headless = false,Args = ArgList.ToArray(),ExecutablePath = !string.IsNullOrWhiteSpace(Options.ChromePath) ? Options.ChromePath : FindChromPath(),DefaultViewport = null};// launch ChromeBrowser = await Puppeteer.LaunchAsync(LaunchOptions);// get the main tab pagePage[] Pages = await Browser.PagesAsync().ConfigureAwait(false);TabPage = Pages[0];// event handler for static filesif (!IsAspNetCoreApp){await TabPage.SetRequestInterceptionAsync(true);TabPage.Request += StaticRequestHandler;await TabPage.GoToAsync(Chrome.HomeUrl, WaitUntilNavigation.DOMContentLoaded);}// event handler for closeTabPage.Close += (sender, ea) => {Closed?.Invoke();Closed = null;TabPage = null;if (!Browser.IsClosed)Browser.CloseAsync();Browser = null;};}
}

“普通” HTML演示应用程序

简单的情况。这是一个.Net Core 3.0控制台应用程序。

输出类型设置为Windows应用程序只是为了在运行时隐藏控制台框。

该应用程序碰巧包含一个名为wwwroot的文件夹,这是该ChromeStartOptions类的ContentFolder属性的默认值。

public string ContentFolder { get; set; } = "wwwroot";

该ContentFolder属性指示放置静态文件(html,js,css)的根目录文件夹。

wwwroot文件夹中包含index.html这又恰好是默认值文件ChromeStartOptions类中的HomeUrl属性的默认值。

public string HomeUrl { get; set; } = @"Index.html";

这是正在运行的应用程序。

AspNet Core演示应用程序

它是一个AspNet Core 3.0 MVC应用程序,没有比Visual Studio 2019预览版模板生成的代码更多的代码。

为了使该应用程序正常工作,需要做一些事情。

项目文件的第一个PropertyGroup应如下所示。

<PropertyGroup><TargetFramework>netcoreapp3.0</TargetFramework><AspNetCoreHostingModel>OutOfProcess</AspNetCoreHostingModel><ApplicationIcon /><OutputType>WinExe</OutputType><StartupObject />
</PropertyGroup>

上面的代码使应用程序处于“进程外”状态,并在运行时隐藏了控制台。

随后是在Properties文件夹中找到的lauchSettings.json文件。

{"profiles": {"PuppetMvc": {"commandName": "Project","environmentVariables": {"ASPNETCORE_ENVIRONMENT": "Development"},"applicationUrl": "http://localhost:5000"}}
}

这就是所有文件内容。只需一个配置文件,完全没有有关IIS Express的设置。该5000端口实际上未被应用程序使用。该Chrome类的发现和使用第一个自由端口。

Program类应该是如下这样。

public class Program
{public static void Main(string[] args){CreateHostBuilder(args).Build().Run();} public static IHostBuilder CreateHostBuilder(string[] args) =>Host.CreateDefaultBuilder(args).ConfigureWebHostDefaults(webBuilder =>{                    webBuilder.ConfigureKestrel(o =>{o.Listen(IPAddress.Loopback, Chrome.Port);  }).UseStartup<Startup>();});}

与模板代码的唯一区别在于,它配置了Kestrel以侦听所选端口。

这是正在运行的应用程序。

发布AspNet Core演示应用程序

这是发布设置。

在“修剪”所有未使用的程序集之后,以上内容在单个文件中创建了一个自包含部署。

这是发布文件夹的内容。* .exe大小为43 MB,包含所有内容,包括AspNet Core。只有静态文件位于wwwroot文件夹中。

最棒的是:双击* .exe在Chrome浏览器中运行该应用程序。

结论

多亏了Chrome和Puppeteer-Sharp,创建了使用Web技术构建的跨平台桌面应用程序的另一种可能性。这不需要Chromium或NodeJS或其他任何东西。它唯一需要知道的是Chrome的安装位置。

使用AspNet Core或纯静态HTML文件的跨平台桌面应用程序相关推荐

  1. Aspnet core迁移 wwwroot静态文件文件

    原项目中Content,JavaScript,css文件中的静态文件都统一配置到wwwroot中 实例: wwwroot是一个存放静态内容的文件夹,存放了诸如css,js,img等文件. 静态文件是A ...

  2. PHP 页面静态化/纯静态化/伪静态化

    转载:https://www.cnblogs.com/caoruiy/p/4698938.html 概念 PHP静态化分为:纯静态化 和 伪静态化:纯静态化又分为:局部静态化 和 完全静态化 纯静态化 ...

  3. 带有.NET Core 3和Electron.NET的多平台桌面HTML编辑器

    目录 介绍 先决条件 应用程序编码 1.创建ASP.NET MVC应用程序 2.将ElectronNET.API NuGet程序包添加到项目中 3.在应用程序中实例化ElectronNET.API 4 ...

  4. ASP.NET Core应用针对静态文件请求的处理[1]: 以Web的形式发布静态文件

    虽然ASP.NET Core是一款"动态"的Web服务端框架,但是在很多情况下都需要处理针对静态文件的请求,最为常见的就是这对JavaScript脚本文件.CSS样式文件和图片文件 ...

  5. ASP.NET Core 中的静态文件

    1.前言 当我们创建Core项目的时候,Web根目录下会有个wwwroot文件目录,wwwroot文件目录里面默认有HTML.CSS.IMG.JavaScript等文件,而这些文件都是Core提供给客 ...

  6. Asp.Net Core中的静态文件-12

    目录 本文出自<从零开始学 ASP.NET CORE MVC>目录  推荐文章:配置 ASP.NET Core 请求(Request)处理管道 Asp.Net Core 中的静态文件 在这 ...

  7. ASP.NET Core应用针对静态文件请求的处理[5]: DefaultFilesMiddleware中间件如何显示默认页面...

    DefaultFilesMiddleware中间件的目的在于将目标目录下的默认文件作为响应内容.我们知道,如果直接请求的就是这个默认文件,那么前面介绍的StaticFileMiddleware中间件会 ...

  8. AspNet Core 下利用普罗米修斯+Grafana构建Metrics和服务器性能的监控

    概述 Prometheus是一套开源的监控&报警&时间序列数据库的组合,起始是由SoundCloud公司开发的.该项目有非常活跃的社区和开发人员,目前是独立的开源项目,现在最常见的Ku ...

  9. 用VSCode开发一个asp.net core2.0+angular5项目(5): Angular5+asp.net core 2.0 web api文件上传...

    第一部分: http://www.cnblogs.com/cgzl/p/8478993.html 第二部分: http://www.cnblogs.com/cgzl/p/8481825.html 第三 ...

最新文章

  1. “治沙女杰”殷玉珍:和沙漠较量的女人
  2. visual studio 2017 创建 android 本地共享库(.so) 并从 C# android 项目中调用
  3. 边工作边刷题:70天一遍leetcode: day 94-1
  4. linux执行某个目录的程序
  5. java静态局部变量_java中成员变量,局部变量,静态变量的辨析
  6. 'ADB server didn't ACK'的解决办法
  7. mysql hint 简书_MySQL
  8. 读书笔记《集体智慧编程》Chapter 2 : Make Recommendations
  9. JavaScript隐式类型转换
  10. 斯坦福大学公开课机器学习:advice for applying machine learning | learning curves (改进学习算法:高偏差和高方差与学习曲线的关系)...
  11. 数据库系统概论第五版 课后习题答案王珊
  12. LCD驱动芯片HT16c21使用注意事项
  13. 怎么简单使用Xftp6
  14. 诺诺开放平台(电子发票、智能编码、发票查验接口调用)
  15. SAS-配对设计资料秩和检验
  16. 假设今天是2015年3月1号星期日,计算13个月零6天后是星期几?距离现在多少秒?
  17. 让博客Docker化,轻松上手Docker
  18. ブリアー / 三星枪
  19. PyPDF2读取PDF文件内容保存到本地TXT
  20. 谈谈数独(Sudoku)

热门文章

  1. iphone个系列尺寸_iPhone“立体边框”壁纸来了,拥有3D效果
  2. 海报psd素材模板|周年海报,仪式感值得珍藏
  3. 就知道你会没灵感,感恩节psd分层海报模板来咯!
  4. 高端轻奢国风美妆海报模板,东方美到极致
  5. python输入正整数n、求n以内能被17整除的最大正整数_求100之内自然数中最大的能被17整除的数资料...
  6. CUDA编程之:Stream(流)
  7. LMbench - Tools for Performance Analysis | 内核基准测试
  8. Linux内核进程管理:进程的“内核栈”、current宏、进程描述符
  9. DPDK笔记 RSS(receive side scaling)网卡分流机制
  10. RabbitMQ架构