Getting OutOfMemoryException when load a document with Microsoft.Office.Interop from IIS website - c#

I have a .NET Core 6 web api that use Office interop to open a ppt document and convert it to pdf.
The application does not have problems when i debug it or when i publish it as a standalone application and run the .exe manually.
I need to publish the web api on IIS on a windows server but when i do i obtain the following error when try to call the api endpoint: "System.OutOfMemoryException: Insufficient memory to continue the execution of the program".
This is the method that made the conversion, exception is thrown by "pptApplication.Presentations.Open(originalPptPath, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse)"
public static bool PowerPointToPdf(string originalPptPath, string pdfPath)
{
PowerPoint.Application pptApplication = null;
PowerPoint.Presentation pptPresentation = null;
object unknownType = Type.Missing;
var result = false;
//start power point
pptApplication = new PowerPoint.Application();
//open powerpoint document
pptPresentation = pptApplication.Presentations.Open(originalPptPath, MsoTriState.msoTrue, MsoTriState.msoTrue, MsoTriState.msoFalse);
if (pptPresentation == null)
return false;
pptPresentation.ExportAsFixedFormat(pdfPath, PowerPoint.PpFixedFormatType.ppFixedFormatTypePDF, PowerPoint.PpFixedFormatIntent.ppFixedFormatIntentPrint);
result = true;
// Close and release the Document object.
if (pptPresentation != null)
{
pptPresentation.Close();
ReleaseObject(pptPresentation);
pptPresentation = null;
}
pptApplication.Quit();
ReleaseObject(pptApplication);
pptApplication = null;
return result;
}
I already tried to change the application pool identity with an admin user but nothing changed. I am aware that microsoft discourages the use of server-side office automation, i have already evaluated several libraries that don't use office automation to make the conversion, but the final result is qualitatively inferior.

You are on the right avenue - Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.
Microsoft strongly recommends that developers find alternatives to Automation of Office if they need to develop server-side solutions. Because of the limitations to Office's design, changes to Office configuration are not enough to resolve all issues. Microsoft strongly recommends a number of alternatives that do not require Office to be installed server-side, and that can perform most common tasks more efficiently and more quickly than Automation. Before you involve Office as a server-side component in your project, consider alternatives.
If you are dealing only with open XML documents in PowerPoint you may consider using the Open XML DSK for dealing with documents or converting them to another file format, see Welcome to the Open XML SDK 2.5 for Office for more information.
Or just consider using any third-party components designed for the server-side execution.

Related

System.Runtime.InteropServices.COMException (0x80004004): Operation aborted (0x80004004 (E_ABORT))

We have a Export Utility which exports all emails from Outlook to local directory. And our tools work perfectly fine. But now we are migrating to O365 and since then we are seeing issues with the tool.
Technically the does all the things like able to read all emails and its properties like Subject, From, To etc and also able to SAVE or MOVE to other folder within Outlook O365.
But I get an error "System.Runtime.InteropServices.COMException (0x80004004): Operation aborted (0x80004004 (E_ABORT))" as soon I execute SAVEAS.
Below is the sample code
public static void ReadEmails()
{
try
{
Outlook.Application oApp = new();
// Get the MAPI namespace.
Outlook.NameSpace oNs = oApp.GetNamespace("MAPI");
oNs.Logon("*****#*****.com", System.Reflection.Missing.Value,
System.Reflection.Missing.Value, System.Reflection.Missing.Value);
Outlook.Folders fols = oNs.Folders;
Outlook.MAPIFolder inboxFolder = fols["****"].Folders["Inbox"];
foreach (Outlook.Folder fol in inboxFolder.Folders)
{
MessageBox.Show(fol.Name);
Outlook.Items items = fol.Items;
foreach(Outlook.MailItem mailItem in items)
{
MessageBox.Show(mailItem.Subject);
try
{
//mailItem.Move(inboxFolder); -- this works
mailItem.SaveAs("test.msg", Outlook.OlSaveAsType.olMSG);
}
catch (System.Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
}
oNs.Logoff();
}
catch (System.Exception e)
{
Console.WriteLine("{0} Exception caught: ", e);
}
}
So do I have to do anything special?
FYI, the tool gets executed on user laptop as a user on his own email account.
The code looks good. I don't see anything strange there. But the following exception may indicate multiple issues:
System.Runtime.InteropServices.COMException (0x80004004): Operation aborted (0x80004004 (E_ABORT))
Most probably you have faced with a security issue in Outlook. "Security" in this context refers to the so-called "object model guard" that triggers security prompts and blocks access to certain features in an effort to prevent malicious programs from harvesting email addresses from Outlook data and using Outlook to propagate viruses and spam. These issues or prompts cannot simply be turned off, except in Outlook 2007 with an anti-virus application running.
The following strategies can be used for avoiding the security prompts/issues in Outlook:
A low-level API on which Outlook is based on - Extended MAPI (or any other third-party wrappers around that API, for example, Redemption).
Outlook Security Manager is a programming tool that allows you to suppress security alerts invoked by the code of your application or add-in that interacts with Microsoft Outlook 2000 - 2013.
In a corporate environment, the administrator may choose to loosen Outlook security for some or all users.
Develop a trusted COM add-in and call it for saving emails instead of using OOM directly. The add-in has access to a secure Application object which doesn't trigger security issues.
Another possible cause is that Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment. Here is what MS states for such cases:
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.
Read more about that in the Considerations for server-side Automation of Office article.
I was able to fix the issue by changing following registry value to 2 (make sure to open registry as ADMIN)
HKEY_USERS > S-1-5-21-1132323721-62323254-1511918330-144209 > SOFTWARE > Policies > Microsoft > office > 16.0 > outlook > security
(Computer\HKEY_USERS\S-1-5-21-1132323721-62323254-1511918330-144209\SOFTWARE\Policies\Microsoft\office\16.0\outlook\security)
Dword: PromptOOMSaveAs
Value: 2
Note: Above BOLD value > you can get this by running whoami /user in command prompt

Cannot save the attachment. The operation failed. An object cannot be found error in server

I am trying of save attachment of outlook mail, i am able to save attachment when it have data. but for empty attachment its throws exception that Cannot save the attachment. The operation failed. An object cannot be found.
In my local i am able to save but this issue is coming in server.
void saveattachments(Outlook.Attachment attachment)
{
string currentTime = DateTime.Now.ToString("hh_MM_ss");
try
{
attachment.SaveAsFile(GetConfigSettings("attachmentPath") + "\\attachment_" + "_" + currentTime + "_" + attachment.FileName);
}
catch(exception e)
{}
}
why it throws error in server for blank file but not in local.
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution. Read more about that in the Considerations for server-side Automation of Office article.
You may consider using MAPI instead (a low-level API on which Outlook is based on).

Open Powerpoint presentation from an ASP.NET Web app running localhost

I'm trying to execute a Powerpoint presentation from a .NET MVC Web app. I'm using the office.interopt.powerpoint libraries and everything works fine while i'm on VisualStudio. But, if i deploy the web app in a IISExpress server (not in VS), the Powerpoint application doesn't open as top-most window and it doesn't works properly, and if i deploy it in a IIS Server, the Powerpoint doesn't starts at all.
I know that the problem has something to be with the IISUSR credentials as i (as a web app) don't have the rights to execute the application.
The question is: is there a way to start a Powerpoint application as a different user using the interop libraries? I know it is possible to start a new Process as a different user with "ProcessStartInfo", but if i do that way i should execute one Powerpoint process for each presentation that i need to open and i wouldn't have access to the presentation's controls like nextSlide and so... The idea is to execute the Powerpoint once and then open, close and control many presentations.
The code that i have for now:
To start the Powerpoint app (this is executed once):
app = new Application();
app.Visible = MsoTriState.msoTrue;
app.PresentationClose += ClosePPT;
app.Activate();
app.WindowState = PpWindowState.ppWindowMinimized;
ppts = app.Presentations;
To open a new presentation:
public void LoadPPT(string pptPath)
{
try
{
//Close all opened presentations if any
if (ppts.Count > 0)
foreach (Presentation p in ppts)
p.Close();
//Open new presentation
ppt = ppts.Open(pptPath, MsoTriState.msoTrue, MsoTriState.msoFalse, MsoTriState.msoFalse);
SlideShowSettings sss = ppt.SlideShowSettings;
sss.Run();
while (app.SlideShowWindows.Count <= 0) ;
SlideShowWindow ssw = ppt.SlideShowWindow;
ssw.Activate();
//if (!SetWindowPos((IntPtr)ssw.HWND, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW))
//{
// int error = Marshal.GetLastWin32Error();
// NLog.LogManager.GetCurrentClassLogger().Debug("Error " + error);
//}
ssv = ssw.View;
}
catch (Exception e)
{
NLog.LogManager.GetCurrentClassLogger().Debug("Excepcion en PPT. " + e.Message);
while (e.InnerException != null)
{
NLog.LogManager.GetCurrentClassLogger().Debug("INNER. " + e.InnerException.Message);
e = e.InnerException;
}
}
}
As you can see, i've also tried to set the window of the slideshow presentation at top-most position using the Win32 "SetWindowPos", but with the same result.
I'm trying to execute a Powerpoint presentation from a .NET MVC Web app. I'm using the office.interopt.powerpoint libraries
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution. Read more about that in the Considerations for server-side Automation of Office article.
You may consider using any third-party components designed for the server-side execution (ASP.NET controls that can host PowerPoint presentations).

Remoting Automation of MS Office on the server

I'm warning you, that yhis question will seems to be very strange for a lot of people:) But I have to post it because my project manager is teeling me that a technical solution exist, even if for me it doesn't.
What we have:
A Windows 7 Console Application with no UI, with our C# application running and no Office and Interop on it
a Windows 2012 server, with Ms Office 2010 + Interop installed on it (also with IIS and .NET of course)
What my PM want (and I told him it is not possible) :
From my C# client application
Automate "Ms office" installed on the server
Automate means "Save" or "print" a doc file to a network printer.
Of course the Ms office process had to run on the server
This kind of solution of "remote Ms Office automation is possible" seems to be impossible for me. But maybe I am wrong, it can be possiblbe using DCOM, WCF, or something else?
Anyone can confirm I am right please ;)
As you already learned from the comments, automating the desktop version of any of the Office applications is bad for several reasons. The details can be found in the Knowledge base article KB257757 Considerations for server-side Automation of Office. The main take away from that article is:
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
But as you are still insisting, consider the following example as a very simple, naive, not to be used near production proof-of-concept that enables you to quickly run into all problems mentioned in the KB article.
In a fresh solution create a WCF Service application and a Console Application. In the WCF application add the following interface:
[ServiceContract]
public interface IPrintService
{
[OperationContract]
string Print(Stream wordDoc);
}
and have a service implement that. Make sure to add a reference to Microsoft.Office.Interop.Word that you can find in the COM tab of the Add Reference dialog.
public class PrintService : IPrintService
{
public string Print(Stream wordDocStream)
{
// copy our stream to a local file
var tempFile = Path.GetTempFileName();
using(var file = File.Create(tempFile))
{
wordDocStream.CopyTo(file);
}
// start word
var wordApp = new Microsoft.Office.Interop.Word.Application();
// setup printer
wordApp.ActivePrinter = "Canon LBP3010/LBP3018/LBP3050";
// open, collect data, print and close
var doc = wordApp.Documents.Open(tempFile);
doc.PrintOut();
var res = doc.Words.Count;
doc.Close(false);
// quit word
wordApp.Quit(false);
// delete temp file
File.Delete(tempFile);
return String.Format("{0} words", res);
}
}
You can see here a barebone solution to print a document that is sent as a stream to the Service. The service copies the stream to a file, starts Word, Opens the file, prints the document, get some data from the document and tears down and cleans up hen finished.
The client is straight forward:
using(var client = new PrintService.PrintServiceClient())
{
using(var file = File.Open(#"small.docx", FileMode.Open))
{
var response = client.Print(file);
Console.WriteLine(response);
}
}
This is technically all there is that is needed to print a Word document from a service. This runs without much problems on the dev server. If you run this on IIS you'll probably have to make sure that the account used as an identity in the AppPool is a "user" that can start Word, is allowed to access the printers etc. I already ran into one known issue: I used the XPS Print driver which caused a dialog to popup. That is something you can't have on a server and there is no real way to prevent or detect that.
Remember that this service interface only allows for a stream to be sent. If you want to add extra data you'll have to use a message contract as is explained on msdn in Large Data and Streaming. Your contract would have to look like this in that case:
[MessageContract]
public class UploadStreamMessage
{
[MessageHeader]
public string appRef;
[MessageBodyMember]
public Stream data;
}
If you run all this, (stress)test, consider deployment and install I'm sure you'll convince anyone that this isn't a good idea.

'Cannot create file' error while trying to send email with image from asp .net windows application using outllook

I am trying to send email from .net windows application using Microsoft.Office.Interop.Outlook. The mail is in html format and has an image embedded to it. Getting the following error when trying to attach the image,
"Cannot create file: XXX.jpg. Right-click the folder you want to create the file in, and then click Properties on the shortcut menu to check your permissions for the folder."
I dont have any issues with folder access. I am running the app on 64 bit computer with 32 bit outlook on it. When i dont embed image, i dont get any errors and it works fine.
string body = string.Empty;
using(StreamReader reader = new StreamReader(Environment.CurrentDirectory + #"/Mail Templates/XXX.txt"))
{
body = reader.ReadToEnd();
}
Outlook.Application oApp = new Outlook.Application();
Outlook._MailItem mailItem = (Outlook._MailItem)oApp.CreateItem(Outlook.OlItemType.olMailItem);
mailItem.To = "XXX";
string filename = Environment.CurrentDirectory + #"/Mail Templates/XXX.jpg";
mailItem.Attachments.Add(filename, (int)Outlook.OlAttachmentType.olEmbeddeditem, 1);
mailItem.HTMLbody = "true"
mailItem.Display(true);
Microsoft does not currently recommend, and does not support, Automation of Microsoft Office applications from any unattended, non-interactive client application or component (including ASP, ASP.NET, DCOM, and NT Services), because Office may exhibit unstable behavior and/or deadlock when Office is run in this environment.
If you are building a solution that runs in a server-side context, you should try to use components that have been made safe for unattended execution. Or, you should try to find alternatives that allow at least part of the code to run client-side. If you use an Office application from a server-side solution, the application will lack many of the necessary capabilities to run successfully. Additionally, you will be taking risks with the stability of your overall solution.
You can read more about that in the Considerations for server-side Automation of Office article.
You may consider using the EWS (Exchange Web Services) or BCL (Base Class Libraries from the .Net framework). See EWS Managed API, EWS, and web services in Exchange for more information.

Categories