Dette dokument er en overbygning til "Callbacks i ASP". Hvis du ikke ved hvordan du skal laves callbacks i VBScript, kan du jo tage et kig på det dokument inden du fortsætter med dette.

Events er i denne sammenhæng bare et spørgsmål om at udbygge callback-metoden til at kunne håndtere et vilkårligt antal callbacks på en let måde, dvs. en måde hvor det meste arbejde omkring administration af hvilke rutiner der skal kaldes og hvornår, er gjort på forhånd og vi bare skal koble vores funktioner på det eller de events vi ønsker at kunne reagere på.

En typisk anvendelse for events er fra klasser (eller funktioner) der gerne vil fortælle at en bestemt hændelse eller tilstand er indtruffet. Som udgangspunkt er det objektet der ejer eventet og derfor også objektet der bestemmer hvornår et event skal rejses. Som abonnent på et event skal man bare være klar til at reagere på eventet når det opstår. Et eksempel på et event i ASP er Session_OnStart, der rejses når et request fra en given maskine kommer til en side der benytter sessions, uden at have en forudgående session oprettet. I dette event kan man udføre kode som bringer den pågældende session i en tilstand som er ønskelig for den givne maskine/bruger. Det er den samme effekt vi skal opnå for vores egne objekter, med dette dokument. Vores metode er dog umiddelbart begrænset af, at events og objekter kun lever imens et request behandles, derefter nedlægges det hele. Det er altså ikke (umiddelbart) en metode der kan bruges til at trigger hændelser på et bestemt tidspunkt, det er snarere en metode til at pakke tingene lidt bedre væk og gøre koden mere robust, overskuelig, vedligeholdelsesvenlig og testbar. Jo mindre man piller ved noget kode, desto mindre er risikoen for at introducere nye fejl og jo mere man indkapsler, desto mindre er risikoen for sideeffekter i forbindelse med udvidelser/rettelser.

Hvis vi lige skal tage et hurtigt eksempel på hvordan events kunne bruges (aktiveres, sættes op og fanges), kunne dette f.eks. se således ud:

' En funktion som rejser et par events i løbet af afviklingen
function X()
  ' signaler at handlingen skal til at starte
  call RaiseEvents("BeforeX")

  ' Udfør den ønskede handling...

  ' signaler at handlingen er udført
  call RaiseEvents("AfterX")
end function

I eksemplet kan vi se at der benyttes en funktion til at rejse eventet (RaiseEvents), denne funktion skal vi også selv lave (ja, der var ingen der sagde det var let endnu...).

sub RaiseEvents(eventname)
  select case eventname
    case "BeforeX"
      execute eventHookBeforeX & "_" & eventname & "()"
    case "AfterX"
      execute eventHookAfterX & "_" & eventname & "()"
  end select
end sub

For at RaiseEvents fungerer skal der igen laves mere bearbejde, nemlig opsætning af eventHookBeforeX og eventHookAfterX, således kaldene ud har et sted at "lande". Dette kræver flere trin, første trin er at skabe funktionerne der skal kaldes. Det kan gøres således:

sub evX_BeforeX()
  ' gør et eller andet
end sub

sub evX_AfterX()
  ' gør et eller andet
end sub

Derefter skal funktionen X kobles op på de event-handlere jeg har lavet. Det gøres ved at fortælle RaiseEvent, hvad mine funktioner hedder:

eventHookBeforeX = "evX"
eventHookAfterX = "evX"

Nu vil funktionen RaiseEvent være i stand til at kalde evX_BeforeX og evX_AfterX!

Den viste metode har dog nogle indlysende ulemper. Følgende obseveres:

  • den er ikke særlig dynamisk idet RaiseEvent skal kodes for hver sæt events man ønsker at rejse
  • den er ikke særlig godt pakket ind idet eventHookBeforeX og eventHookAfterX er globale variable
  • der er ikke meget fejltolerance indbygget, hvilket betyder at hvis et event ikke har nogen handler, så vil koden fejle med et hult drøn!
  • der kan kun kobles et sæt event-handlers på funktionen X, hvilket i realiteten betyder at bare det en en callback og ikke et rigtigt event-hook (event-hooks er et en-til-mange forhold, hvor et callback er et en-til-en forhold)

Dette skal der naturligvis gøres noget ved...

Først kan vi jo tillade at flere handlers bliver koblet hvert eventhook. Det kan vi gøre ved at lave eventHookBeforeX og eventHookAfterX til lister af handlernavn (f.eks. via en kommasepareret streng). Et forsøg kunne se således ud (unhookEvent er medtaget for komplethedens skyld, så vi også har en metode til at slukke for en eventhandler):

sub hookupEvent(byref eventHookList, eventHandlerPrefix)
  if len(eventHookList) > 0 then
    eventHookList = eventHookList & ","
  end if
  eventHookList = eventHookList & "," & eventHandlerPrefix
end sub

sub unhookEvent(byref eventHookList, eventHandlerPrefix)
  dim rx
  set rx = new RegExp
  rx.Global = true
  rx.IgnoreCase = true
  rx.Pattern = "(?:^|,)" & eventHandlerPrefix & "(,|$)"
  eventHookList = rx.Replace(eventHookList,"")
end sub

Funktionen der rejser eventet skal som konsekvens heraf tilpasses, så den tager højde for at er kan være flere eventhandlers koblet på et event. Det løser vi således:

sub RaiseEvents(eventname)
  select case eventname
    case "BeforeX"
      arr = Split(eventHookBeforeX, ",")

    case "AfterX"
      arr = Split(eventHookAfterX, ",")

    case else
      ' Hvis det ikke er et kendt event som rejses, oprettes der blot et tomt
      ' array, så udførslen af events nedenfor ikke umiddelbart fejler
      arr = array()

  end select

  ' Udfør alle de eventhandlers som er koblet på det givne event...
  for each s in arr
    execute s & "_" & eventname & "()"
  next
end sub

Nu kan vi koble flere eventhandlers på de to events. Det kunne gøres således:

hookupEvent eventHookBeforeX, "evX"
hookupEvent eventHookBeforeX, "evX2"
hookupEvent eventHookAfterX, "evX"

Bemærk at evX2, for at illustrere friheden til at reagere på events, ikke reagerer på AfterX-eventet. Vi mangler nu blot at definere evX2-handleren, så det gør vi således:

sub evX2_BeforeX()
  ' gør et eller andet
end sub

Nu er det grundlæggende koncept ridset op, men det er stadig lidt groft i kanten, så hvis du vil videre med det kan du kigge på den næste artikel ("Events i ASP - 2"), som forsøger at pakke tingene lidt ind og gøre grænsefladen til at bruge events mere medgørlig.

 
Sidst opdateret: 10-09-2008 19:02:25
Tilmeld link | Tilføj Link | Tilføj Link | @-begynder
Erklæring om beskyttelse af personlige oplysninger

nope.dk - Danmarks Website Chart