Ir al contenido


Foto

Configuracion de Servidor DataSnap


  • Por favor identifícate para responder
8 respuestas en este tema

#1 chaja

chaja

    Advanced Member

  • Miembros
  • PipPipPip
  • 54 mensajes

Escrito 14 septiembre 2014 - 11:34

Hola:
Bueno, mi pregunta tal vez es obvia pero no se por que no sale. Estoy tratando de hacer mi primer servidor DataSnap. Para ello use el mismo Wizard, y use como ServerMethods el TDataModule.
Uso Como Base de Datos, por ahor Interbase, ya que quiero pasar a Firebird. En el ServerMethods, coloque el conector de Base  un SQLConnection, y lo configure a la base de datos que utilizo. Conecta y todo bien.
Para complicarmela la existencia, el form principal del servidor, intento hacer que el user configure el path de la base de datos, pues puede estar en otra ubicacion de lo habitual. Para ello pense un archivo .ini y guardarla. El tema es que desde el FormPrincipal, no tengo acceso a los componetes incrustados el el ServerMethods, si bien la unidad esta declara en el uses.
Esto es parte del Codigo:



delphi
  1. procedure TFormServidor.BitBtn1Click(Sender: TObject);
  2. begin
  3.   TServerMethods.SQLConnection.DriverName:='INTRBASE';
  4.   TServerMethods.SQLConnection.Params.Add('Database='+edPathBase.Text);
  5.   TServerMethods.SQLConnection.Params.Add('RoleName=RoleName');
  6.   TServerMethods.SQLConnection.Params.Add('User_Name=sysdba');
  7.   TServerMethods.SQLConnection.Params.Add('Password=regulador');
  8.   TServerMethods.SQLConnection.Params.Add('ServerCharSet=');
  9.   TServerMethods.SQLConnection.Params.Add('SQLDialect=1');
  10.   TServerMethods.SQLConnection.Params.Add('ErrorResourceFile=');
  11.   TServerMethods.SQLConnection.Params.Add('LocaleCode=0000');
  12.   TServerMethods.SQLConnection.Params.Add('BlobSize=-1');
  13.   TServerMethods.SQLConnection.Params.Add('CommitRetain=False');
  14.   TServerMethods.SQLConnection.Params.Add('WaitOnLocks=True');
  15.   TServerMethods.SQLConnection.Params.Add('Interbase TransIsolation=ReadCommited');
  16.   TServerMethods.SQLConnection.Params.Add('Trim Char=False');
  17.   try
  18.     TServerMethods.SQLConnection.Connected:=True;
  19.   except
  20.     on e: Exception do
  21.     begin
  22.       Application.MessageBox(pchar (e.ClassName + ';' + e.Message),'error',MB_ICONSTOP);
  23.       ShowMessage('Verificar el Alias de la Base de Datos.....');
  24.       TServerMethods.SQLConnection.Connected:=False;
  25.     end;
  26.   end;
  27. end;



Cuando intento compilar sale esto:

 
[dcc32 Error] UServidor.pas(37): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(37): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(38): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(38): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(39): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(39): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(40): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(40): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(41): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(41): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(42): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(42): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(43): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(43): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(44): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(44): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(45): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(45): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(46): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(46): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(47): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(47): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(48): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(48): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(49): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(49): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(50): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(50): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(52): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(52): E2066 Missing operator or semicolon
[dcc32 Error] UServidor.pas(58): E2096 Method identifier expected
[dcc32 Error] UServidor.pas(58): E2066 Missing operator or semicolon
[dcc32 Fatal Error] ServidorDS.dpr(5): F2063 Could not compile used unit 'UServidor.pas'
Failed
Elapsed time: 00:00:00.6

en la decalaracion del Servidor esta asi:



delphi
  1. unit UServidor;
  2.  
  3. interface
  4.  
  5. uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
  6.   System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
  7.   Vcl.StdCtrls, Vcl.Buttons,IniFiles, UServerContainer,UServerMethods;
  8.  
  9. type
  10.   TFormServidor = class(TForm)
  11.     lbMensaje: TLabel;
  12.     edPathBase: TEdit;
  13.     OpenDialog1: TOpenDialog;
  14.     spDir: TSpeedButton;
  15.     BitBtn1: TBitBtn;
  16.     btIniciarServicio: TBitBtn;
  17.     procedure spDirClick(Sender: TObject);
  18.     procedure FormCreate(Sender: TObject);
  19.     procedure BitBtn1Click(Sender: TObject);
  20.     procedure btIniciarServicioClick(Sender: TObject);
  21.   private
  22.     { Private declarations }
  23.   public
  24.     { Public declarations }
  25.     ArchivoIni:TIniFile;
  26.   end;
  27.  
  28. var
  29.   FormServidor: TFormServidor;
  30.  
  31. implementation
  32. //uses UServerMethods;



Que hay de bien que estoy haciendo mal????

Gracias

Luis Roldan
Mar del Plata
Argentina
  • 0

#2 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 14 septiembre 2014 - 02:25

Hola

El modelo de datasnap, incluye dependiendo del modo en que configures el DSServer, que se cree un datamodule para cada cliente que se conecta, es decir que el datamodule no se crea al momento de arrancar la aplicación del servidor, sino en el momento en que el cliente se conecta al servidor.  dos cosas muy diferentes.

El servidor en cualquier momento puede tener muchas instancias del tdatamodule,  y no es fácil configurar eso desde un form externo.  igualmente no es bueno compartir una conexión de base de datos entre muchos clientes (Por si ya lo habías pensado, y dejar la conexión en un solo datamodule adicional o en el form de la aplicación) ya que el manejo de la concurrencia es complicado y ya hay que entrar a hacer otras cosas.

en últimas, el tdatamodule debe ser autónomo y debe poder configurar su base de datos sin intervención de botones externos o formularios externos. y ese es el problema que tienes.

Yo usualmente creo un .ini y lo leo en el oncreate de tdatamodule y que el se configure automáticamente.  y el Form que crea el wizard se deja sin tocar.

Saludos.
  • 0

#3 chaja

chaja

    Advanced Member

  • Miembros
  • PipPipPip
  • 54 mensajes

Escrito 17 septiembre 2014 - 02:20

Master:

Bueno re hice el servidor y lo hice con la opcion tres la ServerModule.
Lo que yo queria hacer era, que segun el cliente que instale el servidor, configura la ubicacion de la base de datos. Lo hice como me dijistes y todos toman la misma base. Ahora, si cada cliente crea una instancia del datamodule, no se hace lento luego el sistema? puedo tener problems de concurrencia?. En Windows Desktop, bueno varios usuarios pueden abrir el mismo registro y no he tenido nunca problemas... no se estoy pensando en vos escrita. Entonces lo que hice esta, pero debo tener algun control extra???

Gracias
  • 0

#4 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 19 septiembre 2014 - 10:13

Hola, El acceso a la base de datos es concurrente, esto quiere decir que las bases de datos están diseñadas para trabajar con muchos usuarios consultando y actualizando al tiempo.  Por eso es importante revisar bien los parámetros de conexión ya que en ellos puedes definir que pasa cuando dos usuarios intentan acceder al mismo registro.

La Arquitectura de DataSnap, carga a memoria los registros (y creo que eso mismo hace .NET y muchas otras herramientas de BD.) y lo que hace es verificar al momento de guardar si es posible o no, si el registro almacenado sigue siendo el mismo que tenía originalmente en memoria.  de no ser cierto, te enviará un error o lista de errores para que tomes decisiones con respecto a cada registro.

En la documentación de DbExpress y TClientDataSet, explican como solucionar estos inconvenientes.

Yo tengo una aplicación con 200 usuarios conectados simultáneamente y a pesar que tengo las validaciones necesarias, no se me ha presentado ningún caso como ese en dos años de uso.

Saludos.


  • 0

#5 chaja

chaja

    Advanced Member

  • Miembros
  • PipPipPip
  • 54 mensajes

Escrito 04 enero 2015 - 09:42

Hola genriquez:
antes que nada Feliz Año nuevo.
Retomando en parte lo que esta escrito y releyendo, te pregunto si esta bien hacer en el ServerContainer este mi SQLConnection y los SeverModule apunten a ese SQLConnection los Query que contenga.
Otra . En el servidor de dataSnap cree varios ServerModule, como si fuese DataModules , de la misma forma que hacia en Cliente-Servidor, y ahi pongo los Querys con sus DataSetProvider, todo bien. Ahora quiero crear, agregar otro servermodule, y para mi sorpresa veo que hago File->New->Other->DataSnap Server y el icono de ServerModule no esta. Hice la mas tonta, genere desde el wizard otro Server DataSnap, y aparace lo mas bien. No se que he tocado o modificado para que no me permita agregar mas ServerModule.
Gracias
Luis Roldan
  • 0

#6 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 10 enero 2015 - 07:01

Hola, Feliz Año para ti también

Debes tener en cuenta que el Servidor DataSnap, crea automáticamente un módulo para cada conexión con el cliente y ese módulo es exclusivo para ese cliente, no se comparte con otros usuarios.  Esa es la razón por la cual el componente de conexión a base de datos está en ese datamodulo y todos los Queries están siempre encapsulados en un contenedor específico.  De no ser así, sería muy complejo manejar la concurrencia.

Pero lo bonito de Delphi es que el te sugiere cosas, como deberían ser, sin embargo no obliga a que deba ser así. y hay varias formas de hacerlo.

1.  En el Módulo ServerContainer, existe el componente DSServerClass1: TDSServerClass1, el cual tiene una propiedad llamada LifeCycle,  en ella pues decir que el datamodulo se cree por sesión (Por cada Cliente),  por Servidor (Una compartida para todos los clientes) y por llamado (cada vez que es invocada alguna función).  En estos casos te tocaría a ti manejar la concurrencia.

2.  Si quieres crear otro DataModulo y publicar las funciones de ese datamodulo al igual que los DataSets, deberás crear un nuevo datamodulo con el Wizard y se crea un ServerModule,  pero esto no es suficiente para publicarlo,  adicionalmente en el modulo ServerContainer, deberás agregar un nuevo componente del tipo TDSServerClass, y en el método OnGetClass retornar una instancia del nuevo datamodulo.



delphi
  1. procedure TServerContainer1.DSServerClassNGetClass( DSServerClass: TDSServerClass; var PersistentClass: TPersistentClass);
  2. begin
  3.   PersistentClass := ServerMethodsUnitN.TServerMethodsN;
  4. end;



Pero esto solo si quieres publicar otro datamodulo.

En el lado del cliente debes realizar una nueva conexión al segundo datamodulo con un TDSProviderConection, ya que representa un elemento diferente.

3. Si lo que quieres es organizar mejor tus queries internos y no es necesarios publicar las funciones o los datasets, sino que los llamas desde el Datamodulo principal, puedes crear un DataModulo normal, ya sea en el OnCreate del DataModulo y eliminarlo en el OnDestroy respectivo, así cada conexión debe tener su propio DataModulo normal.

Espero haya sido claro en la explicación.

Saludos.


  • 0

#7 chaja

chaja

    Advanced Member

  • Miembros
  • PipPipPip
  • 54 mensajes

Escrito 10 enero 2015 - 08:57

Ok gracias por la respuesta.... si basicamebte es lo que e hecho. Ahora me queda claro con le lifecycle, yo los tengo como session.
Lo que yo te decia, que hasta no hace mucho, en el servidor datasnap queria agregar un server module y lo podia hacer, y ahora no me deja. es como que el icono desaparecio. eso me intrigaba.
Ahora, como puedo hacer que si el cliente pierde conecion con el servidor, capturar el error del lado del cliente.... a veces me sucede que hay un microcorte de internet y el cliente pierde coneccion  con el servidor y no te das cuenta hasta que no hagas una peticion al servidor, en ese caso te tira una excepcion y se cuelga la aplicacion.


  • 0

#8 genriquez

genriquez

    Advanced Member

  • Miembro Platino
  • PipPipPip
  • 539 mensajes
  • LocationCali, Colombia

Escrito 12 enero 2015 - 03:50

Hola

Yo cree una función en la cual le envio una palabra y la función me retorna la misma palabra, y antes de enviar cualquier petición al servidor, pruebo la conexión, si falla, pues restauro la conexión y ejecuto la función.

La verdad no sé si exista otra alternativa, y si la hay, espero la compartan. ;)

Saludos.
  • 0

#9 Wilson

Wilson

    Advanced Member

  • Moderadores
  • PipPipPip
  • 2.137 mensajes

Escrito 13 enero 2015 - 08:27

Hola

Yo cree una función en la cual le envio una palabra y la función me retorna la misma palabra, y antes de enviar cualquier petición al servidor, pruebo la conexión, si falla, pues restauro la conexión y ejecuto la función.

La verdad no sé si exista otra alternativa, y si la hay, espero la compartan. ;)

Saludos.


Yo hago algo muy parecido, solo que además yo utilizo un Timer que periódicamente trae la hora del servidor, si falla pues intenta reconectarse.
Además he definido en la unit del módulo de conexión un campo booleano de nombre "FActivo", a modo de bandera, de tal manera que cuando inicio la ejecución de cualquier método que involucre la conexión vale True y cuando termina vale False, así el Timer solo opera cunado FActivo vale False para evitar choques, de este modo mantengo "viva" la conexión el mayor tiempo posible y pienso que el consumo de recursos es irrelevante.

Un saludo.
  • 0




IP.Board spam blocked by CleanTalk.