Pues eso… algo tan simple como usar en .NET MAUI una DLL creada a partir de un proyecto del tipo class library, puede ser toda una odisea. Te lo explico para que te quede claro.
Como ya sabrás, puedes crear proyectos del tipo class library para añadirlos como referencia a otros proyectos que usen esa DLL o biblioteca de clases. Algo que es bastante común en cualquier aplicación para .NET ya sea .NET Framework como para .NET a secas incluido los proyectos para aplicaciones móviles con Xamarin.Forms. En estes último, lo que se suele hacer es usar una DLL compilada para .NET Standard. Hasta aquí todo bien.
La idea de usar una biblioteca de clases es para reutilizar el código en proyectos diferentes, es decir, creas la biblioteca de clases con cierta funcionalidad y esa misma biblioteca de clases la utilizas en proyectos diferentes. Al menos si esos tipos de proyectos son compatibles en el sentido de usar el mismo .NET.
Y como ahora estoy haciendo pruebas de Google Cloud Natural Language, pues pensé crear algún proyecto para .NET MAUI que usara esa API. Y como ya tenía el código de ciertas clases creado como proyecto DLL (Class Library) pensé agregar la referencia al proyecto de .NET MAUI y… ¡yaumate! (una expresión de mi zona que quiere decir algo así como… ¡tararí que te vi! o… ¡que te lo has creído!)
¡Y así fue! ¡Me lo creí! Pensaba que en .NET MAUI las cosas seguirían siendo como en el resto de .NET, pero no…
De hecho, hasta creé una class library usando la plantilla de MAUI, pero ni por esas… el proyecto de .NET MAUI nada más que daba errores de que no se podía tener referencia a esas clases definidas en la DLL (o class library).
La solución que tomé fue añadir directamente el código de esas clases en el mismo proyecto de .NET MAUI y así funcionó, pero no era eso lo que yo pretendía, ya que además del proyecto para .NET MAUI tenía otros proyectos: de tipo consola de Windows Forms para C# y Visual Basic y en todos ellos pretendía usar la misma DLL o biblioteca de clases.
Pero la solución buena ha sido creando una DLL (proyecto del tipo Class Library), crear un paquete de NuGet y usar ese paquete como referencia en lugar de una referencia al proyecto de tipo class library.
Decirte que esa referencia, al proyecto, sí que funciona en los proyectos de tipo consola o de tipo Windows Forms, tanto para VB como para C#, pero no si el proyecto es de .NET MAUI.
Te lo explico por si alguna vez te pasa esto… para que no te calientes la cabeza ni pierdas todo el tiempo que yo he perdido.
Y para muestra, el proyecto ElizaNET y el correspondiente Eliza MAUI (los enlaces van al repositorio de GitHub), que ambos usan una DLL compilada para .NET 7.0 y que funcionan a la perfección (salvo los bugs que se puedan producir en esa biblioteca de clases, que algunos pueden surgir).
Esos dos proyectos usan el código publicado en NuGet de Eliza gcnl Library que ahora va por la versión 1.0.2.
El código fuente de esa DLL (o paquete de NuGet) está en este enlace (dentro del repositorio ElizaNET).
Y esto es todo… espero que te sea de utilidad. Esa es la intención.
Con esas API podrás analizar textos (también en español) y ver las palabras que la forman (tokens), su estructura sintáctica, etc.
Nota: Para usar este código tendrás que crearte una cuenta en Google Cloud, generar una «key» para usarla y poco más, todos los pasos están explicados en este enlace (el código de ejemplo es para C#, pero te servirá.
Pasos para crear un proyecto usando dotnet (cli):
– Abre una ventana de consola (o terminal) – Posicionarse en la carpeta donde crear el proyecto – Crear el proyecto dotnet new console -n <nombre-proyecto> dotnet new console -lang VB -n <nombre-proyecto> – Cambiar al directorio del proyecto cd <nombre-proyecto> – Añadir el paquete de Google Cloud Natural Language API dotnet add package Google.Cloud.Language.V1 – Copiar el fichero key.json con las claves y permisos – Ver estos pasos para crearla: https://codelabs.developers.google.com/codelabs/cloud-natural-language-csharp#3 – En IAM, añadir la cuenta creada (incluida en el fichero key.json) en +OTORGAR ACCESO Solo estará la principal y/o las otras añadidas – Si se ha usado otra cuenta, estará en IAM>Cuentas de Servicio – Modificar Program.cs (o Program.vb) para usar el código que accede a la API de Natural Language – Ejecutar el código dotnet run
Notas: – Debes crear una variable de entorno en Windows, (lo puedes hacer desde la misma consola) indicando el path donde estará el fichero key.json. – Lo que yo hago es copiar ese fichero en la carpeta del ejecutable y la variable de entorno la defino de esta forma: set GOOGLE_APPLICATION_CREDENTIALS=key.json – Puedes modificar el fichero del proyecto y añadir lo siguiente:
Pues eso… este post es para tener actualizada la utilidad CrearClaseTabla que en su día (allá por 2004) creé para generar o crear clases para acceder a una base de datos de SQL Server o de Access.
La idea de esta utilidad (la aplicación y la DLL que es la que hace el trabajo) es crear clases de Visual Basic o C# de cada tabla de la base de datos, con idea de facilitar el acceso por código a esas tablas.
Actualizado el código y publicada una release en GitHub
Pues eso, con fecha de hoy 14 de mayo de 2023 he estado puliendo un poco el código tanto de la DLL que se encarga de hacer la conversión como del EXE que hace de intermediario.
En GitHub está todo, tanto el código fuente de VB y C# para la aplicación de Windows con un paquete con el exe para Windows. Y también el código para .NET MAUI para aplicaciones móviles, ya sabes Windows, iOs y Android.
También he agregado las clases ConversorTipos.vb y ConversorTipos.cs que utiliza el código generado para hacer las conversiones de tipos.
En la última actualización de hoy 1 de octubre de 2022 se contempla, entre otras cosas, la definición de variables asignadas sin indicar el tipo (inferencia de tipos) además de convertir adecuadamente las conversiones de tipo de Visual Basic a C# (aunque en el código solo uso CInt).
Nota: He creado el proyecto para .NET 6.0 (Windows) y está disponible en GitHub: gsCrearClasesTablas. Por ahora el código es el mismo en este nuevo proyecto como en el que referencio en este post/artículo que es para .NET Framework 4.8.1
El código «base» que utilizo es el que yo uso con Visual Basic y la clase CrearClase apoyada de ConvLag se encarga de generar el código de Visual Basic o el de C#.
Por ejemplo, el código que te muestro primero, en el generador de clases lo defino como te muestro en el segundo bloque de código:
Este es el código en que me he basado:
cmd.Transaction = tran
cmd.ExecuteNonQuery()
' Si llega aquí es que todo fue bien,
' por tanto, llamamos al método Commit.
tran.Commit()
msg = "Se ha actualizado el Cliente correctamente."
Catch ex AsException
msg = $"ERROR: {ex.Message}"
' Si hay error, deshacemos lo que se haya hecho.
Try
If tran IsNotNothingThen
tran.Rollback()
EndIf
Catch ex2 AsException
msg = $" (ERROR RollBack: {ex.Message})"
EndTry
Finally
con.Close()
EndTry
EndUsing
Return msg
Este es el código interno que uso en el conversor (el método generarClase): En los comentarios está el código mostrado antes y el equivalente para generar el código de VB o de C#.
sb.AppendLine()
' cmd.Transaction = tran
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("cmd.Transaction", "tran"), vbCrLf)
' cmd.ExecuteNonQuery()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("cmd.ExecuteNonQuery()"), vbCrLf)
sb.AppendLine()
' ' Si llega aquí es que todo fue bien,
' ' por tanto, llamamos al método Commit
sb.AppendFormat(" {0}{1}", ConvLang.Comentario(" Si llega aquí es que todo fue bien,"), vbCrLf)
sb.AppendFormat(" {0}{1}", ConvLang.Comentario(" por tanto, llamamos al método Commit."), vbCrLf)
' tran.Commit()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("tran.Commit()"), vbCrLf)
sb.AppendLine()
' msg = "Se ha actualizado el Cliente correctamente."
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("msg", """Se ha actualizado un " & nombreClase & " correctamente."""), vbCrLf)
sb.AppendLine()
' Catch ex As Exception
sb.AppendFormat(" {0}{1}", ConvLang.Catch("ex", "Exception"), vbCrLf)
' msg = $"ERROR: {ex.Message}"
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("msg", "$""ERROR: {ex.Message}"""), vbCrLf)
' ' Si hay error, deshacemos lo que se haya hecho
sb.AppendFormat(" {0}{1}", ConvLang.Comentario(" Si hay error, deshacemos lo que se haya hecho."), vbCrLf)
' Try
sb.AppendFormat(" {0}{1}", ConvLang.Try(), vbCrLf)
' Añadir comprobación de nulo en el objeto tran (17-abr-21)
' If tran IsNot Nothing Then
sb.AppendFormat(" {0}{1}", ConvLang.If("tran", "IsNot", "Nothing"), vbCrLf)
' tran.Rollback()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("tran.Rollback()"), vbCrLf)
' End If
sb.AppendFormat(" {0}{1}", ConvLang.EndIf, vbCrLf)
' Catch ex2 As Exception
sb.AppendFormat(" {0}{1}", ConvLang.Catch("ex2", "Exception"), vbCrLf)
' msg &= $" (ERROR RollBack: {ex.Message})"
sb.AppendFormat(" {0}{1}", ConvLang.Asigna("msg", "$""ERROR RollBack: {ex2.Message}"""), vbCrLf)
' End Try
sb.AppendFormat(" {0}{1}", ConvLang.EndTry(), vbCrLf)
sb.AppendLine()
sb.AppendFormat(" {0}{1}", ConvLang.Finally, vbCrLf)
' If Not (con is nothing) then
sb.AppendFormat(" {0}{1}", ConvLang.If("", "Not", "(con Is Nothing)"), vbCrLf)
' con.Close()
sb.AppendFormat(" {0}{1}", ConvLang.Instruccion("con.Close()"), vbCrLf)
' End If
sb.AppendFormat(" {0}{1}", ConvLang.EndIf, vbCrLf)
' End Try
sb.AppendFormat(" {0}{1}", ConvLang.EndTry(), vbCrLf)
sb.AppendLine()
' End Using
sb.AppendFormat(" {0}{1}", ConvLang.EndUsing(), vbCrLf)
sb.AppendLine()
' Return msg
sb.AppendFormat(" {0}{1}", ConvLang.Return("msg"), vbCrLf)
Y el código generado de Visual Basic sería como te he mostrado arriba y el de C# sería más o menos este:
cmd.Transaction = tran;
cmd.ExecuteNonQuery();
// Si llega aquí es que todo fue bien,// por tanto, llamamos al método Commit.
tran.Commit();
msg = "Se ha actualizado un Producto correctamente.";
}catch(Exception ex){
msg = $"ERROR: {ex.Message}";
// Si hay error, deshacemos lo que se haya hecho.try{
if(tran != null ){
tran.Rollback();
}
}catch(Exception ex2){
msg = $"ERROR RollBack: {ex2.Message}";
}
finally{
if( ! (con == null )){
con.Close();
}
}
}
return msg;
Como ves, no está bien formateado, (es el código generado directamente) pero si lo pegas en Visual Studio te lo formateará bien y lo coloreará mejor 😉
Y para muestra, ese trozo de código en un fichero abierto en Visual Studio 2022: (Aunque todo hay que decirlo, en VB lo formatea bien, aunque solo sea un fichero abierto directamente (sin formar parte de ningún proyecto) mientras que en C# le he tenido casi que dar el formato manualmente, en fin…)
cmd.Transaction = tran;
cmd.ExecuteNonQuery();
// Si llega aquí es que todo fue bien,
// por tanto, llamamos al método Commit.
tran.Commit();
msg = "Se ha actualizado un Producto correctamente.";
}
catch(Exception ex)
{
msg = $"ERROR: {ex.Message}";
// Si hay error, deshacemos lo que se haya hecho.
try
{
if (tran != null)
{
tran.Rollback();
}
}
catch(Exception ex2)
{
msg = $"ERROR RollBack: {ex2.Message}";
}
finally
{
if (!(con == null))
{
con.Close();
}
}
}
Pero la idea es que te quedes con lo que la clase hace.
También es cierto que yo suelo generar el código para Visual Basic y es lo que realmente he probado más, hoy he estado viendo cómo lo generaría para C# y he estado haciendo algunas correcciones (que he indicado en el fichero Revisiones.md publicado con GitHub).
Una captura de la utilidad tal como la tengo a día 1 de octubre de 2022.
Figura 1. La utilidad en funcionamiento a día de hoy 1 de octubre de 2022
Y esto es todo amigo (o amiga), ya sabes, si quieres participar en el proyecto para mejorarlo, puedes hacerlo, creo que en algún sitio indico cómo avisarme de los errores que encuentres y cómo actualizar el fichero Revisiones.txt que ahora es Revisiones.md.
Y si quieres usarlo sin más aportaciones, estaría bien que hicieras una pequeña aportación monetaria en PayPal (no es obligatorio, pero es de agradecer).
En breve publicaré en GitHub el ejecutable compilado con .NET Framework 4.8.1.
Por cierto, en el proyecto (los dos) he incluido un fichero de nombre seguro (strong name) para firmar los ensamblados, ese fichero (elGuille_compartido.snk) lo puedes usar «libremente» (ya sabes todo está con la licencia MIT) para firmar los ensamblados con nombre seguro.
Espero que te sirva de utilidad.
Nos vemos. Guillermo
P.S. Sería interesante convertir el proyecto para .NET 6 (o 7) y también usando el código completamente en C#. Actualmente está creado para usar con .NET Framework 4.8.1 y escrito enteramente en Visual Basic.
P.S.2 Ya está creado el proyecto para .NET 6.0 (net6.0-windows) y publicado en GitHub (gsCrearClasesTablas).