2012-08-13 90 views
1

我在VS2010中有一個解決方案,它包含兩個項目,一個ASP.NET MVC3項目和一個Windows服務項目。該服務由於dll參考問題而崩潰(我在這裏查看了類似的問題,並沒有什麼特別相關的)。Windows服務在運行時未找到引用的dll

windows服務遍歷一個目錄結構,並創建一個由MVC站點顯示的html文件。爲此,我使用HtmlAgilityPack dll創建html文件。

在該站點的Global.asax.cs中,調用一個方法來檢查服務是否已安裝,如果不是,則會安裝並運行它。這裏是文件:

using System.ServiceProcess; 
using System.Configuration.Install; 
using KBDocumentConverterService.Converter; 
using KBDocumentConverterService; 

namespace Knowledgebase 
{ 
    public class MvcApplication : System.Web.HttpApplication 
    { 
     ... 

     // Check if service has been stopped, start if it has 
     void CheckServiceStatus(ServiceController sc) 
     { 
      if (sc.Status == ServiceControllerStatus.Stopped) 
      { 
       sc.Start(); 
      } 
     } 

     // Check if service is installed, install if it has not, then check 
     // to see if it needs to be started 
     void TryInstallService() 
     { 
      ServiceController sc = ServiceController.GetServices() 
       .Where(service => service.ServiceName == "KBDocumentConverterService") 
       .FirstOrDefault(); 

      if (sc == null) 
      { 
       // Call static method that will attempt to install service 
       // and return bool representation of install's success 
       if (MyServiceInstaller.InstallMe()) 
       { 
        sc = ServiceController.GetServices() 
         .Where(service => service.ServiceName == "KBDocumentConverterService") 
         .FirstOrDefault(); 

        CheckServiceStatus(sc); 
       } 
      } 
      else 
      { 
       CheckServiceStatus(sc); 
      } 
     } 

     protected void Application_Start() 
     { 
      AreaRegistration.RegisterAllAreas(); 

      RegisterGlobalFilters(GlobalFilters.Filters); 
      RegisterRoutes(RouteTable.Routes); 

      TryInstallService(); 
     } 
    } 
} 

該服務正在安裝到LocalSystem帳戶;它將安裝,它將運行,但只要它獲取包含參考HtmlAgilityPack DLL,它拋出以下信息的異常類:如果我爲服務創建單獨的解決方案

Could not load file or assembly 'HtmlAgilityPack, Version=1.4.5.0, Culture=neutral, PublicKeyToken=bd319b19eaf3b43a' 
or one of its dependencies. The system cannot find the file specified. 

KBDocumentConverterService 
    at KBDocumentConverterService.Converter.ConvertToHtml.CreateContentList() 
    at KBDocumentConverterService.Converter.ConvertToHtml.RunConversion() 
    in C:\Documents and Settings\Administrator\My Documents\Dropbox\Programming\CSharp\Websites\Knowledgebase\ 
    KBDocumentConverterService\Converter\ConvertToHtml.cs:line 263 
    at KBDocumentConverterService.Service1.StartConversion() 
    in C:\Documents and Settings\Administrator\My Documents\Dropbox\Programming\CSharp\Websites\ 
    Knowledgebase\KBDocumentConverterService\Service1.cs:line 39 

,並安裝它,它會運行良好。如果包含在另一個項目的解決方案中,那麼爲什麼服務在參考路徑中存在困難(HtmlAgilityPack文件夾包含在服務項目文件夾中),我有點不知所措。

下面是在服務相關的類 -

用於編程安裝類:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Reflection; 
using System.Configuration.Install; 

namespace KBDocumentConverterService 
{ 
    public static class MyServiceInstaller 
    { 
     private static readonly string _exePath = Assembly.GetExecutingAssembly().Location; 

     public static bool InstallMe() 
     { 
      try 
      { 
       ManagedInstallerClass.InstallHelper(new string[]{ _exePath }); 
      } 
      catch 
      { 
       return false; 
      } 

      return true; 
     } 
    } 
} 

創建HTML文件,該DLL被引用的類:使用系統 ; using System.Collections.Generic;使用System.Linq的 ; using System.Web; 使用Microsoft.Office; 使用Microsoft.Office.Interop.Word; using System.Diagnostics;使用System.IO的 ; using System.Reflection; using KBDocumentConverterService.Models; 使用HtmlAgilityPack;

namespace KBDocumentConverterService.Converter 
{ 
    public class ConvertToHtml 
    { 
     //This creates new object of Word.ApplicationClass 
     static Microsoft.Office.Interop.Word.Application objWord; 

     // Directory for files converted from Word docs to Html. 
     static readonly string _htmlKnowledgeBaseDir = Path.GetPathRoot(Environment.SystemDirectory) + 
      "\\Knowledgebase\\HTML"; 

     // Directory for Word files to be converted. 
     static readonly string _docKnowledgeBaseDir = Path.GetPathRoot(Environment.SystemDirectory) + 
      "\\Knowledgebase\\DOCS"; 

     // Directory for holding the Content List which represents the knowledgebase 
     // directory and file structure. Will be used to create menu for user to browse 
     // articles. 
     static readonly string _htmlContentDir = Path.GetPathRoot(Environment.SystemDirectory) + 
      "\\Knowledgebase\\Content"; 

     //Path to upload files "Uploaded" 
     static string strPathToUpload; 

     //Path to convert uploaded files and save 
     static string strPathToConvert; 

     //For filtered HTML Output 
     static object fltDocFormat = 10; 

     //Is just to skeep the parameters which are passed as boject reference, these are seems to be optional parameters 
     static object missing = System.Reflection.Missing.Value; 

     static object readOnly = false; 

     //The process has to be in invisible mode 
     static object isVisible = false; 

     // List of files that have already been converted to html 
     static List<string> _htmlKnowledgebaseFiles = new List<string>(); 

     // List of file contained in the folder structure that represents 
     // a knowledgebase; these files will be converted to html to be 
     // displayed on a website. 
     static List<string> _docKnowledgebaseFiles = new List<string>(); 

     static void ConvertDocToHTML(string fileName) 
     { 
      try 
      { 
       objWord = new Microsoft.Office.Interop.Word.Application(); 

       //To check the file extension if it is word document or something else 
       string strFileName = Path.GetFileNameWithoutExtension(fileName); 
       string strExt = Path.GetExtension(fileName); 

       //Map-path to the folder where html to be saved 
       strPathToConvert = Path.GetDirectoryName(fileName).Replace("Knowledgebase\\DOCS", "Knowledgebase\\HTML"); 

       object FileName = fileName.Clone(); 
       object FileToSave = strPathToConvert + "\\" + strFileName + ".htm"; 

       if(!File.Exists((string) FileToSave)) 
       { 
        if (strExt.ToLower().Equals(".doc") || strExt.ToLower().Equals(".docx")) 
        { 
         //open the file internally in word. In the method all the parameters should be passed by object reference 
         objWord.Documents.Open(ref FileName, ref readOnly, ref missing, ref missing, ref missing, ref missing, 
         ref missing, ref missing, ref missing, ref missing, ref isVisible, ref missing, ref missing, ref missing, 
         ref missing, ref missing); 

         //Do the background activity 
         objWord.Visible = false; 
         Microsoft.Office.Interop.Word.Document oDoc = objWord.ActiveDocument; 

         //Save to Html format 
         oDoc.SaveAs(ref FileToSave, ref fltDocFormat, ref missing, ref missing, ref missing, ref missing, 
         ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, ref missing, 
         ref missing, ref missing); 
        } 
       } 

       //Close/quit word 
       ((_Application)objWord).Quit(); 

       _htmlKnowledgebaseFiles.Add((string) FileToSave); 
      } 
      catch(Exception ex) 
      { 
       ((_Application)objWord).Quit(); 
      } 
     } 

     // Check that knowledgebase folders exist. 
     static void InitialiseFolders() 
     { 

      if(!Directory.Exists(_docKnowledgeBaseDir)) 
      { 
       Directory.CreateDirectory(_docKnowledgeBaseDir); 
      } 

      if(!Directory.Exists(_htmlKnowledgeBaseDir)) 
      { 
       Directory.CreateDirectory(_htmlKnowledgeBaseDir); 
      } 

      if (!Directory.Exists(_htmlContentDir)) 
      { 
       Directory.CreateDirectory(_htmlContentDir); 
      } 
     } 

     //Initialise lists that contain files to be converted, and converted files. 
     static void InitialiseFileCollections() 
     { 
      // Check if converted document's source still exists. If it does, add to convertedFileNames list, 
      // otherwise delete it so that the "HTMLKnowledgeBase" structure is consistent with the 
      // "DOCKnowledgeBase" structure. 
      try 
      { 
       // Get all HTML and HTM files. 
       string[] convertedFiles = Directory.GetFiles(_htmlKnowledgeBaseDir, "*.*", SearchOption.AllDirectories) 
        .Where(file => file.ToLower().EndsWith("htm") || file.ToLower().EndsWith("html")) 
        .ToArray(); 

       // Delete converted file if source does not exist 
       foreach (string file in convertedFiles) 
       { 
        if (!File.Exists(file.Replace("Knowledgebase\\HTML", "Knowledgebase\\DOCS").Replace(".htm", ".doc")) || 
         !File.Exists(file.Replace("Knowledgebase\\HTML", "Knowledgebase\\DOCS").Replace(".html", ".doc")) || 
         !File.Exists(file.Replace("Knowledgebase\\HTML", "Knowledgebase\\DOCS").Replace(".htm", ".docx")) || 
         !File.Exists(file.Replace("Knowledgebase\\HTML", "Knowledgebase\\DOCS").Replace(".html", ".docx"))) 
        { 
         File.Delete(file); 

         // Delete folder that contains the content(images etc) for the html files. 
         if (Directory.Exists(Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file) + "_files")) 
         { 
          bool deleteFiles = true; 
          Directory.Delete(Path.GetDirectoryName(file) + "\\" + Path.GetFileNameWithoutExtension(file) + "_files", deleteFiles); 
         } 
        } 
        else 
        { 
         _htmlKnowledgebaseFiles.Add(file); 
        } 
       } 
      } 
      catch (UnauthorizedAccessException uaEx) 
      { 
       // To implement 
      } 
      catch (IOException ioEx) 
      { 
       // To implement 
      } 

      // Get all files in the "DOCKnowledgeBase" folder. 
      string[] filesToConvert = Directory.GetFiles(_docKnowledgeBaseDir, "*.*", SearchOption.AllDirectories) 
       .Where(file => file.ToLower().EndsWith("doc") || file.ToLower().EndsWith("docx")) 
       .ToArray(); 

      // Check each file to be converted, if there is no corresponding converted file, add 
      // to list. 
      foreach (string file in filesToConvert) 
      { 
       if(!_docKnowledgebaseFiles.Contains(file)) _docKnowledgebaseFiles.Add(file); 
      } 
     } 

     // Traverse list of files to be converted and convert. 
     static void ConvertFiles() 
     { 
      foreach (string file in _docKnowledgebaseFiles) 
      { 
       if (!File.Exists(file.Replace("Knowledgebase\\DOCS", "Knowledgebase\\HTML").Replace(".doc", ".html")) && 
         !File.Exists(file.Replace("Knowledgebase\\DOCS", "Knowledgebase\\HTML").Replace(".docx", ".html")) && 
         !File.Exists(file.Replace("Knowledgebase\\DOCS", "Knowledgebase\\HTML").Replace(".doc", ".htm")) && 
         !File.Exists(file.Replace("Knowledgebase\\DOCS", "Knowledgebase\\HTML").Replace(".docx", ".htm"))) 
       { 

        if (!Directory.Exists(Path.GetDirectoryName(file).Replace("Knowledgebase\\DOCS", "Knowledgebase\\HTML"))) 
        { 
         Directory.CreateDirectory(Path.GetDirectoryName(file).Replace("Knowledgebase\\DOCS", "Knowledgebase\\HTML")); 
        } 

        ConvertDocToHTML(file); 
       } 
      } 
     } 


     static void GenerateHTML(DirectoryModel directory, HtmlDocument listFileDoc, HtmlNode directoryDiv) 
     { 
      HtmlNode linkContainerNode = listFileDoc.CreateElement("ul"); 

      foreach (string key in directory.Files.Keys) 
      { 
       HtmlNode listItem = listFileDoc.CreateElement("li"); 
       HtmlTextNode textNode = listFileDoc.CreateTextNode(key); 
       listItem.AppendChild(textNode); 

       HtmlAttribute id = listFileDoc.CreateAttribute("id", directory.Files[key]); 
       listItem.Attributes.Add(id); 

       linkContainerNode.AppendChild(listItem); 
      } 

      directoryDiv.AppendChild(linkContainerNode); 

      HtmlNode subdirectoryNode = listFileDoc.CreateElement("div"); 
      linkContainerNode.AppendChild(subdirectoryNode); 

      foreach(DirectoryModel subdirectory in directory.Subdirectories) 
      { 
       GenerateHTML(subdirectory, listFileDoc, subdirectoryNode); 
      } 
     } 

     // Create and populate html file to represent the existing knowledgebase 
     // file and directory structure. 
     static void CreateContentList() 
     { 
      string listFilePath = String.Empty; 

      // If no content list file exists, create it. if one does exist, create an alternative, this version 
      // will be pulled up by the site, and renamed to replace the orginal content list file. This is to ensure 
      // there are no errors with the site and this class trying to open the same file. 
      if (!File.Exists(_htmlContentDir + "\\content_list.htm")) 
      { 
       FileStream fs = File.Create(_htmlContentDir + "\\content_list.htm"); 
       listFilePath = _htmlContentDir + "\\content_list.htm"; 
       fs.Close(); 
      } 
      else 
      { 
       FileStream fs = File.Create(_htmlContentDir + "\\content_list_new.htm"); 
       listFilePath = _htmlContentDir + "\\content_list_new.htm"; 
       fs.Close(); 
      } 

      //Create html document 
      HtmlDocument listFileDoc = new HtmlDocument(); 
      listFileDoc.Load(listFilePath); 

      // Create instance of DirectoryModel which will hold knowledgebase directory and file structure 
      DirectoryModel rootDirectory = DirectoryModel.GenerateDirectoryStructure(_htmlKnowledgeBaseDir); 

      foreach(DirectoryModel directory in rootDirectory.Subdirectories) 
      { 
       HtmlNode directoryDiv = listFileDoc.CreateElement("div"); 
       GenerateHTML(directory, listFileDoc, directoryDiv); 
       listFileDoc.DocumentNode.ChildNodes.Add(directoryDiv); 
      } 

      listFileDoc.Save(listFilePath); 
     } 

     public static void RunConversion() 
     { 
      InitialiseFolders(); 
      InitialiseFileCollections(); 
      ConvertFiles(); 
      CreateContentList(); 
     } 
    } 
} 

而服務本身:

using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Diagnostics; 
using System.Linq; 
using System.ServiceProcess; 
using System.Text; 
using System.IO; 
using System.Threading; 
using KBDocumentConverterService.Converter; 

namespace KBDocumentConverterService 
{ 
    public partial class Service1 : ServiceBase 
    { 
     Thread conversionThread; 

     public Service1() 
     { 
      InitializeComponent(); 
      this.ServiceName = "KBDocumentConverterService"; 
     } 

     public string Name 
     { 
      get { return this.ServiceName; } 
     } 

     protected void StartConversion() 
     { 
      try 
      { 
       while (true) 
       { 
        if(!File.Exists("C:\\Service.txt")) 
         File.Create("C:\\Service.txt").Close(); 

        ConvertToHtml.RunConversion(); 
        Thread.Sleep(60000); 
       } 
      } 
      catch (Exception ex) 
      { 
       StreamWriter sw = File.AppendText("C:\\Service.txt"); 
       string mess = ex.Message + "\n" + ex.InnerException + "\n" + ex.Source + "\n" + ex.StackTrace; 
       sw.WriteLine(mess); 
       sw.Flush(); 
       sw.Close(); 
      } 
     } 

     protected override void OnStart(string[] args) 
     { 
      conversionThread = new Thread(new ThreadStart(StartConversion)); 

      conversionThread.Start(); 
     } 

     protected override void OnStop() 
     { 
     } 
    } 
} 

任何援助將不勝感激!

+1

好的,所以我知道它與問題沒有關係,但是......您授予ASP.NET Serice Pool安裝服務的權利?作爲LocalSystem?從安全角度來看,這不是最佳做法。當然有更好的辦法呢? – blowdart 2012-08-13 18:13:07

+0

我刪除了對ManagedInstallerHelper的直接調用,將​​其放到第三個項目中;如果服務看起來不存在,我只需從bin文件夾中的位置運行此程序集。 這樣做,隨着將DLL放入bin文件夾並相應地更新引用似乎也解決了我最初的問題。 感謝您的輸入! – achillesminor 2012-08-13 21:52:34

回答

1

您收到的錯誤信息並不完全準確,因爲它可能是HtmlAgilityPack失敗或它依賴的某個程序集。您通常可以使用fuslogvw實用程序調試這些問題。

+0

我在日誌中沒有看到任何內容,但在閱讀blowdart的評論之後,我刪除了對ManagedInstallerClass的直接調用,將​​它放到第三個項目中,並在檢查過程是否存在時從Global文件中簡單地運行該過程。 這與將dll移動到站點的bin文件夾並引用該位置似乎緩解了問題。 – achillesminor 2012-08-13 21:53:14

+0

感謝您的意見。 – achillesminor 2012-08-13 21:54:07

相關問題