wait Task.WhenAll 自动关闭程序

TCP*_*W01 0 c# async-await cefsharp

我有一个方法可以进行 Chromium 浏览器初始化。运行两个异步方法后,程序自动关闭。难道是我用Task.WhenAll错了?

这是程序的入口点:

开始.cs

static class Start
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Initializer.Start();
        }
    }
Run Code Online (Sandbox Code Playgroud)

初始化程序.cs

public static class Initializer
    {
        public static async void Start()
        {
            // The task that automatically close the program.
            Task<bool> chromiumInitTask = ChromiumInfo.InitializeAsync();
            await chromiumInitTask;

            Task webviewInitTask = WebViewInfo.InitializeAsync();

            Task guiInitTask = GUIInfo.InitializeAsync();

            HardwareManager.Initialize();

            await webviewInitTask;

            await guiInitTask;

            GUIInfo.Layout.ChangeMainDisplay(ChromiumInfo.Browser);
            Application.Run(GUIInfo.Layout.GetLayoutForm());
        }
    }
Run Code Online (Sandbox Code Playgroud)

ChromiumInfo.cs

public static class ChromiumInfo
    {
        private static CefSettings _settings;
        private static ChromiumWebBrowser _browser;
        private static BrowserSettings _browserSettings;
        private static Dictionary<string, bool> _initTasks = new Dictionary<string, bool>()
        {
            { "Settings", false },
            { "Browser Settings", false },
            { "Browser", false },
            { "Cef", false }
        };
        private static KeyboardHandler _keyboardHandler;

        /// <summary>
        /// An setting which using on initialize.
        /// </summary>
        public static CefSettings Setting => _settings;

        /// <summary>
        /// Representing a browser which can be show in UI.
        /// </summary>
        public static ChromiumWebBrowser Browser => _browser;

        /// <summary>
        /// A keyboard handler which handle various keyboard events.
        /// </summary>
        public static KeyboardHandler KeyboardHandler => _keyboardHandler;

        /// <summary>
        /// Occur when request to change the browser.
        /// </summary>
        public static event RequestChangeBrowserEventHandler RequestChangeBrowser;

        /// <summary>
        /// Initialize all Chromium components in asynchronously.
        /// </summary>
        /// <param name="initAllScripts">Indicate should initialize all scripts contain in the root script directory.</param>
        /// <returns>Return a task can be awaited. True means sucess. Otherwise, return false.</returns>
        public static async Task<bool> InitializeAsync(bool initAllScripts = true)
        {
            Task settingInit = SettingsInitializeAsync();
            Task browserSettingInit = BrowserSettingsInitializeAsync();
            // The below line that automatically close the program.
            await Task.WhenAll(settingInit, browserSettingInit);
            
            Task cefInit = Cef.InitializeAsync(_settings);
            await cefInit;
            _initTasks["Cef"] = true;

            Task browserInit = BrowserInitializeAsync();
            await browserInit;

            Task eventInit = EventInitializeAsync();
            await eventInit;

            Task scriptInit = ScriptInitializeAsync();
            await scriptInit;

            return _initTasks.Values.Where(it => it).Count() == _initTasks.Count;
        }

        private static async Task SettingsInitializeAsync()
        {
            try
            {
                _settings = new CefSettings();

                _settings.CommandLineArgsDisabled = false;
                _settings.CefCommandLineArgs.Clear();
                _settings.CefCommandLineArgs.Add("enable-3d-apis", "1");
                _settings.CefCommandLineArgs.Add("enable-webgl-draft-extensions", "1");
                _settings.CefCommandLineArgs.Add("enable-gpu", "1");
                _settings.CefCommandLineArgs.Add("enable-webgl", "1");
                _settings.CefCommandLineArgs.Add("gpu_compositing", "1");
                _settings.CefCommandLineArgs.Add("ignore-gpu-blocklist", "1");

                await Task.Delay(1000).ConfigureAwait(false);
                _initTasks["Settings"] = true;
            }
            catch (Exception e)
            {
                SystemLog.Write(e);
            }
        }

        private static async Task BrowserSettingsInitializeAsync()
        {
            try
            {
                _browserSettings = new BrowserSettings();
                _browserSettings.WebGl = CefState.Enabled;
                await Task.Delay(1000).ConfigureAwait(false);

                _initTasks["Browser Settings"] = true;
            }
            catch (Exception e)
            {
                SystemLog.Write(e);
            }
        }

        private static async Task BrowserInitializeAsync()
        {
            try
            {
                _browser = new ChromiumWebBrowser(Properties.Settings.Default.DefaultURL);
                _browser.BrowserSettings = _browserSettings;
                _browser.Dock = System.Windows.Forms.DockStyle.Fill;
                await Task.Delay(1000).ConfigureAwait(false);

                _initTasks["Browser"] = true;
            }
            catch (Exception e)
            {
                SystemLog.Write(e);
            }
        }

        private static async Task EventInitializeAsync()
        {
            KeyboardHandler keyboardHandler = new KeyboardHandler();
            WebCommandHandler commandHandler = new WebCommandHandler();
            _browser.ConsoleMessage += keyboardHandler.Handle;
            _browser.ConsoleMessage += commandHandler.Handle;
            _browser.AddressChanged += Custom_AddressChanged;
            _keyboardHandler = keyboardHandler;
            await Task.Delay(1000).ConfigureAwait(false);
        }

        private static async Task ScriptInitializeAsync()
        {
            string scriptPath = $@"{ProgramInfo.RootPath}\scripts";
            if (Directory.Exists(scriptPath))
            {
                var files = Directory.GetFiles(scriptPath, "*.js");
                files?.ToList().ForEach(f => _browser.GetMainFrame().ExecuteJavaScriptAsync(f, _browser.Address));
            }

            await Task.Delay(1000).ConfigureAwait(false);
        }

        private static void Custom_AddressChanged(object sender, AddressChangedEventArgs e)
        {
            var wv2SiteCount = Properties.Settings.Default.WebToWV2.Cast<string>()
                .Where(s => s.IndexOf(e.Address) >= 0).Count();

            if (wv2SiteCount > 0)
            {
                WebViewInfo.Navigate(e.Address);
                RequestChangeBrowser?.Invoke(null, new RequestChangeBrowserEventArgs(WebViewInfo.Browser));
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

Gab*_*uci 5

这是因为await工作原理。await当作用于不完整的 a时Task,它返回。所以你的程序是这样工作的:

  1. Main运行并调用Initializer.Start()
  2. Initializer.Start()运行和调用ChromiumInfo.InitializeAsync()
  3. ChromiumInfo.InitializeAsync()运行直到调用await Task.WhenAll(settingInit, browserSettingInit)
  4. 因为Task.WhenAll返回一个不完整的TaskChromiumInfo.InitializeAsync()返回它自己的不完整Task并且执行返回到Initializer.Start()
  5. in看到不完整并返回await它自己的不完整并且执行返回到。Initializer.Start()TaskTaskMain()
  6. 因为Main()不作用于Task返回的Initializer.Start(),所以执行继续到下一行,即程序的结尾。

解决方案非常简单:将Main方法更改为async并使用await.

public static async Task Main()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    await Initializer.Start();
}
Run Code Online (Sandbox Code Playgroud)

make 的能力Main() asyncC# 7.1 中引入的一项功能