5

我有一个执行许多定期活动的 Windows 服务,我想从 Windows 窗体应用程序更改此服务的设置。不过,我不确定确保服务中包含最新用户首选项的最佳方法(运行频率、用于事物的文件夹、用户可以指定的任何其他内容)。用户可以随时随意更改设置,我希望服务几乎立即知道它。以下是我正在权衡的选项:

  1. 表单和服务共享使用来自第三个共享项目的相同“设置”对象,并且表单使用 WCF“UpdateSettings(newSettings)”调用让服务知道发生了更改(或者,可以选择调用更新每个单独的设置,尽管这在不同的调用中似乎很多)。我目前将 WCF 用于基本消息,但设置对象可能很大,因为那里有很多其他的东西
  2. 表单和服务使用一个通用的配置文件(XML,或来自 #1 的相同设置对象,但序列化到磁盘)。表单只是在对象被更改后写入对象的新副本,服务会不时检查并拾取它,如果它是新的,则更新其设置副本
  3. 与 #2 相同,但有一个基本的 WCF 调用,告诉服务去获取设置。本质上,是#2 的“按需”而不是“轮询”版本。

我知道最好是主观的,但我对这些选择的任何明显的利弊原因感兴趣。由于我必须在应用程序运行(重新启动等)之间保存我的设置,所以无论如何我都必须将设置序列化到磁盘,所以我已经倾向于#2 或#3。我需要一个可以保存设置的磁盘位置,但也许 AppData 文件夹可以正常工作,尽管这只允许管理员更改设置,因为他们是唯一有权写入此位置的人(每个用户,包括服务帐户,都可以阅读它)。

感谢您的洞察力!

4

4 回答 4

3

我有点用你的2号。

但我只在 .NET 2 中使用我的应用程序,但它仍然应该适用。

我有一个在我的 2 个程序中使用的设置类。在这个设置类中,我设置了一个 查看设置文件的FileSystemWatcher对象。

如果设置文件被其他应用程序更新,我的当前会收到一个事件触发器,指示需要重新加载设置。

您还可以在设置屏幕中应用相同的原则,以便如果(服务)其他应用程序在设置编辑期间更新任何内容,则会反映在您的屏幕中。

我使用 AppData(我的公司/应用程序名称目录)来存储文件。

要记住的另一件事是,在写入文件时可以锁定文件,因此您可以使用临时名称保存、删除旧、重命名临时方法,或者在读取文件后对文件进行一些保护性锁定filewatcher 事件触发已进行更改。

在继续之前,我在FileSystemWatcher中使用了这种方法

IPSDependency.FileSystem.WaitForLockOnFile(Me.mFilePath)

代码是这样的。(现在阅读本文后,可能有更好的方法我在这里使用一些睡眠来减少 CPU 抖动)

Public Shared Function IsLockAvailable(ByVal filename As String, ByVal fnfIsOK As Boolean) As Boolean
    Dim fi As FileInfo
    fi = New FileInfo(filename)
    Return IsLockAvailable(New FileInfo(filename), fnfIsOK)
End Function

Public Shared Function IsLockAvailable(ByVal theFile As FileInfo, ByVal fnfIsOK As Boolean) As Boolean
    Dim fs As FileStream
    Try
        If theFile.Exists Then
            fs = New FileStream(theFile.FullName, FileMode.Open, FileAccess.ReadWrite, FileShare.None)
            fs.Close()
            Return True
        Else
            Return fnfIsOK
        End If
    Catch ex As IOException
        'we just let the exception go, because we are only testing the file rather than trying to use it.
        Return False
    End Try
End Function

Public Shared Sub WaitForLockOnFile(ByVal theFilename As String)
    WaitForLockOnFile(New FileInfo(theFilename))
End Sub

Public Shared Sub WaitForLockOnFile(ByVal theFile As FileInfo)
    Dim lockAvailable As Boolean
    If theFile.Exists Then
        While Not lockAvailable
            lockAvailable = IsLockAvailable(theFile, False)
        End While
    End If
End Sub
于 2010-07-19T01:56:18.277 回答
3

假设一切都在同一台机器上运行,那么这个怎么样:

  1. 定义定义设置的通用 c# 结构。所有项目都包含此 .cs 文件。将此类定义为具有SequentialExplicitStructLayout结构,以便它可以直接映射到非托管共享内存中。例如:

    [StructLayout(LayoutKind.Sequential)] 不安全的 struct MySharedSettings { public int setting1; 公共 int 设置2;公共字符串设置3;// 在此处添加更多字段。}

  2. 使用命名共享内存(又名:内存映射文件)。这允许同一台计算机上的多个进程共享数据,而没有RemotingWCF的开销。共享内存非常快,并且与管道不同,它提供对共享内存数据的随机访问。该服务将创建命名的共享内存,并且 UI 应用程序将打开共享内存。您必须使用 pinvoke 才能使用底层的 Windows API,但这没什么大不了的。

  3. UI 应用程序将 MySharedSettings 写入共享内存,而服务读取共享内存。

  4. 使用命名的 Semaphore和/或命名的 Mutex来保护对共享内存的访问并指示新设置的可用性。该服务有一个专门的后台线程,只需在信号量上执行 WaitOne(),UI 线程将在写入新数据时发出信号。

于 2010-07-24T01:42:11.347 回答
2

通常,执行“轮询操作”(即同步文件)的服务在其轮询间隔中有足够的延迟时间,您可以轻松地在每个循环中重新读取所有设置,甚至可以根据需要重新读取。

如果您的服务更接近 SOA 后端,那么更改可能会影响在服务生命周期中通常只使用一次的设置。如果这是您的应用程序类型,那么您上面描述的选项 #2 是最可靠的。我不能说我很关心 Paul 的实现,因为轮询这样的文件会产生不可靠的结果。我建议使用全局命名的等待句柄来指示您的更改过程。我相信你可以在这里找到一个关于 SO 的例子。如果您不想这样做,那么您可以轮询配置文件的最后修改时间更改。

总的来说,我更喜欢使用注册表进行存储的第一种方法。将您的所有设置以离散值写入注册表配置单元中,并在您的服务中按需读取它们。它比您想象的要快,并且在前端和后端都易于实现。

于 2010-07-20T01:33:24.040 回答
0

我必须同意你最初倾向于#2 和#3。我特别喜欢#3,因为我不喜欢投票,但最终我认为#2 或#3 之间的决定将取决于您的服务要求。

至于用户设置的存储,我建议探索隔离存储 ( http://msdn.microsoft.com/en-us/library/3ak841sy.aspx )。它为安全、一致和可靠地访问用户文件提供了一种出色的机制。除非管理员完全关闭了独立存储,否则您不必担心用户的权限。另外,如果您启用漫游,如果用户在同一个域上使用不同的系统,他们甚至可以随身携带他们的设置,非常漂亮吧?

于 2010-07-22T21:04:42.140 回答