![]() |
Webserveranwendung: EXE ruft ISAPI
Hi zusammen
Der Titel ist vielleicht etwas...äääh...gewöhnungsbedürftig, aber mir ist nichts besseres eingefallen. Der Hintergrund: In einer Projektgroup befinden sich 2 Projekte: Eine mit Webbroker erstellte ISAPI-DLL und eine EXE. Aufgabe der EXE ist es, die Anfrage entgegenzunehmen und einer existierenden Session zuzuweisen, bzw. eine solche im Falle einner Erstanfrage neu zu erstellen. Anschliessend soll die Anfrage an die DLL, bzw. deren Webmodul weitergeleitet werden. Anfänglich hab ich das mit IdHttpServer versucht. Das klappt insofern ganz 'gut', als dass ein in der IdHTTPServer1CommandGet-Methode gesetzter Haltepunkt angesprungen wird, wenn im Browser die URL eingegeben wird. Aber jetzt mal erst der Code:
Delphi-Quellcode:
Nachdem die ersten Versuche sich nur auf die Verwendung des IdHTTPServers beschränkten, diese aber immer AVs lieferten(fehlende Servervariablen) habe ich TIdWebbrokerBridge eingebaut - eigentlich schon vom Klassennamen her einleuchtend.
{$R *.dfm}
procedure TDelborMainServer.FormCreate(Sender: TObject); var AClass: TComponentClass; begin // FHTMLDir := ExtractFilePath(Application.ExeName) + 'HTML'; FIdHTTPWebBrokerBridge := TIdHTTPWebBrokerBridge.Create; FIdHTTPWebBrokerBridge.AutoStartSession := True; FIdHTTPWebBrokerBridge.ServerSoftware := 'DelborMainServer'; FIdHTTPWebBrokerBridge.OnConnect := OnIdHTTPWebBrokerBridgeConnect; FIdHTTPWebBrokerBridge.OnCommandOther := OnIdHTTPWebBrokerBridgeComandother; FIdHTTPWebBrokerBridge.DefaultPort := 8000; FIdHTTPWebBrokerBridge.Active := True; end; procedure TDelborMainServer.IdHTTPServer1CommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); var LFileName, LPathname: String; OK: Boolean; ECB: TEXTENSION_CONTROL_BLOCK; begin OK := DelborFotoGalery(AContext,ARequestInfo, AResponseInfo); end; procedure TDelborMainServer.OnIdHTTPWebBrokerBridgeComandother(AThread: TIdContext; //<=== ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo); begin beep; end; procedure TDelborMainServer.OnIdHTTPWebBrokerBridgeConnect(AContext: TIdContext); //<=== begin beep; end; function DelborFotoGalery(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo):Boolean; var Handle: THandle; DelborFotoGalery: TDelborFotoGalery; begin Handle:=LoadLibrary(PChar(ExtractFilePath(ParamStr(0))+'DelborProject1.dll')); if Handle <> 0 then begin @DelborFotoGalery := GetProcAddress(Handle, 'HttpExtensionProc'); // ): DWORD if @DelborFotoGalery <> nil then begin result := DelborFotoGalery(AContext,ARequestInfo, AResponseInfo); end; end; end; Der Stand der Dinge ist allerdings: auch hier gibts eine AV. Von zwei gesetzten Haltepunkten (durch Pfeile markiert)wird vor Auslösen der AV gerademal der untere (OnIdHTTPWebBrokerBridgeConnect) ausgelöst. Was mache ich falsch? Alles, was für mich schon fast sicher ist: Ich brauche die DLL gar nicht so aufzurufen, wie ich das in DelborFotoGalery tue... Auch die DLL ist im Grunde noch nicht fertig entwickelt; das Webmodul dieser Webbroker-Anwendung wird noch durch ein normales Datenmodul mit Webdispatcher ersetzt. Mein Konzept sieht vor, dass die gesamte Anwendung letzten Endes auf einer(?) Datenbank basiert. Und zum Schluss vielleicht noch die Info, die wohl an den Anfang gehört hätte: die Anwendung soll auf einem Windows-Server laufen. Vielen Dank für eure - hoffentlich zahlreichen - Antworten! Auch über Sinn und Unsinn einer EXE (die ja nicht zwingend eine CGI-Anwendung sein muss(??), lasse ich gerne mit mir reden. Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Delphi-Quellcode:
Die Argumente der ISAPI
@DelborFotoGalery := GetProcAddress(Handle, 'HttpExtensionProc'); // ): DWORD
if @DelborFotoGalery <> nil then begin result := DelborFotoGalery(AContext,ARequestInfo, AResponseInfo); end; ![]() |
AW: Webserveranwendung: EXE ruft ISAPI
Hi zusammmen
Die Grundfrage (wieso die verd.. AV's??:evil:) hat sich in Luft aufgelöst, die Seite wird mir im Browser angezeigt:
Delphi-Quellcode:
Laut Kommmentar existiert diese Prozedure nur noch wegen der Abwärtskompatibilität:
procedure TDelborMainServer.OnIdHTTPWebBrokerBridgeConnect(AContext: TIdContext);
begin FIdHTTPWebBrokerBridge.RegisterWebModuleClass(WebModuleClass); end; Zitat:
Zitat:
Das Einbinden als Iapi-Extension in den IIS alleine hätte allerdings nicht viel gebracht - es wären einfach nur die Anfrage bearbeitet worden. Nach meinem bisherigen Verständnis können in den IIS allerdings auch Isapi-Filter eingebunden werden. Aber genau da hörte bisher mein Verständnis auf, da ich so zwar 2 Isapi-Dlls in den IIS eingebunden hätte - aber eben ohne, dass die eine von der anderen etwas weiss. Die einzige 'Verbindung' wäre wohl eine gemeinsam genutzte DB gewesen. Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Hi mjustin
Vielen Dank für deine Antwort! Zitat:
Ich gehe mal davon aus, dass eine Isapi-Dll, in den IIS eingebunden, von diesen die Werte für den ECB erhält. Aber schon das alein wirft chon wieder eine Menge Fragen auf.... Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
Indy enthält dann mit der Klasse TIdHTTPProxyServer vermutlich schon (fast) alles, was dafür benötigt wird. |
AW: Webserveranwendung: EXE ruft ISAPI
H mjustin
Nein, das solll kein Proxi-Server werdsen, zumindest, soweit ich diesen ![]() Die IIS habe ich auf meinem Kistchen nur, weil die Anwendung später auf dem Hostserver unter den IIS laufen soll. Die reine, mit dem Delphi-Experten erstellte Webbroker-Isapi (ohne Exe), habe ich auf meinem Computer unter den IIS nie zum laufen gebracht. Da nach meinen Infos unter den IIS aber auch Executables laufen, hab ich diese Variante gewählt wobei mir dies aber auch im Hinblick auf eine Session- und Cookieverwaltung wichtig schien. Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Hi zusammen
Gerade eben hab ich mir selbst ein Bein gestellt - ich hab das getan, was Embarcadero ![]() In der Projekt-Unit habe ich folgendes geändert:
Delphi-Quellcode:
in
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := Webmodul1;
Delphi-Quellcode:
Dadurch startet zwar das Projekt. Aber wenn ich im Browser die URL eingebe, wird eine AV geworfen, wenn der WebRequestHandler das Webmodul aktivieren will, aber keins findet.
if WebRequestHandler <> nil then
WebRequestHandler.WebModuleClass := TDelborWebDataModul; So, wie's aussieht, ist die Empfehlung Embarcaderos nur dann gültig, wenn die mit Webbroker erstellt ISAPI-Dll als separate Anwendung im IIS eingebunden wird. Ich kann jetzt nur hoffen, dass das Webmodul DBExpress-Komponenten akzeptiert... Oder weiss jemand, wie man ein Datenmodul endgültig zum Webmodul macht? Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
ABER: Ich habe immer noch nicht verstanden, warum du 2 getrennte ISAPIs/EXEs benötigst und nicht gleich alles in eine ISAPI packst?! |
AW: Webserveranwendung: EXE ruft ISAPI
Hi Olly73
Zitat:
Diese beiden Beispiele hätte ich mir gerne per schrittweisem durchsteppen etwas näher angeschaut, doch wie geschrieben, konnte ich die IIS nie dazu übereden, mir die Seiten aus meinem eigenen Webbroker-Projekt auch anzuzeigen. Zusammen mit der EXE klappt das aber, und gesetzte Haltepunkte werden auch angesprungen. Zitat:
Ein weiterer Grund war aber eben auch: Mit einer Filter-Isapi und einer Isapi-Extension hätte ich offensichtlich/scheinbar zwei unabhängige Projekte gehabt und habe mir zumindest vorerst absolut nicht vorstellen können, wie die beiden zusammenarbeiten, Dazu kommt - eine EXE gibt mir die Möglichkeit, Programmlogik an einem Ort zu verarbeiten (Sessions, Cookies), wie ich das sonst auch mache. Etwas anderes sollte vielleicht auch nicht ausser acht gelassen werden: Microsoft selbst beschreibt die ISAPI-Filter als veraltet; man solle an ihrer Stelle doch eher Module definieren. Und wenn ich richtig gelesen habe, können die auch executables sein. Zitat:
Nachdem ich mir wie oben beschreiben, das ganze durch einfügen des Datemoduls zerschossen habe und eine neue DLL auch nicht viel änderte, werde ich wohl das ganze neu aufsetzen... Das hier hätte ich beinahe überlesen: Zitat:
Und eine Session in die DB zu schreiben, solange sie nicht beendet wird, denke ich, sollte im Interesse der Performance wohl besser unterbleiben. Ich denke, das ergibt viel zu viele Datenbankzugriffe, vor allem, wenn ich auch anonyme Zugriffe über Sessions ablaufen. Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
Zitat:
![]() Aber davon wird explizit abgeraten, außer zum Debuggen. Mit UniGui (unigui.com) kann man auch eine ISAPI-DLL erstellen und die ist "statefull" (hält also Daten für jede aktive Session im Speicher)! Zitat:
Globale Variablen sind grundsätzlich Pfui, da ![]() In die einzelnen Sessions (Session-Objekte) kannst du dann deine Daten, (Daten-)Objekte, Datenmodule etc. packen. Dabei muss ein Objekt oder Datenmodul für jede Session neu erstellt werden und es dürfen auch dort keine globalen Variablen, sondern nur Felder/Properties verwendet werden. Gruß Olli |
AW: Webserveranwendung: EXE ruft ISAPI
Hi Olli73
Zitat:
![]() Ich habe jetzt doch eine Weile gesucht und bislang nur oben verlinkte Seite gefunden, die meine Aussage unterstützt. Aber vielleicht sollten ich doch mal ein Missverständnis ausräumen: Ich wollte nicht behaupten, dass die dll aus dem Speicher entfernt wird: Zitat:
Zitat:
Ich hab jetzt gerade noch etwas in den Sourcen gestöbert. Bislang hatte ich geglaubt, durch die Verwendung der Isapi-Units, die Delphi mitliefert, würde ein Thread automatisch gestarte, konnte bislang aber keinen Code finden, der sowas macht...:?: Solche Aussaggen veranlassten mich zu dieser Annahme: Na ja, mir schwant, dass ein ausführliches Studium zuverlässiger als die Embarcadero-Help ist... Andrerseits - was ist eigentlich genau die Aufgabe der IIS? Sorgen die für den ThreadStart? Da sind leider keine Sourcen dabei, wo man selbst nachsehen könnte, was genau abläuft. Das mit den globalen Variablen war mir bekannt: Das war für mich einer, wenn nicht gar der Hauptgrund, für eine EXE. Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
Zitat:
Zitat:
Wenn also eine neue Anfrage in deinem Webmodul landet, musst du zuerst über die sessionList (unter Beachtung der CriticalSection!) aufrufen und dir darüber deine Daten für diese Session besorgen, bzw. einen neuen Eintrag in der Liste anlegen und eine neue Instanz der Datenstruktur erstellen, wenn es eine neue Session ist (der Client benötigt dann auch diese Session-ID und muss die beim nächsten mal mitsenden). Zitat:
Zitat:
Zitat:
Zitat:
Gruß, Olli |
AW: Webserveranwendung: EXE ruft ISAPI
Hi Olli
Zitat:
Die wohl wichtigste Klasse ist hier TIdWebbrokerBriodge, über die die Webbroker-Anwendung, bzw die erzeugte dll, aufgerufen wird - aber deswegen wohl die Apostrophe. Zitat:
Mein vorheriges Projekt war eine Bilderdatenbank. Für die hatte ich eine Klasse erstellt, die die Daten aus einer SQL-Anfrage übernimmt (ein DS pro Instanz). Dasselbe gedachte ich eigentlich hier zu realisieren. Kurz skizziert:
Aber bevor ich das realisiere, muss ich mir über den genauen Ablauf klar werden - wenn nämlich der Isapi-Tread entegegen meiner bisherigeen Erkenntnis trotzdem automatisch gestartet wird, wird es... na ja, sagen wir mal: interessant. Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
@Delbor
Ein Synchronize ist eigentlich nur für die GUI notwendig. Alles andere kann man über die Synchro-Objekte so steuern, dass immer nur ein Thread-Kontext gleichzeitig zugreift (zugreifen kann) Zudem wiegt man sich mit dem Synchronize auch in eine falsche Sicherheit. Also erstelle die gemeinsam genutzten Klassen threadsafe und benutze die einfach (ohne Synchronize) |
AW: Webserveranwendung: EXE ruft ISAPI
Hi Sir Rufo
Laut Help gilt das mit der falschen Sicherheit für CriticalSections ebenso wie für Synchronize. Ich denke mir, eine CriticalSection beim Create des Threads und bestücken seiner Felder sollte ausreichen, da der Thread zu seiner Laufzeit nur auf seinen eigenen Speicherbereich zugreift. Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Wenn du bei einem Thread von aussen die Felder bestücken kannst, dann hast du den Thread absolut falsch aufgebaut.
Von aussen sollte man mit dem Thread ausschliesslich über Methoden und Eigenschaften kommunizieren können. Diese kann man zuverlässig mit den SynchroObjekten threadsafe gestalten. Eigentlich ist es ganz einfach: Man sorgt dafür, dass es nicht möglich ist auf einen Speicherbereich mit unterschiedlichen Threads gleichzeitig zuzugreifen. Wenn man das mit Synchronize versucht (im MainThreadKontext), dann muss man höllisch aufpassen, dass jeder Zugriff darauf per Synchronize erfolgt (hört sich irgendwie schon komisch an). Zitat:
|
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
(1) Der Thread hat keinen "eigenen Speicherbereich", es gibt nur 1 gemeinsamen Speicherbereich für den gesamten Prozess; das "getrennt" zu halten bzw. gegenseitige Zugriffe in sicherer Weise zu erlauben ist deine Aufgabe. (2) Die CriticalSection musst du vor jedem Zugriff betreten und anschließend wieder verlassen und zwar aus dem Thread heraus, der auf die Daten zugreifen will; so wird der gleichzeitige Zugriff von 2 Threads aus verhindert. Das ist aber auch der Grund, warum die CriticalSection dir bei GUI-Komponenten nichts bringt: Da die VCL/WinApi deine CriticalSection nicht kennt, wird sie sie auch nicht beachten. |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
Die VCL ist nicht threadsafe ausgelegt und darum darf man auf die VCL-Teile eben nur synchronisiert zugreifen. Der andere Weg ist doch simpel über Getter und Setter zu erreichen, die dann die CriticalSection betreten und wieder verlassen. Irgendwie beschleicht mich das Gefühl, dass hier von einer globalen CriticalSection gesprochen wird ... ist dem so, oder kommt nur meine Paranoia wieder hoch? :) |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
Zitat:
|
AW: Webserveranwendung: EXE ruft ISAPI
Hi zusammen
Ich sehe das bisher so vor :
Zitat:
Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
Aber dass bei Verwendung von TIdHttpServer, TIdHttpWebBrokerBridge etc. bereits "automatisch" mehrere Threads existieren, ist dir bewusst? Gruß, Olli |
AW: Webserveranwendung: EXE ruft ISAPI
Hi Olli
Heute morgen ist es mir wie Schuppen von den Augen gefallen: Der Parameter IdContext ist vom Typ AThread, und der wird bei den Sockets das erste mal deklariert und dann an alle Nachkommen weitergereicht, damit diese eine CriticalSection für den existierenden Thread einrichten können. Pro Anfrage existiert also genau ein Thread, und zwar genau so lange, bis dieser die Antwort über die Sockets ausgegeben hat. Natürlich kann es trotzdem zu Überschneidungen kommen; nämlich dann, wenn kurz nacheinander mehrere Threads gestartet werden, aber einer (oder mehrere) schneller arbeitet als andere. Wenn dann die Anfrage beim Webmodul angekommen ist, ist ein Speicherzugriff ohne Criticalsection nicht mehr möglich, bzw. ein Hazzardspiel. Und das bedeutet, dass mein Konzept, dem Thread alle Infos beim Start mitzugeben, hier nicht möglich ist. Zitat:
Gruss Delbor |
AW: Webserveranwendung: EXE ruft ISAPI
Zitat:
Deshalb solltest du einfach eine DLL (oder EXE) verwenden und dir dort eine eigene Session-Verwaltung (mit CriticalSections !) einbauen. Gru0, Olli |
Alle Zeitangaben in WEZ +1. Es ist jetzt 11:40 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz