PuppeteerSharp 在asp.net中使用 PuppeteerSharp生命周期管理

2020-12-22 更新,以下代码有坑不要使用,回过头来看,发现以前写的东西好烂呀,哈哈哈哈。。。

博客就放这里给自己留个纪念。

---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

1.PuppeteerSharp在asp.net中使用的坑:

  1.如果使用nuget下载PuppeteerSharp 则还需要添加PuppeteerSharp.AspNetFramework包依赖。

  2.需要下载chromium 浏览器文件 参考https://www.cnblogs.com/cdyy/p/PuppeteerSharp.html 这篇博客。

  3.手动添加依赖包,参考如下:

      a.通过nuget 添加以下包

 

 

 

  左图是包版本,右图是需要下载的包。

2.将PuppeteerSharp 生命周期交给autofac管理

  前提:一个asp.net 应用程序只需要启动一个chromium 进程,当寄宿在IIS中的asp.net应用程序 停止或被回收 时,chromium 进程也需要被关闭掉。

     通过启动的chromium浏览器开启“Page”页,每一次的请求打开的page页(一个或多个),将在请求结束后自动销毁掉。

 

  这里提供下思路,参考代码如下: 

  1).创建 IChromiumBrowser,这里封装了下PuppeteerSharp 的 Browser 对象。

    public interface IChromiumBrowser : IDisposable,IAsyncDisposable
    {  
        Task<Browser> GetBrowserAsync();
    }

       实现

public class ChromiumBrowserAspNet : IChromiumBrowser
    {
        private readonly LaunchOptions _launchOptions;

        public ChromiumBrowserAspNet()
        {
            _launchOptions = new LaunchOptions();
            DetectBrowserFile();
        }

        private Browser _browser;
        private bool _existsBrowserFile;
        private static readonly object Lock = new object();

        public async Task<Browser> GetBrowserAsync()
        {
            if (_browser != null) return _browser;

            await Task.Run(() =>
            {
                lock (Lock)
                {
                    if (_browser == null)
                    {
                        //请提前下载好浏览器相关文件
                        //await new BrowserFetcher().DownloadAsync(BrowserFetcher.DefaultRevision);
                        _browser = Puppeteer.LaunchAsync(_launchOptions).Result;
                        //如果浏览器进程被其他操作强制关闭,释放_browser。
                        _browser.Disconnected += (a, b) =>
                        {
                            if (_browser == null) return;
                            Dispose(true);
                        };
                    }
                }
            });
            return _browser;
        }

        private void DetectBrowserFile()
        {
            if (_existsBrowserFile) return;
            string platForm = null;
            if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                platForm = Platform.MacOS.ToString();
            }

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                platForm = Platform.Linux.ToString();
            }

            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                platForm = RuntimeInformation.OSArchitecture == Architecture.X64 ? Platform.Win64.ToString() : Platform.Win32.ToString();
            }

            string folder = Path.Combine(Directory.GetCurrentDirectory(), ".local-chromium");
            string filePath = Path.Combine(folder, $"{platForm}-{BrowserFetcher.DefaultRevision}");
            _existsBrowserFile = new DirectoryInfo(filePath).Exists;
            if (!_existsBrowserFile)
            {
                throw new Exception($"{filePath}");
            }
        }

        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _browser?.Dispose();
            }
            _browser = null;
        }

        public void Dispose()
        {
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }

        public async ValueTask DisposeAsync()
        {
            await DisposeAsyncCore();

            Dispose(disposing: false);
            GC.SuppressFinalize(this);
        }

        protected virtual async ValueTask DisposeAsyncCore()
        {
            if (_browser != null)
            {
                await _browser.DisposeAsync();
            }

            _browser = null;
        }

    }

   2).通过browser创建page 页 。名字你自己取,我的叫IPuppeteerSharpContext

    public interface IPuppeteerSharpContext : IDisposable, IAsyncDisposable
    {

        List<IPuppeteerSharpPage> PuppeteerSharpPages { get; }
        Task<List<IPuppeteerSharpPage>> GetPagesAsync(List<PageSetting> pageSettings);
      Task<IPuppeteerSharpPage> GetPageAsync(PageSetting pageSetting);
    }

    实现

    public class PuppeteerSharpContextAspNet : IPuppeteerSharpContext
    {
        private readonly IChromiumBrowser _chromiumBrowser;

        public PuppeteerSharpContextAspNet(IChromiumBrowser chromiumBrowser)
        {
            _chromiumBrowser = chromiumBrowser;
            _puppeteerSharpPages = new List<IPuppeteerSharpPage>();
        }

        private Browser _browser;

        private async Task StarUpPageAsync()
        {
            if (_browser == null)
            {
                _browser = await _chromiumBrowser.GetBrowserAsync();
            }
        }

        private List<IPuppeteerSharpPage> _puppeteerSharpPages;

        public List<IPuppeteerSharpPage> PuppeteerSharpPages => _puppeteerSharpPages;

        public async Task<List<IPuppeteerSharpPage>> GetPagesAsync(List<PageSetting> pageSettings)
        {
            if (pageSettings == null) throw new Exception("pageSettings is null");

            await StarUpPageAsync();

            var list = new List<IPuppeteerSharpPage>();
            pageSettings.ForEach(item =>
            {
                var page = new PuppeteerSharpPage(item, _browser);
                list.Add(page);
                _puppeteerSharpPages.Add(page);
            });
            return list;
        }


        public async Task<IPuppeteerSharpPage> GetPageAsync(PageSetting pageSetting)
        {
            if (pageSetting == null) throw new Exception("pageSetting is null");

            await StarUpPageAsync();

            var page = new PuppeteerSharpPage(pageSetting, _browser);
            _puppeteerSharpPages.Add(page);
            return page;
        }


        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                _puppeteerSharpPages?.ForEach(item => item.Dispose());
            }
            _puppeteerSharpPages = null;
        }

        public void Dispose()
        {
            Dispose(disposing: true);
            GC.SuppressFinalize(this);
        }

        public async ValueTask DisposeAsync()
        {
            await DisposeAsyncCore();
            Dispose(disposing: false);
            GC.SuppressFinalize(this);
        }

        protected virtual async ValueTask DisposeAsyncCore()
        {
            if (_puppeteerSharpPages != null)
            {
                foreach (var item in _puppeteerSharpPages)
                {
                    await item.DisposeAsync();
                }
            }
            _puppeteerSharpPages = null;
        }
    }

    IPuppeteerSharpPage和PuppeteerSharpPage 根据你自己情况去实现。

  3).将ChromiumBrowser 、“Page”交给autofac管理,参考 https://www.cnblogs.com/bluesummer/p/9041802.html  “IRegisteredObject”

    /// <summary>
    /// Asp.Net IIS宿主环境配置 <see cref="WebAppEnviroment" />.
    /// </summary>
    public class WebAppEnviroment : IRegisteredObject
    {
        public WebAppEnviroment()
        {
            HostingEnvironment.RegisterObject(this);
        }

        private static IChromiumBrowser _chromiumBrowser;

        public void RegisterBrowserModule(ContainerBuilder builder)
        {
            builder.Register(context =>
            {
                IChromiumBrowser browser = new ChromiumBrowserAspNet();
                _chromiumBrowser = browser;
                return browser;
            }).As<IChromiumBrowser>().SingleInstance();
            builder.RegisterType<PuppeteerSharpContextAspNet>().As<IPuppeteerSharpContext>().InstancePerRequest();
        }

        public void Stop(bool immediate)
        {
            if (_chromiumBrowser != null)
            {
                _chromiumBrowser.Dispose();
                _chromiumBrowser = null;
            }
            HostingEnvironment.UnregisterObject(this);
        }
    }

    public static class ContainerBuilderExtsionTes
    {
        public static void RegisterBrowserModule(this ContainerBuilder builder)
        {
            var app = new WebAppEnviroment();
            app.RegisterBrowserModule(builder);
        }
    }

  这里是将ChromiumBrowser创建成了单例,因为只需要存在一个(只需要存在一个browser 浏览器),IPuppeteerSharpContext 则是每次请求一个只创建一个实例,然后通过 IPuppeteerSharpContext去创建page页和释放page页。

  大致思路就是这样,也不知道有没有讲清楚。 这里不提供具体实现代码。

posted @ 2020-11-22 22:44  youliCC  阅读(944)  评论(0编辑  收藏  举报