前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >CefSharp请求资源拦截及自定义处理

CefSharp请求资源拦截及自定义处理

作者头像
w4ngzhen
发布于 2023-10-18 10:44:10
发布于 2023-10-18 10:44:10
1.5K00
代码可运行
举报
文章被收录于专栏:编译思想编译思想
运行总次数:0
代码可运行

CefSharp请求资源拦截及自定义处理

前言

在CefSharp中,我们不仅可以使用Chromium浏览器内核,还可以通过Cef暴露出来的各种Handler来实现我们自己的资源请求处理。

什么是资源请求呢?简单来说,就是前端页面在加载的过程中,请求的各种文本(js、css以及html)。在以Chromium内核的浏览器上,我们可以使用浏览器为我们提供的开发者工具来检查每一次页面加载发生的请求。

准备

鉴于本文的重心是了解CefSharp的资源拦截处理,所以我们不讨论前端的开发以及客户端嵌入CefSharp组件的细节。我们首先完成一个基本的嵌入CefSharp的WinForm程序:该程序界面如下,拥有一个地址输入栏和一个显示网页的Panel:

并且编写一个极其简单的页面,该页面会请求1个js资源和1个css资源:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
demo:
    - index.html
    - test1.js
    - test1.css

这几个文件的代码都十分简单:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
body
{
    background-color: aqua
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function myFunc() {
    return 'test1 js file';
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8" />
    <title>Home</title>
    <!-- 如下记载js、css资源 -->
    <script type="text/javascript" src="test1.js"></script>
    <link type="text/css" rel="stylesheet" href="test1.css"/>
</head>
<body>
<h1>Resource Intercept Example</h1>
<h2 id="result"></h2>
<script>
    // 调用test1.js中的myFunc
    document.getElementById('result').innerHTML = myFunc();
</script>
</body>
</html>

代码很简单,效果也很容易知道,页面加载后,页面背景色为aqua,页面上会显示文本“test1 js file”。同时,当我们使用开发工具,刷新页面,能够看到对应的资源加载:

CefSharp资源拦截及自定义处理

完成上述准备后,我们进入正文:资源拦截及自定义处理。首先我们需要对目标的理解达成一致,资源拦截是指我们能够检测到上图中的html、js还有css的资源请求事件,在接下来的Example中,因为我们是使用的客户端程序,所以会在请求的过程中弹出提示;自定义处理是指,在完成拦截提示后,我们还能够替换这些资源,这里我们设定完成拦截后,可以把js和css换为我们想要另外的文件:test2.js和test2.css:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function myFunc() {
    return 'test2 js file';
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
body
{
    background-color: beige
}

即我们希望拦截并替换后,页面上的文字不再是之前的,而是“test2 js file”,页面的背景色是beige。

IRequestHandler

在CefSharp中,要想对请求进行拦截处理,最为核心的Handler就是IRequestHandler这个接口,查看官方的源码,会发现里面有数个方法的定义,通过阅读官方的summary,我们可以聚焦到如下的两个定义(注释本人进行了删减):

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// Called before browser navigation.
/// 译:在浏览器导航前调用
/// If the navigation is allowed <see cref="E:CefSharp.IWebBrowser.FrameLoadStart" /> and <see cref="E:CefSharp.IWebBrowser.FrameLoadEnd" />
/// will be called. If the navigation is canceled <see cref="E:CefSharp.IWebBrowser.LoadError" /> will be called with an ErrorCode
/// value of <see cref="F:CefSharp.CefErrorCode.Aborted" />.
/// </summary>
bool OnBeforeBrowse(
  IWebBrowser chromiumWebBrowser,
  IBrowser browser,
  IFrame frame,
  IRequest request,
  bool userGesture,
  bool isRedirect);

/// <summary>
/// Called on the CEF IO thread before a resource request is initiated.
/// 在一个资源请求初始化前在CEF IO线程上调用
/// </summary>
IResourceRequestHandler GetResourceRequestHandler(
  IWebBrowser chromiumWebBrowser,
  IBrowser browser,
  IFrame frame,
  IRequest request,
  bool isNavigation,
  bool isDownload,
  string requestInitiator,
  ref bool disableDefaultHandling);

于是,我们继承一个默认的名为RequestHandler的类(请区分DefaultRequestHandler),只重写上述的两个方法。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 public class MyRequestHandler : RequestHandler
{
    protected override bool OnBeforeBrowse(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request, bool userGesture,
        bool isRedirect)
    {
        // 先调用基类的实现,断点调试
        return base.OnBeforeBrowse(chromiumWebBrowser, browser, frame, request, userGesture, isRedirect);
    }

    protected override IResourceRequestHandler GetResourceRequestHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame,
        IRequest request, bool isNavigation, bool isDownload, string requestInitiator, ref bool disableDefaultHandling)
    {
        // 先调用基类的实现,断点调试
        return base.GetResourceRequestHandler(
            chromiumWebBrowser, browser, frame, request, isNavigation, 
            isDownload, requestInitiator, ref disableDefaultHandling);
    }
}   

然后完成对该Handler的注册:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 this._webBrowser = new ChromiumWebBrowser(string.Empty)
{
    RequestHandler = new MyRequestHandler()
}; 

打上断点,开始访问我们的Example:index.html。这里会发现,OnBeforeBrowse调用了一次,而GetResourceRequestHandler会调用3次。检查OnBeforeBrowse中的request参数内容,是一次主页的请求,而GetResourceRequestHandler中的3次分别是:主页html资源、test1.js和test1.css。

结合官方注释和调试的结果,我们可以得出结论:要进行导航的拦截,我们可以重写OnBeforeBrowse方法,要想进行资源的拦截,我们需要实现自己的ResourceRequestHandler。

IResourceRequestHandler

查看IResourceRequestHandler的定义,我们再次聚焦一个函数定义:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// Called on the CEF IO thread before a resource is loaded. To specify a handler for the resource return a <see cref="T:CefSharp.IResourceHandler" /> object
/// </summary>
/// <returns>To allow the resource to load using the default network loader return null otherwise return an instance of <see cref="T:CefSharp.IResourceHandler" /> with a valid stream</returns>
IResourceHandler GetResourceHandler(
  IWebBrowser chromiumWebBrowser,
  IBrowser browser,
  IFrame frame,
  IRequest request);

该定义从注释可以看出,如果实现返回null,那么Cef会使用默认的网络加载器来发起请求,或者我们可以返回一个自定义的资源处理器ResourceHandler来处理一个合法的数据流(Stream)。也就是说,对于资源的处理,要想实现自定义的处理(不是拦截,拦截到目前为止我们可以在上述的两个Handler中进行处理)我们还需要实现一个IResourceHandler接口的实例,并在GetResourceHandler处进行返回,Cef才会在进行处理的时候使用我们的Handler。所以在GetResourceHandler中,我们进行资源的判断,如果是想要替换的资源,我们就使用WinForm提供的OpenFileDialog来选择本地的js或是css文件,并传给我们自定义的ResourceHandler,如果不是想要拦截的资源或是用户未选择任何的文件就走默认的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public class MyResourceRequestHandler : ResourceRequestHandler
{
    protected override IResourceHandler GetResourceHandler(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, IRequest request)
    {
        if (request.Url.EndsWith("test1.js") || request.Url.EndsWith("test1.css"))
        {
            MessageBox.Show($@"资源拦截:{request.Url}");

            string type = request.Url.EndsWith(".js") ? "js" : "css"; // 这里简单判断js还是css,不过多编写
            string fileName = null;
            using (OpenFileDialog openFileDialog = new OpenFileDialog())
            {
                openFileDialog.Filter = $@"{type}文件|*.{type}"; // 过滤
                openFileDialog.Multiselect = true;
                if (openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    fileName = openFileDialog.FileName;
                }
            }

            if (string.IsNullOrWhiteSpace(fileName))
            {
                // 没有选择文件,还是走默认的Handler
                return base.GetResourceHandler(chromiumWebBrowser, browser, frame, request);
            }
            // 否则使用选择的资源返回
            return new MyResourceHandler(fileName);
        }

        return base.GetResourceHandler(chromiumWebBrowser, browser, frame, request);
    }
}

IResourceHandler

根据上文,我们进一步探究IResourceHandler,对该Handler,官方有一个默认的实现:RequestHandler,该Handler通过阅读源码可以知道是网络加载的Handler,这里为了实现我们自定义拦截策略,我们最好单独实现自己的IResourceHandler。对于该接口,有如下的注释:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// Class used to implement a custom resource handler. The methods of this class will always be called on the CEF IO thread.
/// Blocking the CEF IO thread will adversely affect browser performance. We suggest you execute your code in a Task (or similar).
/// To implement async handling, spawn a new Task (or similar), keep a reference to the callback. When you have a
/// fully populated stream, execute the callback. Once the callback Executes, GetResponseHeaders will be called where you
/// can modify the response including headers, or even redirect to a new Url. Set your responseLength and headers
/// Populate the dataOut stream in ReadResponse. For those looking for a sample implementation or upgrading from
/// a previous version <see cref="T:CefSharp.ResourceHandler" />. For those upgrading, inherit from ResourceHandler instead of IResourceHandler
/// add the override keywoard to existing methods e.g. ProcessRequestAsync.
/// </summary>
public interface IResourceHandler : IDisposable
{ ... }

该类的注释意思大致为:我们可以通过实现该接口来实现自定义资源的处理类。该类中的方法总是在CEF的IO线程中调用。然而,阻塞CEF IO线程将会不利于浏览器的性能。所以官方建议开发者通过把自己的处理代码放在Task(或是类似的异步编程框架)中异步执行,然后在完成或取消(失败)时,在异步中调用callback对应的操作函数(continue、cancel等方法)。当你拥有一个完全填充(fully populated)好了的Stream的时候,再执行callback(这一步对应Open方法)。一旦callback执行了,GetResponseHeaders这个方法将会调用,于是你可以在这个方法里面对Reponse的内容包括headers进行修改,或者甚至是重定向到一个新的Url。设置你自己的reponseLength和headers。接下来,通过在ReadResponse(实际上即将作废,而是Read)函数中,实现并填充dataOut这个Stream。最终CEF会对该Stream进行读取数据,获得资源数据。

事实上,该Handler的实现可以有很多花样,这里我们实现一个最简单的。

Dispose

对于通常进行资源释放的Dispose,因为我们这里只是一个Demo,所以暂时留空。

Open(ProcessRequest)

官方注释指出,ProcessRequest将会在不久的将来弃用,改为Open。所以ProcessRequest我们直接返回true。对于Open方法,其注释告诉我们:

  • 要想要立刻进行资源处理(同步),请设置handleRequest参数为true,并返回true
  • 决定稍后再进行资源的处理(异步),设置handleRequest为false,并调用callback对应的continue和cancel方法来让请求处理继续还是取消,并且当前Open返回false。
  • 要立刻取消资源的处理,设置handleRequest为true,并返回false。

也就是说,handleRequest的true或false决定是同步还是异步处理。若同步,则Cef会立刻通过Open的返回值true或false来决定后续继续进行还是取消。若为异步,则Cef会通过异步的方式来检查callback的调用情况(这里的callback实际上是要我们创建Task回调触发的)。这里我们选择同步的方式(选择异步也没有问题)编写如下的代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public bool Open(IRequest request, out bool handleRequest, ICallback callback)
{
    handleRequest = true;
    return true;
}
GetResponseHeaders

在上小节中我们已经完成了对资源数据的入口(Open)的分析。既然我们已经告诉了Cef我们准备开始进行资源请求的处理了,那么接下来我们显然需要着手进行资源的处理。根据前面的概要注释,我们需要实现GetResponseHeaders方法,因为这是资源处理的第二步。该方法的注释如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// Retrieve response header information. If the response length is not known
/// set <paramref name="responseLength" /> to -1 and ReadResponse() will be called until it
/// returns false. If the response length is known set <paramref name="responseLength" />
/// to a positive value and ReadResponse() will be called until it returns
/// false or the specified number of bytes have been read.
/// 
/// It is also possible to set <paramref name="response" /> to a redirect http status code
/// and pass the new URL via a Location header. Likewise with <paramref name="redirectUrl" /> it
/// is valid to set a relative or fully qualified URL as the Location header
/// value. If an error occured while setting up the request you can call
/// <see cref="P:CefSharp.IResponse.ErrorCode" /> on <paramref name="response" /> to indicate the error condition.
/// </summary>
void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl);

Summary翻译解释如下:获取响应头信息。如果响应的数据长度未知,则设置responseLength-1,然后CEF会一直调用ReadResponse(即将废除,实际上是Read方法)直到该Read方法返回false。如果响应数据的长度是已知的,可以直接设置responseLength长度为一个正数,然后ReadResponseRead)将会一直调用,直到该Read方法返回false或者在已经读取的数据的字节长度达到了设置的responseLength的值。当然你也可以通过设置response.StatusCode值为重定向的值(30x)以及redirectUrl为对应的重定向Url来实现资源重定向。

在本文中,我们采取简单的方式:直接返回资源的长度,然后交给下一步的Read方法来进行真正的资源处理。在该步骤中,我们编写获取本地文件字节数据来实现js和css文件的本地加载,并且将该数据保存在该ResourceHanlder实例私有变量中。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public void GetResponseHeaders(IResponse response, out long responseLength, out string redirectUrl)
{
    using (FileStream fileStream = new FileStream(this._localResourceFileName, FileMode.Open, FileAccess.Read))
    {
        using (BinaryReader binaryReader = new BinaryReader(fileStream))
        {
            long length = fileStream.Length;
            this._localResourceData = new byte[length];
            // 读取文件中的内容并保存到私有变量字节数组中
            binaryReader.Read(this._localResourceData, 0, this._localResourceData.Length);
        }
    }

    responseLength = this._localResourceData.LongLength;
    redirectUrl = null;
}
Read

该方法的定义和注释如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/// <summary>
/// Read response data. If data is available immediately copy up to
/// dataOut.Length bytes into dataOut, set bytesRead to the number of
/// bytes copied, and return true. To read the data at a later time keep a
/// pointer to dataOut, set bytesRead to 0, return true and execute
/// callback when the data is available (dataOut will remain valid until
/// the callback is executed). To indicate response completion set bytesRead
/// to 0 and return false. To indicate failure set bytesRead to &lt; 0 (e.g. -2
/// for ERR_FAILED) and return false. This method will be called in sequence
/// but not from a dedicated thread.
/// 
/// For backwards compatibility set bytesRead to -1 and return false and the ReadResponse method will be called.
/// </summary>
bool Read(Stream dataOut, out int bytesRead, IResourceReadCallback callback);

Summary的翻译大致为:读取响应数据。如果数据是可以立即获得的,那么可以直接将dataOut.Length长度的字节数据拷贝到dataOut这个流中,然后设置bytesRead的值为拷贝的数据字节长度值,最后再返回true。如果开发者希望继续持有dataOut的引用(注释是pointer指针,但是个人觉得这里写为指向该dataOut的引用更好)然后在稍后填充该数据流,那么可以设置bytesRead0,通过异步方式在数据准备好的时候执行callback的操作函数,然后立刻返回true。(dataOut这个流会一直保持不被释放直到callback被调用为止)。为了让CEF知道当前的响应数据已经填充完毕,需要设置bytesRead0然后返回false。要想让CEF知道响应失败,需要设置bytesRead为一个小于零的数(例如ERR_FAILED: -2),然后返回false。这个方法将会依次调用但不是在一个专有线程。

根据上述的注释,总结如下:

  • bytesRead > 0,return true:填充了数据,但Read还会被调用
  • bytesRead = 0,return false:数据填充完毕,当前为最后一次调用
  • bytesRead < 0,return false:出错,当前为最后一次调用
  • bytesRead = 0,return true:CEF不会释放dataOut流,在异步调用中准备好数据后调用callback

针对本例,我们增加一个该类的私有变量_dataReadCount用于标识已读的资源数据字节量并在构造函数中初始化为0。

每次在Read中进行读取的时候,首先检查剩余待读取字节数this._localResourceData.LongLength - this._dataReadCount,如果该值为零,则表明已经将所有的数据通过dataOut拷贝给了外围,此时设置bytesRead为0,直接返回false;若剩余值大于0,则需要继续进行拷贝操作,但需要注意的是dataOut并不是一个无限大的流,而是一个类似于缓存的流,它的Length值为2^16 = 65536,所以我们需要设置bytesRead来让外围知道我们实际在这个流中放了多少字节的数据。同时在使用Stream.WriteAPI的时候,需要设置正确的offset和count。

最终,Read的实现如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
public bool Read(Stream dataOut, out int bytesRead, IResourceReadCallback callback)
{
    int leftToRead = this._localResourceData.Length - this._dataReadCount;
    if (leftToRead == 0)
    {
        bytesRead = 0;
        return false;
    }

    int needRead = Math.Min((int)dataOut.Length, leftToRead); // 最大为dataOut.Lenght
    dataOut.Write(this._localResourceData, this._dataReadCount, needRead);
    this._dataReadCount += needRead;
    bytesRead = needRead;
    return true;
}
其他的几个方法

对于Cancel和Skip方法,在本例不会调用,所以这里使用默认实现,不进行讨论,感兴趣的伙伴可以自己去研究。

最终效果

通过上文的代码设计和编写,我们最终完成了一个简单的资源拦截及自定义处理的Example。首先我们在不进行资源拦截的情况下,加载我们的web页面:

可以看到界面中呈现“test1 js file”的字样以及背景色为海蓝色。接下来我们开启资源拦截,再次加载页面,在加载过程中会有对应资源的拦截时的弹窗以及我们需要选择我们自定义的资源文件:

完成处理后,得到如下的显示页面:

源码

本Example的源码已经开源在Github上,整个Demo较为简单,主要是对本文的验证

链接

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-08-232,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
CefSharp 中过滤图片 RequestHandler
具体内同参照 附录;将 OnBeforeResourceLoad方法替换成2中的内容,很简单;
全栈程序员站长
2022/11/04
9600
CefSharp之二–如何看懂demo中的例子,以及按照例子进行开发「建议收藏」
CefSharp是做什么用的?请看前一篇文章:怎么用c#编写浏览器或者执行javascript代码?
全栈程序员站长
2022/10/02
8880
CefSharp之二–如何看懂demo中的例子,以及按照例子进行开发「建议收藏」
CefSharp中文帮助文档「建议收藏」
CefSharp是围绕Chromium嵌入式框架( Chromium Embedded Framework,CEF)的.Net包装器。CEF是一个基于Google Chromium项目的开源项目。与Chromium项目本身(主要专注于Google Chrome应用程序开发)不同,CEF专注于促进第三方应用程序中的嵌入式浏览器用例。 CEF基于多进程Chromium Content API,因此,当前仅存在Chromium的部分功能。例如,对扩展的支持是有限的,仅实现了一部分Extension API。
全栈程序员站长
2022/11/04
14.2K0
CefSharp自定义缓存实现
上文介绍了《C# 使用 CefSharp 内嵌网页 - 并给出 C# 与 JS 的交互示例》,本文介绍 CefSharp 的缓存实现,先来说说添加缓存的好处:
沙漠尽头的狼
2023/04/26
1.5K0
使用CEfSharp之旅(6)拦截网络请求 截取get post response返回「建议收藏」
工作随笔,有需要的或者不懂的加我QQ群191065815 微信huo_cheng_yan
全栈程序员站长
2022/09/27
2K0
spring boot框架学习8-【干货】spring boot的web开发(4)-自定义拦截器处理权限
通过前面的学习,我们了解并快速完成了spring boot第一个应用。spring boot企业级框架,那么spring boot怎么读取静态资源?如js文件夹,css文件以及png/jpg图片呢?怎么自定义消息转换器呢?怎么自定义spring mvc的配置呢?这些我们在公司都需要用的。这些怎么解决呢?在接下来的小节详细讲解这些。好了,现在开启spring boot的web开发第四节
凯哥Java
2019/07/01
3660
WPF中使用CEFSharp加载网页及交互
几种方案都各有利弊,可以根据团队的情况选用,都是相对不错的,其他的方案比如Flutter,Java就不太推荐。
码客说
2021/11/01
5K0
WPF中使用CEFSharp加载网页及交互
winform与cefsharp混合开发_winform窗体
CefSharp简单来说就是一款.Net编写的浏览器包,方便你在Winform和WPF中内嵌的Chrome浏览器组件。
全栈程序员站长
2022/11/05
3K0
winform与cefsharp混合开发_winform窗体
CefSharp自定义滚动条样式
在WinForm/WPF中使用CefSharp混合开发时,通常需要自定义滚动条样式,以保证应用的整体风格统一。本文将给出一个简单的示例介绍如何自定义CefSharp中滚动条的样式。
czwy
2023/10/22
6090
CefSharp自定义滚动条样式
ManualResetEvent实现线程的暂停与恢复
前些天遇到一个需求,在没有第三方源码的情况下,刷新一个第三方UI,并且拦截到其ajax请求的返回结果。当结果为AVALIABLE的时候,停止刷新并语音提示,否则继续刷新。
Chester Chen
2022/08/18
8950
ManualResetEvent实现线程的暂停与恢复
IDEA Web渲染插件开发(二)— 自定义JsDialog
《IDEA Web渲染插件开发(一)》中,我们了解到了如何编写一款用于显示网页的插件,所需要的核心知识点就是IDEA插件开发和JCEF,在本文中,我们将继续插件的开发,为该插件的JS Dialog显示进行自定义处理。
w4ngzhen
2023/10/16
9480
IDEA Web渲染插件开发(二)— 自定义JsDialog
CefSharp中c#和JavaScript交互读取电脑信息
CEF是由Marshall Greenblatt于2008年创建的基于Google Chromium的BSD许可开源项目。与主要关注谷歌Chrome应用程序开发的Chromium项目本身不同,CEF专注于在第三方应用程序中促进嵌入式浏览器用例。CEF通过提供生产质量稳定的API,发布跟踪特定Chromium版本和二进制发行版的分支机构,使用户免受基础Chromium和Blink代码复杂性的影响。CEF中的大多数功能都具有默认实现,这些实现提供丰富的功能,同时几乎不需要用户进行集成工作。目前,全球已有超过1亿个CEF安装实例嵌入到来自各种公司和行业的产品中。CEF维基百科页面上提供了使用CEF的公司和产品的部分列表。CEF的一些用例包括:
心莱科技雪雁
2019/04/22
5.3K0
cefsharp教程_常见的数据分析方法有哪些
本节汇总一些关于cefsharp的使用方法,包括c#调用HTML页面中的js,也可以是HTML中的按钮调用c#的方法。汇总后,方便以后使用和查看。
全栈程序员站长
2022/09/29
1.9K0
cefsharp教程_常见的数据分析方法有哪些
【原创】006 | 搭上SpringBoot实战专车系列六:自定义拦截器
该趟专车是开往SpringBoot自定义拦截器的实战专车,拦截器通常用来实现请求鉴权,判断用户是否具有当前请求资源的权限,如果存在权限,则允许用户访问该资源,如果不存在权限,则不允许用户访问该资源的权限。
java进阶架构师
2021/02/22
5120
【原创】006 | 搭上SpringBoot实战专车系列六:自定义拦截器
在 ASP.NET Core 项目中使用 MediatR 实现中介者模式
   最近有在看 DDD 的相关资料以及微软的 eShopOnContainers 这个项目中基于 DDD 的架构设计,在 Ordering 这个示例服务中,可以看到各层之间的代码调用与我们之前传统的调用方式似乎差异很大,整个项目各个层之间的代码全部是通过注入 IMediator 进行调用的,F12 查看源码后可以看到该接口是属于 MediatR 这个组件的。既然要照葫芦画瓢,那我们就先来了解下如何在 ASP.NET Core 项目中使用 MediatR。
程序员宇说
2019/11/20
1K0
在 ASP.NET Core 项目中使用 MediatR 实现中介者模式
ASP.NET的session操作方法总结
该文章介绍了.NET中的HttpSessionStateBase类,它提供了存储会话状态的方法,并提供了从会话状态中检索数据的公共方法。此外,该类还提供了同步访问会话状态的方法,以确保线程安全。
彭泽0902
2018/01/04
2.8K0
将浏览器嵌入 .NET 应用程序中:DotNetBrowser 还是 CefSharp?
CefSharp 实际上是 Chromium Embedded Framework[3] (CEF) 的 .NET 包装器。包装通过 C++/CLI 完成。
沙漠尽头的狼
2023/08/31
6820
将浏览器嵌入 .NET 应用程序中:DotNetBrowser 还是 CefSharp?
将浏览器嵌入 .NET 应用程序中:DotNetBrowser 还是 CefSharp?
为 WPF 或 WinForms 应用程序选择浏览器组件,对于那些搜索基于Chrome的解决方案的人来说,DotNetBrowser[1]和CefSharp[2]是最明显的选择。
用户9127601
2023/08/30
7840
将浏览器嵌入 .NET 应用程序中:DotNetBrowser 还是 CefSharp?
cefsharp文档在哪_hdfs创建目录
参考:https://github.com/cefsharp/CefSharp/issues/601 https://gist.github.com/BlackBooth/19ce027c4f68c1eb4fc1144988ca6662
全栈程序员站长
2022/10/02
1.4K0
cefsharp文档在哪_hdfs创建目录
C#开发BIMFACE系列53 WinForm程序中使用CefSharp加载模型图纸1 简单应用
  在我的博客《C#开发BIMFACE系列52 CS客户端集成BIMFACE应用的技术方案》中介绍了多种集成BIMFACE到客户端程序中的方案。最后推荐大家使用 CefSharp组件与WebView2组件。本篇文章介绍使用CefSharp组件如何集成BIMFACE到客户端程序中。
张传宁IT讲堂
2021/10/21
2.6K0
推荐阅读
相关推荐
CefSharp 中过滤图片 RequestHandler
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验