sql >> Database >  >> RDS >> Sqlserver

Zijn er efficiëntere alternatieven voor ASP.NET 2.0 anonieme profielen?

Ik heb de oplossing geïmplementeerd die ik in mijn oorspronkelijke bericht had bedacht, maar het bleek een beetje anders te zijn dan wat ik oorspronkelijk beschreef. De oplossing kan eigenlijk in 2 delen worden opgesplitst:een om het probleem op te lossen met de database die wordt bijgewerkt wanneer cookies zijn uitgeschakeld, en de tweede om te detecteren wanneer cookies zijn uitgeschakeld zonder een omleiding uit te voeren.

Ik heb de oplossing voor de anonieme profielen die records maken wanneer cookies zijn uitgeschakeld .

Dus nu zal ik me concentreren op het tweede deel - informatie in het profiel krijgen vanaf de eerste gevraagde pagina. Dit hoeft alleen te worden gedaan als u analytische tracking of iets dergelijks uitvoert - het eerste deel zorgt ervoor dat de database wordt beschermd tegen het vullen met totaal nutteloze gegevens wanneer 1) cookies zijn uitgeschakeld en 2) anonieme profieleigenschappen worden gebruikt en werken vanaf het tweede verzoek (of de eerste postback) en later.

Toen ik onderzoek deed naar het controleren of cookies zijn ingeschakeld, gebruikten de meeste oplossingen een omleiding naar dezelfde pagina of een andere pagina en weer terug. Interessant is dat MSDN was degene die de 2-redirect oplossing bedacht.

Hoewel in bepaalde omstandigheden een omleiding acceptabel is, wilde ik niet dat de extra prestatie-impact gevolgen zou hebben voor de meerderheid van onze gebruikers. In plaats daarvan koos ik voor een andere benadering - gebruik AJAX om code op de server uit te voeren nadat het eerste verzoek is voltooid. Hoewel dit het voordeel heeft dat het geen omleiding veroorzaakt, heeft het als nadeel dat het niet werkt wanneer JavaScript is uitgeschakeld. Ik heb echter voor deze aanpak gekozen omdat het percentage gegevens dat verloren gaat bij het eerste verzoek onbeduidend is en de applicatie zelf niet afhankelijk is van deze gegevens.

Dus, doorlopen van het begin van het proces tot het einde...

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

Dit is de Page_Load-methode die in mijn aangepaste PageBase-klasse is geplaatst, waarvan alle pagina's in het project erven. Het eerste dat we controleren is of dit een nieuwe sessie is door de eigenschap Session.IsNewSession aan te vinken. Deze eigenschap is altijd waar als cookies zijn uitgeschakeld of als dit het eerste verzoek is. In beide gevallen willen we niet naar de database schrijven.

De sectie "anders als" wordt uitgevoerd als de client de sessiecookie heeft geaccepteerd en dit niet het eerste verzoek aan de server is. Het ding om op te merken over dit codefragment is dat beide secties niet in hetzelfde verzoek kunnen worden uitgevoerd, wat betekent dat het profiel slechts 1 (of 0) keer per verzoek kan worden bijgewerkt.

De klasse AnonymousProfile is opgenomen in mijn andere post .

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

Vervolgens hebben we onze methode om een ​​AJAX-aanroep in de pagina te injecteren. Houd er rekening mee dat dit nog steeds de basisklasse is, dus ongeacht de pagina waarop de gebruiker op deze code terechtkomt, wordt deze code uitgevoerd bij het eerste paginaverzoek.

Binnen de JavaScript testen we eerst of cookies zijn ingeschakeld en, zo ja, roepen we een aangepaste handler op de server aan met behulp van AJAX en JQuery. We geven de parameters van de server door aan deze code (hoewel 2 ervan net door de client kunnen zijn geleverd, zijn de extra bytes niet zo belangrijk).

De tweede methode werkt het profiel bij en bevat mijn aangepaste logica om dit te doen. Ik heb een fragment opgenomen over hoe de querystring-waarden van een gedeeltelijke URL kunnen worden geparseerd. Maar het enige dat hier echt bekend moet zijn, is dat dit de gedeelde methode is die het profiel bijwerkt.

Belangrijk: Om de AJAX-aanroep te laten werken, moet de volgende handler worden toegevoegd aan de system.web-sectie van het web.config-bestand:

<httpModules>
    <add name="ScriptModule" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
</httpModules>

Ik besloot dat het het beste zou zijn om te testen op cookies op de client en niet de extra AJAX-oproep te doen als cookies zijn uitgeschakeld. Gebruik deze code om de cookies te testen:

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() + ';' + ';';
}

Dit zijn 2 JavaScript-functies (in een aangepast .js-bestand) die eenvoudigweg een cookie schrijven en teruglezen om te bepalen of cookies kunnen worden gelezen. Vervolgens ruimt het de cookie op door een vervaldatum in het verleden in te stellen.

<%@ 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

Dit is onze Custom HttpHandler-klasse die het AJAX-verzoek ontvangt. Het verzoek wordt alleen verwerkt als de .ASPXANONYMOUS-cookie wordt doorgegeven (nogmaals gecontroleerd door de klasse AnonymousProfile uit mijn andere post te gebruiken), waardoor wordt voorkomen dat robots en andere scripts het uitvoeren.

Vervolgens voeren we wat code uit om het sessie-object bij te werken als dit nodig is. Om de een of andere vreemde reden blijft de IsNewSession-waarde waar totdat de sessie daadwerkelijk is bijgewerkt, maar alleen als er geen handler voor Session_Start bestaat in de Global.asax. Dus om deze code zowel met als zonder een Global.asax-bestand te laten werken en zonder enige andere code die het sessie-object bijwerkt, voeren we hier een update uit.

Het volgende stukje code dat ik pakte van dit bericht en bevat een afhankelijkheid van de JSON.NET-serializer. Ik was verscheurd over het gebruik van deze aanpak vanwege de extra afhankelijkheid, maar besloot uiteindelijk dat de JSON-serializer in de toekomst waarschijnlijk waardevol zal zijn als ik AJAX en JQuery aan de site blijf toevoegen.

Dan halen we gewoon de parameters op en geven ze door aan onze gedeelde UpdateProfile-methode in de PageBase-klasse die eerder is gedefinieerd.

<!-- 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>

Ten slotte hebben we onze configuratiesectie voor de profieleigenschappen, ingesteld om anoniem te worden gebruikt (ik heb met opzet de sectie met verbindingsreeksen weggelaten, maar een overeenkomstige verbindingsreeks en database zijn ook vereist). Het belangrijkste om hier op te merken is de opname van het inherits-attribuut in het profiel. Dit is weer voor de klasse AnonymousProfile die is gedefinieerd in mijn andere post .




  1. Ingewikkelde MySQL-query

  2. Bitsgewijze MySQL-bewerkingen, bloeifilter

  3. Hoe een unieke sleutel aan een bestaande tabel toevoegen (met niet-unieke rijen)

  4. Hoe converteer ik een geheel getal naar een string als onderdeel van een PostgreSQL-query?