多くの調査と試行錯誤の末、私はこの問題の解決策を発見しました。ただし、ユーザーが1つのリクエストからのみCookieをサポートしているかどうかを判断することは不可能であるため、このソリューションはユーザーが最初に行うリクエストに対しては機能しません。
最初のリクエストでプロファイルに設定を書き込むために、AJAXを使用してサーバーに2番目の(非表示の)リクエストを行う巧妙なソリューションを思いつきましたが、CookieとJavaScriptが有効になっている場合に限ります。もちろん、最初のリクエストでプロファイル設定を保存していない場合は、これを使用する必要はありません。詳細については、他の投稿を参照してください。
Imports System.Web.Configuration
Public MustInherit Class AnonymousProfile
Inherits ProfileBase
Public Shared ReadOnly Property AnonymousCookieName() As String
Get
Dim anon As AnonymousIdentificationSection = CType(ConfigurationManager.GetSection("system.web/anonymousIdentification"), AnonymousIdentificationSection)
Return anon.CookieName
End Get
End Property
Public Shared ReadOnly Property IsAnonymousCookieStored() As Boolean
Get
Dim cookies As String = HttpContext.Current.Request.Headers("Cookie")
Return Not String.IsNullOrEmpty(cookies) AndAlso cookies.IndexOf(AnonymousCookieName) > -1
End Get
End Property
Private ReadOnly Property IsWritable() As Boolean
Get
Return IsAnonymous = False OrElse IsAnonymous AndAlso IsAnonymousCookieStored
End Get
End Property
Private Function IsObjectMatch(ByVal obj1 As Object, ByVal obj2 As Object) As Boolean
If Not obj1 Is Nothing Then
Return obj1.Equals(obj2)
Else
If obj2 Is Nothing Then
Return True
Else
Return False
End If
End If
End Function
Public Overloads Sub SetPropertyValue(ByVal propertyName As String, ByVal propertyValue As Object)
If (Not IsObjectMatch(Me.GetPropertyValue(propertyName), propertyValue)) AndAlso IsWritable Then
MyBase.SetPropertyValue(propertyName, propertyValue)
End If
End Sub
Public Overrides Sub Save()
If IsWritable Then
MyBase.Save()
End If
End Sub
End Class
簡単に言うと、このクラスは、プロファイルが匿名であり、匿名のCookieがブラウザからまだ受信されていない場合に、プロファイルが書き込まれたり保存されたりするのを防ぎます。
このクラスを使用するには、このクラスをApp_Codeディレクトリに配置し、次のようにweb.configファイルのprofile要素に「inherits」属性を追加します。
<profile defaultProvider="SqlProvider" inherits="AnonymousProfile">
ASP.NETは、自動的に生成されるときに、このクラスからProfileCommonクラスを継承します。
AnonymousCookieNameプロパティとIsAnonymousCookieStoredプロパティは公開共有されているため、次のようにプロジェクト内の他の場所で使用できます。
If AnonymousProfile.IsAnonymousCookieStored Then
'It is safe to write to the profile here
End If
これにより、ユーザーが匿名Cookieを拒否した場合に実行する必要のないコードを実行することで、CPUサイクルを節約できますが、新しいプロファイルクラスはとにかくチェックするため、厳密には必要ありません。
このサンプルには別のバグ修正も含まれています。プロパティを既に含まれているのと同じ値に設定すると、元のプロファイルクラスは「ダーティ」になり、何も変更されていなくてもデータベースが更新されます。この問題を修正するオーバーロードされたSetPropertyValueメソッドにこの条件のチェックがあります。
Public Overloads Sub SetPropertyValue(ByVal propertyName As String, ByVal propertyValue As Object)
If (Not IsObjectMatch(Me.GetPropertyValue(propertyName), propertyValue)) AndAlso IsWritable Then
MyBase.SetPropertyValue(propertyName, propertyValue)
End If
End Sub
参照:ProfileBaseクラス(MSDN)