IR
irwinrodriguez.dev
Back to docs

Examples

20 progressive examples taking you from .NET basics to real-world use cases: generic collections, async/await, HttpClient and more. Each example is self-contained and ready to paste into your project.

About initialization Every example assumes loBridge is already initialized AND ACTIVATED. Without Activate() none of them works: any call answers "FoxBridge is not activated". Run this once at start-up:
Create and activate the bridge (once at start-up)
loBridge = NEWOBJECT("FoxBridge", "FoxBridge.prg")
IF !loBridge.Activate(lcJwt)
    ? loBridge.GetLastError()
    RETURN
ENDIF

Basic level: first steps

Example 1: StringBuilder, your first .NET object

StringBuilder is the best starting point: simple, predictable and demonstrates the full cycle of Create, call methods, get result.

StringBuilder: building a string in .NET
loBuilder = loBridge.Create("System.Text.StringBuilder", "Hola ")
loBuilder.Append("mundo ")
loBuilder.Append("desde FoxBridge!")
? loBuilder.ToString()   && "Hola mundo desde FoxBridge!"
? loBuilder.Length       && 27
loBuilder = .NULL.

Example 2: Uri, inspecting a URL

System.Uri breaks a URL into its parts (host, port, path, query). Demonstrates the use of Qualified Assembly Names (AQN) with the comma.

System.Uri: breaking a URL into its parts
loUri = loBridge.Create("System.Uri, System", "https://api.miempresa.com:8080/v1/clientes?estado=activo")
? "Host:  ", loUri.Host           && "api.miempresa.com"
? "Puerto:", loUri.Port           && 8080
? "Ruta:  ", loUri.AbsolutePath   && "/v1/clientes"
? "Query: ", loUri.Query          && "?estado=activo"
loUri = .NULL.

Example 3: LoadAssembly, using your own DLL

The real power of FoxBridge: load a DLL you compiled yourself in C# or VB.NET and call its classes as if they were native VFP objects.

LoadAssembly: computing the total with VAT from your DLL
llOk = loBridge.LoadAssembly("C:\MiApp\bin\MiLogica.dll")
IF llOk
    loFactura = loBridge.Create("MiLogica.Facturacion", 0.16)  && IVA 16%
    lnTotal   = loFactura.CalcularTotal(1000.00)
    ? "Total con IVA:", lnTotal   && 1160.00
    loFactura = .NULL.
ENDIF

Intermediate level: collections, statics and exceptions

Example 4: List<String>, generic lists

FoxBridge automatically converts List<T> to a proxy with Add, Remove, Item and Count methods. Indexing is 1-based, like VFP.

List<String>: adding, looping over and removing items
loLista = loBridge.Create("List<String>")
loLista.Add("Visual FoxPro")
loLista.Add("C#")
loLista.Add("F#")
loLista.Add("Go")

? "Total:", loLista.Count()    && 4
? "Tercero:", loLista.Item(3)  && "F#"

* Recorrer
For i = 1 to loLista.Count()
  ? Transform(i) + ". " + loLista.Item(i)
Next

loLista.Remove("Go")
? "Despues de Remove:", loLista.Count()   && 3
loLista = .NULL.

Example 5: DirectoryInfo, listing files

GetFiles() returns an array of FileInfo objects. Each element is a FoxBridge proxy with its own properties. We use GetObject(i) to access each element.

DirectoryInfo: name, size and extension of each file
loDir   = loBridge.Create("System.IO.DirectoryInfo", "C:\Windows")
loFiles = loDir.GetFiles()

? "Archivos encontrados:", loFiles.Count()

For i = 1 to Min(5, loFiles.Count())
    loFile = loFiles.GetObject(i)
    ? "Nombre:  " + loFile.Name
    ? "Tamano:  " + Transform(loFile.Length) + " bytes"
    ? "Extension: " + loFile.Extension
    loFile = .NULL.
Next

loFiles = .NULL.
loDir   = .NULL.

Example 6: Dictionary<String, String>, key-value

.NET dictionaries in FoxBridge use Set, Get, ContainsKey and Remove. Mind the name: it is ContainsKey, not Contains. When the value is a complex object, use GetObject() instead of Get().

Dictionary<String, String>: storing, looking up and removing keys
loDict = loBridge.Create("Dictionary<String, String>")
loDict.Set("nombre", "Irwin Rodriguez")
loDict.Set("pais",   "Mexico")
loDict.Set("lang",   "Visual FoxPro")

? "Contiene 'nombre':", loDict.ContainsKey("nombre")   && .T.
? "Valor:", loDict.Get("nombre")                        && "Irwin Rodriguez"

loDict.Remove("lang")
? "Contiene 'lang' tras Remove:", loDict.ContainsKey("lang")   && .F.

loDict = .NULL.

Example 7: Overload resolution, the Binder in action

VFP has only one numeric type (Double). FoxBridge automatically detects the correct overload for each call. Here we test it with Append(), which has 18 overloads in .NET.

StringBuilder.Append: one overload for each VFP type
loSB = loBridge.Create("System.Text.StringBuilder")

loSB.Append("Entero: ")
loSB.Append(100)        && VFP manda Double y el Binder busca la firma
                        && exacta: resuelve a Append(double)

loSB.Append(" | Booleano: ")
loSB.Append(.T.)        && VFP envia Logical, .NET resuelve a Append(bool)

loSB.Append(" | Double: ")
loSB.Append(45.67)      && .NET resuelve a Append(double)

? loSB.ToString()   && "Entero: 100 | Booleano: True | Double: 45.67"
loSB = .NULL.

Example 8: Catching .NET exceptions

When a .NET method throws an exception, FoxBridge converts it to a VFP error that you can catch with TRY/CATCH. The message includes the original exception and InnerException.

Catching the exception of an invalid URL with TRY/CATCH
TRY
    * Un URI invalido lanza FormatException en .NET
    loUri = loBridge.Create("System.Uri, System", "esto no es una URL")
    ? "ERROR: no deberia llegar aqui"
CATCH TO loEx
    ? "Excepcion capturada:"
    ? loEx.Message   && describe el error de .NET
ENDTRY

Example 9: Static members, File, Guid, Environment

Classes like System.IO.File, System.Guid and System.Environment are fully static. loBridge.Static() returns a proxy that exposes all their methods and properties.

File, Guid and Environment: static members
* Escribir y leer un archivo
loFile = loBridge.Static("System.IO.File")
loFile.WriteAllText("C:\foxbridge_test.txt", "Prueba de escritura estatica")
? loFile.Exists("C:\foxbridge_test.txt")   && .T.
? loFile.ReadAllText("C:\foxbridge_test.txt")
loFile.Delete("C:\foxbridge_test.txt")

* Generar un GUID unico
loGuid = loBridge.Static("System.Guid")
loNewGuid = loGuid.NewGuid()
? "GUID nuevo:", loNewGuid.ToString()   && "a1b2c3d4-..."

* Informacion del sistema
loEnv = loBridge.Static("System.Environment")
? "Maquina:     ", loEnv.MachineName
? "Version OS:  ", loEnv.OSVersion.ToString()
? "Procesadores:", loEnv.ProcessorCount

loFile = .NULL.
loGuid = .NULL.
loEnv  = .NULL.

Example 10: Read/write static properties

Some static properties are read/write (get+set). FoxBridge treats them like normal proxy properties.

Environment.CurrentDirectory: changing and restoring the working directory
loEnv = loBridge.Static("System.Environment")
lcDirActual = loEnv.CurrentDirectory
? "Directorio actual:", lcDirActual

* Cambiar el directorio de trabajo
loEnv.CurrentDirectory = "C:\"
? "Nuevo directorio:", loEnv.CurrentDirectory   && "C:\"

* Restaurar
loEnv.CurrentDirectory = lcDirActual
loEnv = .NULL.

Advanced level: performance, binaries and async

Example 11: Enums as numbers, File.Open with FileMode and FileAccess

VFP has no enums, but .NET uses them constantly. FoxBridge accepts the integer value of the enum directly. Consult MSDN documentation for numeric values.

File.Open with FileMode and FileAccess passed as numbers
* FileMode.Open = 3, FileAccess.Read = 1
lcPath = "C:\foxbridge_enum_test.txt"
SET SAFETY OFF
StrToFile("datos de prueba", lcPath)

loFile = loBridge.Static("System.IO.File")

TRY
    loStream = loFile.Open(lcPath, 3, 1)  && Open para lectura
    IF !IsNull(loStream)
        ? "Stream abierto. Longitud:", loStream.Length
        loStream.Close()
        loStream = .NULL.
    ENDIF
CATCH TO loEx
    ? "Error:", loEx.Message
ENDTRY

IF File(lcPath)
    Erase (lcPath)
ENDIF

loFile = .NULL.

Example 12: Performance stress, 1000 calls to System.Math

FoxBridge caches method resolution after the first call. Subsequent invocations of the same method are significantly faster.

Timing 1000 calls in a row to System.Math
loMath = loBridge.Static("System.Math")
lnStart = Seconds()

For i = 1 to 1000
    lnVal = loMath.Max(i, 500)
    lnVal = loMath.Sqrt(lnVal)
    lnVal = loMath.Round(lnVal, 2)
Next

? "1000 llamadas en:", Seconds() - lnStart, "segundos"
? "Ultimo valor:", lnVal

loMath = .NULL.

Example 13: Chained nested properties

When a property returns another object, FoxBridge automatically wraps it in a new proxy. You can chain accesses with dot notation normally.

The current process and its main module, property by property
TRY
    loProcess = loBridge.Static("System.Diagnostics.Process, System")
    loProc    = loProcess.GetCurrentProcess()

    ? "Proceso:", loProc.ProcessName

    loModule = loProc.MainModule
    ? "Modulo: ", loModule.ModuleName
    ? "Ruta:   ", loModule.FileName

    loModule = .NULL.
    loProc   = .NULL.
CATCH TO loEx
    ? "Error:", loEx.Message
ENDTRY

Example 14: Handling null values

FoxBridge translates VFP .NULL. to .NET null when the method accepts it. When the method expects a value type (int, bool), it will throw an exception that you can catch normally.

.NULL. into .NET: a list accepts it, an int does not
loSB = loBridge.Create("System.Text.StringBuilder")

* .NULL. a un parametro de tipo referencia: aceptado.
*
* Ojo con el caso de Append: tiene varias sobrecargas de referencia
* (string, object, char[], StringBuilder...), y el Binder resuelve por
* coincidencia exacta, sin heuristicas, asi que un null a secas puede
* quedar ambiguo. Cuando quieras un null de un tipo concreto, pasalo
* por una variable del tipo que sea, o usa un metodo de una sola
* sobrecarga.
TRY
    loLista = loBridge.Create("List<String>")
    loLista.Add(.NULL.)
    ? "OK: la lista acepta null como elemento"
CATCH TO loEx
    ? "Error:", loEx.Message
ENDTRY

* .NULL. a un parametro int: error controlado
TRY
    loSB.EnsureCapacity(.NULL.)
CATCH TO loEx
    ? "Error esperado (int no acepta null):", loEx.Message
ENDTRY

loSB = .NULL.

Example 15: Large strings, data transfer

FoxBridge handles multi-megabyte strings without issues. The bridge copies memory once in each direction, so time scales linearly with size.

Sending and receiving 1 MB of text between VFP and .NET
lcGrande = Replicate("X", 1024 * 1024)  && 1 MB

loSB = loBridge.Create("System.Text.StringBuilder")

lnStart = Seconds()
loSB.Append(lcGrande)
? "Envio 1MB a .NET en:", Seconds() - lnStart, "seg"

lnStart = Seconds()
lcRecibido = loSB.ToString()
? "Recibo 1MB desde .NET en:", Seconds() - lnStart, "seg"

? "Longitud recibida:", Len(lcRecibido)  && 1048576
? "Objetos en heap .NET:", loBridge.GetObjectCount()

loSB = .NULL.

Example 16: Dictionary with object values

When the dictionary value is a .NET object (not a scalar), use GetObject() to retrieve it as a FoxBridge proxy. You can compare objects by handle.

A StringBuilder as a Dictionary value
loDict = loBridge.Create("Dictionary<String, System.Text.StringBuilder>")

* Insertar un StringBuilder como valor
loSB = loBridge.Create("System.Text.StringBuilder", "Contenido inicial")
loDict.Set("doc1", loSB)

* Recuperar y modificar
loRecuperado = loDict.GetObject("doc1")
loRecuperado.Append(" — modificado!")
? loRecuperado.ToString()   && "Contenido inicial — modificado!"

* Es el mismo objeto?
? loSB.GetHandle() == loRecuperado.GetHandle()   && .T.

loDict       = .NULL.
loSB         = .NULL.
loRecuperado = .NULL.

Example 17: DateTime, creating and manipulating dates

System.DateTime is the one case where FoxBridge does NOT hand you a proxy: dates cross converted, so what you get is a VFP DATETIME and you handle it with YEAR(), MONTH() and the usual arithmetic. The same happens the other way round, which is why you can pass a VFP date to a .NET method that expects a DateTime.

DateTime: .NET dates as VFP DATETIME values
* System.DateTime NO cruza como proxy: FoxBridge lo convierte a un
* DATETIME de VFP (por OLE Automation Date) en los dos sentidos. Asi
* que lo que vuelve es un valor de tipo T, y se trata con las funciones
* de fecha de VFP de toda la vida.
loDt    = loBridge.Static("System.DateTime")
ltAhora = loDt.Now

? "Fecha y hora:", ltAhora        && un DATETIME de VFP
? "Ano:",  YEAR(ltAhora)
? "Mes:",  MONTH(ltAhora)
? "Dia:",  DAY(ltAhora)

* La aritmetica tambien es la de VFP, en segundos
ltManana = ltAhora + 86400

* Y de vuelta: un DATETIME de VFP entra tal cual en un metodo .NET
* que espera un DateTime.
SET SAFETY OFF
STRTOFILE("prueba", "fb_dt.tmp")

loFile = loBridge.Static("System.IO.File")
loFile.SetCreationTime("fb_dt.tmp", ltManana)

loInfo = loBridge.Create("System.IO.FileInfo", "fb_dt.tmp")
? "Fecha de creacion:", loInfo.CreationTime   && otro DATETIME de VFP
ERASE fb_dt.tmp

loDt   = .NULL.
loFile = .NULL.
loInfo = .NULL.

Example 18: Transparent async, Task.Delay

When a .NET method returns a Task (async), FoxBridge automatically waits for it before continuing. From VFP it looks like a normal synchronous call.

Task.Delay: awaiting an async task with no extra code
loTask = loBridge.Static("System.Threading.Tasks.Task")

? "Llamando Task.Delay(2000) — espera 2 segundos..."
lnStart = Seconds()

loTask.Delay(2000)   && FoxBridge espera automaticamente

? "Tiempo transcurrido:", Seconds() - lnStart, "seg"  && ~2 seg
? "El bridge espero sin necesidad de codigo adicional"

loTask = .NULL.

Example 19: HttpClient, downloading web content

HttpClient is an async .NET class. FoxBridge makes it synchronous automatically. This replaces WinHTTP, XMLHTTP and any other COM dependency you use today.

HttpClient: downloading a page with GET
loHttp = loBridge.Create("System.Net.Http.HttpClient, System.Net.Http")

TRY
    lcUrl  = "https://httpbin.org/get"
    ? "Descargando:", lcUrl

    lcJson = loHttp.GetStringAsync(lcUrl)   && async, FoxBridge espera

    ? "Recibidos:", Len(lcJson), "bytes"
    ? "Primeros 200 chars:"
    ? Left(lcJson, 200)
CATCH TO loEx
    ? "Error de red:", loEx.Message
ENDTRY

loHttp = .NULL.

Example 20: HttpClient with POST and JSON, calling a REST API

The most complete use case: build a JSON payload with StringBuilder, send it with HttpClient.PostAsync and read the response. This is a complete REST client written 100% in VFP.

HttpClient: POSTing JSON to a REST API
loHttp = loBridge.Create("System.Net.Http.HttpClient, System.Net.Http")

* Construir el JSON con StringBuilder
loSB = loBridge.Create("System.Text.StringBuilder")
loSB.Append("{")
loSB.Append("""title"": ""Alta de cliente"",")
loSB.Append("""body"": ""Enviado desde VFP"",")
loSB.Append("""userId"": 1")
loSB.Append("}")
lcJson = loSB.ToString()
loSB   = .NULL.

TRY
    * Encoding.UTF8 es una propiedad estatica, y devuelve un OBJETO.
    * Hay que pasarlo como tal: con .NULL. el Binder no encuentra el
    * constructor StringContent(string, Encoding, string).
    loEnc  = loBridge.Static("System.Text.Encoding")
    loUTF8 = loEnc.UTF8

    loBody = loBridge.Create("System.Net.Http.StringContent, System.Net.Http", ;
        lcJson, loUTF8, "application/json")

    * POST. Es async, y FoxBridge espera la Task por ti.
    loResp = loHttp.PostAsync("https://jsonplaceholder.typicode.com/posts", loBody)

    * Content es un proxy; ReadAsStringAsync() tambien se espera sola.
    loContent   = loResp.Content
    lcRespuesta = loContent.ReadAsStringAsync()
    ? "Respuesta del servidor:"
    ? lcRespuesta

    loContent = .NULL.
    loBody    = .NULL.
    loResp    = .NULL.
    loUTF8    = .NULL.
    loEnc     = .NULL.
CATCH TO loEx
    ? "Error:", loEx.Message
ENDTRY

loHttp = .NULL.

Back to API reference: API Reference ->