sql >> Databasteknik >  >> RDS >> Sqlserver

Finns det mer effektiva alternativ till anonyma profiler i ASP.NET 2.0?

Jag implementerade lösningen jag kom på i mitt ursprungliga inlägg, men det visade sig vara lite annorlunda än vad jag ursprungligen beskrev. Korrigeringen kan faktiskt delas upp i två delar - en för att åtgärda problemet med att databasen uppdateras när cookies är inaktiverade, och den andra för att upptäcka när cookies är inaktiverade utan att göra en omdirigering.

Jag har redan lagt upp lösning för de anonyma profilerna som skapar poster när cookies är inaktiverade .

Så nu kommer jag att fokusera på den andra delen - att få in information i profilen från den första sidan som efterfrågas. Detta behöver bara göras om du håller på med analysspårning eller liknande - den första delen kommer att ta hand om att skydda databasen från att fyllas med totalt värdelös data när 1) cookies är inaktiverade och 2) anonyma profilegenskaper används och fungerar från den andra begäran (eller första postback) och framåt.

När jag undersökte frågan om att kontrollera om cookies är aktiverade använde de flesta lösningarna en omdirigering antingen till samma sida eller en annan sida och tillbaka igen. Intressant nog är MSDN var den som kom med 2-omdirigeringslösningen.

Även om en omdirigering under vissa omständigheter är acceptabel, ville jag inte att den extra prestandapåverkan skulle påverka majoriteten av våra användare. Istället valde jag ett annat tillvägagångssätt - använd AJAX för att köra kod på servern efter att den första begäran har slutförts. Även om detta har fördelen att det inte orsakar en omdirigering, har det nackdelen att det inte fungerar när JavaScript är inaktiverat. Jag valde dock detta tillvägagångssätt eftersom andelen data som går förlorad vid den första begäran är obetydlig och själva applikationen är inte beroende av dessa data.

Så, gå igenom från början av processen till slutet...

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

Detta är metoden Page_Load placerad i min anpassade PageBase-klass, som alla sidor i projektet ärver från. Det första vi kontrollerar är om detta är en ny session genom att kontrollera egenskapen Session.IsNewSession. Den här egenskapen är alltid sann om cookies är inaktiverade eller om detta är den första begäran. I båda fallen vill vi inte skriva till databasen.

Avsnittet "annat om" körs om klienten accepterade sessionskakan och detta inte är den första begäran till servern. Saken att notera med detta kodavsnitt är att båda avsnitten inte kan köras i samma begäran, vilket innebär att profilen bara kan uppdateras 1 (eller 0) gånger per begäran.

Klassen AnonymousProfile ingår i mina annat inlägg .

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

Därefter har vi vår metod för att injicera ett AJAX-anrop på sidan. Tänk på att detta fortfarande är basklassen så oavsett vilken sida som användaren landar på den här koden kommer den att köras på den första sidans begäran.

Inuti JavaScript testar vi först för att se om cookies är aktiverade och i så fall anropar vi en anpassad hanterare på servern med AJAX och JQuery. Vi skickar parametrarna från servern till den här koden (även om två av dem bara kunde ha levererats av klienten, är de extra byten inte så betydande).

Den andra metoden uppdaterar profilen och kommer att innehålla min anpassade logik för att göra det. Jag inkluderade ett utdrag om hur man analyserar frågesträngsvärdena från en delvis URL. Men det enda som verkligen behöver vara känt här är att detta är den delade metoden som uppdaterar profilen.

Viktigt: För att AJAX-anropet ska fungera måste följande hanterare läggas till i system.web-delen av web.config-filen:

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

Jag bestämde mig för att det skulle vara bäst att testa för cookies på klienten och inte göra det extra AJAX-anropet om cookies är inaktiverade. För att testa cookies, använd denna kod:

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

Det här är 2 JavaScript-funktioner (i en anpassad .js-fil) som helt enkelt skriver en cookie och läser tillbaka den för att avgöra om cookies kan läsas. Den rensar sedan upp kakan genom att ange ett utgångsdatum i det förflutna.

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

Detta är vår Custom HttpHandler-klass som tar emot AJAX-förfrågan. Begäran behandlas endast om .ASPXANONYMOUS-cookien skickas in (kontrolleras igen genom att använda klassen AnonymousProfile från mitt andra inlägg), vilket kommer att förhindra robotar och andra skript från att köra den.

Därefter kör vi lite kod för att uppdatera sessionsobjektet om det krävs. Av någon konstig anledning kommer IsNewSession-värdet att förbli sant tills sessionen faktiskt uppdateras, men bara om en hanterare för Session_Start inte finns i Global.asax. Så för att få den här koden att fungera både med och utan en Global.asax-fil och utan någon annan kod som uppdaterar sessionsobjektet, kör vi en uppdatering här.

Nästa bit kod hämtade jag från det här inlägget och innehåller ett beroende till JSON.NET serializer. Jag var sliten över att använda det här tillvägagångssättet på grund av det extra beroendet, men beslutade till slut att JSON-serializern sannolikt kommer att vara värdefull i framtiden när jag fortsätter att lägga till AJAX och JQuery på webbplatsen.

Sedan hämtar vi helt enkelt parametrarna och skickar dem till vår delade UpdateProfile-metod i klassen PageBase som definierades tidigare.

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

Slutligen har vi vår konfigurationssektion för profilegenskaperna, inställd för att användas anonymt (jag har avsiktligt utelämnat anslutningssträngsektionen, men en motsvarande anslutningssträng och databas krävs också). Det viktigaste att notera här är inkluderingen av arvsattributet i profilen. Detta är återigen för klassen AnonymousProfile som definieras i min annat inlägg .




  1. Välj en rad tillsammans med dess nästa och föregående rad

  2. Hur infogar jag json-data i tabellen?

  3. Installerar magento, får databasanslutningsfel.

  4. Mysql group_concat av upprepade nycklar och antal upprepningar av flera kolumner i en fråga (Frågeoptimering)