如何使用Selenium C#自动化WPF应用内嵌的CefSharp浏览器
WPF内嵌CefSharp登录后加载主应用实现方案
核心逻辑很直接:应用启动先加载内嵌浏览器展示登录页,持续检测登录状态,检测到合法登录态后销毁/隐藏浏览器控件,加载WPF主业务内容,同时留存登录凭证给后续业务逻辑调用。
前置准备
先给项目安装NuGet包CefSharp.Wpf,注意安装完成后要把项目目标平台从默认的Any CPU改成固定的x86或x64(和你引用的CefSharp版本架构一致),否则启动会直接抛加载异常。
代码实现
1. 全局Cef配置(App.xaml.cs)
Cef全局初始化只需要执行一次,放在应用启动生命周期里,退出时记得释放资源避免内存泄漏:
using CefSharp; using System.IO; using System.Windows; namespace CefSharpLoginDemo { public partial class App : Application { protected override void OnStartup(StartupEventArgs e) { base.OnStartup(e); var cefSettings = new CefSettings { // 指定缓存目录,保存登录Cookie,下次启动不用重复登录 CachePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "CefAppCache") }; Cef.Initialize(cefSettings); } protected override void OnExit(ExitEventArgs e) { base.OnExit(e); Cef.Shutdown(); } } }
2. 界面布局(MainWindow.xaml)
用两层容器叠放,启动默认显示浏览器层、隐藏主业务层,登录成功后切换显示状态:
<Window x:Class="CefSharpLoginDemo.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:cef="clr-namespace:CefSharp.Wpf;assembly=CefSharp.Wpf" Title="业务系统" Height="800" Width="1200"> <Grid> <!-- 登录页浏览器控件 --> <cef:ChromiumWebBrowser x:Name="LoginBrowser" Address="https://你的业务系统登录页地址" FrameLoadEnd="LoginBrowser_FrameLoadEnd"/> <!-- WPF主业务容器,启动时默认隐藏 --> <Grid x:Name="MainAppContainer" Visibility="Collapsed"> <!-- 这里替换成你原有WPF应用的所有业务控件、页面 --> <TextBlock Text="登录成功,进入系统" FontSize="24" HorizontalAlignment="Center" VerticalAlignment="Center"/> </Grid> </Grid> </Window>
3. 登录检测与界面切换逻辑(MainWindow.xaml.cs)
监听浏览器页面加载完成事件,每次主页面加载完就校验登录态,校验通过就切换到主应用:
using CefSharp; using System.Linq; using System.Windows; namespace CefSharpLoginDemo { public partial class MainWindow : Window { // 替换成你业务系统实际的登录凭证Cookie名,比如SESSION、token、auth_id等 private const string LoginCookieKey = "SESSION"; public MainWindow() { InitializeComponent(); } private async void LoginBrowser_FrameLoadEnd(object sender, FrameLoadEndEventArgs e) { // 忽略iframe内的加载事件,只处理主页面 if (!e.Frame.IsMain) return; bool loginSuccess = false; // 登录态校验选其中一种方式即可 // 方式1:读Cookie判断(适合服务端Session、HttpOnly Cookie的场景) var cookieMgr = Cef.GetGlobalCookieManager(); var cookieList = await cookieMgr.VisitCookiesAsync("https://你的业务系统域名", true); loginSuccess = cookieList.Any(c => c.Name == LoginCookieKey && !string.IsNullOrWhiteSpace(c.Value)); // 方式2:执行JS读前端存储(适合登录态存在localStorage/sessionStorage的场景) // var jsRes = await LoginBrowser.EvaluateScriptAsync("window.localStorage.getItem('accessToken')"); // loginSuccess = jsRes.Success && !string.IsNullOrWhiteSpace(jsRes.Result?.ToString()); if (loginSuccess) { // 跨线程更新UI必须走Dispatcher Dispatcher.Invoke(() => { // 后续不需要用浏览器就直接Dispose释放资源,还要用就设置Visibility=Collapsed LoginBrowser.Dispose(); MainAppContainer.Visibility = Visibility.Visible; }); // 这里可以把拿到的Cookie/Token存到全局配置类,后续WPF发接口请求直接用 } } } }
常用扩展
- 需要自动填充账号密码的话,在登录页加载完成后执行JS注入即可:
// 放在FrameLoadEnd事件里,判断是登录页地址的时候执行 await LoginBrowser.EvaluateScriptAsync(@" document.querySelector('#账号输入框选择器').value = '你的账号'; document.querySelector('#密码输入框选择器').value = '你的密码'; document.querySelector('#登录按钮选择器').click(); "); - 如果需要拦截登录接口的返回值获取Token,可以实现
IRequestHandler或者IResourceRequestHandler监听指定接口的响应内容,比读Cookie/执行JS更稳定。
新手注意点
- 第一次运行如果报错找不到Cef相关dll,先检查项目平台目标是不是改成了x86/x64,不要用Any CPU。
- Cef的初始化和Shutdown必须成对出现,不要重复初始化。
- 所有涉及CefSharp的异步调用、JS执行,不要直接在非UI线程更新WPF控件,必须用
Dispatcher封送回UI线程。
内容的提问来源于stack exchange,提问作者Vino
相关产品推荐
相关产品推荐

