دریافت و نصب Awesomium
پروژه Awesomium دارای یک SDK است که از اینجا قابل دریافت میباشد. بعد از نصب آن در مسیر Awesomium SDK\1.7.3.0\wrappers\Awesomium.NET\Assemblies\Packed میتوانید محصور کنندهی دات نتی آنرا مشاهده کنید. منظور از Packed در اینجا، استفاده از DLLهای فشرده شدهی native آن است که در مسیر Awesomium SDK\1.7.3.0\build\bin\packed کپی شدهاند. بنابراین برای توزیع این نوع برنامهها نیاز است اسمبلی دات نتی Awesomium.Core.dll به همراه دو فایل بومی icudt.dll و awesomium.dll ارائه شوند.
تهیه تصاویر سایتها به کمک Awesomium.NET
پس از نصب Awesomium اگر به مسیر Documents\Awesomium SDK Samples\1.7.3.0\Awesomium.NET\Samples\Core\CSharp\BasicSample مراجعه کنید، مثالی را در مورد تهیه تصاویر سایتها به کمک Awesomium.NET، مشاهده خواهید کرد. خلاصهی آن چند سطر ذیل است:
try { using (WebSession mywebsession = WebCore.CreateWebSession( new WebPreferences() { CustomCSS = "::-webkit-scrollbar { visibility: hidden; }" })) { using (var view = WebCore.CreateWebView(1240, 1000, mywebsession)) { view.Source = new Uri("https://site.com/"); bool finishedLoading = false; view.LoadingFrameComplete += (s, e) => { if (e.IsMainFrame) finishedLoading = true; }; while (!finishedLoading) { Thread.Sleep(100); WebCore.Update(); } using (var surface = (BitmapSurface)view.Surface) { surface.SaveToJPEG("result.jpg"); } } } } finally { WebCore.Shutdown(); }
مشکل! این روش در برنامههای ASP.NET کار نمیکند!
مثال همراه آن یک مثال کنسول ویندوزی است و به خوبی کار میکند؛ اما در برنامههای وب پس از چند روز سعی و خطا مشخص شد که:
الف) WebCore.Shutdown فقط باید در پایان کار یک برنامه فراخوانی شود. یعنی اصلا نیازی نیست تا در برنامههای وب فراخوانی شود.
System.InvalidOperationException: You are attempting to re-initialize the WebCore. The WebCore must only be initialized once per process and must be shut down only when the process exits.
System.AccessViolationException: Attempted to read or write protected memory. This is often an indication that other memory is corrupt. at Awesomium.Core.NativeMethods.WebCore_CreateWebView_1(HandleRef jarg1, Int32 jarg2, Int32 jarg3, HandleRef jarg4)
خطای فوق هم از آن نوع خطاهایی است که پروسهی IIS را درجا خاموش میکند.
استفاده از Awesomium در یک ترد پس زمینه
راه حلی که نهایتا پاسخ داد و به خوبی و پایدار کار میکند، شامل ایجاد یک ترد مجزای Awesomium در زمان آغاز برنامهی وب و زنده نگه داشتن آن تا زمان پایان کار برنامه است.
using System; using System.Collections.Concurrent; using System.IO; using System.Threading; using System.Web; using Awesomium.Core; namespace AwesomiumWebModule { public class AwesomiumModule : IHttpModule { private static readonly Thread WorkerThread = new Thread(awesomiumWorker); private static readonly ConcurrentQueue<AwesomiumRequest> TaskQueue = new ConcurrentQueue<AwesomiumRequest>(); private static bool _isRunning = true; static AwesomiumModule() { WorkerThread.Start(); } private static void awesomiumWorker() { while (_isRunning) { if (TaskQueue.Count != 0) { AwesomiumRequest outRequest; if (TaskQueue.TryDequeue(out outRequest)) { var img = AwesomiumThumbnail.FetchWebPageThumbnail(outRequest); File.WriteAllBytes(outRequest.SavePath, img); Thread.Sleep(500); } } Thread.Sleep(5); } } public void Dispose() { _isRunning = false; WebCore.Shutdown(); } public void Init(HttpApplication context) { context.EndRequest += endRequest; } static void endRequest(object sender, EventArgs e) { var url = HttpContext.Current.Items[Constants.AwesomiumRequest] as AwesomiumRequest; if (url!=null) { TaskQueue.Enqueue(url); } } } }
نمونهی استفاده از آن، در سمت یک برنامهی وب نیز به صورت زیر است. ابتدا ماژول تهیه شده باید در برنامه ثبت شود:
<?xml version="1.0"?> <configuration> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpModules> <add name="AwesomiumWebModule" type="AwesomiumWebModule.AwesomiumModule"/> </httpModules> </system.web> <system.webServer> <validation validateIntegratedModeConfiguration="false"/> <modules> <add name="AwesomiumWebModule" type="AwesomiumWebModule.AwesomiumModule"/> </modules> </system.webServer> </configuration>
protected void btnStart_Click(object sender, EventArgs e) { var host = new Uri(txtUrl.Text).Host; HttpContext.Current.Items.Add(Constants.AwesomiumRequest, new AwesomiumRequest { Url = txtUrl.Text, SavePath = Path.Combine(HttpRuntime.AppDomainAppPath, "App_Data\\Thumbnails\\" + host + ".jpg"), TempDir = Path.Combine(HttpRuntime.AppDomainAppPath, "App_Data\\Temp") }); lblInfo.Text = "Please wait. Your request will be served shortly."; }
Url، آدرس وب سایتی است که میخواهید تصویر آن تهیه شود. SavePath مسیر کامل فایل jpg نهایی است که قرار است دریافت و ذخیره گردد. TempDir محل ذخیره سازی فایلهای موقتی Awesomium است. Awesomium یک سری کوکی، تصاویر و فایلهای هر سایت را به این ترتیب کش کرده و در دفعات بعدی سریعتر عمل میکند.
پروژهی کامل آنرا از اینجا میتوانید دریافت کنید:
AwesomiumWebApplication_V1.0.zip