CefSharp 是一个开源项目,它为 .NET 提供了嵌入式的 Chromium (CEF),如果你想用前端技术做界面,后端采用 C# 编写,那 CefSharp 是不错的选择。
本文将讲述:CefSharp 自定义属于自己的 Scheme,将前端资源目录下的所有文件全部嵌入 .NET APP 中(即嵌入到 .exe 文件中),并且做到 已嵌入资源 可通过 URL 直接访问
URL Scheme 是什么?
对于 URL 我们都很熟悉,例如 https://www.google.com 就是一个 URL,我们也叫它链接或网址。
可以简单理解:Schemes 表示的是 URL 中的一个位置,Schemes 是 :// 之前的那段字符。
举个栗子 https://www.google.com 这个 URL 的 Schemes 是 https
又例如 file:///C:/Users/qwqcode/Desktop,它的 Schemes 是 file
URL 和 URI 的关系:
URL是URI的一种,不仅标识了 Web 资源,还指定了操作或者获取方式,同时指出了主要访问机制和网络位置。
1. 嵌入前端资源目录下的所有文件
假如有一个解决方案,待嵌入的 前端目录 相对于 这个解决方案 的路径是 ..\Frontend\dist ,那么则在这个解决方案的 .csproj 文件中加入:
1
2
3
html_res\%(RecursiveDir)%(Filename)%(Extension)
之后,你会发现在该解决方案的文件树列表中,出现了 html_res 文件夹,里面会包含所有前端文件,且已成为嵌入的资源。
值得注意的是:解决方案中的目录名只能为小写字母,如 html_res,不能大写。
2. SchemeHandler
接下来,开始写 SchemeHandler 类
SchemeHandler 用于处理用户对指定 Scheme 的请求,并返回响应数据
ResourceSchemeHandler.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70using CefSharp;
using System;
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading.Tasks;
public class ResourceSchemeHandler : ResourceHandler
{
public override bool ProcessRequestAsync(IRequest request, ICallback callback)
{
var names = this.GetType().Assembly.GetManifestResourceNames();
Console.WriteLine(names);
Uri u = new Uri(request.Url);
String file = u.Authority + u.AbsolutePath; // 注:目录名需全为小写字母,否则将无法得到 Resource
Assembly ass = Assembly.GetExecutingAssembly();
String resourcePath = ass.GetName().Name + "." + file.Replace("/", "."); // 你可以设置断点看看这里的值
Task.Run(() =>
{
using (callback)
{
if (ass.GetManifestResourceInfo(resourcePath) != null)
{
Stream stream = ass.GetManifestResourceStream(resourcePath);
string mimeType = "application/octet-stream";
switch (Path.GetExtension(file))
{
case ".html":
mimeType = "text/html";
break;
case ".js":
mimeType = "text/javascript";
break;
case ".css":
mimeType = "text/css";
break;
case ".png":
mimeType = "image/png";
break;
case ".appcache":
break;
case ".manifest":
mimeType = "text/cache-manifest";
break;
}
// Reset the stream position to 0 so the stream can be copied into the underlying unmanaged buffer
stream.Position = 0;
// Populate the response values - No longer need to implement GetResponseHeaders (unless you need to perform a redirect)
ResponseLength = stream.Length;
MimeType = mimeType;
StatusCode = (int)HttpStatusCode.OK;
Stream = stream;
callback.Continue();
}
else
{
callback.Cancel();
}
}
});
return true;
}
}
3. SchemeHandlerFactory
最后一步,写 SchemeHandlerFactory
SchemeHandlerFactory 用于负责 实例化 相应的 SchemeHandler,并向外界提供 SchemeName。
ResourceSchemeHandlerFactory.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CefSharp;
class ResourceSchemeHandlerFactory : ISchemeHandlerFactory
{
public IResourceHandler Create(IBrowser browser, IFrame frame, string schemeName, IRequest request)
{
return new ResourceSchemeHandler();
}
public static string SchemeName {
get {
return "nacollector"; // 这里我设置的 SchemeName 为 nacollector,当然你也可以改成其他的
}
}
}
4. 注册 Scheme
需在调用 Cef.Initialize 前添加 settings.RegisterScheme 进行对 Scheme 的注册,如下:
1
2
3
4
5
6
7
8
9
10
11var settings = new CefSettings();
// ...
settings.RegisterScheme(new CefCustomScheme()
{
SchemeName = ResourceSchemeHandlerFactory.SchemeName,
SchemeHandlerFactory = new ResourceSchemeHandlerFactory()
});
// ...
Cef.Initialize(settings, performDependencyCheck: true, browserProcessHandler: null);
5. 完成
到这一步,你就可以访问 nacollector://html_res/index.html 了
1var browser = new ChromiumWebBrowser("nacollector://html_res/index.html");