Question

I wrote an application which is setup to hit our server, check if there are any pending jobs created, process those jobs if there are any available, create an excel document with the results, then email them to our user. It is written in c#.net v3.5 utilizing microsoft excel 2010 and is launched every 30 minutes via task scheduler. Our task scheduler operates on a server running 2008 r2. The task scheduler runs successfully, the database is successfully updated as if the job is processed, however, it never creates an excel file and I cannot figure out why. If I manually run the application on our server machine it runs without a hitch, but has yet to work even once when the task scheduler invokes it. There are no permissions issues as I am an administrator and I have even attempted to run it under our IT directors credentials to no avail. Also checked that the folder has full access to create/delete/edit/etc. Also attempted to supply an absolute path to the file in lieu of a relative one. The code used to create the excel file may be found below as well as the code to call it. Thanks in advance.

Excel code:

public static void Export(System.Data.DataTable dt,
                                  string FileName,
                                  string EmailTo)
        {
            Application xls = new Application();
            xls.SheetsInNewWorkbook = 1;

            // Create our new excel application and add our workbooks/worksheets
            Workbooks workbooks = xls.Workbooks;
            Workbook workbook = workbooks.Add();
            Worksheet CompPartsWorksheet = (Worksheet)xls.Worksheets[1];

            // Hide our excel object if it's visible.
            xls.Visible = false;

            // Turn off screen updating so our export will process more quickly.
            xls.ScreenUpdating = false;

            // Turn off calculations if set to automatic; this can help prevent memory leaks.
            xls.Calculation = xls.Calculation == XlCalculation.xlCalculationAutomatic ? XlCalculation.xlCalculationManual : XlCalculation.xlCalculationManual;

            // Create an excel table and fill it will our query table.
            CompPartsWorksheet.Name = "Comp Request";
            CompPartsWorksheet.Select();
            {

                // Create a row with our column headers.
                for (int column = 0; column < dt.Columns.Count; column++)
                {
                    CompPartsWorksheet.Cells[1, column + 1] = dt.Columns[column].ColumnName;
                }

                // Export our datatable information to excel.
                for (int row = 0; row < dt.Rows.Count; row++)
                {
                    for (int column = 0; column < dt.Columns.Count; column++)
                    {
                        CompPartsWorksheet.Cells[row + 2, column + 1] = (dt.Rows[row][column].ToString());
                    }
                }
            }

            // Freeze our column headers.
            xls.Application.Range["2:2"].Select();
            xls.ActiveWindow.FreezePanes = true;
            xls.ActiveWindow.DisplayGridlines = false;

            // Autofit our rows and columns.
            xls.Application.Cells.EntireColumn.AutoFit();
            xls.Application.Cells.EntireRow.AutoFit();

            // Select the first cell in the worksheet.
            xls.Application.Range["$A$2"].Select();

            // Turn off alerts to prevent asking for 'overwrite existing' and 'save changes' messages.
            xls.DisplayAlerts = false;

            // ******************************************************************************************************************
            // This section is commented out for now but can be enabled later to have excel sheets show on screen after creation.
            // ******************************************************************************************************************
            // Make our excel application visible
            //xls.Visible = true;

            //// Turn screen updating back on
            //xls.ScreenUpdating = true;

            //// Turn automatic calulation back on
            //xls.Calculation = XlCalculation.xlCalculationAutomatic;

            string SaveFilePath = string.Format(@"{0}\Jobs\{1}.xlsx", Directory.GetCurrentDirectory(), FileName);
            // string SaveFilePath = @"\\netapp02\Batch_Processes\Comp_Wisp\Comp_Wisp\bin\Debug\Jobs";
            workbook.SaveAs(SaveFilePath, XlFileFormat.xlWorkbookNormal, Type.Missing, Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlExclusive, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
            workbook.Close();

            // Release our resources.
            Marshal.ReleaseComObject(workbook);
            Marshal.ReleaseComObject(workbooks);
            Marshal.ReleaseComObject(CompPartsWorksheet);
            Marshal.ReleaseComObject(xls);
            Marshal.FinalReleaseComObject(xls);

            Send(Subject: FileName,
                 AttachmentPath: SaveFilePath,
                 EmailTo: EmailTo);
        }

Code Calling the Excel Creation Method:

public static void ProcessJob(System.Data.DataTable Job)
        {
            try
            {
                for (int j = 0; j < Job.Rows.Count; j++)
                {
                    // Temporary datatable to store our excel data.
                    System.Data.DataTable dt = new System.Data.DataTable();

                    // Output the current job name and split out our parts.
                    Console.Write(string.Format("JOB: {0}\r\n", Job.Rows[j]["JobID"]));
                    string[] searchlines = Job.Rows[j]["PartsList"].ToString().Replace("\n", "|").Split('|');

                    if (searchlines.Count() > MAX_TO_PROCESS)
                    {
                        // If our search is going to be above the desired processing maximum start the next job as well.
                        Thread RecursiveJob = new Thread(GetJob);
                        RecursiveJob.Start();
                    }

                    for (int i = 0; i < searchlines.Count(); i++)
                    {
                        // Determine if data reporting is turned on or off.
                        Boolean isReporting = DataCollection();
                        if (searchlines[i].Trim() != string.Empty)
                        {
                            Console.WriteLine(string.Format("Processing: {0}", searchlines[i]));
                            using (SqlConnection con = new SqlConnection(dbComp))
                            {
                                using (SqlDataAdapter da = Connect.ExecuteAdapter("[CompDatabase_SelectPartsFromComp]", con,
                                                                                     new SqlParameter("@PartNumber", searchlines[i].Trim()),
                                                                                     new SqlParameter("@CurrentMember", Job.Rows[j]["Email"].ToString()),
                                                                                     new SqlParameter("@DataCollection", isReporting)))
                                {
                                    da.Fill(dt);
                                }
                            }
                        }
                    }

                    // Export our datatable to an excel sheet and save it.
                    try
                    {
                        Export(dt: dt,
                               FileName: string.Format("Comp Scheduled Job {0}", Job.Rows[j]["JobID"].ToString()),
                               EmailTo: Job.Rows[j]["Email"].ToString().Trim());
                    }
                    catch (Exception ex)
                    {
                        ErrorLog.Write(SourceName: "Comp Wisp",
                                       ErrorMessage: ex.ToString(),
                                       MethodOrFunction: "ProcessJob",
                                       MemberName: Environment.UserName,
                                       ErrorDescription: string.Format("Failed to create excel file on Job {0}.", Job.Rows[j]["JobID"].ToString()));
                    }

                    // Update the job to Complete in our database.
                    using (SqlConnection con = new SqlConnection(dbComp))
                    {
                        Console.WriteLine("Updating Job Status");
                        using (SqlDataReader dr = Connect.ExecuteReader("[CompWisp_UpdateJobStatus]", con,
                                                                           new SqlParameter("@JobID", Job.Rows[j]["JobID"].ToString()))) { }
                    }
                    Console.Write("Complete\r\n\r\n");
                }
                GetJob();
            }
            catch (Exception ex)
            {
                ErrorLog.Write(SourceName: "CompWisp",
                               ErrorMessage: ex.ToString(),
                               MethodOrFunction: "ProcessJob");
            }
        }
Was it helpful?

Solution

The call to Directory.GetCurrentDirectory() might be returning a different value when the Task Scheduler runs the job, versus when you run the app manually.

To test this, you could try doing a search on the server for the missing excel files.

OTHER TIPS

There are a couple of things you might try:

  1. Make sure the user that the task is running under does not have UAC on. This can cause execution problems.

  2. As well, see if the following article helps. The answer (perhaps) is the first listed response: MSDN forum question.

I had trouble getting Task Scheduler to run apps that create Excel spreadsheets. I needed to create this folder to get it working. C:\windows\syswow64\config\systemprofile\desktop

This is where I got the information from

Reading excel using microsoft interop in 64 bit

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top