PuppeteerSharp in IIS - puppeteer-sharp

I am facing a bit of an annoying situation. We try to use PuppeteerSharp in our application to generate background PDF, and while it works well in dev mode, it doesn't work when in production.
The app is a WebAPI 2.0 site, .NET4.7.1, Windows 10 machine. The main differences I would see beween the two environments are:
build in Release instead of Debug: calling my code from a console app either in Debug or Release mode seems to work in the same way
Hosting in IIS Express in development and full IIS in Production
We use the following code:
var launchOptions = new LaunchOptions
{
DefaultViewport = new ViewPortOptions
{
Width = 1920,
Height = 1080,
IsLandscape = printOptions.Orientation == PrintOrientation.Landscape
},
ExecutablePath = this._chromiumPath,
Timeout = Timeout,
TransportFactory = AspNetWebSocketTransport.AspNetTransportFactory
};
var browser = await Puppeteer.LaunchAsync(launchOptions)
.ConfigureAwait(false);
var page = await browser.NewPageAsync()
.ConfigureAwait(false);
await page.EmulateMediaTypeAsync(PuppeteerSharp.Media.MediaType.Print)
.ConfigureAwait(false);
await page.GoToAsync(url, Timeout, new[] { WaitUntilNavigation.Networkidle0 })
.ConfigureAwait(false);
await page.WaitForTimeoutAsync(2000)
.ConfigureAwait(false);
var options = new PdfOptions
{
Width = printOptions.Format == PrintFormat.A4 ? "210mm" : "297mm",
Height = printOptions.Format == PrintFormat.A4 ? "297mm" : "420mm",
PrintBackground = true,
Landscape = printOptions.Orientation == PrintOrientation.Landscape,
MarginOptions = new PuppeteerSharp.Media.MarginOptions
{
Top = ".4in",
Bottom = ".4in",
Left = ".4in",
Right = ".4in"
}
};
await page.PdfAsync(outputFile, options)
.ConfigureAwait(false);
return result;
page.GoToAsync never returns, and eventually times out.
Edit:
I set ConfigureAwait to false in all async calls
I tried using the AspNetWebSocketTransport.AspNetTransportFactory transport factory, which doesn't seem to work either

using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions()
{
Headless = true,
ExecutablePath = browserFetcher.GetExecutablePath(BrowserFetcher.DefaultRevision)
})
Helped me fix the issue, AspNetWebSocketTransport presents references issues and does not seem useful anymore

If you are deploying your .NET Framework app on IIS. You need to also use PuppeteerSharp.AspNetFramwork and set the TransportFactory to the browser:
using (var browser = await Puppeteer.LaunchAsync(new LaunchOptions()
{
Headless = true,
TransportFactory = AspNetWebSocketTransport.AspNetTransportFactory,
ExecutablePath = browserFetcher.GetExecutablePath(BrowserFetcher.DefaultRevision)
}).ConfigureAwait(false))
Update: the Nuget package is outdated (hard reference to PuppeteerSharp 1.0.0.0), but the source can be found here: https://github.com/hardkoded/puppeteer-sharp/blob/076897d0cf627c947c61a1192fcb20d968d05cbc/lib/PuppeteerSharp.AspNetFramework/AspNetWebSocketTransport.cs

Related

UWP FileOpenPicker locks\freezes app in debug

If the debugger is attached, calling this function causes the app to hang. If I run without a debugger, there is no hang, and file pickers work perfectly.
private async void OnClick(object sender, RoutedEventArgs e)
{
FileOpenPicker openPicker = new FileOpenPicker();
}
I'm certain this is something super simple, but I just don't know.
Edit:
Here's how I'm using it. Keep in mind, that the simpler function creates the hang issue without all my extra code after it. I've stuffed up the image saving, but that's a separate issue I want to debug when I solve what this post is about.
.
public async Task ImportHeader()
{
FileOpenPicker openPicker = new FileOpenPicker();
openPicker.ViewMode = PickerViewMode.Thumbnail;
openPicker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
openPicker.FileTypeFilter.Add(".jpg");
openPicker.FileTypeFilter.Add(".png");
// For multiple image selection
var files = await openPicker.PickMultipleFilesAsync();
foreach (StorageFile singleImage in files)
{
IRandomAccessStream stream = await singleImage.OpenAsync(Windows.Storage.FileAccessMode.Read);
var image = new BitmapImage();
image.SetSource(stream);
HeaderImage.Source = image;
//We also save this to disk for later
Windows.Storage.StorageFolder storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
Windows.Storage.StorageFile file = await storageFolder.CreateFileAsync("header.jpg", Windows.Storage.CreationCollisionOption.ReplaceExisting);
stream.Seek(0);
using (StreamWriter bw = new StreamWriter(file.OpenStreamForWriteAsync().Result))
{
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(HeaderImage, (int)HeaderImage.Width, (int)HeaderImage.Height);
var pixels = await renderTargetBitmap.GetPixelsAsync();
byte[] bytes = pixels.ToArray();
bw.Write(stream);
}
}
}
This has happened to me as well on some of the recent Windows 10 Insider Preview builds, while the process works flawlessly on stable builds of Windows 10. I think you can assume the cause is there instead of your code.

Player Notifications with Xamarin MediaManager plugin

I'm using the media manager nuget plugin and it's great, but for the life of me, I can't get the lock screen or car bluetooth to show the notifications. I'm using the following to display the notifications (set within OnAppearing)
ViewModel.PropertyChanged += (sender, e) =>
{
switch (e.PropertyName)
{
case "RadioSchedule":
if (listData != null)
{
listData.ItemsSource = null;
var first = ViewModel.RadioSchedule[0];
Device.BeginInvokeOnMainThread(() =>
{
listData.ItemsSource = ViewModel.RadioSchedule;
MediaFile.Metadata.Artist = MediaFile.Metadata.DisplaySubtitle = MediaFile.Metadata.AlbumArtist = first.Artist;
MediaFile.Metadata.Title = MediaFile.Metadata.DisplayTitle = first.Track;
MediaFile.Metadata.DisplayIcon = new Image { Source = "icon".CorrectedImageSource() };
MediaFile.Metadata.BluetoothFolderType = "1";
MediaFile.Type = MediaFileType.Audio;
MediaFile.Url = Constants.RadioStream;
MediaFile.Availability = ResourceAvailability.Remote;
MediaFile.MetadataExtracted = true;
MediaFile.Metadata.Date = DateTime.Now;
MediaFile.Metadata.Duration = 300;
MediaFile.Metadata.Genre = "Rock";
MediaFile.Metadata.TrackNumber = MediaFile.Metadata.NumTracks = 1;
MediaFile.Metadata.DisplayDescription = "Radio Station";
if (!ViewModel.NotificationStarted)
{
if (CrossMediaManager.Current.MediaNotificationManager != null)
CrossMediaManager.Current.MediaNotificationManager.StartNotification(MediaFile);
ViewModel.NotificationStarted = true;
}
CrossMediaManager.Current.MediaNotificationManager?.UpdateNotifications(MediaFile, MediaPlayerStatus.Playing);
});
}
break;
The code itself is being hit (I can set break points and they are hit). I've tried it on and off the UI thread as well.
The playlist comes from a webapi which works fine. The notifier gives unknown/unknown on the device media player (both iOS and Android) and nothing in-car. For Android, the permissions the readme file says to use have also been set.
Is there some sort of magic I have to do to get this to work? This is a Xam.Forms package rather than something native.
The MediaPlayer is started further in the class using the following code
CrossMediaManager.Current.Play(Constants.RadioStream, MediaFileType.Audio, ResourceAvailability.Remote);
Where Constants.RadioStream is the URL of the radio stream.

Windows 8.1 store apps OnCommandsRequested doesn't add ApplicationCommands when async used

On the App.xaml.cs I have the following code
private async void OnCommandsRequested(SettingsPane settingsPane, SettingsPaneCommandsRequestedEventArgs e)
{
var loader = ResourceLoader.GetForCurrentView();
var generalCommand = new SettingsCommand("General Settings", "General Settings", handler =>
{
var generalSettings = new GeneralSettingsFlyout();
generalSettings.Show();
});
e.Request.ApplicationCommands.Add(generalCommand);
object data;
IAuthService _authService = new AuthService();
if (Global.UserId == 0)
data = await _authService.GetSettingValueBySettingName(DatabaseType.GeneralDb, ApplicationConstants.GeneralDbSettingNames.ShowSupportInfo);
else
data = await _authService.GetSettingValueBySettingName(DatabaseType.UserDb, ApplicationConstants.UserDbSettingNames.ShowSupportInfo);
if (data != null && data.ToString().Equals("1"))
{
var supportCommand = new SettingsCommand("Support", "Support", handler =>
{
var supportPane = new SupportFlyout();
supportPane.Show();
});
e.Request.ApplicationCommands.Add(supportCommand);
}
var aboutCommand = new SettingsCommand("About", loader.GetString("Settings_OptionLabels_About"), handler =>
{
var aboutPane = new About();
aboutPane.Show();
});
e.Request.ApplicationCommands.Add(aboutCommand);
}
This code adds the setting "General Settings" but neither "Support" or "About" commands. Can anyone advice what's wrong with this code?
Instead of querying the commands from your service when they are requested you'll need to query them ahead of time and then add the already known commands.
You cannot use await in OnCommandsRequested.
A method returns when it gets to the first await, so only commands added to the request before the await will be used.
Since the SettingsPaneCommandsRequestedEventArgs doesn't provide a deferral there is no way to tell the requester to wait for internal async calls to complete.
Note also that SettingsPane is deprecated and not recommended for new app development for Windows 10.

Pechkin to Tuespechkin

For a project, we are migrating to Windows Azure. I have to make sure that the HTML to PDF converter will run on a 64 bit worker role.
Since Pechkin can't run as a 64bit application I have decided to use Tuespechkin, because they should be very alike and both use wkhtmltopdf to convert the HTML to PDF.
Now, i got this all set up but the resulting PDF is kind of disappointing.
Problems:
The font is rendered differently. With Pechkin the font is always 'sharp' where tuespechkin makes it very bold.
Results here:
http://postimg.org/image/xngqxryn1/
I tried using different fonts (even browser default). All render very bold
I tried using different Object- and Globalsettings (DPI, Outline, compression, name it; it never changes much).
All contents is selectable and copyable. I would like it to be more like an image (which is default in pechkin). Any advice on this would be appreciated.
Here is the code i am using to convert the HTML to PDF:
Pechkin, old:
var documentConfig = new ObjectConfig()
.SetAllowLocalContent(true)
.SetLoadImages(true)
.SetRunJavascript(true)
.SetPrintBackground(true)
.SetRenderDelay(15000);
var globalConfig = new GlobalConfig()
.SetMargins(new Margins(50, 50, 100, 100))
.SetDocumentTitle(company.Name)
.SetPaperSize(PaperKind.A4);
var pechkin = new SynchronizedPechkin(globalConfig);
var buffer = pechkin.Convert(documentConfig, parsedHtml);
Tuespechkin:
var converter = new ThreadSafeConverter(
//new ImageToolset(
new PdfToolset(
new Win64EmbeddedDeployment(
new TempFolderDeployment()
)
)
);
var documentConfig = new ObjectSettings {
WebSettings = new WebSettings {
EnableJavascript = true,
PrintBackground = true,
PrintMediaType = true
},
LoadSettings = new LoadSettings {
BlockLocalFileAccess = false,
RenderDelay = 15000,
},
HtmlText = parsedHtml
};
var globalConfig = new GlobalSettings();
globalConfig.Margins = new MarginSettings(2.645833333333, 1.322916666667, 2.645833333333, 1.322916666667);
globalConfig.Margins.Unit = Unit.Centimeters;
globalConfig.DocumentTitle = company.Name;
globalConfig.PaperSize = PaperKind.A4;
globalConfig.UseCompression = false;
globalConfig.DPI = 1200;
var doc = new HtmlToPdfDocument {
Objects = {
documentConfig
},
GlobalSettings = globalConfig
};
var buffer = converter.Convert(doc);
Any help on either problem would be much appreciated!
As you say, I can't solve the problem.
But IIS can be set to run 32-bit applications.
as this photo:
http://i.stack.imgur.com/6l6Es.png
So you can run Pechkin in you Azure.
You can see more in this.
https://codeutil.wordpress.com/2013/09/16/convert-html-to-pdf/

Firefox add-on access all the console log information

I am developing an add-on in Firefox. As a part of the add-on, I am opening a tab with a new page, and once the page is completely loaded, I would like access the web console log information (css/javascript errors.....
How do I access all the console log information once the page is loaded ?
First you have to get the innerID of the window that you want to obtain messages from.
With the sdk you can get this with var innerID = require("sdk/window/utils").getInnerId(require("sdk/view/core").viewFor(require("sdk/windows").activeWindow))
or more cleanly:
var utils = require("sdk/window/utils");
var viewFor = require("sdk/view/core").viewFor;
var windows = require("sdk/windows");
var innerID = utils.getInnerId(viewFor(windows.activeWindow));
Then you want to observe console notifications for that window:
var system = require("sdk/system/events");
system.on('console-api-log-event', onMessage);
function onMessage(subject) {
subject = subject.wrappedJSObject;
if (subject.innerID != innerID) {
return null; //ignore this console log, because it is for a window/thing that I don't care about
}
if (subject.level != "log") {
return null; // ignore anything but console.log, like: console.info, console.error, console.debug, etc.
}
var message = subject.arguments[0]; // first string argument to console.log()
// do something with the console.log("") message
}

Resources