Announcement

Collapse
No announcement yet.

RDS und HTTP

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • RDS und HTTP

    Hallo !

    Ich möchte mit eigenen MTS-Objekten recordsets via HTTP Übertragen. Meine Anwendung ist im Prinzip dem Delphi Demo nachempfunden. Die Übertragung via DCOM klappt. Mit HTTP bekomme ich zwar Zugriff auf mein Objekt (wird im MTS instanziiert), erhalte aber die Fehlermeldung "Member nicht gefunden".
    Danke für jede Hilfe.

  • #2
    Hallo,

    in der Frage taucht RDS und HTTP auf - welches davon soll denn nun verwendet werden? Im Normalfall wird man mit DCOM auf das MTS/COM+ Objekt zugreifen. Für den Fall, dass die Verbindung über <b>TWebConnection</b> laufen soll, ist folgendes möglich:

    Das COM+ Objekt liefert ein RecordSet-Objekt an den Client zurück:
    <pre>
    function TOSManagerObj.GetRecordSet(sID: Integer): OleVariant;
    var
    aConnection : _Connection;
    aRS : _Recordset;
    swSQL : WideString;
    begin
    aConnection := CoConnection.Create;
    aConnection.CursorLocation := adUseClient;
    aConnection.Open(cCONNSTR, '', '', adConnectUnspecified);
    aRS := CoRecordset.Create;
    swSQL := 'SELECT * FROM ...';
    aRS.Open(swSQL, aConnection, adOpenKeyset, adLockBatchOptimistic, 0);
    Result := aRS;
    aRS.Set_ActiveConnection(nil);
    aConnection.Close;
    SetComplete;
    end;
    </pre>
    Der Client baut die Verbindung zum Server über <b>TWebConnection</b> und damit über das HTTP-Protokoll auf und holt sich die Daten des RecordSet-Objekts vom Server ab:
    <pre>
    procedure TForm1.Button1Click(Sender: TObject);
    var
    vRS : OleVariant;
    sData : String;
    begin
    WebConnection1.Connected := True;
    vRS := WebConnection1.AppServer.GetRecordSet(89010100);
    sData := vRS.Collect[1] + #10#13 +
    vRS.Collect[2] + #10#13 +
    vRS.Collect[3];
    ShowMessage(sData);
    vRS.Close;
    WebConnection1.Connected := False;
    end;
    </pre>
    Wenn der Zugriff allerdings über <b>RDS</b> laufen soll, wird anstelle von TWebConnection eine Instanz von <b>TRDSConnection</b> eingesetzt. Wenn dann die <i>MSDFMAP.INI</i> auf dem Application Server angepasst wird, kann der Client direkt auf die Daten zugreifen. Das könnte so aussehen:
    <pre>
    {
    MSDFMAP.INI auf dem Notebook:

    [connect default]
    ;If we want to disable unknown connect values, we set Access to NoAccess
    ;14.01.2000 NoAccess auf ReadWrite geändert
    Access=ReadWrite

    [sql default]
    ;If we want to disable unknown sql values, we set Sql to an invalid query.
    ;14.01.2001 Sql auskommentiert
    ;Sql=" "
    }

    procedure TForm1.OpenButtonClick(Sender: TObject);
    begin
    RDSConnection1.Close;
    Employee.Close;
    Employee.Open;
    end;

    procedure TForm1.ButtonUpdateClick(Sender: TObject);
    begin
    RDSConnection1.AppServer.Update(Employee.Recordset );
    end;
    </pre>
    Bei der TRDSConnection-Instanz wird die Eigenschaft <b>ServerName</b> auf 'RServer.RDSAppServer' gesetzt (um beim Borland-Beispiel zu bleiben)

    Comment


    • #3
      Ich möchte die RDSConnection bzw. RDS einsetzten um ein recordset via HTTP vom Server zum Client zu übertragen, wie im Artikel
      http://www.eu.microsoft.com/germany/msdn/artikel/rds.htm
      für VB beschrieben

      Comment


      • #4
        Hallo,

        auch das ist kein Problem. Das Beispiel aus dem Abschnitt <i>Implicit Remoting mit ADO</i> aus dem o.g. Artikel ist auch mit Delphi in exakt der gleichen Art und Weise möglich:
        <pre>
        uses ADOInt;

        procedure TForm1.Button1Click(Sender: TObject);
        var
        aRS : _Recordset;
        swSQL : WideString;
        swConn : WideString;
        begin
        aRS := CoRecordset.Create;

        swSQL := 'SELECT * FROM VIEW_GiFromGENNR WHERE ..';

        swConn := 'Provider=MS Remote;RemoteServer=http://192.168.1.101;' +
        'Remote Provider=SQLOLEDB.1;Persist Security Info=False;' +
        'User ID=sa;Initial Catalog=OSSISOFT;Data Source=(local)';

        aRS.Open(swSQL, swConn, adOpenStatic, adLockBatchOptimistic, 0);
        ShowMessage(aRS.Collect[1]);
        aRS.Close;
        end;
        </pre&gt

        Comment


        • #5
          Stimmt, aber mir gelingt einfach keine Nachbildung des Beispiels aus dem Abschnitt "Explicit Remoting mit eigenen COM-Komponenten".
          Der Client steigt in der Methode RDSConnection.GetRecordset --> GetFromProperty mit dem Fehler "Member nicht gefunden" aus. In der MSDN Libary habe ich gefunden das dieser Fehler bei einem Aufruf von IDispatch.invoke mit dem Flag DISPATCH_METHOD auftreten kann, wenn die dispid eine property identifiziert. Wie kann ich an dieser Stelle eine Methode oder Eigenschaft meines Servers abfragen

          Comment


          • #6
            Hallo,

            beim Thema <i>Explicit Remoting mit eigenen COM-Objekten</i> stellt sich für uns Delphianer die Frage, warum wir überhaupt ein VB6-Beispiel über RDS nachbauen wollen, wenn Delphi besseres im Angebot hat ;-)

            Wie sieht das konkrete Beispiel aus, das mit der Fehlermeldung fehlschlägt

            Comment


            • #7
              Hallo !

              Problem vorerst gelößt! Wenn ich statt einer Property eine Methode des Serverobjekts in der Eigenschaft TADODataSet.CommandText angebe, kann die RDSConnection das recorset, was von dieser Methode zurückgegeben wird, via HTTP ziehen.
              Frage, gibt es hier auch eine Möglichkeit ähnlich wie in dem genannten VB6-Beispiel dem Server Parameter zu übergeben?
              Der Aufruf in ADODB.pas sieht so aus:

              FAppServer: OleVariant;
              FDataSpace: DataSpace;

              FAppServer := FDataSpace.CreateObject(ServerName, ComputerName);

              function GetFromProperty: _RecordSet;
              var
              Status, DispID: Integer;
              ExcepInfo: TExcepInfo;
              VarResult: OleVariant;
              FServDisp: IDispatch;
              DispParams: TDispParams;
              begin
              FServDisp := IUnknown(FAppServer) as IDispatch;
              FillChar(DispParams, SizeOf(DispParams), 0);
              OLECheck(FServDisp.GetIDsOfNames(GUID_NULL, @CommandText, 1, 0, @DispID));
              Status := FServDisp.Invoke(DispID, GUID_NULL, LOCALE_USER_DEFAULT,
              DISPATCH_PROPERTYGET, DispParams, @VarResult, @ExcepInfo, nil);
              if Status <> 0 then DispatchInvokeError(Status, ExcepInfo);
              Result := IUnknown(VarResult) as _Recordset;
              end;

              Wie muß ich die DispParams befüllen? Haben sie vielleicht ein Beispiel, wie man das DataSpace Objekt auf diese Weise nutzen kann. Mir geht es nur darum ADODataSets auf dem Client möglichst elegant und schnell über HTTP mit Daten zu füllen, möglichst mit eigenen MTS-Objekten und ohne die DataFactory. Dieser Weg scheint mir hier sinnvoll. Die Übertragung zurück zum Server ist bereits auf anderem Weg, ebenfalls über HTTP, gelöst

              Comment


              • #8
                Verzeihung für die peinliche Unordnung.

                function GetFromProperty: _RecordSet;<br>
                var<br>
                Status, DispID: Integer;<br>
                ExcepInfo: TExcepInfo;<br>
                VarResult: OleVariant;<br>
                FServDisp: IDispatch;<br>
                DispParams: TDispParams;<br>
                begin<br>
                FServDisp := IUnknown(FAppServer) as IDispatch;<br>
                FillChar(DispParams, SizeOf(DispParams), 0);<br>
                OLECheck(FServDisp.GetIDsOfNames(GUID_NULL, @CommandText, 1, 0, @DispID));<br>
                Status := FServDisp.Invoke(DispID, GUID_NULL, LOCALE_USER_DEFAULT,<br>
                DISPATCH_PROPERTYGET, DispParams, @VarResult, @ExcepInfo, nil);<br>
                if Status <> 0 then DispatchInvokeError(Status, ExcepInfo);<br>
                Result := IUnknown(VarResult) as _Recordset;<br>
                end;<br&gt

                Comment


                • #9
                  Hallo,

                  wenn über RDS eine Methode des COM-Objekts aufgerufen wird und diese Methode ein RecordSet an den Client zurückliefert, kann man doch die variablen Teile als Parameter der Methode direkt übergeben. Innerhalb der Methode werden dann die Parameter-Werte verwendet, um nur die gesuchten Datensätze im RecordSet zurückzuliefern.

                  Mit Delphi stehen außer RDS noch andere Wege über HTTP zur Verfügung, die sogar einfacher sind: <br>
                  a) ASP liefert RecordSet als XML zurück (7 Programmzeilen im ASP-Script), Delphi-Client ordnet das RecordSet-Objekt einer TADODataSet-Instanz zu, so dass die Daten im DBGrid angezeigt werden können. <br>
                  b) Delphi-Client greift über TWebConnection (HTTP) auf das COM-Objekt auf dem Server zu, wobei eigene Interface-Methoden als Schnittstelle verwendet werden. Auch hier kann man (analog zu RDS) ein RecordSet zurückliefern lassen

                  Comment


                  • #10
                    2. Teil

                    Für den Fall, dass mit RDS ein parametisierte SELECT-Abfrage als RecordSet zurückgeliefert werden soll, könnte man folgendes machen:

                    <b>Interface-Methode im COM+ Server</b>
                    <pre>
                    function TExplicitRDSObj.GetRSwithParam(sCity: OleVariant): _Recordset;
                    var
                    aConnection : _Connection;
                    aRS : _Recordset;
                    swSQL : WideString;
                    swConnStr : WideString;
                    begin
                    swConnStr := 'Provider=SQLOLEDB.1;Persist Security Info=False;' +
                    'User ID=sa;Initial Catalog=Northwind;'+
                    'Data Source=192.168.10.22';
                    aConnection := CoConnection.Create;
                    aConnection.CursorLocation := adUseClient;
                    aConnection.Open(swConnStr, '', '', adConnectUnspecified);
                    aRS := CoRecordset.Create;
                    swSQL := 'SELECT * FROM Customers WHERE City = ' + QuotedStr(sCity);
                    aRS.Open(swSQL, aConnection, adOpenStatic, adLockBatchOptimistic, 0);
                    Result := aRS;
                    aRS.Set_ActiveConnection(nil);
                    aConnection.Close;
                    end;
                    </pre>
                    <b>Client holt über RDS das RecordSet ab: </b>
                    <pre>
                    procedure TForm1.ButtonGetRSwithParamClick(Sender: TObject);
                    var
                    vRS : OleVariant;
                    aRS : _RecordSet;
                    begin
                    RDSConnection1.ComputerName := 'http://192.168.10.12';
                    RDSConnection1.ServerName := 'ExplicitRDS.ExplicitRDSObj';
                    RDSConnection1.Connected := True;
                    vRS := RDSConnection1.AppServer.GetRSwithParam(EditCity.T ext);
                    aRS := IUnknown(vRS) as _RecordSet;
                    ADODataSetResult.RecordSet := aRS;
                    ADODataSetResult.Active := True;
                    end;
                    </pre&gt

                    Comment


                    • #11
                      Danke,

                      danach hatte ich gesucht. Ihr Beispiel funktioniert einwandfrei. Irgendwie hab ich es auf diese einfache Weise nie ans laufen bekommen und dann zu kompliziert gedacht. Per RDS lassen sich so doch auf einfache Weise statuslose MTS-Objeke ueber HTTP aufrufen. Mich wundert ein wenig, das man ueber diese Moeglichkeiten so weing hoert. Wenn auf dem Client ADO (MDAC) vorhanden ist, benötigt man, solange man auf dem Server Microsoft Produkte einsetzt, nichts anderes mehr

                      Comment


                      • #12
                        Hallo,

                        aus verständlichen Gründen legt Borland mehr Wert auf <b>MIDAS + TWebConnection</b> (wegen der zusätzlichen Lizenzeinnahmen). Da in neuen Windows-Versionen MDAC automatisch vorinstalliert ist und alte Betriebssysteme völlig kostenfrei auf MDAC aktualisierbar sind, ist RDS (falls HTTP über Port 80 benötigt wird) in der Tat eine sehr effektive Sache

                        Comment


                        • #13
                          Hallo,<br>
                          das mit RDS ist ja eine feine Sache - wenigstens klappt (bei mir) die Objektfreigabe nach einem Aufruf (neben Socket- und DCOMConnection) im Gegensatz zu WebConnection. Ich habe das auch mal getestet - allerdings funtioniert das nur über den lokalen Aufruf (Computername ist leer). Gebe ich die URL an, erhalte ich den Fehler <i>Unexpected Error (0x80070005)</i>. Was ist zu beachten ? (Der Zugriff auf die MSADC Anwendung auf dem IIS funktioniert).<br>
                          Vielen Dank<br>
                          Herman

                          Comment


                          • #14
                            Hallo,

                            wenn Sie beim Aufruf die OLE-Exception 80070005 erhalten, ist der als Server angesprochene Rechner gegenüber allen RDS-Aufrufen geschottet.
                            Aus Sicherheitsgründen sind alle Zugriffe von externen Rechners aus solange gesperrt, bis ein spezieller Registry-Eintrag vorgefunden wird. Damit das COM+ Objekt von außen über RDS gestartet werden kann, muss ein Berechtigungs-Schlüssel in der Registry eingetragen werden. Unter <i>HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Ser vices\W3SVC\Parameters</i> wird ein neuer Schlüssel mit der <b>ProgID</b> des COM+ Objekts angelegt, Microsoft hat 2 Beispiel bereits dort untergebracht

                            Comment


                            • #15
                              Hallo,<br>
                              <i>Unter HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Servic es\W3SVC\Parameters wird ein neuer Schlüssel mit der ProgID des COM+ Objekts angelegt, Microsoft hat 2 Beispiel bereits dort untergebracht. </i>:<br>
                              Unter diesem Schlüssel Parameters stehen (auf 3 verschiedenen IIS) bei mir nur zwei (3) Schlüssel (ADCLaunch (nur IIS4 unter NT4Srv), Script Map, Virtual Roots). Von Microsoft Beispielen keine Spur (RDSServer.DataFactory). Ist das wirklich die richtige Stelle ? Denn auch wenn ich dort den Schlüssel für das COM+ Objekt anlege, bleibt es bei dem Fehler. Im SDK habe ich gelesen, dass das COM+ Objekt als Bibliotheksanwendung gestartet werden muss. Ist das korrekt ?<br&gt

                              Comment

                              Working...
                              X