Missing method calling puppeteer LaunchAsync - axapta

When I try to use puppeteersharp in AX I get a error
"Method not found: 'Void Microsoft.Extensions.Logging.LoggerExtensions.LogError(Microsoft.Extensions.Logging.ILogger, System.Exception, System.String, System.Object[])'."
I have a custom DLL added to my AX project where I create a PDF but I call this method from AX. The DLL alone is working fine since I tested it outside of my AX project yet when I call it from AX the error occours. I tried different verions but there is always a problem with Microsoft.Extensions.Logging DLL.
EDIT!
As I looked at code the method I seek is in Microsoft.Extensions.Logging.Abstractions. Since in AX i found that the DLL version is 1.1.2 and has no 4th method for LogError where you can add Exception value. Is there any safe way to update DLL in AX365 onprem?
//X++ code
class ConvertXMLtoPDF
{
public static void main(Args _args)
{
try
{
helper.PuppeteerPDF();
}
catch(Exception::CLRError)
{
System.Exception ex = CLRInterop::getLastException();
info(ex.ToString());
}
}}
C# code
using PuppeteerSharp;
using PuppeteerSharp.Media;
using Microsoft.Extensions.Logging;
public async void PuppeteerPDF()
{
string path = #"C:\Temp\test\tes2t.pdf";
string save = #"C:\Temp\test\test.html";
var options = new LaunchOptions
{
Headless = true,
ExecutablePath = "C:\\Program Files\\Google\\Chrome\\Application\\Chrome.exe"
};
try
{
using (var browser = await Puppeteer.LaunchAsync(options)) // <--- here the error occours
using (var page = await browser.NewPageAsync())
{
await page.GoToAsync(save);
var result = await page.GetContentAsync();
await page.PdfAsync(path, new PdfOptions
{
Format = PaperFormat.A4,
DisplayHeaderFooter = true,
Scale = (decimal)0.5,
PrintBackground = true,
});
await page.DisposeAsync();
await browser.DisposeAsync();
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
logger.LogError(ex, "test");
logger.LogInformation(ex, "test");
}
}

Related

How do I create a CSharpCompilation using Roslyn in Blazor WebAssembly?

I am trying to write a Blazor WebAssembly (WASM) app that accepts some code (from some text input field) and compiles the code using Roslyn.
I'm using Roslyn's CSharpCompilation class to create the compilation. Its Create method takes four parameters, one of which is a list of MetadataReferences (aka assembly references). In other (non-blazor) type applications, like a C# console app, you could get these MetadataReferences based on Asssembly Location, like this:
var locatedAssemblies = AppDomain.CurrentDomain.GetAssemblies().Where(a => !string.IsNullOrEmpty(a.Location)).ToArray();
foreach (var assembly in locatedAssemblies)
{
MetadataReference reference = MetadataReference.CreateFromFile(assembly.Location);
}
This unfortunately no longer works in Blazor WASM, because the Locations of the assemblies are empty.
I had tried getting assemblies in different ways, like AppDomain.CurrentDomain.GetAssemblies() and Assembly.GetEntryAssembly().GetReferencedAssemblies(), but all had empty Locations. I also tried calling Assembly.Load(), but to no avail.
Does anyone know how to get MetadataReferences in Blazor WASM, or how I would otherwise create a compilation in Blazor WASM?
(I'm also aware of MetadataReference.CreateFromStream() that I'll probably need to use, but it still requires the assembly location).
Thanks in advance.
I also wanted to compile C# inside a Blazor WASM app and found your question without an answer. After some digging I was able to create a working demo (repo link below.) Basically get the bytes for each assembly with HttpClient and use MetadataReference.CreateFromImage(bytes).
Full basic example repo I created: https://github.com/LostBeard/BlazorWASMScriptLoader
ScriptLoaderService.cs source:
using Microsoft.AspNetCore.Components;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using System.Collections.Immutable;
using System.Reflection;
namespace BlazorWASMScriptLoader
{
// requires "Microsoft.CodeAnalysis.CSharp"
// can be added via nuget
public class ScriptLoaderService
{
HttpClient _httpClient = new HttpClient();
public ScriptLoaderService(NavigationManager navigationManager)
{
_httpClient.BaseAddress = new Uri(navigationManager.BaseUri);
}
async Task<MetadataReference?> GetAssemblyMetadataReference(Assembly assembly)
{
MetadataReference? ret = null;
var assmeblyName = assembly.GetName().Name;
var assemblyUrl = $"./_framework/{assmeblyName}.dll";
try
{
var tmp = await _httpClient.GetAsync(assemblyUrl);
if (tmp.IsSuccessStatusCode)
{
var bytes = await tmp.Content.ReadAsByteArrayAsync();
ret = MetadataReference.CreateFromImage(bytes);
}
}
catch { }
return ret;
}
public async Task<Assembly?> CompileToDLLAssembly(string sourceCode, string assemblyName = "")
{
if (string.IsNullOrEmpty(assemblyName)) assemblyName = Path.GetRandomFileName();
var codeString = SourceText.From(sourceCode);
var options = CSharpParseOptions.Default.WithLanguageVersion(LanguageVersion.CSharp11);
var parsedSyntaxTree = SyntaxFactory.ParseSyntaxTree(codeString, options);
var appAssemblies = Assembly.GetEntryAssembly()?.GetReferencedAssemblies().Select(o => Assembly.Load(o)).ToList();
appAssemblies.Add(typeof(object).Assembly);
var references = new List<MetadataReference>();
foreach (var assembly in appAssemblies)
{
var metadataReference = await GetAssemblyMetadataReference(assembly);
if (metadataReference == null)
{
// assembly may be located elsewhere ... handle if needed
continue;
}
var metadataReferene = metadataReference;
references.Add(metadataReferene);
}
CSharpCompilation compilation = CSharpCompilation.Create(
assemblyName,
syntaxTrees: new[] { parsedSyntaxTree },
references: references,
options: new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary,
concurrentBuild: false,
optimizationLevel: OptimizationLevel.Debug
)
);
using (var ms = new MemoryStream())
{
EmitResult result = compilation.Emit(ms);
if (!result.Success)
{
IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
diagnostic.IsWarningAsError ||
diagnostic.Severity == DiagnosticSeverity.Error);
foreach (Diagnostic diagnostic in failures)
{
Console.Error.WriteLine("{0}: {1}", diagnostic.Id, diagnostic.GetMessage());
}
return null;
}
else
{
ms.Seek(0, SeekOrigin.Begin);
var assembly = Assembly.Load(ms.ToArray());
return assembly;
}
}
}
}
}

Quartz 3.06 not Executing Jobs from XML file

I tried to execute this code.. but unfortunately code not running.. its working in older versions
static async void QuartzInitializer()
{
try
{
ILog log = LogManager.GetLogger(typeof(Program));
// our properties that enable XML configuration plugin
var properties = new NameValueCollection
{
["quartz.plugin.triggHistory.type"] = "Quartz.Plugin.History.LoggingJobHistoryPlugin, Quartz.Plugins",
["quartz.plugin.jobInitializer.type"] = "Quartz.Plugin.Xml.XMLSchedulingDataProcessorPlugin, Quartz.Plugins",
["quartz.plugin.jobInitializer.fileNames"] = "quartz_jobs.xml",
["quartz.plugin.jobInitializer.failOnFileNotFound"] = "true",
["quartz.plugin.jobInitializer.scanInterval"] = "60",
};
ISchedulerFactory sf = new StdSchedulerFactory(properties);
IScheduler sched = await sf.GetScheduler();
await sched.Start();
await Task.Delay(TimeSpan.FromMinutes(5));
}
catch (Exception ex)
{
Main();
}
}
No Exeception is thrown. I tried using try catch also.
its exiting at await sched.Start();

I get invalidRequest Exception thrown: 'Microsoft.Graph.ServiceException' in mscorlib.ni.dll

I am integrating Onedrive SDK with the UWP part of my Xamarin App. Once I press the download button I get the Onedrive signin page but it throws the above error in this line:
try
{
var appFolder = await OneDriveClient.Drive.Special.AppRoot.Request().GetAsync();
Debug.WriteLine(appFolder.Name);
}
catch (ServiceException e )
{
Debug.WriteLine(e.Message +" " + e.Error.Code);
}
here is the full relevant code:
public async Task Download(string filename)
{
//AccountSelectionLoaded();
await InitializeClient();
try
{
var appFolder = await OneDriveClient.Drive.Special.AppRoot.Request().GetAsync();
Debug.WriteLine(appFolder.Name);
}
catch (ServiceException e )
{
Debug.WriteLine(e.Message +" " + e.Error.Code);
}
var file = await OneDriveClient.Drive.Special.AppRoot.Children[filename].Content.Request().GetAsync();
//var fileStream = await fileBuilder.Content.Request().GetAsync();
IStorageFile appFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("test.db3",
CreationCollisionOption.OpenIfExists);
byte[] fileBytes;
using (DataReader reader = new DataReader(file.AsInputStream()))
{
fileBytes = new byte[file.Length];
await reader.LoadAsync((uint)file.Length);
reader.ReadBytes(fileBytes);
}
Debug.WriteLine(fileBytes.Length);
Debug.WriteLine("Writing");
await FileIO.WriteBytesAsync(appFile, fileBytes);
Debug.WriteLine("End of writing");
}
private async Task InitializeClient()
{
if (OneDriveClient == null)
{
Task authTask;
var msaAuthProvider = new MsaAuthenticationProvider(oneDriveConsumerClientId,oneDriveConsumerReturnUrl,scopes);
await msaAuthProvider.AuthenticateUserAsync();
OneDriveClient = new OneDriveClient(oneDriveConsumerBaseUrl, msaAuthProvider);
AuthenticationProvider = msaAuthProvider;
}
}
Thank you for reporting this issue. Indeed, we can see a associated issue using OneDrive .NET SDK 2.0.4 in a UWP app
I will report this issue through internal way.
As a workaround, please see this blog: Windows 10 - Implementing a UWP App with the Official OneDrive SDK
Laurent Bugnion described the detailed steps(and also a demo) to enable OneDrive features in a UWP app.
private IOneDriveClient _client;
public MainPage()
{
InitializeComponent();
AuthenticateButton.Click += async (s, e) =>
{
var scopes = new[]
{
"onedrive.readwrite",
"onedrive.appfolder",
"wl.signin"
};
_client = OneDriveClientExtensions.GetClientUsingOnlineIdAuthenticator(
_scopes);
var session = await client.AuthenticateAsync();
Debug.WriteLine($"Token: {session.AccessToken}");
};
}
At that time, the project is using 1.2.0 SDK which is still working now.

Generating PDFs using Phantom JS on .NET applications

I have been looking into phantomJS and looks like it could be a great tool to use generating PDFs. I wonder if anyone have successfully used it for their .NET applications.
My specific question is: how would you use modules like rasterize.js on the server, receive requests and send back generated pdfs as a response.
My general question is: is there any best practice for using phantomJS with .NET Applications. What would be the best way to achieve it?
I am fairly new in .NET World and I would appreciate the more detailed answers. Thanks everyone. :)
I don't know about best practices, but, I'm using phantomJS with no problems with the following code.
public ActionResult DownloadStatement(int id)
{
string serverPath = HttpContext.Server.MapPath("~/Phantomjs/");
string filename = DateTime.Now.ToString("ddMMyyyy_hhmmss") + ".pdf";
new Thread(new ParameterizedThreadStart(x =>
{
ExecuteCommand("cd " + serverPath + #" & phantomjs rasterize.js http://localhost:8080/filetopdf/" + id.ToString() + " " + filename + #" ""A4""");
})).Start();
var filePath = Path.Combine(HttpContext.Server.MapPath("~/Phantomjs/"), filename);
var stream = new MemoryStream();
byte[] bytes = DoWhile(filePath);
return File(bytes, "application/pdf", filename);
}
private void ExecuteCommand(string Command)
{
try
{
ProcessStartInfo ProcessInfo;
Process Process;
ProcessInfo = new ProcessStartInfo("cmd.exe", "/K " + Command);
ProcessInfo.CreateNoWindow = true;
ProcessInfo.UseShellExecute = false;
Process = Process.Start(ProcessInfo);
}
catch { }
}
public ViewResult FileToPDF(int id)
{
var viewModel = file.Get(id);
return View(viewModel);
}
private byte[] DoWhile(string filePath)
{
byte[] bytes = new byte[0];
bool fail = true;
while (fail)
{
try
{
using (FileStream file = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
bytes = new byte[file.Length];
file.Read(bytes, 0, (int)file.Length);
}
fail = false;
}
catch
{
Thread.Sleep(1000);
}
}
System.IO.File.Delete(filePath);
return bytes;
}
Here is the action flow:
The user clicks on a link to DownloadStatement Action. Inside there, a new Thread is created to call the ExecuteCommand method.
The ExecuteCommand method is responsible to call phantomJS. The string passed as an argument do the following.
Go to the location where the phantomJS app is and, after that, call rasterize.js with an URL, the filename to be created and a print format. (More about rasterize here).
In my case, what I really want to print is the content delivered by the action filetoupload. It's a simple action that returns a simple view. PhantomJS will call the URL passed as parameter and do all the magic.
While phantomJS is still creating the file, (I guess) I can not return the request made by the client. And that is why I used the DoWhile method. It will hold the request until the file is created by phantomJS and loaded by the app to the request.
If you're open to using NReco.PhantomJS, which provides a .NET wrapper for PhantomJS, you can do this very succinctly.
public async Task<ActionResult> DownloadPdf() {
var phantomJS = new PhantomJS();
try {
var temp = Path.Combine(Path.GetTempPath(),
Path.ChangeExtension(Path.GetRandomFileName(), "pdf")); //must end in .pdf
try {
await phantomJS.RunAsync(HttpContext.Server.MapPath("~/Scripts/rasterize.js"),
new[] { "https://www.google.com", temp });
return File(System.IO.File.ReadAllBytes(temp), "application/pdf");
}
finally {
System.IO.File.Delete(temp);
}
}
finally {
phantomJS.Abort();
}
}
Here's some very basic code to generate a PDF using Phantom.JS but you can find more information here: https://buttercms.com/blog/generating-pdfs-with-node
var webPage = require('webpage');
var page = webPage.create();
page.viewportSize = { width: 1920, height: 1080 };
page.open("http://www.google.com", function start(status) {
page.render('google_home.pdf, {format: 'pdf', quality: '100'});
phantom.exit();
});

Using geolocalisation with windows phone, await error

I'm trying to get the current location of an user, but the code show me an error...
// try get user location
Geolocator geo = new Windows.Devices.Geolocation.Geolocator();
geo.DesiredAccuracyInMeters = 10;
try {
Geoposition position = await geo.GetGeopositionAsync();
} catch (Exception e) { }
My problem is that the compiler show me an error at await geo.GetGeopositionAsync();
The 'await' operator can only be used when its containing method or lambda expression is marked with the 'async' modifier.
But from what I have seen, this is the same code as shown by Microsoft
I already restart VS12 and the pc (which is a VM but still) and the error is still here...
What's going wrong ?
I also try this and still get the same error:
Geoposition position = await geo.GetGeopositionAsync().asTask<Geoposition>();
You need to mark your method with async:
void **async** themethod()
{
// try get user location
Geolocator geo = new Windows.Devices.Geolocation.Geolocator();
geo.DesiredAccuracyInMeters = 10;
try {
Geoposition position = await geo.GetGeopositionAsync();
} catch (Exception e) { }
}

Resources