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頁。

大致思路就是這樣,也不知道有沒有講清楚。 這里不提供具體實現代碼。
