代码之家  ›  专栏  ›  技术社区  ›  SqlRyan

保持窗体应用程序和Windows服务(或任何n层)之间的设置同步。

  •  5
  • SqlRyan  · 技术社区  · 14 年前

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

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

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

    谢谢你的洞察力!

    4 回复  |  直到 14 年前
        1
  •  3
  •   Paul Farry    14 年前

    我有点用你的2号。

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

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

    如果另一个应用程序更新了设置文件,则我的当前应用程序将获得一个事件触发器,指示需要重新加载设置。

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

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

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

    我在我的 文件系统监视程序 在继续之前

    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
    
        2
  •  3
  •   Adel Hazzah    14 年前

    假设所有的东西都在同一台机器上运行,那么这样做如何:

    1. 定义定义设置的通用C结构。所有项目都包含此.cs文件。将此类定义为 结构 用一个 结构布局 属于 相继的 明确的 所以它可以直接映射到非托管共享内存中。例如:

      [结构布局(layoutkind.sequential)] 不安全的结构mySharedSettings { 公共信息设置1; 公共情报设置2; 公共字符串设置3; //在此添加更多字段。 }

    2. 使用 命名共享内存 (又名: 内存映射文件 )这允许同一台计算机上的多个进程共享数据,而不需要 远程处理 WCF . 共享内存非常快,与管道不同,它提供对共享内存数据的随机访问。服务将创建命名的共享内存,而UI应用程序将打开共享内存。您必须使用pinvoke来使用底层的Windows API,但这不是什么大问题。

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

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

        3
  •  2
  •   csharptest.net    14 年前

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

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

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

        4
  •  0
  •   Matthew    14 年前

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

    至于用户设置的存储,我建议您探索独立存储( http://msdn.microsoft.com/en-us/library/3ak841sy.aspx )它为安全、一致和可靠地访问用户文件提供了一种极好的机制。除非管理员完全关闭了独立存储,否则您不必担心用户是否具有权限。另外,如果你启用漫游,如果用户在同一个域上使用不同的系统,他们甚至可以使用自己的设置,相当灵活,是吗?