Converting docx to html with dotnet-mammoth fails at deploy server - c#

I'm using dotnet-mammoth (mammoth.js with edge.js) to convert a docx document to html in .net
I added it to my project via its nuget package.
I'm using the code provided by the sample, which is working correctly in my development enviroment (running IIS Express):
var documentConverter = new Mammoth.DocumentConverter();
var result = documentConverter.ConvertToHtml(Server.MapPath("~/files/document.docx")); // problem here at production enviroment
string theResult = result.Value
However, once I deploy it to production server, when the executed code reaches documentConverter.ConvertToHtml() method, it's redirecting me to the login page. Without displaying any error messages, without saving anything on IIS log file.
If I remove that line, everything else executes normally.
I assume it could be an issue related to permissions but I don't know what could it be. Any ideas?

The latest version of Mammoth on NuGet no longer uses edge.js, and is now just .NET code, so should work more reliably.

You can resolve this by getting the exact error when the process is trying to read the file. Below is the code from dotnet-mammoth DocumentConverter.cs. As shown below on call it is trying to read all bytes to be sent to edge
public Result<string> ConvertToHtml(string path)
{
var mammothJs = ReadResource("Mammoth.mammoth.browser.js") + ReadResource("Mammoth.mammoth.edge.js");
var f = Edge.Func(mammothJs);
var result = f(File.ReadAllBytes(path));
Task.WaitAll(result);
return ReadResult(result.Result);
}
I suppose you are giving absolute path to the input. In that case the absolute path should be accessible by app identity hosting the app pool of the web application.
If the path specified is in web root directory - (not advised) - but if it is then you can use Server.MapPath

Related

DinkToPDF PDF generation only works once on Azure before giving 502 errors

I've written a PDF generation API that uses dinktopdf to convert some templated HTML to a byte array. This all works fine on my local machine but when I deploy to my azure web application the API only works once. When I try it a second time I get the following message and a 502 error:
The specified CGI application encountered an error and the server terminated the process.
Here's a stripped down version of my code that still presents the same error:
static IPdfConverter pdfConverter = new SynchronizedConverter(new PdfTools());
public static byte[] BuildPdf(string html)
{
return pdfConverter.Convert(new HtmlToPdfDocument()
{
Objects =
{
new ObjectSettings
{
HtmlContent = html
}
}
});
}
I've also tried using IronPDF to do the HTML to PDF conversion and gotten the same exact issue (works perfectly on local machine but only once on Azure deployment before giving consistent 502 errors).
If you initialize converter with var converter = new SynchronizedConverter(new PdfTools());ยด, remove it, and just injectIConverterin your service.
I tried and this approach is working, after all, we already register the converter, we don't need to create an instance using thenew` keyword. My app is not on Azure, but I have the same problem, the converter hangs after the first call, for that reason I decide to write down this comment.
Update: Problem was solved by changing the Azure App Service Plan to Basic rather than free (PDF generation requires at minimum the Basic plan apparently).

How to get a web app to serve static files from a different server

I have an ASP.Net Core 2 MVC webapp that needs to retrieve and serve a pdf that's stored on a different server on the same LAN. It knows the full pathname. This code works well while developing on local machine (I stripped down the code to the bare minimum to get to the point):
public IActionResult GetPdf()
{
FileStream fileStream = new FileStream(#"\\SRV1\Drawings\mydrawing.pdf", FileMode.Open, FileAccess.Read);
var fsResult = new FileStreamResult(fileStream, "application/pdf");
return fsResult;
}
However, when I publish the app on the server where I'm testing the deployment, I get this error:
System.IO.FileNotFoundException: Could not find file '/var/www/myapp/\\SRV1\Drawings\mydrawing.pdf'
Now, I get it that the app is only supposed to serve static files from within its wwwroot, so that doesn't surprise me. Therefore, based on this post and similar other posts, I added this code to Startup.cs:
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(#"\\SRV1\Drawings"),
RequestPath = new PathString("/PdfDrawings"),
EnableDirectoryBrowsing = false
});
and changed the controller's action like so:
public IActionResult GetPdf()
{
FileStream fileStream = new FileStream(#"\PdfDrawings\mydrawing.pdf", FileMode.Open, FileAccess.Read);
var fsResult = new FileStreamResult(fileStream, "application/pdf");
return fsResult;
}
but this way it doesn't work neither on the development machine nor on the server, as both fail to find the path. The only difference between the two is that the local machine will run the app, and return this error only when I request the GetPdf action, because it will point to C:\
DirectoryNotFoundException: Could not find a part of the path 'C:\PdfDrawings\mydrawing.pdf'.
while the deployed app will not even run because a similar error occurs at the very start, while executing the Startup's Configure method.
I also tried this in Startup.cs:
app.UseStaticFiles(new StaticFileOptions()
{
FileProvider = new PhysicalFileProvider(#"\\SRV1\Drawings"),
RequestPath = "/PdfDrawings"
});
I was expecting to encounter credentials issues, but I never got that far. I'm also aware that there may be security concerns with this approach, but the app will reside in the LAN and will only be used by trusted personnel, so that's not an issue.
Additional info, in case it matters: I'm deploying the app to an Ubuntu server 18.04. The files I'm trying to access are on a different server in the same LAN.
Ultimately, the app will need to read and write on this second server also in other parts of code, so would someone be kind enough to point me to a post/tutorial that explains how to achieve that?
Your Ubuntu server does not understand Windows share paths. Simply try to access the path you provided on your Ubuntu server and you'll see the issue.
You will have to mount the share on your server to be able to access it. You also will have to use a different path for your local development and your deployment.
On Ubuntu it may be something like /mnt/srv1/Drawings (provided you mounted the share in /mnt/srv1) while on windows your path stays the same.

WCF Azure create PDF file in virtual directory with DevExpress

We have a wcf service that uses DevExpress XtraReports to generate a pdf file.
How this normally works is we have in the web.config the physical directory Example C:\PdfDocs\ that we specify as the path when executing the devexpress ExportToPdf function. This works fine on a normal virtual machine.
We are now busy moving to Microsoft Azure enviroment and I am having trouble getting this to work.
My Setup - The wcf service is created as a App Service. Unfortunately I am not at liberty to give names so lets assume the following:
App Service Name - testdocservice,
Url Azure gives - https://testdocservices.azurewebsites.net
What I have tried:
In Application settings, I have created a virtual directory. In the project itself I have created a folder that the virtual directory will point to.
The virtual path is https://testdocservices.azurewebsites.net/ItinDocs and the physical path is site\wwwroot\ItinDocuments
This is setup correctly as I have tested it by FTP test pdf in and then hit the following url: https://testdocservices.azurewebsites.net/ItinDocs/test.pdf
So in the wcf service I took a chance and set the location to render the pdf to "site\wwwroot\ItinDocuments" - This did not work.
The exception was as follows: Access to the path 'D:\Windows\system32\site\wwwroot\ItinDocuments\TestQuote21.pdf' is denied.
I then tried using Server.MapPath example:
QuoteV3 oQuote = new QuoteV3();
oQuote.DataSource = dSource;
oQuote.ExportToPdf(System.Web.HttpContext.Current.Server.MapPath($"~{ConfigurationManager.AppSettings["DocLocation"]}{fileName}"));
The DocLocation look like the following: site\wwwroot\ItinDocuments\
This also did not work. The following error is given:
'~https:/testdocservices.azurewebsites.net/ItinDocs/TestQuote21.pdf' is not a valid virtual path.
I thought the first character "~" could be a problem so I removed it and got the same error as above - 'https:/testdocservices.azurewebsites.net/ItinDocs/TravelQuote21.pdf' is not a valid virtual path.
I then noticed that the above errors only have one forward-slash after the https. At this point I am not sure if that could be causing the problem and then how to correct it as the Server.MapPath is generating that part.
In conclusion, I am not sure if I am even working in the right direction with the above approach. My knowledge around azure is still minimal.
Any help/assistance/solution would be greatly appreciated.
Many thanks.
This can be closed as I have instead setup azure storage and my pdfs are saving in a container instead.
Thanks.

Puzzling differences in behavior between console and web apps

I have a piece of code in a Web API app:
private Stream ConvertWorkBookToStream(WorkBook workBook)
{
var tempFileName = Path.GetTempFileName();
// The following line throws a NullReferenceException
workBook.write(tempFileName);
// Remainder elided for brevity
}
Neither workBook nor tempFileName are null.
On a whim, I changed the app pool to run under a domain administrator account, to eliminate any permissions issues (since I've observed some general wonkiness on my machine of late) and re-ran it. The same exception was thrown.
Then I created a console application and copied the method, verbatim, into the app and ran it. No exception was thrown.
Now, it bears noting that just yesterday, I ran into a similar puzzling behavior regarding File.Exists.
Consider the following call:
var exists = File.Exists(#"\\myshare\\myexistingfile.ext");
Assuming that the path refers to a file that actually exists:
Under a web app, exists returns false on my machine.
The same operation, in a console application, returns true.
My coworkers are experiencing the opposite behaviors.
Can anyone explain this? I'm rather at my wits' end.
Check to see if the return from Path.GetTempFileName is different from the console app and the web app. Windows could be playing tricks with you. I had similar issues attempting to write log files. I just gave up and put them int the same directory as my web service.
In your IIS Authentication settings, are you only having Anonymous Authentication enabled? If I remember correctly Anonymous Authentication impersonates the IUSR account with restricted privileges.

Use external xml file after publishing the c# desktop application

I have developed a c# desktop application that needs to be hosted on a server and will be scheduled to fetch data based on queries stored in XML files. while developing, I was using the following code to read XML files:
var query = new XPathDocument(#"C:\\Documents and Settings\\XYZ\\Desktop\\productplanningquery.xml");
as you can see I had put the XML file conveniently on my desktop and it worked fine while development. What I want to do now, is to give at a path such that where ever I host the application plus the XML files, it does not throw an exception. One way i thought could be to have a folder in a directory where the application will be installed but for that i will have to figure out the path to current directory dynamically (which i could not figure out).
Please help.
You could pass the location of you XML using args this way you're code would look like so:
var query = new XPathDocument(args[0])
You can also use relative path. Make sure that when deploying your code you keep the location of the file in the same relative location. For example if you place the XML in the same directory as the application
var query = new XPathDocument("productplanningquery.xml")
I am not sure what you want to achieve whether you want to read xml using winform app and do some operation and then pass it web app or some thing else. But here is my understandings:
Case 1: If you need to create XML outside the IIS and that XML will be consumed by ASP.Net app, then :
For using a desktop application with IIS server , you need to have full administrative access to the Live Machine. If its not then you should consider building windows services to operate on the XML files or any task that will run behind the scenes to decrease the load of the asp.net app.
Still in this case if you dont own a server then you need some Virtual Private Hosting or similar kind of hosting where you have almost all previleges to access the system. Then deploy the Windows Service, set the output path in such a manner so that it can be accessed by asp.net app too. And do whatever you want.
Case 2: If you want o read XML in ASP.Net Solely, then
In this case you case read it easily by using XDocument.But note, XML should in the same application directory or under the reach of the ASP.Net app
MSDN Article for Web-Windows Services with ASP.Net
You can use something like this:
var path = string.Format("{0}\\{1}", Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "productplanningquery.xml");
var pathForCurrentApp = string.Format("{0}\\{1}", Environment.CurrentDirectory, "productplanningquery.xml");

Categories

Resources