Я написал приложение, настроенное на доступ к нашему серверу, проверку наличия каких-либо ожидающих заданий, обработку этих заданий, если они есть, создание документа Excel с результатами, а затем отправку их по электронной почте нашему пользователю. Он написан на c#.net v3.5 с использованием Microsoft Excel 2010 и запускается каждые 30 минут через планировщик задач. Наш планировщик задач работает на сервере под управлением 2008 r2. Планировщик задач работает успешно, база данных успешно обновляется, как будто задание обрабатывается, однако он никогда не создает файл excel, и я не могу понять, почему. Если я вручную запускаю приложение на нашем сервере, оно работает без сучка и задоринки, но еще ни разу не сработало, когда его вызывает планировщик задач. Нет проблем с разрешениями, так как я администратор, и я даже пытался запустить его под учетными данными нашего ИТ-директора, но безрезультатно. Также проверил, что к папке есть полный доступ для создания/удаления/редактирования/и т.д. Также предпринята попытка указать абсолютный путь к файлу вместо относительного. Код, используемый для создания файла Excel, можно найти ниже, а также код для его вызова. Заранее спасибо.
Код Эксель:
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);
}
Код, вызывающий метод создания Excel:
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");
}
}