[C#] 什么是安装.Net服务期间创建自定义事件日志和事件源的最可靠的方法


Answers

ServiceInstaller类自动创建一个EventLogInstaller ,并将其放入其自己的Installers集合中。

试试这个代码:

ServiceProcessInstaller serviceProcessInstaller = new ServiceProcessInstaller();
serviceProcessInstaller.Password = null;
serviceProcessInstaller.Username = null;
serviceProcessInstaller.Account = ServiceAccount.LocalSystem;

// serviceInstaller
ServiceInstaller serviceInstaller = new ServiceInstaller();
serviceInstaller.ServiceName = "MyService";
serviceInstaller.DisplayName = "My Service";
serviceInstaller.StartType = ServiceStartMode.Automatic;
serviceInstaller.Description = "My Service Description";
// kill the default event log installer
serviceInstaller.Installers.Clear(); 

// Create Event Source and Event Log     
EventLogInstaller logInstaller = new EventLogInstaller();
logInstaller.Source = "MyService"; // use same as ServiceName
logInstaller.Log = "MyLog";

// Add all installers
this.Installers.AddRange(new Installer[] {
   serviceProcessInstaller, serviceInstaller, logInstaller
});
Question

在安装.Net Windows服务期间,我无法可靠地创建/删除事件源。

以下是我的ProjectInstaller类中的代码:

// Create Process Installer
ServiceProcessInstaller spi = new ServiceProcessInstaller();
spi.Account = ServiceAccount.LocalSystem;

// Create Service
ServiceInstaller si = new ServiceInstaller();
si.ServiceName = Facade.GetServiceName();
si.Description = "Processes ...";
si.DisplayName = "Auto Checkout";
si.StartType = ServiceStartMode.Automatic;

// Remove Event Source if already there
if (EventLog.SourceExists("AutoCheckout"))
    EventLog.DeleteEventSource("AutoCheckout");

// Create Event Source and Event Log     
EventLogInstaller log = new EventLogInstaller();
log.Source = "AutoCheckout";
log.Log = "AutoCheckoutLog";

Installers.AddRange(new Installer[] { spi, si, log });

引用的外观方法只是返回日志,服务等名称的字符串。

这段代码大部分时间工作,但最近安装后,我开始让我的日志条目显示在应用程序日志,而不是自定义日志。 以下错误也在日志中:

源(AutoCheckout)中的事件ID(0)的说明找不到。 本地计算机可能没有必要的注册表信息或消息DLL文件来显示来自远程计算机的消息。 您可能能够使用/ AUXSOURCE =标志来检索此说明; 详细信息请参阅帮助和支持。

由于某种原因,它在卸载过程中或者没有正确地移除源代码,或者在安装过程中没有创建它。

任何有关最佳做法的帮助,在此表示赞赏

谢谢!

另外,下面是我如何写日志的例外:

// Write to Log
EventLog.WriteEntry(Facade.GetEventLogSource(), errorDetails, EventLogEntryType.Error, 99);

关于stephbu的回答:建议的路径是安装程序脚本和installutil或Windows安装例程。

我正在使用安装项目,它执行服务的安装并设置日志。 无论我使用installutil.exe还是Windows安装项目,我都相信他们都会调用上面显示的同一个ProjectInstaller类。

我看到如果日志没有真正删除,直到重新启动,我的测试机器的状态可能会导致错误。 我会试验更多,看看是否解决了这个问题。

编辑:我有兴趣在安装服务的过程中注册源和日志名称。 因此,如果之前已经安装了该服务,则会在随后的安装过程中删除源代码或重新使用源代码。

我还没有机会学习WiX来尝试这条路线。




我不得不同意stephbu关于事件日志进入的“奇怪状态”,我之前遇到过。 如果我猜测,你的一些困难就在那里。

但是,我知道在应用程序中执行事件日志记录的最好方法实际上是使用TraceListener。 您可以通过服务的app.config配置它们:

http://msdn.microsoft.com/en-us/library/system.diagnostics.eventlogtracelistener.aspx

该页面中间附近有一节介绍如何使用EventLog属性指定要写入的EventLog。

希望有所帮助。




我有同样的问题。 在我看来,Windows安装程序似乎是自动添加与我的服务同名的事件源,这似乎会导致问题。 你是使用相同的名称为Windows服务和日志源? 尝试更改它,以便您的事件日志源被称为不同,然后服务的名称。




我只是在MSDN论坛上发布了一个解决方案,这是我设法使用标准安装MSI项目来解决这个问题。 我所做的就是将代码添加到PreInstall和Committed事件中,这意味着我可以将所有其他事物保持原样:

SortedList<string, string> eventSources = new SortedList<string, string>();
private void serviceProcessInstaller_BeforeInstall(object sender, InstallEventArgs e)
{
  RemoveServiceEventLogs();
}

private void RemoveServiceEventLogs()
{
  foreach (Installer installer in this.Installers)
    if (installer is ServiceInstaller)
    {
      ServiceInstaller serviceInstaller = installer as ServiceInstaller;
      if (EventLog.SourceExists(serviceInstaller.ServiceName))
      {
        eventSources.Add(serviceInstaller.ServiceName, EventLog.LogNameFromSourceName(serviceInstaller.ServiceName, Environment.MachineName));
        EventLog.DeleteEventSource(serviceInstaller.ServiceName);
      }
    }
}

private void serviceProcessInstaller_Committed(object sender, InstallEventArgs e)
{
  RemoveServiceEventLogs();
  foreach (KeyValuePair<string, string> eventSource in eventSources)
  {
    if (EventLog.SourceExists(eventSource.Key))
      EventLog.DeleteEventSource(eventSource.Key);

    EventLog.CreateEventSource(eventSource.Key, eventSource.Value);
  }
}

代码可以进一步修改,只删除尚不存在的事件源或创建它们(尽管日志名需要存储在安装程序的某处),但是由于我的应用程序代码实际上创建了事件源那么对我来说没有意义。 如果已经有事件,那么应该已经有一个事件源。 为了确保它们被创建,您可以自动启动服务。




以下helb的建议为我解决了这个问题。 杀死默认的事件日志安装程序,在他的例子中指出的点,阻止安装程序自动注册我的Windows服务下的应用程序事件日志。

试图解决这个令人沮丧的怪癖失去了太多的时间。 太感谢了!

FWIW,我不能修改我的设计器生成的ProjectInstaller类中的代码,而不会导致VS鲤鱼关于MODS。 我放弃了设计师生成的代码,并手动进入课堂。




一个简单的方法来改变默认行为(也就是说,项目安装程序使用应用程序日志中的服务名称来创建一个事件日志源文件),可以很容易地修改项目安装程序的构造函数,如下所示:

[RunInstaller( true )]
public partial class ProjectInstaller : System.Configuration.Install.Installer
{
    public ProjectInstaller()
    {
        InitializeComponent();

        //Skip through all ServiceInstallers.
        foreach( ServiceInstaller ThisInstaller in Installers.OfType<ServiceInstaller>() )
        {
            //Find the first default EventLogInstaller.
            EventLogInstaller ThisLogInstaller = ThisInstaller.Installers.OfType<EventLogInstaller>().FirstOrDefault();
            if( ThisLogInstaller == null )
                continue;

            //Modify the used log from "Application" to the same name as the source name. This creates a source in the "Applications and Services log" which separates your service logs from the default application log.
            ThisLogInstaller.Log = ThisLogInstaller.Source;
        }
    }
}