Use NetOffice.PowerPointApi on azure app service - azure

I have written a code to save all the slides in a presentation as jpeg. It works well in visual studio locally on my system, but when I deploy it on Azure app service, I get 500 internal server error.
IIS received the request; however, an internal error occurred during the processing of the request. The root cause of this error depends on which module handles the request and what was happening in the worker process when this error occurred. IIS was not able to access the web.config file for the Web site or application. This can occur if the NTFS permissions are set incorrectly. IIS was not able to process configuration for the Web site or application. The authenticated user does not have permission to use this DLL. The request is mapped to a managed handler but the .NET Extensibility Feature is not installed.
The code:
using pptd = NetOffice.PowerPointApi;
using NetOffice.PowerPointApi.Enums;
using NetOffice.OfficeApi.Enums;
public void genThumbnails(string originalfileName,string renamedFilename, string dirPath)
{
pptd.Application pptApplication = new pptd.Application();
pptd.Presentation pptPresentation = pptApplication.Presentations.Open(dirPath + renamedFilename, MsoTriState.msoFalse, MsoTriState.msoFalse, MsoTriState.msoFalse);
int i = 0;
foreach (pptd.Slide pptSlide in pptPresentation.Slides)
{
pptSlide.Export(dirPath + originalfileName + "_slide" + i + ".jpg", "jpg", 1280, 720);
i++;
}
pptPresentation.Close();
}
What is the mistake that I am doing? Does NetOffice package also need MS Office installed on the server like Office.Interop?

The standard windows and Linux web apps used blessed operating system images. As part of the PaaS design, customers are limited as to what they can run as there is no MS Office inter-op present and also because Azure Web Apps is a sandbox.
My suggestion would be to create a container image that has the necessary dependencies that you need and then deploy your custom container to an Azure Web App Container.

Related

SSL based webserver on Windows IoT

I am working on a project which involves gathering some sensor data and build a GUI on it, with controlling of sensors. It has following two basic requirements.
Should be a web based solution (Although it will only be used on LAN or even same PC)
It should be executable on both windows IoT core and standard windows PC (Windows 7 and above)
I have decided to use Embedded webserver for Windows IoT, which seems to be a good embedded server based on PCL targeting .NET 4.5 and UWP. So I can execute it on both environments. That is great! But the problem is this web server doesn't support SSL, I have tried to search other servers and have come up with Restup for UWP, which is also a good REST based web server, but it also doesn't support SSL.
I needs an expert opinion, that if there is any possibility I can use SSL protocol in these web servers. Is it possible that it can be implemented using some libraries like OpenSSL etc? (Although I think that it would be too complex and much time taking to implement it correctly)
Edit
I would even like to know about ASP.NET core on Windows 10 IoT Core, if I can build an application for both windows. I found one example but it is DNXbased, and I don't want to follow this way, as DNX is deprecated.
Any help is highly appreciated.
Late answer, but .NET Core 2.0 looks promising with Kestrel. I successfully created a .Net Core 2.0 app on the PI 3 this morning. Pretty nifty and If you already have an Apache web server, you’re almost done. I’m actually going to embed (might not be the right term) my .Net Core 2.0 web application into a UWP app, rather than create multiple unique apps for the touchscreens around the house.
.Net Core 2.0 is still in preview though.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel?tabs=aspnetcore2x
I know this post is pretty old, but I have built the solution which you are asking bout. I’m currently running .Net 5.0 on a Raspberry pi. When you build the .net core web project, select the correct target framework and the target runtime to win-arm. Copy the output some directory on the pi and you will have to access the device using powershell to create a scheduled task to start the web project. Something like this:
schtasks /create /tn "Startup Web" /tr c:\startup.bat /sc onstart /ru SYSTEM
That starts a bat file which runs a powershell command which has the following command:
Set-Location C:\apps\vradWebServer\ .\VradTrackerWeb.exe (the .\VradTrackerWeb.exe is on a second line in the file) - the name of the webapp.
That starts the server. If you have any web or apps posting to the webserver you will need an ssl cert. I used no-ip and let’s encrypt for this. For let’s encrypt to work, you will need an external facing web server and have the domain name point to it. Run let’s encrypt on the external server and then copy out the cert and place it in your web directory on the pi. I then have a uwp program that runs on the pi and when it starts, it gets it’s local address and then updates no-ip with the local address, so the local devices communicating will be correctly routed and have the ssl cert. Side note, my uwp app is the startup app on the device. The scheduled task is important because it allows you to run you app and the web server. The following snip is how I get the ip address and then update no-ip.
private string GetLocalIP()
{
string localIP = "";
using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 0))
{
socket.Connect("8.8.8.8", 65530);
IPEndPoint endPoint = socket.LocalEndPoint as IPEndPoint;
localIP = endPoint.Address.ToString();
}
return localIP;
}//GetLocalIP
private async void UpdateIP()
{
string localIP = "";
string msg = "";
var client = new HttpClient(new HttpClientHandler { Credentials = new NetworkCredential("YourUserName", "YourPassword") });
try
{
localIP = GetLocalIP();
string noipuri = "http://dynupdate.no-ip.com/nic/update?hostname=YourDoman.hopto.org&myip=" + localIP;
using (var response = await client.GetAsync(noipuri))
using (var content = response.Content)
{
msg= await content.ReadAsStringAsync();
}
if (msg.Contains("good") == true || msg.Contains("nochg")==true)
{
SentDynamicIP = true;
LastIPAddress = localIP;
}
else
{
SentDynamicIP = false;
}
}
catch(Exception ex)
{
string x = ex.Message;
}
finally
{
client.Dispose();
}
}//UpdateIP

SQL Server CE on Azure website

Trying to run SQL Server CE on an Azure website, but I am getting error:
Unable to load the native components of SQL Server Compact corresponding to the ADO.NET provider of version 8876. Install the correct version of SQL Server Compact. Refer to KB article 974247 for more details
You cannot use SQL Server CE on Azure Web Sites. Using Azure Web Sites you have to use external database - such as Azure SQL Database or MySQL.
Generally speaking for the cloud and any cloud service (IaaS, PaaS, SaaS), you shall never rely on local file system, but rather persist your files on a durable storage such as Azure Blob Storage. Thus you can't (shall not) use services like SQL Server CE.
This seems to work:
Reference System.Data.SqlServerCe 4.0, set "Copy Local" = true.
Azure runs as a an x86 process (not Amd):
Environment.GetEnvironmentVariable("PROCESSOR_ARCHITECTURE");
On dev machine find SQLServerCE dependencies:
C:\ProgramFiles\Microsoft SQL Server Compact Edition\v4.0\Private\x86
Create SqlServerCE\x86 folder in web project.
Copy x86 files into new x86 folder:
sqlceca40.dll
sqlcecompact40.dll
sqlceer40EN.dll
sqlceme40.dll
sqlceqp40.dll
sqlcese40.dll
Add this block to top of application_start in global.asax
string dest = AppDomain.CurrentDomain.SetupInformation.PrivateBinPath;
string src = AppDomain.CurrentDomain.SetupInformation.ApplicationBase + "SqlServerCE\\x86";
foreach (var file in Directory.GetFiles(src))
{
var fileinfo = new FileInfo(file);
string destpath = Path.Combine(dest, fileinfo.Name);
if (!File.Exists(destpath))
{
fileinfo.CopyTo(destpath);
}
}
Note: I am not happy with this solution but I can't figure out how to get the files into the bin folder on deployment. post build events don't seem to work. If anyone has a better solution please suggest it.

Deployment of Node native modules to Azure WebSites

I'm trying to deploy the following sample node application to an Azure website:
var http = require('http');
var port = process.env.port || 1337;
http.createServer(function (req, res) {
res.writeHead(200, { 'Content-Type': 'text/html' });
try {
var canvasModule = require('canvas'),
canvas = new canvasModule(200, 200),
ctx = canvas.getContext('2d');
ctx.rotate(0.5);
ctx.font = '30px Impact';
var message = "Hello World";
ctx.fillText(message, 40, 40);
ctx.strokeRect(30, 5, 160, 50);
res.end('<html><img src="' + canvas.toDataURL() + '" /></html>');
} catch (e) {
res.end('Error: ' + e);
}
}).listen(port);
The tricky part is that I'm using a node module called "canvas" that needs to be compiled at install time using node-gyp.
According to this Microsoft page native modules are not supported on Azure Web-sites and the compiled version of the module should be copied to Azure for the app to work properly:
Native Modules
While most modules are simply plain-text JavaScript files, some
modules are platform-specific binary images. These modules are
compiled at install time, usually by using Python and node-gyp. One
specific limitation of Azure Web Sites is that while it natively
understands how to install modules specified in a package.json or
npm-shrinkwrap.json file, it does not provide Python or node-gyp and
cannot build native modules.
Since Azure Cloud Services rely on the node_modules folder being
deployed as part of the application, any native module included as
part of the installed modules should work in a cloud service as long
as it was installed and compiled on a Windows development system.
Native modules are not supported with Azure Web Sites. Some modules
such as JSDOM and MongoDB have optional native dependencies, and will
work with applications hosted in Azure Web Sites.
I deployed everything to Azure (using the publishing Wizard) and all the files were sent to Azure (apparently at least), including the compiled modules. When running the site on Azure I obtain the following exception:
Error: The specified module could not be found.
D:\home\site\wwwroot\node_modules\canvas\build\Release\canvas.node
But that file is in-fact deployed on the server:
Creating a VM would obviously be an option but I would prefer to use web-sites. Anyone has any idea that I can try out?
The error message ""The specified module could not be found" is a bit misleading. It can mean one or more dependent dlls are not found.
I assumed you used the build instruction in Windows. If you built canvas against the GTK2 zip file in the instruction, you can copy %GTKDIR%\bin\freetype6.dll to %YourApp%\node_modules\canvas\build\Release. This dll is not copied during the build process. You would need to do this deploying to a VM as well. Or you can build canvas against the Windows GTK3 bundle.
And unfortunately even after you have all the dll, the sandbox of Azure Websites seems to prevent canvas from running. Hopefully it would be enabled in the near future.
Alright got this working today!
You need to deploy your node_modules directory, in addition to that you need to copy all the contents gtk/bin to the root of your application, which makes it a bit messy, but it works. I imagine you could change the path to look elsewhere but I needed to get the app running so I didn't investigate any further.
That last line in #mtian's answser is key. You can spend time getting it to deploy but ultimately the Azure Website VMs lack the GDI+ APIs that node-canvas relies on to execute (presumably blocked for security considerations). If you want node-canvas on Azure, you can't use Azure Websites and will instead need to setup and manage your own VMs.

Accessing Azure IIS logs from within the same website

I have an Azure website configured to write IIS logs to file system. I would like to have a dashboard page within my website where administrators can view reports about traffic on the site, which has been generated by parsing these logs.
I have tried to access the log directory in code by both DirectoryInfo.GetFiles(), and by attempting to connect over FTP using FtpLib.
From outside of Azure, I can connect to the FTP and download the logs, but from code running in the Azure website, I cannot.My assumption is that Azure does not allow outbound FTP traffic from website code.
The folder structure for Azure (by inspecting the FTP) looks something like:
Site: /site/wwwroot
Logs: /LogFiles/http/RawLogs
Within the Azure portal you can create virtual directories, but they are only allowed within /site.
Site is running as an Azure Web Site, MVC 4, Integrated pipeline, 64bit, .NET 4.5, and for FTP I am using FtpLib v1.0.1.2. FtpLib fails at Login() with message: Unknown error (0x2ee2)
I am aware that I can change the logging within Azure to log to Blob Storage, however this would result in additional monthly cost. Are there any other options to access these files?
Thanks.
Edit: Have been asked to supply code, here is the FTP version (works locally, not on Azure):
using (var ftp = new FtpConnection("XXXXXXXX.windows.net", "XXXXXXXX", "XXXXXXXX"))
{
ftp.Open();
ftp.Login(); //Fails here
ftp.SetLocalDirectory(Server.MapPath("~/")); //Temp
ftp.SetCurrentDirectory("/LogFiles/http/RawLogs");
foreach (var f in ftp.GetFiles("*.log"))
{
ftp.GetFile(f.Name, f.Name, false);
ftp.RemoveFile(f.Name);
}
}
And here is the file system version:
//var logRoot = Server.MapPath("~/../../LogFiles/http/RawLogs"); //Throws error about traversal outside of site root
//var logRoot = "/LogFiles/http/RawLogs"; //Throws error: Could not find a part of the path 'D:\LogFiles\http\RawLogs'.
var logRoot = "LogFiles/http/RawLogs"; //Throws error: Could not find a part of the path 'D:\Windows\system32\LogFiles\http\RawLogs'.
foreach (var f in new DirectoryInfo(logRoot).GetFiles("*.log"))
{
f.CopyTo(root + f.Name, true);
f.Delete();
}
I see the problem with paths to the log files. AzureWebsites uses C Drive, but in your implementation you are getting D Drive. Use Server.MapPath("~") and then do string manipulations on top of it to get the right ROOT Path. So Root directory will be having two more directories - LogFiles and Site. As you already got the Root directory, append it with LogFiles directory and read all files from there.

How to Create a Managed Path through SharePoint Object Model

This is a question for a WSS/SharePoint guru.
Consider this scenario: I have an ASP.Net web service which links our corporate CRM system and WSS-based intranet together. What I am trying to do is provision a new WSS site collection whenever a new client is added to the CRM system. In order to make this work, I need to programmatically add the managed path to the new site collection. I know that this is possible via the Object Model, but when I try it in my own web service, it fails. Sample code extract below:
Dim _ClientSiteUrl As String = "http://myintranet/clients/sampleclient"
Using _RootWeb As SPSite = New SPSite("http://myintranet")
Dim _ManagedPaths As SPPrefixCollection = _RootWeb.WebApplication.Prefixes
If Not (_ManagedPaths.Contains(_ClientSiteUrl)) Then
_ManagedPaths.Add(_ClientSiteUrl, SPPrefixType.ExplicitInclusion)
End If
End Using
This code fails with a NullReferenceException on SPUtility.ValidateFormDigest(). Research suggested that this may be due to insufficient privileges, I tried running the code within an elevated privileges block using SPSecurity.RunWithElevatedPrivileges(AddressOf AddManagedPath), where AddManagedPath is a Sub procedure containing the above code sample.
This then fails with an InvalidOperationException, "Operation is not valid due to the current state of the object."
Where am I going wrong?
One workaround I have managed to do is to call out to STSADM.EXE via Process.Start(), supplying the requisite parameters, and this works.
Update: whilst developing the web service, I am running it using the built-in Visual Studio 2005 web server - what security context will this be running under? Can I change the security context by putting entries in web.config?
Update: I think the problem is definitely to do with not running the web service within the correct SharePoint security context. I decided to go with the workaround I suggested and shell out to STSADM, although to do this, the application pool identity that the web service runs under must be a member of the SharePoint administrators.
Update
I think you have proved that the issue is not with the code.
SPSecurity.RunWithElevatedPrivileges: Normally the code in the SharePoint web application executes with the privileges of the user taking the action. The RunWithElevatedPrivileges runs the code in the context of the SharePoint web application pools account (i think)
The description on MSDN could go into the details a tiny bit more.
The issue with the call may be that the web service is not actually running the code within a SharePoint process, so explaining why it cannot elevate (wild guess alert).
Have a crack at changing the user of your web services application pool and see if that gives any joy.
It is likely to be a permissions issue.
Maybe try:
Dim clientSiteUrl As String = "http://myintranet/clients/sampleclient"
Using SPSite = new SPSite(clientSiteUrl)
webApp As SPWebApplication = SPWebApplication.Lookup(new Uri(clientSiteUrl));
If Not (webApp.Prefixes.Contains(clientSiteUrl)) Then
webApp.Prefixes.Add(clientSiteUrl, SPPrefixType.ExplicitInclusion)
End If
End Using
This is not exact code.
Since the above code is not the exact code, here is the exact working code for a Web Application scopped feature in the Feature Activated event:
On feature activation at the Mange web application features page, activate feature will create a new Explicit managed path in the specified web application (I want to replace the hard coding, maybe with Properties.Feature.Parent, or something similar.)
using (SPSite site = new SPSite("http://dev-moss07-eric/PathHere")) {
SPWebApplication webApp = SPWebApplication.Lookup(new Uri("http://dev-moss07-eric"));
if (webApp.Prefixes.Contains("PathHere"))
{
//
}
else
{
webApp.Prefixes.Add("PathHere", SPPrefixType.ExplicitInclusion);
}
}
Code can probably be improved, but its my attempt at converting the above code.
If you want to create a managed path (explicit) and a site collection at that path, do the following:
using (SPSite site = new SPSite("http://dev-moss07-eric")) {
SPWebApplication webApp = SPWebApplication.Lookup(new Uri("http://dev-moss07-eric"));
if (webApp.Prefixes.Contains("ManagedPathHere"))
{
//
}
else
{
webApp.Prefixes.Add("ManagedPathHere", SPPrefixType.ExplicitInclusion);
}
using (SPWeb web = site.OpenWeb())
{
SPWebApplication webApplication = web.Site.WebApplication;
try
{
webApplication.Sites.Add("ManagedPathHere","Site Title Here","This site is used for hosting styling assets.", 1033, "STS#1", "6scdev\\eric.schrader", "Eric Schrader", "eric.schrader#6sc.com");
}
catch (Exception ex)
{
//ex.ToString;
}
}
}

Resources