我正在用C#开发一个基于.NET4的应用程序,它作为一个Windows服务运行。
我希望这个应用程序能够通过定期连接的Web服务进行升级。有没有可以接受的方法来实现这一目标?它甚至可能吗?
我正在考虑的方式是这样的:
这会有用吗?您可以从我的术语和方法中检测到我来自UNIX背景而不是Windows背景。我已经在UNIX上使用了这种方法,但我不知道可能存在哪种窗口......
更新:我对这个问题的主要动机是围绕自我更新的.NET应用程序的技术可行性(如何进行.DLL的就地替换等)。正如评论中所指出的,实现这样的功能还涉及许多其他考虑因素,特别是关于验证所应用的新软件组件的安全问题实际上是合法的。这些也很重要,但不是特定于.NET或Windows(imo)。当然欢迎对这些领域的评论,但目前它们不是我主要关注的问题......
答案 0 :(得分:1)
您的方法当然合理,但除非您在LocalSystem帐户(不推荐!)下运行,否则您无权写入应用程序文件夹或启动/停止自己的服务。即使你在用户的帐户下运行,你也可能因为UAC而遇到问题,尽管我不确定这一点。无论如何在用户帐户下运行都不好,因为它要求用户输入帐户密码并且由于密码更改,锁定等而产生额外的复杂性。您必须在安装程序上设置ACL,无论如何都必须提升安装服务。
答案 1 :(得分:0)
你应该看看菲尔·哈克(Phil Haack)的this,这是本周早些时候的热门新闻。我不认为这正是你想要的,但它可能会节省你一些时间。无论如何,NuGet都是美好的时光。
答案 2 :(得分:0)
这可以使用ClickOnce完成,但可能不是你想要的程度。
看看这个课程
Imports System.Deployment.Application
Imports System.ComponentModel
Public Class UpdateChecker
Public Enum UpdateType
Automatic
Manual
End Enum
Private Shared MyInstance As UpdateChecker
Public Shared ReadOnly Property Current() As UpdateChecker
Get
If MyInstance Is Nothing Then
MyInstance = New UpdateChecker
End If
Return MyInstance
End Get
End Property
Private WithEvents CurrDeployment As ApplicationDeployment
Private CurrType As UpdateType
Private _checking As Boolean = False
Private _lastErrorSentOnCheck As DateTime?
Public ReadOnly Property LastUpdateCheck() As DateTime?
Get
If CurrDeployment IsNot Nothing Then
Return CurrDeployment.TimeOfLastUpdateCheck
End If
Return Nothing
End Get
End Property
Public Sub CheckAsync(ByVal checkType As UpdateType)
Try
Dim show As Boolean = (checkType = UpdateType.Manual)
If ApplicationDeployment.IsNetworkDeployed AndAlso _
Not WindowActive(show) AndAlso Not _checking AndAlso _
(checkType = UpdateType.Manual OrElse Not LastUpdateCheck.HasValue OrElse LastUpdateCheck.Value.AddMinutes(60) <= Date.UtcNow) Then
_checking = True
CurrDeployment = ApplicationDeployment.CurrentDeployment
CurrType = checkType
Dim bw As New BackgroundWorker
AddHandler bw.RunWorkerCompleted, AddressOf CurrDeployment_CheckForUpdateCompleted
AddHandler bw.DoWork, AddressOf StartAsync
If CurrType = UpdateType.Manual Then ShowWindow()
bw.RunWorkerAsync()
ElseIf checkType = UpdateType.Manual AndAlso _checking Then
CurrType = checkType
WindowActive(True)
ElseIf checkType = UpdateType.Manual AndAlso Not ApplicationDeployment.IsNetworkDeployed Then
MessageBox.Show(MainForm, "Cannot check for updates.", "Update", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
Catch ex As Exception
If Not _lastErrorSentOnCheck.HasValue OrElse _lastErrorSentOnCheck.Value.AddHours(1) <= Now Then
_lastErrorSentOnCheck = Now
My.Application.LogError(ex, New StringPair("Update Check", checkType.ToString))
End If
End Try
End Sub
Private Sub StartAsync(ByVal sender As Object, ByVal e As DoWorkEventArgs)
e.Result = CurrDeployment.CheckForDetailedUpdate
End Sub
Private Sub ShowWindow()
My.Forms.frmUpdates.MdiParent = MainForm
AddHandler My.Forms.frmUpdates.FormClosing, AddressOf frmUpdates_FormClosing
My.Forms.frmUpdates.Show()
End Sub
Protected Sub frmUpdates_FormClosing(ByVal sender As Object, ByVal e As Windows.Forms.FormClosingEventArgs)
My.Forms.frmUpdates = Nothing
End Sub
Private Function WindowActive(ByVal onTop As Boolean) As Boolean
If Not My.Forms.frmUpdates Is Nothing Then
If Not My.Forms.frmUpdates.Visible AndAlso onTop Then
My.Forms.frmUpdates.MdiParent = MainForm
My.Forms.frmUpdates.Show()
ElseIf onTop Then
My.Forms.frmUpdates.Activate()
End If
Return True
End If
Return False
End Function
Private Sub CurrDeployment_CheckForUpdateCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
If MainForm.InvokeRequired Then
MainForm.Invoke(New RunWorkerCompletedEventHandler(AddressOf CurrDeployment_CheckForUpdateCompleted), sender, e)
Else
If e.Error IsNot Nothing Then
If WindowActive(True) Then My.Forms.frmUpdates.ShowError("Please try again later.")
If Not _lastErrorSentOnCheck.HasValue OrElse _lastErrorSentOnCheck.Value.AddHours(1) <= Now Then
_lastErrorSentOnCheck = Now
My.Application.LogError(e.Error, New StringPair("Update Check Async", CurrType.ToString))
End If
Else
Dim updateInfo As UpdateCheckInfo = DirectCast(e.Result, UpdateCheckInfo)
Select Case CurrType
Case UpdateType.Manual
If WindowActive(False) Then My.Forms.frmUpdates.ShowCheckComplete(updateInfo)
Case UpdateType.Automatic
If updateInfo.UpdateAvailable Then
If Not WindowActive(True) Then ShowWindow()
My.Forms.frmUpdates.ShowCheckComplete(updateInfo)
End If
End Select
End If
_checking = False
End If
DirectCast(sender, BackgroundWorker).Dispose()
End Sub
Public Sub UpdateAsync()
If ApplicationDeployment.IsNetworkDeployed Then
CurrDeployment = ApplicationDeployment.CurrentDeployment
Dim bw As New BackgroundWorker
AddHandler bw.RunWorkerCompleted, AddressOf CurrDeployment_UpdateCompleted
AddHandler bw.DoWork, AddressOf StartUpdateAsync
My.Forms.frmUpdates.ShowUpdateStart()
bw.RunWorkerAsync()
End If
End Sub
Public Sub StartUpdateAsync()
CurrDeployment.Update()
End Sub
Private Sub CurrDeployment_UpdateCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles CurrDeployment.UpdateCompleted
If MainForm.InvokeRequired Then
MainForm.Invoke(New AsyncCompletedEventHandler(AddressOf CurrDeployment_UpdateCompleted), sender, e)
Else
If e.Error IsNot Nothing Then
If WindowActive(True) Then My.Forms.frmUpdates.ShowError("Please try again later or close and re-open the application to automatically retrieve updates.")
My.Application.LogError(e.Error, New StringPair("Update Async", CurrType.ToString))
Else
If WindowActive(True) Then My.Forms.frmUpdates.ShowUpdateComplete()
End If
End If
End Sub
End Class
以下是检查是否需要新更新的代码。你可以在计时器上运行它,可能每5分钟
UpdateChecker.Current.CheckAsync(UpdateChecker.UpdateType.Automatic)
然后是下载更新的代码。
UpdateChecker.Current.UpdateAsync()
用户必须退出并启动应用程序以获取新版本或 更新完成后,您还可以使用Application.Restart重新启动应用程序
当程序未运行时,这不会更新,但使用ClickOnce,您可以在程序启动时检查更新。
答案 3 :(得分:0)