2017-02-19 30 views
2

Я пробовал много решений, но не работал Пожалуйста, помогите мне исправить эту проблему. Ниже приведен код, используемый в SSIS Script TaskНе удалось закрыть excel даже после освобождения ресурсов

using Excel = Microsoft.Office.Interop.Excel;   
      Excel.Application xlApp = null; 
      Excel.Workbooks workbooks = null; 
      Excel.Workbook xlWorkbook = null; 
      Excel.Worksheet worksheet = null; 
      Excel.Range xlRange = null;       
     try 
      { 

      xlApp = new Excel.Application(); 
      xlApp.DisplayAlerts = false; 
      xlApp.AskToUpdateLinks = false; 
      workbooks = xlApp.Workbooks; 
      xlWorkbook = workbooks.Open("sample.csv", 2, true); 
      xlWorksheet = xlWorkbook.Sheets[1]; 
      xlRange = xlWorksheet.UsedRange; 
      int rowCount = xlRange.Rows.Count; 
      for (int row = 2; row <= rowCount; row++) 
      { 
       //some logic 

      } 
      } 
    catch (Exception ex) 
    { 
     MessageBox.Show(ex.Message); 
    } 
    finally //releasing all resources 
    { 
     GC.Collect(); 
     GC.WaitForPendingFinalizers(); 
     Marshal.ReleaseComObject(xlRange); 
     Marshal.ReleaseComObject(xlWorksheet); 
     xlRange = null; 
     xlWorksheet = null; 
     xlWorkbook.Close(); 
     Marshal.ReleaseComObject(xlWorkbook); 
     xlWorkbook = null; 
     workbooks = null; 
     xlApp.Quit(); 
     Marshal.ReleaseComObject(xlApp); 
     xlApp=null; 
} 

даже после освобождения ресурсов, по-прежнему видим один процесс первенствовать

ответ

0

Похоже, что вы на правильном пути. Тем не менее, вы в настоящее время являетесь его ExcelApplication, который является фактическим процессом, который вы увидите в Мониторе задач и его ExcelDocument, который должен быть закрыт до того, как WordApplication можно будет убить.

Взгляните на этом простом примере:

public void Foo(string filePath) 
{ 
    var application = new Excel.Application(); 

    // do your stuff here... 
    var document = application.Workbooks.Open(filePath, ReadOnly: true, Visible: false); 

    // this is the magic: clear 'application' and 'document', 
    // once the work is finished 
    if (document != null) 
     document.Close(SaveChanges: false); 

    if (application != null) 
     application.Quit(SaveChanges: false); 

    document = null; 
    application = null; 
} 

Здесь вы увидите, что мы на самом деле правильно Close() учебное пособие (документ) и Quit() приложение. Это часть того, что вы делаете в секции finally, но помните, что переменные инициализированы до вы можете в разделе try ....

Мой совет здесь: не называть сборку мусора (GC) и маршал вручную. Если вы не совсем уверены, что он делает, это может повредить вам позже побочными эффектами. Затем вы можете улучшить выборку, добавив красивую структуру using (...) вокруг ExcelApplication и ExcelWorkbook.

1

Есть два способа для достижения этой цели:

Первый метод

Вы можете создать собственный ReleaseObject функции, как показано ниже:

private void ReleaseObject(object obj) 
{ 
    try { 
     int intRel = 0; 
     do { 
      intRel = System.Runtime.InteropServices.Marshal.ReleaseComObject(obj); 
     } while (intRel > 0); 

    } catch (Exception ex) { 

     obj = null; 
    } finally { 
     GC.Collect(); 
    } 
} 

И используйте следующий порядок код:

xlWorkBook.SaveAs("...."); 
xlWorkBook.Close(); 
xlApp.Quit(); 

ReleaseObject(xlRange); 
ReleaseObject(xlWorkSheet); 
ReleaseObject(xlWorkBook); 
ReleaseObject(xlApp); 

Второй метод

Создание класса внутри задачи сценария, создать функцию, получить идентификатор процесса Excel.Application и убить его

using Excel = Microsoft.Office.Interop.Excel; 
using System.Runtime.InteropServices; 
using System.Diagnostics; 

class Sample 
{ 
    [DllImport("user32.dll")] 
    static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId); 

    Process GetExcelProcess(Excel.Application excelApp) 
    { 
     int id; 
     GetWindowThreadProcessId(excelApp.Hwnd, out id); 
     return Process.GetProcessById(id); 
    } 
} 

, а затем вы можете использовать GetExcelProcess(XlApp).Kill();

0

Правильно очистки up Interop.Excel объектов трудно. Сделайте это неправильно, и вы можете запустить игру SQL или SSIS с множеством экземпляров Zombie Excel.

enter image description here

Интернет является litteredwithadvice о том, как правильно Close(), Quit(), ReleaseObject()Interop.Excel объектов. Совет, который работает для вас, будет зависеть от того, какой порядок вы называете своими объектами и какие методы вы называете. Например, если вы использовали double dot method, тогда вы создали непривлекательный объект. Даже если вы прислушаетесь ко всем советам и структурируете свой код, чтобы избежать ошибок, все меняется, когда пакет SSIS развертывается на сервере.Microsoft в основном сообщила разработчикам, что not do this.

Microsoft в настоящее время не рекомендуется, и не поддерживает, автоматизации приложений Microsoft Office из любого без присмотра, не интерактивного клиентского приложения или компоненты (включая ASP, ASP.NET, DCOM и NT Services), потому что Бюро может проявлять нестабильное поведение и/или тупик, когда Office запущен в этой среде.

Странные вещи случаются. Кроме того, он не масштабируется. Пакеты будут иметь один и тот же экземпляр Excel. Процедура очистки одного пакета может убить в полете другой пакет.

Слушайте, я знаю, что есть много способов, как на Interop.Excel и даже больше, как их очистить. Но эти статьи ориентированы на людей, которые запускают один экземпляр кода на своей машине. Это не рекомендуется для среды предприятия с SSIS. Да, это воняет.

Но есть решения! NetOffice похож на Interop.Excel и помогает обрабатывать закрытие и удаление COM-объектов. Мое сильное предпочтение EPPlus API очень легкое, похожее на Interop.Excel и 10X быстрее без проблем с очисткой. Он может делать почти все, что может сделать Interop, кроме печати и макросов. Даже лучше, чем C#, начнется с использования built-in SSIS Excel components, предоставленного Microsoft для работы с ETL.

Удачи вам!