1

VS2010には、ASP.NETMVC3プロジェクトとWindowsサービスプロジェクトの2つのプロジェクトを含むソリューションがあります。dll参照の問題が原因でサービスがクラッシュしています(ここで同様の質問を確認しましたが、特に関連性があるとは思われませんでした)。

Windowsサービスはディレクトリ構造をトラバースし、MVCサイトで表示されるhtmlファイルを作成します。このため、htmlファイルの作成にはHtmlAgilityPackdllを使用しています。

サイトの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; System.Collections.Genericを使用します。System.Linqを使用します。System.Webを使用します。Microsoft.Officeを使用します。Microsoft.Office.Interop.Wordを使用する; System.Diagnosticsを使用します。System.IOを使用します。System.Reflectionを使用します。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()
        {
        }
    }
}

どんな援助もいただければ幸いです!

4

1 に答える 1

1

表示されるエラー メッセージは完全に正確ではありません。HtmlAgilityPack が失敗しているか、それが依存しているアセンブリである可能性があるためです。通常、これらの問題はfuslogvwユーティリティを使用してデバッグできます。

于 2012-08-13T16:36:39.847 に答える