这里明显的问题是,在刷新时会调用按钮事件并在数据库中创建重复的帖子。我已经阅读了这个网站上关于同样问题的其他问题。
显然答案是为每个帖子创建一个 GUID 并检查以确保 GUID 是唯一的?我不确定如何实现这一点。
这是否意味着在刷新时,它将尝试创建具有相同 GUID 的重复帖子?
如何在数据库中实现 GUID?或者,如果这不是答案,那是什么?
谢谢!
这个想法是您为表单创建一个唯一编号,当表单发布时,您将此唯一编号保存在您正在编辑/创建的记录中的数据库中。在保存之前检查该号码是否已被使用,在这种情况下,它是通过刷新重新发布的表格。
如果您正在更新记录,您只需检查该记录是否已使用相同的唯一编号保存,但如果您要添加新记录,则必须检查是否有任何其他记录具有该编号。
Guid 是一个很好的数字,因为您不太可能得到重复。该类可以生成的 31 位随机数Random
也不太可能产生重复,但 Guid 的 128 位使得它更不可能出现。
您不必在数据库中创建 Guid 值,只需Guid.NewGuid()
在初始化表单的代码中使用即可。您可以将 Guid 放在表单中的隐藏字段中。在数据库中,您只需要一个可以存储 Guid 值的字段,可以是 Guid 数据类型(如果可用),或者只是一个足够大以保存 Guid 的文本表示的文本字段。
您可以使用该ToString
方法获取 Guid 值的字符串表示形式(以便您可以将其放入表单中)。Usingid.ToString("N")
给出了最紧凑的格式,即没有分隔符的 32 个十六进制数字。使用id.ToString("B")
给出更易识别的格式“{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}”。要从字符串(任何一种格式)中取回 Guid,您只需使用new Guid(str)
.
这是我使用的 RefreshValidator 控件。只需将其放在您的页面上,并在保存到数据库之前检查 Page.IsValid。您可以像其他验证器一样添加错误消息,或者如果您想做一些特别的事情,可以捕获 Refreshed 事件。由于它是一个验证器,GridViews 等已经注意到它 - 除了删除或取消操作(是的,我有一个自定义的 GridView 也可以解决这个问题......)
代码非常简单——将 GUID 存储到 ControlState 中,并将副本存储在 Session 中。在加载时,比较 2。如果它们不一样 - 那么它是一个刷新。冲洗、重复并创建一个新的 GUID 并重新开始。
''' <summary>
''' A validator control that detects if the page has been refreshed
''' </summary>
''' <remarks>If <see cref="SessionState.HttpSessionState" /> is not available or is reset, validator will return Valid</remarks>
Public Class RefreshValidator
Inherits BaseValidator
Private isRefreshed As Boolean
Protected Overrides Sub OnInit(ByVal e As System.EventArgs)
MyBase.OnInit(e)
Page.RegisterRequiresControlState(Me)
End Sub
Protected Overrides Function SaveControlState() As Object
Dim obj As Object = MyBase.SaveControlState()
Return New System.Web.UI.Pair(_pageHashValue, obj)
End Function
Protected Overrides Sub LoadControlState(ByVal savedState As Object)
Dim pair As System.Web.UI.Pair = TryCast(savedState, System.Web.UI.Pair)
If pair IsNot Nothing Then
_pageHashValue = TryCast(pair.First, String)
MyBase.LoadControlState(pair.Second)
Else
MyBase.LoadControlState(savedState)
End If
End Sub
Private _pageHashValue As String
Protected Overrides Sub OnLoad(ByVal e As System.EventArgs)
MyBase.OnLoad(e)
If HttpContext.Current Is Nothing OrElse HttpContext.Current.Session Is Nothing Then
isRefreshed = False
Return
End If
' Get hash value from session
Dim currHashValue As String = CType(HttpContext.Current.Session(Me.UniqueID & ":pageHashValue"), String)
If _pageHashValue Is Nothing OrElse currHashValue Is Nothing Then
' No page hash value - must be first render
' No current hash value. Session reset?
isRefreshed = False
ElseIf currHashValue = _pageHashValue Then
' Everything OK
isRefreshed = False
Else
' Was refreshed
isRefreshed = True
End If
' Build new values for form hash
Dim newHashValue As String = Guid.NewGuid().ToString()
_pageHashValue = newHashValue
HttpContext.Current.Session(Me.UniqueID & ":pageHashValue") = newHashValue
End Sub
Protected Overrides Function ControlPropertiesValid() As Boolean
Return True
End Function
Protected Overrides Function EvaluateIsValid() As Boolean
If isRefreshed Then OnRefreshed(EventArgs.Empty)
Return Not isRefreshed
End Function
Protected Overridable Sub OnRefreshed(ByVal e As EventArgs)
RaiseEvent Refreshed(Me, e)
End Sub
''' <summary>
''' Fires when page is detected as a refresh
''' </summary>
Public Event Refreshed As EventHandler
End Class