Saya menerapkan solusi yang saya buat di posting asli saya, namun ternyata sedikit berbeda dari yang saya jelaskan sebelumnya. Perbaikan sebenarnya dapat dipecah menjadi 2 bagian - satu untuk memperbaiki masalah dengan database yang diperbarui saat cookie dinonaktifkan, dan yang kedua untuk mendeteksi saat cookie dinonaktifkan tanpa melakukan pengalihan.
Saya telah memposting solusi untuk profil anonim yang membuat catatan saat cookie dinonaktifkan .
Jadi sekarang saya akan fokus pada bagian kedua - memasukkan informasi ke dalam profil dari halaman pertama yang diminta. Ini hanya perlu dilakukan jika Anda melakukan pelacakan analitik atau yang serupa - bagian pertama akan melindungi database dari pengisian data yang sama sekali tidak berguna ketika 1) cookie dinonaktifkan dan 2) properti profil anonim digunakan dan berfungsi dari permintaan kedua (atau postback pertama) dan seterusnya.
Ketika saya meneliti masalah pemeriksaan untuk melihat apakah cookie diaktifkan, sebagian besar solusi menggunakan pengalihan baik ke halaman yang sama atau halaman yang berbeda dan kembali lagi. Menariknya, MSDN adalah orang yang menemukan solusi 2-pengalihan.
Meskipun dalam keadaan tertentu pengalihan dapat diterima, saya tidak ingin dampak kinerja ekstra memengaruhi sebagian besar pengguna kami. Sebagai gantinya, saya memilih pendekatan lain - gunakan AJAX untuk menjalankan kode di server setelah permintaan pertama selesai. Meskipun ini memiliki keuntungan karena tidak menyebabkan pengalihan, ini memiliki kelemahan karena tidak berfungsi saat JavaScript dinonaktifkan. Namun, saya memilih pendekatan ini karena persentase data yang hilang pada permintaan awal tidak signifikan dan aplikasi itu sendiri tidak bergantung pada data ini.
Jadi, berjalan melalui dari awal proses sampai akhir...
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Me.IsPostBack Then
If Session.IsNewSession Then
Me.InjectProfileJavaScript()
ElseIf AnonymousProfile.IsAnonymousCookieStored Then
'If cookies are supported, and this isn't the first request, update the
'profile using the current page data.
UpdateProfile(Request.RawUrl, Request.UrlReferrer.OriginalString, CurrentProductID.ToString)
End If
End If
End Sub
Ini adalah metode Page_Load yang ditempatkan di kelas PageBase kustom saya, yang diwarisi dari semua halaman dalam proyek. Hal pertama yang kami periksa adalah apakah ini sesi baru dengan memeriksa properti Session.IsNewSession. Properti ini selalu benar jika cookie dinonaktifkan atau jika ini adalah permintaan pertama. Dalam kedua kasus, kami tidak ingin menulis ke database.
Bagian "else if" berjalan jika klien menerima cookie sesi dan ini bukan permintaan pertama ke server. Hal yang perlu diperhatikan tentang cuplikan kode ini adalah kedua bagian tidak dapat dijalankan dalam permintaan yang sama, artinya profil hanya dapat diperbarui 1 (atau 0) kali per permintaan.
Kelas AnonymousProfile termasuk dalam postingan lain .
Private Sub InjectProfileJavaScript()
Dim sb As New StringBuilder
sb.AppendLine("$(document).ready(function() {")
sb.AppendLine(" if (areCookiesSupported() == true) {")
sb.AppendLine(" $.ajax({")
sb.AppendLine(" type: 'POST',")
sb.AppendLine(" url: 'HttpHandlers/UpdateProfile.ashx',")
sb.AppendLine(" contentType: 'application/json; charset=utf-8',")
sb.AppendFormat(" data: ""{3}'RawUrl':'{0}', 'ReferralUrl':'{1}', 'ProductID':{2}{4}"",", Request.RawUrl, Request.UrlReferrer, CurrentProductID.ToString, "{", "}")
sb.AppendLine()
sb.AppendLine(" dataType: 'json'")
sb.AppendLine(" });")
sb.AppendLine(" }")
sb.AppendLine("});")
Page.ClientScript.RegisterClientScriptBlock(GetType(Page), "UpdateProfile", sb.ToString, True)
End Sub
Public Shared Sub UpdateProfile(ByVal RawUrl As String, ByVal ReferralUrl As String, ByVal ProductID As Integer)
Dim context As HttpContext = HttpContext.Current
Dim profile As ProfileCommon = CType(context.Profile, ProfileCommon)
Dim CurrentUrl As New System.Uri("http://www.test.com" & RawUrl)
Dim query As NameValueCollection = HttpUtility.ParseQueryString(CurrentUrl.Query)
Dim source As String = query.Item("source")
Dim search As String = query.Item("search")
Dim OVKEY As String = query.Item("OVKEY")
'Update the profile
profile.TestValue1 = source
profile.TestValue2 = search
End Sub
Selanjutnya, kami memiliki metode kami untuk menyuntikkan panggilan AJAX ke halaman. Perlu diingat, ini masih kelas dasar sehingga terlepas dari halaman yang dibuka pengguna di kode ini akan berjalan pada permintaan halaman pertama.
Di dalam JavaScript, pertama-tama kami menguji untuk melihat apakah cookie diaktifkan dan, jika demikian, panggil handler khusus di server menggunakan AJAX dan JQuery. Kami meneruskan parameter dari server ke kode ini (walaupun 2 di antaranya bisa saja diberikan oleh klien, byte tambahan tidak terlalu signifikan).
Metode kedua memperbarui profil dan akan berisi logika khusus saya untuk melakukannya. Saya menyertakan cuplikan tentang cara mengurai nilai string kueri dari URL parsial. Tapi satu-satunya hal yang benar-benar perlu diketahui di sini adalah bahwa ini adalah metode bersama yang memperbarui profil.
Penting: Agar panggilan AJAX berfungsi, handler berikut harus ditambahkan ke bagian system.web dari file web.config:
<httpModules>
<add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpModules>
Saya memutuskan akan lebih baik untuk menguji cookie pada klien dan tidak melakukan panggilan AJAX tambahan jika cookie dinonaktifkan. Untuk menguji cookie, gunakan kode ini:
function areCookiesSupported() {
var c='c';var ret = false;
document.cookie = 'c=2;';
if (document.cookie.indexOf(c,0) > -1) {
ret = true;
} else {
ret = false;
}
deleteCookie(c);
return ret
}
function deleteCookie(name) {
var d = new Date();
document.cookie = name + '=1;expires=' + d.toGMTString() + ';' + ';';
}
Ini adalah 2 fungsi JavaScript (dalam file .js khusus) yang hanya menulis cookie dan membacanya kembali untuk menentukan apakah cookie dapat dibaca. Ini kemudian membersihkan cookie dengan menetapkan tanggal kedaluwarsa di masa lalu.
<%@ WebHandler Language="VB" Class="Handlers.UpdateProfile" %>
Imports System
Imports System.Web
Imports System.Web.SessionState
Imports Newtonsoft.Json
Imports System.Collections.Generic
Imports System.IO
Namespace Handlers
Public Class UpdateProfile : Implements IHttpHandler : Implements IRequiresSessionState
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
If AnonymousProfile.IsAnonymousCookieStored Then
If context.Session.IsNewSession Then
'Writing to session state will reset the IsNewSession flag on the
'next request. This will fix a problem if there is no Session_Start
'defined in global.asax and no other session variables are written.
context.Session("ActivateSession") = ""
End If
Dim reader As New StreamReader(context.Request.InputStream)
Dim params As Dictionary(Of String, String) = JsonConvert.DeserializeObject(Of Dictionary(Of String, String))(reader.ReadToEnd())
Dim RawUrl As String = params("RawUrl")
Dim ReferralUrl As String = params("ReferralUrl")
Dim ProductID As Integer = params("ProductID")
PageBase.UpdateProfile(RawUrl, ReferralUrl, ProductID)
End If
End Sub
Public ReadOnly Property IsReusable() As Boolean Implements IHttpHandler.IsReusable
Get
Return False
End Get
End Property
End Class
End Namespace
Ini adalah kelas Custom HttpHandler kami yang menerima permintaan AJAX. Permintaan diproses hanya jika cookie .ASPXANONYMOUS dilewatkan (diperiksa sekali lagi dengan menggunakan kelas AnonymousProfile dari posting saya yang lain), yang akan mencegah robot dan skrip lain untuk mengeksekusinya.
Selanjutnya kita menjalankan beberapa kode untuk memperbarui objek sesi jika diperlukan. Untuk beberapa alasan aneh, nilai IsNewSession akan tetap benar sampai sesi benar-benar diperbarui, tetapi hanya jika pengendali untuk Session_Start tidak ada di Global.asax. Jadi untuk membuat kode ini berfungsi baik dengan dan tanpa file Global.asax dan tanpa kode lain yang memperbarui objek sesi, kami menjalankan pembaruan di sini.
Kode berikutnya yang saya ambil dari postingan ini dan berisi ketergantungan ke serializer JSON.NET. Saya bingung menggunakan pendekatan ini karena ketergantungan ekstra, tetapi akhirnya memutuskan bahwa serializer JSON kemungkinan akan berharga di masa mendatang karena saya terus menambahkan AJAX dan JQuery ke situs.
Kemudian kita cukup mendapatkan parameter dan meneruskannya ke metode UpdateProfile yang kita bagikan di kelas PageBase yang telah ditentukan sebelumnya.
<!-- Required for anonymous profiles -->
<anonymousIdentification enabled="true"/>
<profile defaultProvider="SqlProvider" inherits="AnonymousProfile">
<providers>
<clear/>
<add name="SqlProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="SqlServices" applicationName="MyApp" description="SqlProfileProvider for profile test web site"/>
</providers>
<properties>
<add name="TestValue1" allowAnonymous="true"/>
<add name="TestValue2" allowAnonymous="true"/>
</properties>
</profile>
Terakhir, kami memiliki bagian konfigurasi kami untuk properti profil, diatur untuk digunakan secara anonim (saya sengaja menghilangkan bagian string koneksi, tetapi string koneksi dan database yang sesuai juga diperlukan). Hal utama yang perlu diperhatikan di sini adalah pencantuman atribut pewarisan pada profil. Ini sekali lagi untuk kelas AnonymousProfile yang didefinisikan dalam postingan lain .