Sqlserver
 sql >> Baza danych >  >> RDS >> Sqlserver

Czy istnieją bardziej wydajne alternatywy dla anonimowych profili ASP.NET 2,0?

Zaimplementowałem obejście, które wymyśliłem w moim oryginalnym poście, jednak okazało się, że jest nieco inne niż to, co pierwotnie opisałem. Poprawkę można w rzeczywistości podzielić na 2 części - jedną, aby rozwiązać problem z aktualizacją bazy danych, gdy pliki cookie są wyłączone, a drugą, aby wykryć, kiedy pliki cookie są wyłączone bez wykonywania przekierowania.

Zamieściłem już rozwiązanie anonimowych profili tworzących rekordy, gdy pliki cookie są wyłączone .

Więc teraz skoncentruję się na drugiej części - dostaniu informacji do profilu z pierwszej żądanej strony. Należy to zrobić tylko wtedy, gdy wykonujesz śledzenie analityczne lub coś podobnego - pierwsza część zajmie się ochroną bazy danych przed wypełnieniem całkowicie bezużytecznymi danymi, gdy 1) pliki cookie są wyłączone i 2) używane są anonimowe właściwości profilu i działa od od drugiego żądania (lub pierwszego ogłaszania zwrotnego).

Kiedy badałem problem sprawdzania, czy pliki cookie są włączone, większość rozwiązań wykorzystywała przekierowanie do tej samej strony lub innej strony i z powrotem. Co ciekawe, MSDN był tym, który wymyślił rozwiązanie 2-redirect.

Chociaż w pewnych okolicznościach przekierowanie jest dopuszczalne, nie chciałem, aby dodatkowy wpływ na wydajność miał wpływ na większość naszych użytkowników. Zamiast tego zdecydowałem się na inne podejście - użyj AJAX do uruchomienia kodu na serwerze po zakończeniu pierwszego żądania. Chociaż ma to tę zaletę, że nie powoduje przekierowania, ma wadę, że nie działa, gdy JavaScript jest wyłączony. Zdecydowałem się jednak na to podejście, ponieważ odsetek danych, które są tracone podczas początkowego żądania, jest nieznaczny, a sama aplikacja nie zależy od tych danych.

Przechodząc od początku do końca procesu...

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

Jest to metoda Page_Load umieszczona w mojej niestandardowej klasie PageBase, z której dziedziczą wszystkie strony w projekcie. Pierwszą rzeczą, którą sprawdzamy, jest to, czy jest to nowa sesja, sprawdzając właściwość Session.IsNewSession. Ta właściwość jest zawsze prawdziwa, jeśli pliki cookie są wyłączone lub jeśli jest to pierwsze żądanie. W obu przypadkach nie chcemy pisać do bazy danych.

Sekcja „else if” jest uruchamiana, jeśli klient zaakceptował plik cookie sesji i nie jest to pierwsze żądanie do serwera. Należy pamiętać o tym fragmencie kodu, że obie sekcje nie mogą działać w tym samym żądaniu, co oznacza, że ​​profil może być aktualizowany tylko 1 (lub 0) razy na żądanie.

Klasa AnonymousProfile jest zawarta w moim inny 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

Następnie mamy naszą metodę wstrzyknięcia wywołania AJAX na stronę. Pamiętaj, że nadal jest to klasa bazowa, więc niezależnie od strony, na którą użytkownik trafi ten kod, zostanie uruchomiona przy pierwszym żądaniu strony.

Wewnątrz JavaScript najpierw testujemy, czy pliki cookie są włączone, a jeśli tak, wywołujemy niestandardową procedurę obsługi na serwerze za pomocą AJAX i JQuery. Przekazujemy parametry z serwera do tego kodu (chociaż 2 z nich mogły właśnie zostać dostarczone przez klienta, dodatkowe bajty nie są tak znaczące).

Druga metoda aktualizuje profil i będzie zawierać moją niestandardową logikę, aby to zrobić. Dołączyłem fragment informacji o tym, jak analizować wartości ciągu zapytania z częściowego adresu URL. Ale jedyną rzeczą, którą naprawdę trzeba tutaj wiedzieć, jest to, że jest to wspólna metoda, która aktualizuje profil.

Ważne: Aby wywołanie AJAX działało, należy dodać następujący program obsługi do sekcji system.web pliku web.config:

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

Zdecydowałem, że najlepiej będzie przetestować pliki cookie na kliencie i nie wykonywać dodatkowego wywołania AJAX, jeśli pliki cookie są wyłączone. Aby przetestować pliki cookie, użyj tego kodu:

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

Są to 2 funkcje JavaScript (w niestandardowym pliku .js), które po prostu zapisują plik cookie i odczytują go z powrotem, aby określić, czy można odczytać pliki cookie. Następnie czyści plik cookie, ustawiając datę wygaśnięcia w przeszłości.

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

To jest nasza niestandardowa klasa HttpHandler, która odbiera żądanie AJAX. Żądanie jest przetwarzane tylko wtedy, gdy zostanie przekazany plik cookie .ASPXANONYMOUS (sprawdzony ponownie przy użyciu klasy AnonymousProfile z mojego innego postu), co uniemożliwi wykonanie go przez roboty i inne skrypty.

Następnie uruchamiamy kod, aby zaktualizować obiekt sesji, jeśli jest to wymagane. Z jakiegoś dziwnego powodu wartość IsNewSession pozostanie prawdziwa, dopóki sesja nie zostanie faktycznie zaktualizowana, ale tylko wtedy, gdy program obsługi Session_Start nie istnieje w Global.asax. Aby ten kod działał zarówno z plikiem Global.asax, jak i bez niego, a także bez żadnego innego kodu, który aktualizuje obiekt sesji, uruchamiamy aktualizację tutaj.

Następny fragment kodu, który pobrałem z ten post i zawiera zależność od serializatora JSON.NET. Byłem rozdarty na temat korzystania z tego podejścia z powodu dodatkowej zależności, ale ostatecznie zdecydowałem, że serializator JSON będzie prawdopodobnie cenny w przyszłości, gdy będę kontynuował dodawanie AJAX i JQuery do witryny.

Następnie po prostu pobieramy parametry i przekazujemy je do naszej udostępnionej metody UpdateProfile w klasie PageBase, która została wcześniej zdefiniowana.

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

Na koniec mamy sekcję konfiguracyjną dla właściwości profilu, skonfigurowaną do używania anonimowo (celowo pominąłem sekcję parametrów połączenia, ale wymagane są również odpowiednie parametry połączenia i baza danych). Najważniejszą rzeczą, na którą należy zwrócić uwagę, jest włączenie atrybutu inherits do profilu. To po raz kolejny dotyczy klasy AnonymousProfile, która jest zdefiniowana w moim inny post .




  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Czy istnieje odpowiednik SELECT... INTO OUTFILE w SQL Server Management Studio?

  2. Debugowanie procedury składowanej w SQL Server 2008

  3. SQL Server 2008 przekazujący typ danych jako parametr funkcji

  4. Czy w tsql wstawka z instrukcją Select jest bezpieczna pod względem współbieżności?

  5. Proszę wyjaśnić części PIVOT