Logo de Adafaceadaface

108 preguntas de entrevista sobre .NET Core para contratar a los mejores desarrolladores

Contratar desarrolladores de .NET Core puede ser un desafío sin las preguntas correctas. Los reclutadores a menudo tienen dificultades para evaluar la competencia de un candidato en .NET Core, lo que lleva a errores y recursos desperdiciados, y una rápida mirada a las habilidades requeridas para un desarrollador .NET puede abrumarte rápidamente.

Esta publicación de blog proporciona una lista curada de preguntas de entrevista de .NET Core adaptadas para varios niveles de experiencia, desde recién graduados hasta profesionales experimentados. Además, encontrará un conjunto de preguntas de opción múltiple (MCQ) para evaluar aún más su comprensión.

Al usar estas preguntas, podrá identificar candidatos con la experiencia y el ajuste adecuados para su equipo; antes de la entrevista, puede evaluar aún más sus conocimientos utilizando nuestra prueba en línea de C# .NET.

Tabla de contenido

Preguntas de entrevista de .NET Core para recién graduados

Preguntas de entrevista de .NET Core para juniors

Preguntas de entrevista intermedias de .NET Core

Preguntas de entrevista de .NET Core para experimentados

MCQ de .NET Core

¿Qué habilidades de .NET Core debe evaluar durante la fase de entrevista?

3 consejos para usar preguntas de entrevista de .NET Core

Evalúe a los candidatos de .NET con precisión: pruebas de habilidades y preguntas de entrevista específicas

Descargue la plantilla de preguntas de entrevista de .NET Core en múltiples formatos

Preguntas de entrevista de .NET Core para recién graduados

1. ¿Qué es .NET Core y por qué deberíamos usarlo en lugar del antiguo .NET Framework?

.NET Core es un framework multiplataforma, de código abierto y modular para construir aplicaciones modernas. A diferencia del antiguo .NET Framework, que se centraba principalmente en Windows, .NET Core puede ejecutarse en Windows, macOS y Linux.

Las razones para usar .NET Core en lugar de .NET Framework incluyen:

  • Compatibilidad multiplataforma: Crea aplicaciones que se ejecutan en diferentes sistemas operativos sin cambios en el código.
  • Rendimiento mejorado: .NET Core es generalmente más rápido y eficiente que .NET Framework.
  • Modularidad: Solo incluye los componentes necesarios, reduciendo el tamaño y las dependencias de la aplicación.
  • Código abierto: Benefíciese de las contribuciones de la comunidad y la transparencia. Está disponible en GitHub.
  • Arquitectura moderna: Diseñado para prácticas de desarrollo modernas como microservicios y contenedorización. Por ejemplo, use esto para definir un controlador:

[ApiController] [Route("[controller]")] public class MyController : ControllerBase { [HttpGet] public ActionResult<string> Get() { return "¡Hola Mundo!"; } }

2. ¿Puede explicar la diferencia entre .NET Core y .NET Standard?

.NET Standard es una especificación de las API que las implementaciones de .NET deben proporcionar. Piense en ello como un contrato. .NET Standard le permite escribir código que puede ejecutarse en diferentes plataformas .NET (por ejemplo, .NET Framework, .NET Core, .NET 5+). Define un conjunto común de API que todas las implementaciones de .NET compatibles deben admitir.

.NET Core (y posteriormente .NET 5, 6, 7, etc.) es una implementación específica de .NET Standard. Es un tiempo de ejecución, bibliotecas y compilador. .NET Core (y las versiones más nuevas de .NET) puede apuntar a una versión específica de .NET Standard, indicando qué API soporta. Esencialmente, .NET Standard define qué APIs existen, mientras que .NET Core/5+/etc. es cómo se implementan y ejecutan esas APIs.

3. ¿Cuáles son los beneficios clave de usar .NET Core para construir aplicaciones?

Los beneficios clave de usar .NET Core (ahora .NET 6, 7, 8, etc.) incluyen compatibilidad multiplataforma, alto rendimiento y un diseño modular. Las capacidades multiplataforma permiten que las aplicaciones se ejecuten en Windows, macOS y Linux, lo que amplía significativamente las opciones de despliegue.

Las mejoras de rendimiento son sustanciales debido a las optimizaciones en el tiempo de ejecución CoreCLR y el framework ASP.NET Core. El diseño modular permite a los desarrolladores incluir solo los componentes necesarios, lo que resulta en tamaños de aplicación más pequeños y una mejor seguridad. También ofrece características como la inyección de dependencias integrada, un sistema de configuración moderno y soporte para arquitecturas de microservicios. Herramientas como dotnet publish -r <RID> permiten despliegues dependientes del framework.

4. ¿Cuál es el papel de la CLI de .NET (Interfaz de Línea de Comandos) y cuáles son algunos comandos comunes que usaría?

La CLI de .NET (Interfaz de Línea de Comandos) es una cadena de herramientas multiplataforma para desarrollar, construir, ejecutar y publicar aplicaciones .NET. Permite a los desarrolladores realizar estas tareas desde la línea de comandos, proporcionando una forma consistente y automatizada de gestionar proyectos .NET. Es particularmente útil para la creación de scripts, la automatización y las canalizaciones de integración continua/despliegue continuo (CI/CD).

Algunos comandos comunes de la CLI de .NET incluyen:

  • dotnet new: Crea un nuevo proyecto o solución de .NET.
  • dotnet build: Compila un proyecto de .NET.
  • dotnet run: Ejecuta una aplicación .NET.
  • dotnet test: Ejecuta pruebas unitarias.
  • dotnet publish: Publica una aplicación .NET para su implementación.
  • dotnet add package: Agrega un paquete NuGet a un proyecto.
  • dotnet restore: Restaura las dependencias especificadas en el archivo del proyecto.
  • dotnet ef: Ejecuta comandos de Entity Framework Core (por ejemplo, migraciones).
  • dotnet tool install: Instala una herramienta .NET.
  • dotnet --version: Muestra la versión del SDK de .NET instalada.

5. Explica qué es una aplicación 'multiplataforma' y cómo .NET Core la habilita.

Una aplicación multiplataforma es un software que puede ejecutarse en múltiples sistemas operativos (como Windows, macOS y Linux) sin requerir cambios significativos en el código. Esto contrasta con las aplicaciones específicas de plataforma, que están diseñadas para ejecutarse solo en un único sistema operativo.

.NET Core (ahora .NET) habilita el desarrollo multiplataforma a través de su diseño y entorno de tiempo de ejecución. Es un framework modular y de código abierto que se ejecuta en diferentes sistemas operativos. El runtime de .NET, junto con las implementaciones específicas de la plataforma, gestiona la ejecución del código de lenguaje intermedio (IL) de la aplicación. Las características clave que permiten esto incluyen:

  • .NET Runtime: Proporciona un entorno de ejecución consistente en todas las plataformas.
  • Bibliotecas multiplataforma: Ofrece un conjunto de bibliotecas y APIs que funcionan de manera uniforme en diferentes sistemas operativos.
  • Abstracción del framework: Abstrae los detalles específicos de la plataforma, permitiendo a los desarrolladores escribir código que interactúa con el sistema operativo subyacente a través de una interfaz común. Esto permite construir e implementar la misma base de código en diferentes sistemas operativos. Por ejemplo, puedes escribir código C# usando bibliotecas .NET que interactúan con el sistema de archivos, la red o elementos de la interfaz de usuario, y este código funcionará en Windows, macOS y Linux.

6. ¿Qué es un paquete NuGet y por qué son importantes en el desarrollo de .NET Core?

Un paquete NuGet es un único archivo ZIP con la extensión .nupkg que contiene código compilado (DLLs), archivos relacionados como imágenes y configuración, y un archivo de manifiesto (un archivo .nuspec) que describe el paquete, sus dependencias e información de versión.

Los paquetes NuGet son cruciales en el desarrollo de .NET Core porque proporcionan una forma estandarizada de distribuir y consumir código reutilizable. Simplifican la gestión de dependencias al permitir a los desarrolladores agregar, actualizar y eliminar fácilmente bibliotecas de sus proyectos, resolviendo las dependencias automáticamente. Esto promueve la reutilización del código, reduce el tiempo de desarrollo y garantiza la consistencia en todos los proyectos.

7. ¿Cómo se crea un nuevo proyecto .NET Core usando la línea de comandos?

Para crear un nuevo proyecto .NET Core utilizando la línea de comandos, se utiliza el comando dotnet new. Este comando requiere que especifiques una plantilla para el tipo de proyecto que deseas crear. Las plantillas comunes incluyen console, webapi, mvc, classlib y razorclasslib. Por ejemplo, para crear una nueva aplicación de consola llamada 'MiNuevaApp', ejecutarías el siguiente comando:

dotnet new console -n MyNewApp

Después de ejecutar este comando, se creará un nuevo directorio llamado MyNewApp, que contendrá los archivos necesarios para una aplicación de consola básica. Luego puede navegar a ese directorio (cd MyNewApp) y construir/ejecutar la aplicación usando dotnet build y dotnet run respectivamente.

8. ¿Cuál es el propósito del archivo 'Program.cs' en una aplicación de consola .NET Core?

En una aplicación de consola .NET Core, Program.cs sirve como el punto de entrada de la aplicación. Contiene el método Main, que es el primer método que se ejecuta cuando la aplicación se inicia.

El método Main normalmente maneja tareas como:

  • Inicializar recursos.
  • Analizar argumentos de línea de comandos.
  • Crear objetos.
  • Llamar a otros métodos para realizar la lógica principal de la aplicación. Esencialmente, es el punto de partida desde donde el código de su aplicación comienza a ejecutarse.

9. ¿Cuál es la diferencia entre los comandos 'build' y 'run' en .NET Core?

dotnet build compila el código fuente en código de lenguaje intermedio (IL) y produce los ensamblados necesarios (DLL y EXEs). Comprueba si hay errores de sintaxis y asegura que todas las dependencias estén disponibles. Esencialmente prepara su aplicación para la ejecución, pero en realidad no la ejecuta. dotnet run, por otro lado, combina el proceso de compilación (si es necesario o si se han realizado cambios desde la última compilación) con la ejecución. Primero compila la aplicación y luego la ejecuta inmediatamente. dotnet run se utiliza normalmente para pruebas rápidas y ciclos de desarrollo. Si necesita implementar, debe compilarlo y luego copiar los archivos DLL correspondientes.

10. ¿Cómo puede agregar un paquete NuGet a su proyecto .NET Core?

Puede agregar un paquete NuGet a su proyecto .NET Core utilizando varios métodos:

  • Consola del Administrador de paquetes NuGet: Use el comando Install-Package en la consola del Administrador de paquetes dentro de Visual Studio. Por ejemplo, Install-Package Newtonsoft.Json.

  • UI del Administrador de paquetes NuGet: Haga clic con el botón derecho en su proyecto en el Explorador de soluciones, seleccione "Administrar paquetes NuGet..." y busque o busque el paquete deseado. Luego, haga clic en "Instalar".

  • Archivo .csproj: Agregue manualmente un elemento <PackageReference> al archivo .csproj de su proyecto dentro del elemento <ItemGroup> y luego restaure los paquetes NuGet. Por ejemplo:

<ItemGroup> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> </ItemGroup>
  • CLI de dotnet: Use el comando dotnet add package en la línea de comandos. Por ejemplo, dotnet add package Newtonsoft.Json.

11. ¿Cuál es el propósito del archivo 'csproj' en un proyecto .NET Core?

El archivo .csproj en un proyecto .NET (incluyendo .NET Core, .NET 5+, y .NET Framework) sirve como el archivo del proyecto, definiendo la estructura del proyecto, las dependencias, la configuración de la compilación y los metadatos. Esencialmente, le dice al SDK de .NET cómo construir, empaquetar y ejecutar la aplicación o biblioteca. Utiliza un formato XML, que ha evolucionado con el tiempo para ser más optimizado y legible, especialmente con la introducción de proyectos de estilo SDK.

Específicamente, el archivo .csproj gestiona cosas como:

  • Dependencias: Referencias a paquetes NuGet y otros proyectos.
  • Archivos fuente: Listas de archivos de código fuente para incluir en el proyecto.
  • Marco(s) de destino: Especifica la(s) versión(es) del entorno de ejecución de .NET a la(s) que el proyecto está dirigido (por ejemplo, net6.0, net7.0).
  • Configuración de la compilación: Define propiedades de compilación como el tipo de salida (aplicación de consola, biblioteca), opciones del compilador y eventos previos/posteriores a la compilación.
  • Metadatos del proyecto: Incluye el nombre del proyecto, la versión, la descripción y otra información. Por ejemplo, puede incluir esto en las etiquetas PropertyGroup:
<PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>net7.0</TargetFramework> <ImplicitUsings>enable</ImplicitUsings> <Nullable>enable</Nullable> </PropertyGroup>

12. Explique qué son las variables de entorno y cómo se utilizan en las aplicaciones .NET Core.

Las variables de entorno son pares nombre-valor que contienen información de configuración accesible para las aplicaciones y los procesos que se ejecutan en un sistema. Definen el entorno en el que operan estos procesos, lo que permite la personalización sin modificar directamente el código de la aplicación. En las aplicaciones .NET Core, las variables de entorno se utilizan comúnmente para almacenar configuraciones como cadenas de conexión a bases de datos, claves API y configuraciones específicas de la aplicación que pueden diferir entre los entornos de desarrollo, pruebas y producción.

Las aplicaciones .NET Core acceden a las variables de entorno a través de la clase System.Environment. Por ejemplo, Environment.GetEnvironmentVariable("MI_VARIABLE") recupera el valor de la variable de entorno llamada 'MI_VARIABLE'. Las aplicaciones ASP.NET Core también aprovechan ampliamente las variables de entorno, a menudo utilizándolas en archivos de configuración (appsettings.json) a través de proveedores de configuración. Estos proveedores cargan configuraciones de variables de entorno, argumentos de línea de comandos y otras fuentes, lo que permite a los desarrolladores administrar fácilmente las configuraciones de la aplicación en diferentes entornos. Por ejemplo, se puede establecer una variable de entorno llamada ASPNETCORE_ENVIRONMENT para especificar el entorno (Desarrollo, Ensayo, Producción) que ASP.NET Core debe utilizar.

13. ¿Cómo manejas la configuración en una aplicación .NET Core (por ejemplo, cadenas de conexión)?

En .NET Core, la configuración generalmente se maneja utilizando el paquete Microsoft.Extensions.Configuration. Podemos usar appsettings.json para almacenar configuraciones como cadenas de conexión y configuraciones específicas de la aplicación. Este archivo se carga al inicio usando ConfigurationBuilder. Luego accedemos a la configuración a través de la interfaz IConfiguration.

Por ejemplo, para leer una cadena de conexión:

var connectionString = Configuration.GetConnectionString("DefaultConnection");

También podemos usar variables de entorno para anular la configuración en appsettings.json para diferentes entornos (Desarrollo, Staging, Producción). Luego podemos vincular la configuración a clases fuertemente tipadas usando el patrón de opciones. Los secretos como las claves de API se pueden almacenar en secretos de usuario durante el desarrollo, o en Azure Key Vault en producción para evitar almacenarlos directamente en el código o en los archivos de configuración.

14. ¿Qué es la inyección de dependencias (DI) y por qué se usa en .NET Core?

La Inyección de Dependencias (DI) es un patrón de diseño en el que una clase recibe sus dependencias de fuentes externas en lugar de crearlas por sí misma. Esto promueve el desacoplamiento y hace que el código sea más testeable y mantenible. Esencialmente, las dependencias se "inyectan" en una clase.

En .NET Core, DI es un ciudadano de primera clase, integrado en el framework. Se utiliza por varias razones:

  • Desacoplamiento: Reduce las dependencias entre clases, lo que permite cambiarlas de forma independiente.
  • Testeabilidad: Es más fácil simular o simular dependencias durante las pruebas unitarias.
  • Mantenibilidad: Es más fácil cambiar las implementaciones sin afectar a las clases dependientes.
  • Reusabilidad: Las dependencias se pueden intercambiar fácilmente con diferentes implementaciones.
  • Configuración: Simplifica la configuración de los componentes de la aplicación.

15. ¿Cómo se registran los servicios para la inyección de dependencias en .NET Core?

En .NET Core, los servicios se registran para la inyección de dependencias dentro del método ConfigureServices del archivo Startup.cs (o en el archivo Program.cs para el modelo de alojamiento mínimo de .NET 6+). Este método toma un IServiceCollection como parámetro, que proporciona métodos de extensión para registrar servicios con diferentes tiempos de vida. Puede registrar servicios utilizando métodos como:

  • AddSingleton: Crea una única instancia del servicio para la duración de la aplicación.
  • AddScoped: Crea una nueva instancia del servicio para cada ámbito (típicamente una solicitud HTTP).
  • AddTransient: Crea una nueva instancia del servicio cada vez que se solicita.

Por ejemplo:

public void ConfigureServices(IServiceCollection services) { services.AddTransient<IMyService, MyService>(); services.AddScoped<IMyRepository, MyRepository>(); services.AddSingleton<IConfiguration>(Configuration); }

16. ¿Puede explicar el concepto de middleware en .NET Core, especialmente dentro de ASP.NET Core?

El middleware en ASP.NET Core forma una tubería para manejar las solicitudes HTTP. Cada componente de middleware en la tubería tiene la oportunidad de procesar la solicitud y la respuesta. Piense en ello como una serie de filtros que actúan sobre la solicitud HTTP antes de que llegue al punto final de su aplicación y luego actúan sobre la respuesta antes de que se envíe de vuelta al cliente.

Cada componente de middleware puede realizar acciones como registro, autenticación, autorización, enrutamiento o modificación de encabezados de solicitud/respuesta. El middleware se configura en el método Configure del archivo Startup.cs, y el orden en que se agregan a la tubería es significativo, ya que determina el orden en que se ejecutan. Por ejemplo:

app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); });

17. ¿Cuáles son algunos componentes de middleware comunes utilizados en las aplicaciones ASP.NET Core?

Los componentes de middleware de ASP.NET Core forman una tubería para manejar las solicitudes y respuestas. Algunos componentes de middleware comunes incluyen:

  • Middleware de autenticación: Gestiona la autenticación del usuario (por ejemplo, mediante cookies, JWT). Verifica las credenciales del usuario.
  • Middleware de enrutamiento: Asigna las peticiones entrantes a puntos finales específicos (controladores y acciones).
  • Middleware de archivos estáticos: Sirve archivos estáticos como HTML, CSS, JavaScript e imágenes directamente al cliente. Se configura la ubicación de los archivos estáticos.
  • Middleware de manejo de excepciones: Captura y maneja las excepciones que ocurren durante el procesamiento de la petición. Proporciona un mecanismo global de manejo de errores.
  • Middleware CORS: Habilita el intercambio de recursos de origen cruzado (CORS), permitiendo peticiones desde diferentes dominios.
  • Middleware de sesión: Gestiona las sesiones de usuario almacenando datos en el servidor y asociándolos con el navegador del usuario.
  • Middleware de compresión de respuesta: Comprime la respuesta HTTP para reducir su tamaño, mejorando el rendimiento.
  • Middleware de enrutamiento de endpoints: Configura los endpoints (por ejemplo, controladores MVC, Razor Pages, APIs minimalistas) para la aplicación.

18. ¿Cómo se crea un punto final de API simple en ASP.NET Core?

Para crear un punto final de API simple en ASP.NET Core, normalmente se comienza creando un nuevo proyecto de API web de ASP.NET Core. Defina una clase de controlador (por ejemplo, MyController) que herede de ControllerBase. Dentro de este controlador, defina métodos de acción (por ejemplo, Get) decorados con atributos como [HttpGet] y [Route("api/[controller]")] para especificar el método HTTP y la ruta. El método de acción devuelve datos, a menudo en formato JSON, utilizando Ok(), BadRequest(), etc.

Aquí hay un ejemplo mínimo:

[ApiController] [Route("api/[controller]")] public class MyController : ControllerBase { [HttpGet] public IActionResult Get() { return Ok(new { message = "Hola desde la API" }); } }

19. ¿Qué son los métodos de solicitud HTTP (como GET, POST, PUT, DELETE) y cómo se utilizan en las API?

Los métodos de solicitud HTTP, también conocidos como verbos HTTP, indican la acción deseada que se va a realizar en un recurso. Los métodos comunes incluyen:

  • GET: Recupera datos de un recurso especificado. Es de solo lectura y no debe tener efectos secundarios.
  • POST: Envía datos para que se procesen a un recurso especificado, a menudo utilizado para crear nuevos recursos.
  • PUT: Reemplaza el recurso actual con el contenido cargado. Requiere conocer la URL completa del recurso.
  • PATCH: Aplica modificaciones parciales a un recurso. Útil para actualizar solo campos específicos.
  • DELETE: Elimina el recurso especificado.

En las API, estos métodos definen cómo los clientes interactúan con los recursos del lado del servidor. Por ejemplo, una solicitud GET /users podría recuperar una lista de usuarios, mientras que una solicitud POST /users podría crear un nuevo usuario. Usar el método correcto es crucial para construir API RESTful, asegurando interacciones predecibles y bien definidas. PUT y PATCH se confunden a menudo; PUT reemplaza todo el recurso, mientras que PATCH modifica partes del mismo.

20. ¿Cómo manejas diferentes códigos de estado HTTP en las respuestas de tu API?

Manejo los códigos de estado HTTP mapeándolos a acciones apropiadas en mi aplicación. Las respuestas exitosas (2xx) desencadenan actualizaciones de la interfaz de usuario o procesamiento de datos. Las redirecciones (3xx) se manejan automáticamente por el cliente o pueden solicitar la interacción del usuario si es necesario. Los errores del cliente (4xx) desencadenan mensajes de error amigables para el usuario en la interfaz de usuario, junto con el registro para la depuración. Los errores del servidor (5xx) muestran mensajes de error genéricos al usuario y desencadenan un registro y monitoreo extensivos para identificar y resolver el problema subyacente.

Específicamente:

  • 200 OK: Éxito, procesar datos como se espera.
  • 201 Created: Recurso creado, redirigir o actualizar la interfaz de usuario.
  • 400 Bad Request: Mostrar mensaje de error al usuario, registrar detalles.
  • 401 Unauthorized: Redirigir a la página de inicio de sesión o solicitar credenciales.
  • 403 Forbidden: Mostrar el mensaje "acceso denegado".
  • 404 Not Found: Mostrar un mensaje amigable para el usuario de "recurso no encontrado".
  • 500 Internal Server Error: Mostrar un mensaje de error genérico, registrar los detalles del error en el servidor y el sistema de monitoreo, y activar alertas.

21. ¿Qué es JSON y por qué se usa comúnmente en las API?

JSON (JavaScript Object Notation) es un formato de intercambio de datos ligero y legible por humanos. Se utiliza para transmitir objetos de datos que consisten en pares de atributo-valor y tipos de datos de matriz (o cualquier otro valor serializable).

JSON se utiliza comúnmente en las API porque es:

  • Fácil de analizar: La mayoría de los lenguajes de programación tienen bibliotecas integradas para analizar y generar JSON fácilmente.
  • Ligero: En comparación con otros formatos como XML, JSON tiene menos sobrecarga, lo que resulta en una transmisión de datos más rápida.
  • Legible para humanos: Su estructura simple facilita su comprensión y depuración.
  • Ampliamente compatible: JSON es compatible con casi todas las plataformas y tecnologías modernas. Por ejemplo, en JavaScript, la conversión de un objeto JavaScript a JSON se puede realizar usando JSON.stringify(object) y la conversión de JSON a un objeto JavaScript se puede realizar usando JSON.parse(jsonString).

22. ¿Cómo se serializan y deserializan datos JSON en .NET Core?

En .NET Core, normalmente se utiliza el espacio de nombres System.Text.Json (o el paquete Newtonsoft.Json) para la serialización y deserialización de JSON.

Para serializar un objeto a JSON, utilice JsonSerializer.Serialize(). Por ejemplo:

using System.Text.Json; string jsonString = JsonSerializer.Serialize(myObject);

Para deserializar JSON en un objeto, utilice JsonSerializer.Deserialize(). Por ejemplo:

using System.Text.Json; MyClass myObject = JsonSerializer.Deserialize<MyClass>(jsonString);

Newtonsoft.Json utiliza métodos similares (JsonConvert.SerializeObject() y JsonConvert.DeserializeObject<T>()).

23. ¿Qué es el manejo de excepciones y cómo se implementa en .NET Core?

El manejo de excepciones es un mecanismo para tratar los errores en tiempo de ejecución que pueden ocurrir durante la ejecución de un programa. Permite manejar con elegancia situaciones inesperadas, prevenir fallos del programa y, potencialmente, recuperarse de errores.

En .NET Core, se implementa el manejo de excepciones utilizando bloques try-catch-finally. El código que podría lanzar una excepción se coloca dentro del bloque try. Si ocurre una excepción, se ejecuta el bloque catch correspondiente. Puede tener múltiples bloques catch para manejar diferentes tipos de excepciones. El bloque finally siempre se ejecuta, independientemente de si se lanzó o no una excepción, y generalmente se usa para liberar recursos. Aquí hay un ejemplo:

intente { // Código que podría lanzar una excepción int resultado = 10 / 0; } catch (DivideByZeroException ex) { // Manejar la excepción específica Console.WriteLine("Error: " + ex.Message); } catch (Exception ex) { // Manejar cualquier otra excepción Console.WriteLine("Ocurrió un error: " + ex.Message); } finally { // Código a ejecutar independientemente de las excepciones Console.WriteLine("Bloque finally ejecutado."); }

24. ¿Cómo se escriben pruebas unitarias para el código .NET Core?

Escribo pruebas unitarias para el código .NET Core utilizando frameworks como xUnit, NUnit o MSTest, a menudo junto con una biblioteca de simulación como Moq o NSubstitute. El proceso general implica:

  • Crear un proyecto de prueba separado dentro de la solución.
  • Referenciar el proyecto a probar.
  • Escribir métodos de prueba para ejercitar diferentes aspectos del código, centrándose en unidades individuales (clases, métodos).
  • Usar métodos Assert proporcionados por el framework de pruebas para verificar los resultados esperados. La simulación de dependencias me permite aislar la unidad bajo prueba y controlar sus entradas y salidas durante la prueba. Por ejemplo, usando xUnit, normalmente escribiría un método de prueba que llama a un método bajo prueba. Luego uso Assert.Equal() u otros métodos Assert para verificar si el resultado es el valor esperado. A menudo, utilizaré fases de arreglo, acción y aserción dentro de los métodos de prueba.

25. ¿Cuáles son algunos frameworks comunes de pruebas unitarias utilizados con .NET Core (por ejemplo, xUnit, NUnit)?

Varios frameworks populares de pruebas unitarias se utilizan comúnmente con .NET Core. Dos de los más frecuentes son xUnit.net y NUnit. xUnit.net es conocido por su enfoque en la extensibilidad y su enfoque basado en atributos. NUnit, por otro lado, es un framework más tradicional con un rico conjunto de aserciones.

Otras opciones notables incluyen MSTest, que es el framework de pruebas desarrollado por Microsoft, y Shouldly, que es una biblioteca de aserciones que mejora la legibilidad. El uso de cualquiera de estos frameworks implica instalar el paquete NuGet apropiado y escribir métodos de prueba marcados con atributos específicos (por ejemplo, [Fact] en xUnit, [Test] en NUnit). Por ejemplo, aquí hay un ejemplo básico de xUnit:

using Xunit; public class MyTests { [Fact] public void MyFirstTest() { Assert.Equal(4, 2 + 2); } }

26. ¿Qué es el control de versiones y por qué es importante cuando se trabaja en proyectos .NET Core?

El control de código fuente (también conocido como control de versiones) es un sistema que rastrea los cambios realizados en los archivos a lo largo del tiempo. Es crucial para la gestión de proyectos .NET Core, especialmente cuando se trabaja en equipos, ya que proporciona un repositorio central para el código, lo que permite que varios desarrolladores trabajen simultáneamente sin sobrescribir los cambios de los demás. También permite revertir fácilmente a versiones anteriores, crear ramas para nuevas funciones y fusionar los cambios de nuevo en la base de código principal.

¿Por qué es importante el control de código fuente? Considere estos puntos:

  • Colaboración: Facilita el trabajo en equipo sin problemas.
  • Historial de versiones: Rastrea todos los cambios, lo que le permite revertir a cualquier estado anterior.
  • Ramificación y fusión: Permite el desarrollo paralelo de funciones.
  • Copia de seguridad y recuperación: Actúa como una copia de seguridad de su base de código.
  • Revisión de código: Admite procesos de revisión de código antes de fusionar los cambios.

Herramientas como Git se utilizan comúnmente con proyectos .NET Core, a menudo integradas con plataformas como GitHub, Azure DevOps o GitLab.

27. Explique los comandos básicos de Git como 'clone', 'commit', 'push' y 'pull'.

Los comandos de Git son fundamentales para el control de versiones. git clone crea una copia local de un repositorio remoto. Por ejemplo, git clone https://github.com/user/repo.git descarga el repositorio en su máquina.

git commit guarda los cambios en tu repositorio local. Primero, prepararías los cambios con git add . o git add <archivo>. Luego, git commit -m "Tu mensaje de commit" crea un nuevo commit con un mensaje descriptivo. git push sube tus commits locales a un repositorio remoto. Por ejemplo, git push origin main empuja la rama 'main' al remoto 'origin'. Finalmente, git pull descarga los cambios de un repositorio remoto y los fusiona en tu rama actual. git pull origin main actualiza tu rama 'main' local con los últimos cambios del remoto 'origin'.

28. ¿Cómo depurarías una aplicación .NET Core que se ejecuta en un contenedor Docker?

Depurar una aplicación .NET Core que se ejecuta en un contenedor Docker se puede lograr de varias maneras. Un método común es usar las herramientas de contenedor de Visual Studio. Puedes adjuntar el depurador de Visual Studio al proceso del contenedor en ejecución. Esto requiere asegurar que la aplicación se construya con símbolos de depuración y que el depurador esté configurado correctamente dentro de Visual Studio para conectarse al contenedor.

Otro enfoque implica el uso de la herramienta de línea de comandos dotnet attach. Primero, necesitarás encontrar el ID del proceso (PID) de la aplicación .NET dentro del contenedor. Puedes usar docker exec para ejecutar ps -ef dentro del contenedor e identificar el PID. Luego, usa dotnet attach <PID> desde tu máquina host, apuntando al contenedor. Recuerda que tu runtime de .NET necesita ser capaz de descubrir este depurador recién adjuntado.

29. ¿Cuáles son algunas de las diferencias clave entre .NET Core y .NET 5/6/7/8?

.NET Core fue la reimplementación inicial multiplataforma y de código abierto de .NET Framework. .NET 5 (y versiones posteriores como 6, 7 y 8) son continuaciones de .NET Core, pero representan la plataforma .NET unificada. .NET 5 y versiones posteriores reemplazaron efectivamente tanto a .NET Framework como a .NET Core.

Las diferencias clave son:

  • .NET Core está al final de su vida útil (EOL). .NET 5+ es la versión compatible.
  • .NET 5+ unifica la plataforma. Su objetivo es tener una única biblioteca de clases base (BCL) y un tiempo de ejecución para todas las cargas de trabajo (escritorio, web, móvil, nube, etc.). .NET Core tenía algunas diferencias en las cargas de trabajo compatibles.
  • .NET 5+ incluye mejoras de rendimiento y nuevas características del lenguaje (de las versiones de C#).
  • .NET 5+ usa un nuevo esquema de versionado. El salto de .NET Core 3.1 a .NET 5 significó este cambio importante y el alejamiento de la marca "Core".

Preguntas de entrevista de .NET Core para principiantes

1. ¿Qué es .NET Core y por qué es especial en comparación con el .NET Framework anterior?

.NET Core (ahora solo .NET) es un framework gratuito, de código abierto y multiplataforma para construir varias aplicaciones, incluidas aplicaciones web, móviles, de escritorio y en la nube. Su naturaleza multiplataforma es una distinción importante del .NET Framework anterior, que estaba principalmente centrado en Windows. Esto permite que las aplicaciones .NET se ejecuten en Windows, macOS y Linux.

En comparación con .NET Framework, .NET ofrece varias ventajas clave:

  • Multiplataforma: Se ejecuta en Windows, macOS y Linux.
  • Modular: Permite incluir solo los paquetes necesarios para su aplicación, reduciendo su tamaño y mejorando el rendimiento.
  • Código abierto: Se beneficia de las contribuciones de la comunidad y la transparencia.
  • Rendimiento: Generalmente ofrece un mejor rendimiento que .NET Framework.
  • Moderno: Adopta las prácticas y herramientas de desarrollo modernas.

2. ¿Puede explicar qué es un 'namespace' en C# y por qué los usamos?

En C#, un namespace es una forma de organizar el código en grupos lógicos y evitar conflictos de nombres. Piense en ello como un contenedor para clases, interfaces, structs, enums y otros namespaces. Los namespaces ayudan a evitar situaciones en las que dos piezas de código diferentes definen el mismo nombre, lo que provocaría errores de compilación.

Usamos namespaces por varias razones:

  • Organización: Los espacios de nombres facilitan la búsqueda y comprensión del código relacionado.
  • Evitar Colisiones de Nombres: Permiten usar el mismo nombre para diferentes tipos, siempre y cuando estén en diferentes espacios de nombres. Por ejemplo, System.IO.File y MyProject.File pueden coexistir sin conflicto.
  • Reutilización de Código: Los espacios de nombres permiten empaquetar el código en componentes reutilizables.
  • Control del Alcance: Los espacios de nombres controlan el alcance de los nombres.

3. ¿Cuál es la diferencia entre 'int' y 'string' en C#, y cuándo usarías cada uno?

En C#, int y string representan diferentes tipos de datos. int es un tipo de valor que almacena números enteros (por ejemplo, -1, 0, 100). Se utiliza para representar números enteros contables. string es un tipo de referencia que representa una secuencia de caracteres (por ejemplo, "Hola", "Mundo").

Usarías int cuando necesites realizar operaciones aritméticas, representar cantidades o usar como índices. Usarías string cuando necesites almacenar datos textuales, como nombres, descripciones o la entrada del usuario.

Ejemplos:

  • int: int edad = 30;, int cuenta = 10;
  • string: string nombre = "Alicia";, string mensaje = "¡Hola mundo!";

4. Imagina que estás explicando 'variables' a un amigo. ¿Cómo describirías lo que son y lo que hacen?

Imagina una variable como un contenedor etiquetado o una caja. Puedes poner información dentro de ella, como un número, una palabra, o incluso una lista de cosas. La etiqueta en la caja (el nombre de la variable) te permite encontrar y usar fácilmente esa información más tarde.

Las variables se usan para almacenar valores que pueden cambiar o ser necesarios varias veces en un programa. Por ejemplo, en x = 5, x es la variable y 5 es el valor almacenado en ella. Más tarde, si quieres usar ese valor, simplemente te refieres a la variable x.

5. ¿Qué es una declaración 'if' y cómo ayuda a tu programa a tomar decisiones?

Una declaración if es una declaración de flujo de control fundamental en la programación que permite a un programa ejecutar diferentes bloques de código en función de si una condición especificada es verdadera o falsa. Es la piedra angular de la toma de decisiones dentro de un programa. La sintaxis básica se ve así en muchos lenguajes:

if (condición) { // Código para ejecutar si la condición es verdadera } else { // Código para ejecutar si la condición es falsa }

Las declaraciones if permiten que los programas respondan dinámicamente a diferentes entradas o situaciones. Por ejemplo, una declaración if podría verificar si un usuario ha iniciado sesión antes de permitirle acceder a datos confidenciales, o si un número es positivo antes de calcular su raíz cuadrada. Esto permite que los programas manejen varios escenarios y ejecuten las acciones apropiadas en consecuencia, haciéndolos más versátiles y robustos.

6. ¿Qué es un 'bucle' y por qué es útil cuando quieres hacer algo muchas veces?

Un 'bucle' es una construcción de programación que te permite ejecutar repetidamente un bloque de código. Es útil porque en lugar de escribir el mismo código varias veces, puedes escribirlo una vez dentro de un bucle, y el bucle se encargará de la repetición por ti.

Por ejemplo, si quisieras imprimir "Hola" 10 veces, en lugar de escribir print("Hola") diez veces, podrías usar un bucle como este (en Python):

for i in range(10): print("Hola")

Esto hace que tu código sea mucho más conciso, legible y mantenible. Los bucles son esenciales para tareas como procesar listas de datos, iterar a través de archivos y realizar cálculos repetitivos.

7. ¿Puedes explicar qué es un 'array' y cómo te ayuda a almacenar múltiples cosas?

Un array es una estructura de datos que almacena una colección de elementos del mismo tipo de datos en ubicaciones de memoria contiguas. Piénsalo como una lista numerada donde cada elemento tiene una posición específica (índice). Esta disposición te permite acceder a cualquier elemento rápidamente usando su índice. Por ejemplo, en muchos lenguajes, el primer elemento tiene el índice 0, el segundo tiene el índice 1, y así sucesivamente.

Las matrices son útiles porque te permiten organizar y administrar múltiples valores relacionados bajo un único nombre de variable. En lugar de crear variables separadas para cada elemento (por ejemplo, elemento1, elemento2, elemento3), puedes almacenarlos todos en una matriz como elementos = [elemento1, elemento2, elemento3]. Esto hace que tu código sea más organizado, legible y fácil de manipular datos al tratar con un grupo de elementos similares. Por ejemplo, considera procesar una serie de lecturas de temperatura o almacenar una lista de nombres de estudiantes.

8. ¿Qué es un 'método' en C#, y por qué los usamos para organizar nuestro código?

En C#, un método es un bloque de código que realiza una tarea específica. Es esencialmente una función que está asociada a una clase o estructura. Los métodos definen el comportamiento de los objetos.

Usamos métodos para organizar nuestro código por varias razones:

  • Modularidad: Los métodos dividen problemas grandes y complejos en piezas más pequeñas y manejables.
  • Reutilización: Un método se puede llamar varias veces desde diferentes partes del código, evitando la duplicación. Ejemplo:

public int Add(int a, int b) { return a + b; }

  • Legibilidad: Los métodos con nombres descriptivos hacen que el código sea más fácil de entender.
  • Mantenibilidad: Los cambios en una funcionalidad específica se pueden aislar a un único método, reduciendo el riesgo de introducir errores en otro lugar.

9. ¿Qué significa 'depuración' y cuál es una forma sencilla de intentar encontrar errores en tu código?

La depuración es el proceso de encontrar y corregir errores (bugs) en el código o software de una computadora. Un bug es un error, defecto o falla en un programa o sistema informático que hace que produzca un resultado incorrecto o inesperado, o que se comporte de manera no intencionada.

Una forma sencilla de encontrar errores es utilizar las instrucciones print o un depurador para recorrer el código línea por línea. Al insertar instrucciones print (por ejemplo, print(nombre_variable)) en varios puntos, puede inspeccionar los valores de las variables y el flujo de ejecución para identificar dónde el código se desvía del comportamiento esperado. Alternativamente, el uso de un depurador le permite pausar la ejecución, examinar las variables y recorrer el código línea por línea, proporcionando una forma más controlada de entender lo que está sucediendo.

10. ¿Qué es el 'control de versiones' (como Git) y por qué es importante para trabajar en proyectos con otros?

El control de versiones, como Git, es un sistema que rastrea los cambios en los archivos a lo largo del tiempo. Es esencialmente un historial de versiones para el código y otros activos de su proyecto. Esto le permite revertir a versiones anteriores, comparar cambios y ver quién hizo modificaciones específicas.

Es crucial para los proyectos colaborativos porque permite que varias personas trabajen en los mismos archivos simultáneamente sin sobrescribir el trabajo de los demás. Git proporciona mecanismos para fusionar cambios, resolver conflictos y mantener un repositorio central del historial del proyecto. Sin el control de versiones, coordinar los cambios y administrar diferentes versiones se vuelve extremadamente difícil y propenso a errores, lo que lleva a la pérdida de trabajo y problemas de integración. Por ejemplo, puede usar comandos como git pull, git push y git merge para administrar los cambios dentro de un equipo.

11. ¿Cuál es la diferencia entre `Console.WriteLine()` y `Console.ReadLine()`?

Console.WriteLine() se utiliza para emitir información a la consola. Toma un valor (o una cadena) como entrada y la muestra en la ventana de la consola. Luego mueve el cursor a la siguiente línea. Piense en ello como "escribir una línea" en la consola.

Console.ReadLine() se usa para leer la entrada desde la consola. Espera a que el usuario escriba algo y presione Enter. Luego, el método devuelve el texto ingresado como una cadena. Si el usuario no ingresa nada y simplemente presiona enter, devuelve "" (una cadena vacía).

12. Explique la diferencia entre una clase y un objeto en C#?

Una clase es un plano o una plantilla para crear objetos. Define las propiedades (datos) y los métodos (comportamiento) que tendrá un objeto de esa clase. Piense en ello como un cortador de galletas; el cortador de galletas es la clase, y las galletas son los objetos.

Un objeto, por otro lado, es una instancia de una clase. Es una realización concreta del plano. Cada objeto tiene su propio conjunto único de valores de datos para las propiedades definidas en la clase. Se pueden crear múltiples objetos a partir de la misma clase, cada uno con su propio estado. Por ejemplo, si Dog es una clase, miPerro y tuPerro son objetos de la clase Dog. Ambos son perros pero tienen diferentes nombres, razas y edades.

13. ¿Cuál es el propósito de usar comentarios en el código y cómo pueden ayudarle a usted y a otros?

El propósito principal de los comentarios en el código es explicar qué hace el código, cómo funciona y por qué se tomaron ciertas decisiones. Sirven como documentación dentro del código mismo, lo que facilita la comprensión y el mantenimiento.

Los comentarios ayudan a los desarrolladores (incluido usted mismo en el futuro) al:

  • Mejorar la legibilidad: Dividen la lógica compleja en términos más simples.
  • Facilitar la colaboración: Permiten que otros desarrolladores comprendan rápidamente el propósito del código.
  • Ayudar a la depuración: Pueden resaltar áreas problemáticas potenciales o explicar el razonamiento detrás de implementaciones específicas.
  • Generar documentación: Las herramientas pueden extraer automáticamente comentarios para generar documentación externa.

Ejemplo:

Calcula el área de un rectángulo

def calcular_area(longitud, anchura):
    # Asegura que las entradas sean positivas
    if longitud <= 0 or anchura <= 0:
        return 0 # Devuelve 0 si las dimensiones no son válidas
    return longitud * anchura

14. ¿Cuáles son algunos tipos de datos básicos que conoce en C# aparte de `int` y `string`?

Además de int y string, C# ofrece varios otros tipos de datos fundamentales. Algunos comunes incluyen:

  • bool: Representa un valor booleano, ya sea true o false.
  • float: Representa un número de punto flotante de precisión simple (32 bits).
  • double: Representa un número de punto flotante de doble precisión (64 bits).
  • char: Representa un solo carácter Unicode.
  • decimal: Representa un valor decimal preciso, adecuado para cálculos financieros (128 bits).
  • byte: Representa un entero sin signo de 8 bits.
  • short: Representa un entero de 16 bits.
  • long: Representa un entero de 64 bits.

15. ¿Cómo se crea un programa simple '¡Hola, mundo!' en .NET Core?

Para crear un programa '¡Hola, mundo!' en .NET Core, puedes utilizar los siguientes pasos:

Primero, crea un nuevo proyecto de aplicación de consola utilizando la CLI de .NET: dotnet new console -o HelloWorld. Esto crea una estructura básica del proyecto. A continuación, navega al directorio del proyecto utilizando la línea de comandos: cd HelloWorld. Ahora, modifica el archivo Program.cs para mostrar '¡Hola, mundo!'. El código relevante dentro de Program.cs sería así:

using System; namespace HelloWorld { class Program { static void Main(string[] args) { Console.WriteLine("Hello, World!"); } } }

Finalmente, ejecuta el programa utilizando el comando: dotnet run. Esto compilará y ejecutará el código, mostrando '¡Hola, mundo!' en la consola.

16. Describe la diferencia entre los modificadores de acceso `public` y `private`.

Los modificadores de acceso public y private controlan la visibilidad y accesibilidad de los miembros de la clase (variables, métodos) en lenguajes de programación orientados a objetos. Los miembros public son accesibles desde cualquier lugar, tanto dentro como fuera de la clase. Esto significa que cualquier parte del código puede acceder o modificar directamente las variables public o llamar a los métodos public.

En contraste, los miembros private solo son accesibles desde dentro de la misma clase. Otras clases, incluso subclases, no pueden acceder directamente a los miembros private. Esto refuerza la encapsulación y el ocultamiento de datos, evitando modificaciones no deseadas y protegiendo el estado interno del objeto. Lenguajes como Java, C++ y C# admiten estos modificadores de acceso. Por ejemplo:

class MyClass { public int publicVar; // Accesible en todas partes private int privateVar; // Solo accesible dentro de MyClass }

17. ¿Puede describir qué entiende por API y cómo se pueden utilizar en .NET Core?

Las API (Interfaces de Programación de Aplicaciones) son esencialmente contratos que permiten que diferentes sistemas de software se comuniquen e intercambien datos. Definen los métodos y formatos de datos que las aplicaciones pueden usar para solicitar servicios entre sí. En .NET Core, las API se pueden crear utilizando ASP.NET Core Web API para exponer funcionalidades a través de HTTP. Estas API pueden ser consumidas por varios clientes como aplicaciones web, aplicaciones móviles u otros servicios.

En .NET Core, podemos crear API RESTful utilizando controladores y acciones que manejan las solicitudes HTTP (GET, POST, PUT, DELETE). Los datos se serializan típicamente en formato JSON o XML para la transmisión. Los clientes pueden usar clientes HTTP (como HttpClient) para interactuar con estas API enviando solicitudes y procesando las respuestas. Por ejemplo, una API simple podría exponer un punto final para recuperar datos de usuario:

[HttpGet("users/{id}")] public IActionResult GetUser(int id) { // Lógica para recuperar el usuario de la base de datos var user = GetUserFromDatabase(id); if (user == null) { return NotFound(); } return Ok(user); }

18. ¿Qué es NuGet y por qué es importante en el desarrollo de .NET Core?

NuGet es un administrador de paquetes para .NET, que proporciona una forma centralizada de descubrir, instalar y administrar componentes de software reutilizables (bibliotecas/paquetes) dentro de sus proyectos .NET. Simplifica el proceso de incluir dependencias externas, como bibliotecas o frameworks de terceros, en su aplicación.

En el desarrollo de .NET Core, NuGet es crucial porque agiliza la gestión de dependencias. En lugar de descargar y referenciar DLLs manualmente, puede agregar fácilmente paquetes de la Galería NuGet (un repositorio central) usando el Administrador de paquetes NuGet en Visual Studio o el comando dotnet add package. Esto garantiza versiones consistentes de las dependencias en todos los proyectos y simplifica la actualización y eliminación de paquetes. Los paquetes NuGet pueden contener código precompilado, scripts u otros activos necesarios para que el paquete funcione.

19. ¿Cómo manejaría un error simple en una aplicación .NET Core?

En una aplicación .NET Core, un error simple se puede manejar usando un bloque try-catch. El código que podría lanzar una excepción se coloca dentro del bloque try. Si ocurre una excepción, el control se transfiere inmediatamente al bloque catch, donde puede registrar el error, mostrar un mensaje amigable para el usuario o tomar otras acciones apropiadas.

Por ejemplo:

intente { // Código que podría lanzar una excepción int resultado = 10 / 0; } catch (DivideByZeroException ex) { // Manejar la excepción Console.WriteLine("Error: División por cero."); // Opcionalmente, registrar los detalles de la excepción utilizando un framework de logging //_logger.LogError(ex, "Se produjo un error de división por cero."); }

20. Explique lo que sabe sobre las pruebas en .NET Core (por ejemplo, pruebas unitarias).

En .NET Core, las pruebas son una parte crucial del desarrollo de software. Las pruebas unitarias, en particular, se centran en verificar componentes o métodos individuales de forma aislada. Los frameworks clave incluyen:

  • xUnit.net: Un framework de pruebas popular y extensible.
  • MSTest: El propio framework de pruebas de Microsoft.
  • NUnit: Otro framework ampliamente utilizado, similar a xUnit.

Estos frameworks permiten escribir métodos de prueba para afirmar los resultados esperados. Por ejemplo:

[Fact] public void Add_TwoNumbers_ReturnsSum() { // Arrange (Preparar) int a = 10; int b = 20; // Act (Actuar) int sum = a + b; // Assert (Afirmar) Assert.Equal(30, sum); }

Además de las pruebas unitarias, otros tipos de pruebas como la integración y end-to-end también son pertinentes, y .NET Core proporciona soporte para ellas. Por ejemplo, TestServer ayuda a probar aplicaciones ASP.NET Core al alojarlas en memoria durante las pruebas de integración.

21. ¿Cuáles son algunos de los beneficios de usar .NET Core para el desarrollo web?

Usar .NET Core para el desarrollo web ofrece varias ventajas. Es multiplataforma, lo que significa que puede desarrollar e implementar aplicaciones en Windows, macOS y Linux. Esto proporciona una mayor flexibilidad y potencialmente reduce los costos de infraestructura. Además, .NET Core ha sido diseñado pensando en el rendimiento y es mucho más rápido en comparación con .NET Framework. También presenta un diseño modular, lo que permite a los desarrolladores incluir solo las dependencias necesarias, reduciendo así la huella de la aplicación.

Además, .NET Core adopta la inyección de dependencias, lo que hace que el sistema esté poco acoplado y que las pruebas unitarias sean mucho más sencillas. La gestión de paquetes se agiliza con NuGet, y la interfaz de línea de comandos (CLI) ofrece una herramienta poderosa para la creación, construcción y publicación de proyectos. Finalmente, las actualizaciones continuas y una comunidad vibrante aseguran que .NET Core se mantenga al día con las últimas tecnologías y mejores prácticas. dotnet new webapi es un comando popular para crear rápidamente un proyecto de API web.

22. Describe lo que entiendes sobre la inyección de dependencias en .NET Core.

La inyección de dependencias (ID) es un patrón de diseño utilizado para lograr la Inversión de Control (IoC) en .NET Core. Permite desarrollar código débilmente acoplado, comprobable y mantenible. En lugar de que una clase cree sus dependencias, estas se 'inyectan' en la clase, generalmente a través de su constructor.

.NET Core tiene soporte integrado para ID. Registras tus servicios (dependencias) en el método ConfigureServices del archivo Startup.cs. Estos servicios se pueden registrar con diferentes tiempos de vida, como: Transient, Scoped o Singleton. Luego, el framework se encarga de resolver e inyectar estas dependencias cuando tu aplicación las necesita. Aquí hay un ejemplo simple:

public interface IMyService { } public class MyService : IMyService { } public void ConfigureServices(IServiceCollection services) { services.AddTransient<IMyService, MyService>(); }

23. ¿Qué son las variables de entorno y cómo podrías usarlas en una aplicación .NET Core?

Las variables de entorno son pares clave-valor que existen fuera del alcance del código de una aplicación. Almacenan configuraciones que pueden variar según el entorno en el que se ejecuta la aplicación (por ejemplo, desarrollo, pruebas, producción). Te permiten configurar el comportamiento de la aplicación sin modificar el código en sí.

En una aplicación .NET Core, puedes acceder a las variables de entorno utilizando el método System.Environment.GetEnvironmentVariable(). Por ejemplo:

string apiKey = Environment.GetEnvironmentVariable("API_KEY"); string connectionString = Environment.GetEnvironmentVariable("CONNECTION_STRING");

Se usan comúnmente para:

  • Cadenas de conexión a la base de datos: Almacenar credenciales confidenciales de la base de datos.
  • Claves de API: Gestionar tokens de acceso a la API.
  • Configuración de la aplicación: Configurar comportamientos específicos de la aplicación (por ejemplo, niveles de registro).
  • Configuraciones específicas del despliegue: Adaptar la aplicación a diferentes entornos de despliegue (por ejemplo, establecer el puerto de la aplicación).

Los archivos de configuración, como appsettings.json, también pueden utilizar variables de entorno para anular la configuración predeterminada, utilizando la sintaxis ${VARIABLE_NAME} dentro del archivo de configuración o a través de proveedores de configuración que cargan específicamente las variables de entorno.

24. Si tuvieras una lista de números, ¿cómo podrías encontrar el número más grande utilizando C#?

Puedes encontrar el número más grande en una lista de números en C# utilizando varios enfoques. Un método sencillo implica iterar a través de la lista y realizar un seguimiento del número más grande encontrado hasta el momento:

using System.Linq; public class Ejemplo { public static int EncontrarMayor(List<int> números) { if (números == null || números.Count == 0) { throw new ArgumentException("La lista no puede ser nula o estar vacía."); } int mayor = números[0]; for (int i = 1; i < números.Count; i++) { if (números[i] > mayor) { mayor = números[i]; } } return mayor; } // Alternativamente, usando LINQ: public static int EncontrarMayorLinq(List<int> números) { if (números == null || números.Count == 0) { throw new ArgumentException("La lista no puede ser nula o estar vacía."); } return números.Max(); } }

Alternativamente, podría usar el método Max() de la biblioteca LINQ para una solución más concisa. Sin embargo, considere las implicaciones de rendimiento de cada método en función del tamaño de su lista. El enfoque iterativo evita la sobrecarga de LINQ, lo que puede ser beneficioso para listas muy grandes donde el rendimiento es crítico. El manejo de errores para listas nulas o vacías es crucial.

25. Explique lo que sabe sobre LINQ y cómo es útil.

LINQ (Language Integrated Query) es una característica poderosa en .NET que proporciona una forma unificada de consultar datos de diversas fuentes, como bases de datos, colecciones, XML y más, directamente dentro del código C# (o VB.NET). Utiliza una sintaxis consistente para consultar diferentes fuentes de datos, eliminando la necesidad de aprender diferentes lenguajes de consulta para cada tipo de datos. LINQ le permite escribir consultas que son seguras para el tipo y se pueden verificar en tiempo de compilación, lo que reduce los errores en tiempo de ejecución.

LINQ es útil porque simplifica el acceso a datos, mejora la legibilidad del código y reduce la cantidad de código necesario para realizar operaciones de datos. Algunos de sus beneficios incluyen:

  • Acceso a datos simplificado: Proporciona una forma consistente de consultar diferentes fuentes de datos.
  • Legibilidad mejorada: Las consultas se escriben en un estilo declarativo, lo que las hace más fáciles de entender.
  • Seguridad de tipos: Detecta errores en tiempo de compilación en lugar de en tiempo de ejecución.
  • Código reducido: Se necesita menos código para realizar operaciones de datos, como filtrar, ordenar y agrupar.
  • Ejemplo: var resultados = from p in productos where p.Precio > 10 select p;

26. ¿Qué es JSON y por qué se utiliza en las aplicaciones .NET Core?

JSON (Notación de Objetos JavaScript) es un formato de intercambio de datos ligero y legible para humanos. Se utiliza para transmitir datos entre un servidor y una aplicación web (u otras aplicaciones) porque es fácil de analizar y generar.

En las aplicaciones .NET Core, JSON se utiliza ampliamente para:

  • Comunicación API: Las API a menudo usan JSON para enviar y recibir datos.
  • Configuración: appsettings.json es una forma común de almacenar datos de configuración.
  • Serialización/deserialización de datos: Convertir objetos .NET a JSON y viceversa utilizando bibliotecas como System.Text.Json o Newtonsoft.Json (aunque System.Text.Json es preferido en las aplicaciones .NET Core modernas).
  • Almacenamiento de datos: Escenarios simples de persistencia de datos.

27. ¿Cómo maneja .NET Core diferentes sistemas operativos (como Windows, macOS y Linux)?

.NET Core (y versiones posteriores .NET 5+) logra la compatibilidad multiplataforma a través de su arquitectura y tiempo de ejecución. Se basa en una capa de abstracción de plataforma que proporciona una API consistente para interactuar con el sistema operativo subyacente. Esta capa maneja las particularidades de cada sistema operativo, como las diferencias en el sistema de archivos, la gestión de la memoria y las llamadas al sistema, lo que permite que el código .NET se ejecute sin modificaciones en Windows, macOS y Linux.

Específicamente, .NET Core utiliza CoreCLR (el tiempo de ejecución) y CoreFX (las bibliotecas de clases). CoreCLR es responsable de compilar y ejecutar el código administrado, mientras que CoreFX proporciona un conjunto de API que se implementan de manera diferente para cada sistema operativo. Por ejemplo, el acceso a un archivo implica diferentes llamadas al sistema en Windows vs. Linux, pero la API de .NET proporciona una interfaz unificada que abstrae esas diferencias. Esta abstracción es clave para la portabilidad. Los desarrolladores construyen aplicaciones contra las bibliotecas estándar de .NET, y el tiempo de ejecución de .NET se encarga de las implementaciones específicas del sistema operativo.

28. ¿Qué herramientas o IDEs (como Visual Studio Code) se pueden utilizar para el desarrollo de .NET Core?

Varias herramientas e IDEs admiten el desarrollo de .NET Core. Visual Studio es un IDE completo con amplias funciones para el desarrollo de .NET, incluyendo la depuración, el perfilado y la gestión de proyectos.

Visual Studio Code es un editor de código ligero pero potente que, con la extensión C#, proporciona un excelente soporte para .NET Core, incluyendo IntelliSense, depuración y tareas de compilación. Otras opciones incluyen JetBrains Rider, un IDE .NET multiplataforma conocido por sus capacidades de análisis de código y refactorización, y herramientas de línea de comandos como el .NET CLI, que es esencial para compilar, ejecutar y publicar aplicaciones .NET Core desde cualquier terminal.

29. Imagine que su programa no funciona como se espera. Explíqueme su proceso para solucionarlo.

Cuando un programa no funciona como se esperaba, generalmente empiezo por intentar reproducir el problema de forma fiable. Esto ayuda a asegurar que estoy abordando un problema real y no solo una casualidad. A continuación, examino los mensajes de error, los registros y cualquier traza de pila disponible para obtener pistas sobre la fuente del problema. A menudo, uso un depurador para recorrer el código, inspeccionar variables y rastrear el flujo de ejecución del programa para señalar la ubicación exacta donde las cosas van mal.

Una vez que he identificado la fuente del error, formulo una solución. Esto puede implicar modificar el código, cambiar configuraciones o incluso ajustar el entorno. Después de aplicar la solución, pruebo a fondo el programa, incluyendo el escenario original que desencadenó el problema y áreas relacionadas, para asegurar que el problema se ha resuelto y que no se han introducido nuevos problemas. También usaría el control de versiones, creando una nueva rama para probar una solución. Si no estoy seguro de la solución, o necesito ayuda, usaré una técnica como la depuración con un patito de goma, o pediré ayuda a un colega con más experiencia.

Preguntas de la entrevista intermedia de .NET Core

1. ¿Cómo funciona la inyección de dependencias de .NET Core y por qué es útil?

La inyección de dependencias (DI) de .NET Core es un patrón de diseño y una técnica que se utiliza para lograr un acoplamiento débil entre las clases y sus dependencias. En lugar de que una clase cree sus propias dependencias, esas dependencias se "inyectan" en la clase, normalmente a través de su constructor, propiedades o métodos. .NET Core tiene un contenedor DI integrado que gestiona la creación y la duración de estas dependencias. Usted registra sus servicios (dependencias) con el contenedor, especificando su ámbito de tiempo de vida (por ejemplo, singleton, scoped, transient). Cuando una clase necesita una dependencia, el contenedor se la proporciona.

DI promueve la capacidad de prueba, la reutilización y el mantenimiento. Al desacoplar los componentes, puede cambiar fácilmente las implementaciones, simular dependencias para las pruebas y reducir el impacto de los cambios. El contenedor integrado simplifica la gestión de dependencias y proporciona una forma estandarizada de configurar y resolver las dependencias en toda su aplicación. Por ejemplo:

public class MyService { private readonly IMyDependency _dependency; public MyService(IMyDependency dependency) { _dependency = dependency; } }

2. Explique la diferencia entre `Task.Run` y `Task.Factory.StartNew` en .NET Core.

Task.Run y Task.Factory.StartNew se utilizan ambos para crear e iniciar tareas en .NET, pero tienen algunas diferencias sutiles. Task.Run es el método preferido y más simple en la mayoría de los casos. Está diseñado para poner en cola el trabajo directamente en el grupo de subprocesos. Implícitamente utiliza el programador de tareas predeterminado y ofrece opciones de sobrecarga para pasar tokens de cancelación y TaskCreationOptions que por defecto son TaskCreationOptions.None.

Task.Factory.StartNew, por otro lado, ofrece más control y flexibilidad. Permite especificar un programador de tareas personalizado, configurar TaskCreationOptions y controlar el comportamiento de ejecución de la tarea con mayor precisión. Por ejemplo, permite utilizar TaskCreationOptions.LongRunning para indicar al programador que una tarea es de ejecución prolongada y que se le debe asignar su propio subproceso dedicado. El valor predeterminado de TaskCreationOptions es TaskCreationOptions.None a menos que se especifique un TaskScheduler, momento en el cual se convierte en TaskCreationOptions.AttachedToParent | TaskCreationOptions.DenyChildAttach.

3. ¿Qué son los componentes de middleware en ASP.NET Core y cómo se utilizan en el pipeline de solicitudes?

Los componentes de middleware en ASP.NET Core son componentes de software que se ensamblan en una tubería de aplicación para manejar las solicitudes y respuestas. Cada componente de middleware realiza una función específica, como autenticación, autorización, registro o servir archivos estáticos. Forman una cadena, donde cada middleware puede procesar la solicitud antes de pasarla al siguiente, y de manera similar procesar la respuesta en el camino de regreso.

Se utilizan en el pipeline de solicitudes agregándolos al método Configure en el archivo Startup.cs. El orden en que los componentes de middleware se agregan al pipeline es crucial, ya que determina el orden en que se ejecutan. Por ejemplo:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }

4. ¿Cómo maneja .NET Core la configuración y cuáles son algunas fuentes de configuración comunes?

.NET Core utiliza un sistema de configuración flexible basado en pares clave-valor. Aprovecha el paquete NuGet Microsoft.Extensions.Configuration. La configuración se construye a partir de uno o más proveedores de configuración, lo que permite configuraciones en capas y anuladas.

Las fuentes de configuración comunes incluyen:

  • appsettings.json: La forma más común, típicamente para configuraciones independientes del entorno.
  • appsettings.{Environment}.json: Configuraciones específicas del entorno (por ejemplo, appsettings.Development.json).
  • Variables de entorno: Útiles para secretos de producción y configuraciones que varían entre entornos.
  • Argumentos de línea de comandos: Para especificar configuraciones al ejecutar la aplicación.
  • Secretos de usuario: Un almacén seguro para secretos de tiempo de desarrollo (evita commits accidentales de secretos al control de código fuente). Se accede a través de dotnet user-secrets.
  • Azure Key Vault: Para almacenar y administrar de forma segura secretos en Azure.
  • Proveedores en memoria: Útiles para pruebas o escenarios donde las configuraciones se generan mediante programación.

El orden en que se agregan las fuentes de configuración determina su precedencia. Las fuentes posteriores sobrescriben a las anteriores. Por ejemplo, las variables de entorno a menudo sobrescriben appsettings.json.

5. Describa el propósito de Kestrel en ASP.NET Core.

Kestrel es un servidor web multiplataforma para ASP.NET Core. Es el servidor web predeterminado incluido en las plantillas de proyectos de ASP.NET Core y está diseñado para ser de alto rendimiento y eficiente.

Kestrel se puede usar como un servidor web directo, con acceso a Internet, o como un servidor proxy inverso, ubicado detrás de otro servidor web como IIS, Nginx o Apache. Cuando se usa como proxy inverso, Kestrel maneja las solicitudes que le pasa el servidor proxy, que puede proporcionar características adicionales como equilibrio de carga, seguridad y almacenamiento en caché.

6. ¿Cómo se puede implementar el registro en una aplicación .NET Core y cuáles son algunas de las mejores prácticas?

En .NET Core, el registro se implementa típicamente usando la biblioteca Microsoft.Extensions.Logging. Primero, agregue el paquete NuGet Microsoft.Extensions.Logging y un proveedor específico como Microsoft.Extensions.Logging.Console o Serilog.AspNetCore. Luego, inyecte ILogger<T> en sus clases. Registre mensajes usando métodos como LogInformation(), LogError(), LogWarning(), etc. Ejemplo:

public class MyClass { private readonly ILogger<MyClass> _logger; public MyClass(ILogger<MyClass> logger) { _logger = logger; } public void DoSomething() { _logger.LogInformation("Haciendo algo..."); // ... } }

Las mejores prácticas incluyen: usar registros estructurados para facilitar la consulta y el análisis; configurar diferentes niveles de registro (por ejemplo, Depuración, Información, Advertencia, Error, Crítico) según el entorno; registrar excepciones con contexto relevante; evitar el registro de datos confidenciales; usar una solución de registro centralizada como Serilog o NLog para funciones más avanzadas como la agregación y el filtrado de registros. Además, aproveche la inyección de dependencias para facilitar el acceso al registrador y configure el registro en Program.cs.

7. ¿Cuál es la función de la CLI `dotnet`, y cuáles son algunos comandos comunes?

La CLI (Interfaz de línea de comandos) dotnet es una cadena de herramientas multiplataforma para desarrollar, construir, ejecutar y publicar aplicaciones .NET. Proporciona un conjunto de comandos que permiten a los desarrolladores realizar diversas tareas desde la línea de comandos, reemplazando la necesidad de un IDE en muchos escenarios. Es la forma principal de interactuar con el SDK de .NET.

Algunos comandos comunes de la CLI dotnet incluyen:

  • dotnet new: Crea un nuevo proyecto, solución o archivo de configuración de .NET basado en una plantilla. Ejemplo: dotnet new console
  • dotnet build: Compila un proyecto .NET y sus dependencias.
  • dotnet run: Compila y ejecuta un proyecto .NET.
  • dotnet publish: Empaqueta una aplicación .NET para su implementación.
  • dotnet add package: Agrega un paquete NuGet a un proyecto. Ejemplo: dotnet add package Newtonsoft.Json
  • dotnet restore: Restaura las dependencias especificadas en un archivo de proyecto.
  • dotnet test: Ejecuta pruebas unitarias en un proyecto.
  • dotnet ef: Comandos para las herramientas de Entity Framework Core. Ejemplo: dotnet ef migrations add InitialCreate

8. Explique la diferencia entre `ProjectReference`, `PackageReference`, y `Analyzer` en un archivo de proyecto .NET Core.

ProjectReference, PackageReference y Analyzer son diferentes formas de administrar dependencias en un archivo de proyecto .NET (típicamente un archivo .csproj). ProjectReference se usa cuando su proyecto depende de otro proyecto dentro de la misma solución. Esencialmente, le dice al sistema de compilación que primero compile el proyecto referenciado y luego use su salida como una dependencia. Esto es común para soluciones de múltiples proyectos donde tiene bibliotecas o módulos de los que depende su aplicación principal.

PackageReference se utiliza para incluir paquetes NuGet como dependencias. Los paquetes NuGet son bibliotecas o componentes preconstruidos que puede agregar fácilmente a su proyecto. Cuando agrega un PackageReference, el sistema de compilación descargará el paquete del feed NuGet y lo incluirá en las dependencias de su proyecto. Los elementos Analyzer, distintos de los PackageReference regulares, especifican analizadores de código y generadores de código fuente para incorporar en el proceso de compilación del proyecto. Estos pueden incluir analizadores de Roslyn o analizadores personalizados que hacen cumplir los estándares de codificación, identifican problemas potenciales o generan código automáticamente durante la compilación. Se incorporan como paquetes NuGet, identificados de manera similar a los paquetes estándar a través del mecanismo PackageReference, pero su propósito se limita estrictamente al análisis y la generación de código en lugar de proporcionar dependencias en tiempo de ejecución.

9. ¿Cómo .NET Core admite el desarrollo multiplataforma y cuáles son algunas consideraciones?

.NET Core (y versiones posteriores .NET 5+) logra el desarrollo multiplataforma principalmente a través de su entorno de tiempo de ejecución, que está disponible para Windows, macOS y Linux. Se basa en un conjunto compartido de bibliotecas y API abstraídas del sistema operativo subyacente. Esto permite a los desarrolladores escribir código una vez y, con mínimas modificaciones (si las hay), implementarlo en estas diferentes plataformas. CoreCLR (el tiempo de ejecución de .NET) es responsable de compilar JIT el código IL generado por el compilador de C# en código de máquina nativo para el sistema operativo de destino.

Algunas consideraciones incluyen: APIs específicas de la plataforma (puede que necesites usar directivas #if para código específico de la plataforma), diferencias en las rutas del sistema de archivos y asegurar que todas las dependencias estén disponibles para cada sistema operativo objetivo. Las pruebas en cada plataforma son cruciales. Las estrategias de implementación también pueden variar significativamente entre Windows, macOS y Linux.

10. ¿Cuál es el propósito de la interfaz IConfiguration y cómo se usa?

La interfaz IConfiguration en .NET proporciona una forma de acceder a la configuración de la aplicación desde varias fuentes, como appsettings.json, variables de entorno, argumentos de línea de comandos y secretos del usuario. Su propósito principal es abstraer los detalles de dónde provienen los datos de configuración, lo que permite que el código de su aplicación acceda a la configuración de manera consistente. Promueve el desacoplamiento y facilita el cambio de fuentes de configuración sin modificar el código de la aplicación.

Se utiliza inyectándolo en clases o métodos. La interfaz IConfiguration proporciona métodos como GetValue<T>() y GetSection() para recuperar valores de configuración. Por ejemplo, _configuration.GetValue<string>("Logging:LogLevel:Default") recupera el nivel de registro predeterminado de la configuración. La Inyección de Dependencias (DI) es la forma típica de suministrar una instancia de IConfiguration a los componentes que la necesitan.

11. Explique cómo implementaría el manejo de excepciones en una aplicación ASP.NET Core.

En ASP.NET Core, el manejo de excepciones se puede implementar utilizando varios enfoques. Un enfoque común es usar middleware. Puede crear un middleware personalizado que capture las excepciones y las maneje, como registrar el error y devolver un mensaje de error amigable para el usuario. Esto asegura una ubicación centralizada para el manejo de excepciones en toda su aplicación. Por ejemplo:

public class ExceptionHandlingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ExceptionHandlingMiddleware> _logger; public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext context) { try { await _next(context); } catch (Exception ex) { _logger.LogError(ex, "Se produjo una excepción no controlada."); context.Response.StatusCode = 500; await context.Response.WriteAsync("Se produjo un error inesperado."); } } }

Otra aproximación es utilizar filtros de excepción en sus controladores. Estos filtros le permiten manejar excepciones que ocurren dentro de acciones específicas del controlador o en todas las acciones de un controlador. También puede combinar middleware y filtros de excepción para una gestión integral de excepciones. app.UseExceptionHandler() en Program.cs también proporciona una gestión global de excepciones.

12. ¿Cómo puede asegurar una API web de .NET Core?

Asegurar una API web de .NET Core implica varias capas. La autenticación verifica la identidad del usuario, a menudo utilizando técnicas como:

  • Claves API: Simples pero menos seguras.
  • JWT (JSON Web Tokens): Estándar de la industria, utilizando tokens de portador en el encabezado Authorization. Necesita una gestión y validación adecuadas de la clave secreta.
  • OAuth 2.0 / OpenID Connect: Delega la autenticación a un proveedor de confianza (como Google, Azure AD).

La autorización determina a qué recursos puede acceder el usuario autenticado. Implemente la autorización basada en roles o en reclamos utilizando el atributo [Authorize] o políticas personalizadas. Otras medidas incluyen: validación de entrada para prevenir ataques de inyección, HTTPS para comunicación cifrada, limitación de velocidad para prevenir abusos, configuración de CORS y auditorías de seguridad periódicas.

13. ¿Qué son las Razor Pages en ASP.NET Core y en qué se diferencian de MVC tradicional?

Las Razor Pages son un enfoque centrado en páginas para construir la interfaz de usuario web en ASP.NET Core, lo que facilita y hace más productiva la creación de páginas web. Se organizan en torno a páginas individuales en una estructura de directorios (por ejemplo, Pages/Index.cshtml y Pages/Index.cshtml.cs), donde cada página normalmente maneja una única solicitud.

La diferencia clave con MVC tradicional es cómo se estructura el manejo de solicitudes. En MVC, las solicitudes pasan por un controlador que luego selecciona una vista. En Razor Pages, cada página tiene su propio archivo de código subyacente (.cshtml.cs) que maneja directamente las solicitudes, simplificando la estructura. Esto elimina la necesidad de controladores separados y a menudo reduce el código repetitivo, especialmente para aplicaciones simples. El código está co-ubicado, con la interfaz de usuario (.cshtml) y su lógica (.cshtml.cs) residiendo en el mismo directorio. Razor Pages promueve la separación de responsabilidades al encapsular la lógica de la interfaz de usuario dentro del modelo de página y la lógica de renderizado de la interfaz de usuario en la vista Razor.

14. ¿Cómo maneja .NET Core la gestión de la memoria y cuáles son algunas fugas de memoria comunes?

.NET Core utiliza un recolector de basura (GC) para administrar la memoria automáticamente. El GC escanea periódicamente el montón, identifica los objetos que ya no son accesibles por la aplicación y recupera la memoria que ocupan. Sin embargo, incluso con un GC, las fugas de memoria aún pueden ocurrir. Estas fugas generalmente ocurren cuando los objetos se mantienen vivos involuntariamente más tiempo de lo necesario, impidiendo que el GC los recoja.

Las fugas de memoria comunes de .NET Core incluyen: aferrarse a los manejadores de eventos sin anular el registro, almacenar objetos en variables estáticas o cachés de larga duración, no desechar objetos IDisposable (como flujos o conexiones a bases de datos) dentro de una declaración using o un bloque try-finally, y usar clausuras que capturan involuntariamente variables del ámbito externo e impiden que se recolecten como basura. Por ejemplo:

using(var connection = new SqlConnection(connectionString)) { //usar la conexión } //connection.Dispose() se llama automáticamente

15. Explica el concepto de 'patrón de opciones' en .NET Core.

El patrón de opciones en .NET Core proporciona una forma de acceder a los valores de configuración de forma fuertemente tipada. En lugar de acceder directamente a los objetos Configuration, define clases que representan secciones de su archivo de configuración (por ejemplo, appsettings.json), y enlaza los valores de configuración a las propiedades de estas clases. Esto promueve la mantenibilidad del código, la capacidad de prueba y la seguridad de tipos.

Para usar el patrón de opciones:

  1. Defina una clase de opciones (un POCO simple) con propiedades que coincidan con las claves de configuración.
  2. Registre la clase de opciones con el contenedor de inyección de dependencias usando services.Configure<YourOptionsClass>(Configuration.GetSection("YourSectionName")).
  3. Inyecte IOptions<YourOptionsClass> en sus clases para acceder a los valores de configuración a través de la propiedad Value (por ejemplo, _options.Value.YourSetting).
  4. IOptionsSnapshot<YourOptionsClass> se puede usar si necesita obtener los valores actualizados de la clase de opciones después de los cambios de configuración. Tiene un alcance.
  5. IOptionsMonitor<YourOptionsClass> se puede usar si necesita obtener los valores actualizados de la clase de opciones después de los cambios de configuración. Es singleton y puede notificarle los cambios.

16. ¿Cómo implementaría pruebas unitarias en un proyecto .NET Core y cuáles son algunos frameworks de prueba comunes?

Para implementar pruebas unitarias en un proyecto .NET Core, normalmente usaría un framework de pruebas como xUnit, NUnit o MSTest. Primero, agregue los paquetes NuGet necesarios para el framework elegido y una biblioteca de simulación como Moq. Luego, cree un proyecto de prueba separado que refleje la estructura del proyecto principal. Dentro del proyecto de prueba, escriba métodos de prueba para ejercitar unidades individuales de código (por ejemplo, clases, métodos). Use el patrón Arrange-Act-Assert dentro de cada método de prueba.

Los marcos de pruebas comunes incluyen:

  • xUnit: Un marco popular y extensible.
  • NUnit: Otro marco ampliamente utilizado con un rico conjunto de características.
  • MSTest: El propio marco de pruebas de Microsoft.

Ejemplo:

[Fact] public void Add_ValidInput_ReturnsSum() { // Arrange var calculator = new Calculator(); int a = 5; int b = 10; // Act int result = calculator.Add(a, b); // Assert Assert.Equal(15, result); }

17. ¿Cuál es el propósito de la interfaz `IHttpClientFactory` en .NET Core?

La interfaz IHttpClientFactory en .NET Core proporciona una ubicación central para crear y configurar instancias de HttpClient. Aborda problemas comunes relacionados con la gestión de los ciclos de vida de HttpClient, como el agotamiento de los sockets debido a la eliminación incorrecta. En lugar de crear una nueva instancia de HttpClient cada vez que necesita hacer una solicitud HTTP, IHttpClientFactory gestiona un grupo de instancias de HttpClient, reutilizando las conexiones cuando es posible.

Los beneficios clave incluyen:

  • Configuración Centralizada: Permite configurar instancias de HttpClient con encabezados específicos, tiempos de espera y otras configuraciones en una única ubicación.
  • Gestión del Ciclo de Vida: Gestiona la creación y eliminación de instancias de HttpClient, previniendo el agotamiento de sockets.
  • Integración con Polly: Soporta el uso de Polly, una biblioteca de resiliencia y manejo de fallos transitorios, para agregar políticas de reintento, disyuntores y otros patrones de resiliencia a las solicitudes HTTP.
  • Testabilidad Mejorada: Simplifica las pruebas unitarias al permitir simular o sustituir la implementación de IHttpClientFactory.

18. ¿Cómo se puede publicar una aplicación .NET Core en diferentes plataformas?

Puede publicar una aplicación .NET Core en diferentes plataformas usando el comando dotnet publish. Este comando crea una implementación autocontenida o una implementación dependiente del framework.

Para publicar para una plataforma específica, especifique el Identificador de Tiempo de Ejecución (RID) usando la opción -r o --runtime. Por ejemplo, dotnet publish -c Release -r linux-x64 publica para Linux de 64 bits. Los RID comunes incluyen win-x64, linux-x64, osx-x64, etc. Puede encontrar una lista completa en la documentación de .NET. Para implementaciones autocontenidas (SCD), el tiempo de ejecución está incluido, haciéndola más grande pero independiente. Las implementaciones dependientes del framework (FDD) se basan en que el tiempo de ejecución de .NET esté instalado en el sistema de destino. El framework de destino se especifica en el archivo .csproj.

Ejemplo de modificación del archivo .csproj para apuntar a múltiples frameworks:

<TargetFrameworks>net6.0;net7.0</TargetFrameworks>

19. Describa el papel de las variables de entorno en una aplicación .NET Core.

Las variables de entorno en las aplicaciones .NET Core proporcionan una forma de configurar el comportamiento de la aplicación sin modificar el código en sí. Actúan como parámetros de configuración externos que se pueden establecer a nivel del sistema operativo o dentro del entorno de alojamiento de la aplicación (por ejemplo, Docker, Azure App Service). Esta separación de la configuración del código promueve la portabilidad y le permite adaptar fácilmente la aplicación a diferentes entornos (desarrollo, pruebas, producción) sin recompilación.

Se utilizan comúnmente para almacenar información confidencial como cadenas de conexión a bases de datos, claves de API o configuraciones de indicadores de funciones. En .NET Core, puede acceder a las variables de entorno utilizando System.Environment.GetEnvironmentVariable("VARIABLE_NAME"). La interfaz IConfiguration también se integra con las variables de entorno, por lo que se puede acceder a ellas de forma fuertemente tipada.

20. ¿Cómo implementa el almacenamiento en caché en .NET Core para mejorar el rendimiento?

En .NET Core, el almacenamiento en caché se puede implementar utilizando la interfaz IMemoryCache. Primero, inyecte IMemoryCache en su clase a través de la inyección de dependencias. Luego, use los métodos TryGetValue, Set y Remove para interactuar con la caché. Por ejemplo:

private readonly IMemoryCache _cache; public MyClass(IMemoryCache cache) { _cache = cache; } public string GetData(string key) { if (!_cache.TryGetValue(key, out string data)) { // Data not in cache, retrieve it data = RetrieveDataFromSource(key); // Set cache options var cacheEntryOptions = new MemoryCacheEntryOptions() .SetSlidingExpiration(TimeSpan.FromSeconds(30)); // Save data in cache _cache.Set(key, data, cacheEntryOptions); } return data; }

Alternativamente, podría usar el almacenamiento en caché distribuido usando Redis o SQL Server. Esto requiere agregar el paquete NuGet apropiado (por ejemplo, Microsoft.Extensions.Caching.StackExchangeRedis) y configurar el proveedor de caché en Startup.cs usando services.AddStackExchangeRedisCache() o services.AddDistributedSqlServerCache(). Luego, inyecte IDistributedCache en lugar de IMemoryCache.

Preguntas de entrevista de .NET Core para personas con experiencia

1. ¿Cómo maneja el recolector de basura de .NET Core los montones de objetos grandes y qué estrategias puede emplear para minimizar la fragmentación en estos montones?

El recolector de basura (GC) de .NET Core maneja los montones de objetos grandes (LOH) de manera diferente a los montones más pequeños. Los objetos mayores a aproximadamente 85,000 bytes se colocan en el LOH. El LOH no se compacta tan frecuentemente como los montones más pequeños debido al costo de rendimiento de mover objetos grandes. Esto puede provocar fragmentación, donde el espacio libre se dispersa por todo el montón, lo que dificulta la asignación de bloques contiguos para nuevos objetos grandes.

Para minimizar la fragmentación de LOH, puede emplear varias estrategias:

  • Reducir las asignaciones de objetos grandes: Siempre que sea posible, intente evitar asignar objetos extremadamente grandes en primer lugar. Considere usar objetos o flujos más pequeños.
  • Agrupación de objetos: Implemente la agrupación de objetos para objetos grandes de uso frecuente. Esto reutiliza los objetos existentes en lugar de asignar otros nuevos.
  • Eliminación explícita: Asegúrese de que los objetos grandes se eliminen explícitamente cuando ya no sean necesarios, lo que permite al recolector de basura (GC) reclamar la memoria antes. Use IDisposable para los recursos y las sentencias using o los bloques try...finally para una eliminación determinista.
  • Evitar el anclaje: Minimice el anclaje de objetos, ya que los objetos anclados no pueden ser movidos por el GC, lo que contribuye a la fragmentación. Si debe anclar, intente mantener la duración anclada lo más corta posible usando GC.AllocHandle y GCHandleType.Pinned.
  • Usar estructuras (tipos de valor): Si es apropiado, considere usar estructuras en lugar de clases para colecciones de datos si el tamaño de los datos lo permite y si el rendimiento de la copia es aceptable. Las estructuras se asignan en la pila o en línea dentro de otros objetos y, por lo tanto, evitan el LOH.
  • Preasignar búferes: Si conoce el tamaño de un objeto grande de antemano, pre-asigne un búfer para evitar reasignaciones y fragmentación que podrían ocurrir con el cambio de tamaño de los arreglos.
  • Considerar diferentes estructuras de datos: Explore estructuras de datos o algoritmos alternativos que puedan reducir la necesidad de grandes bloques de memoria contiguos.

2. Describe las diferencias entre `Task.Run` y `Task.Factory.StartNew` en .NET Core, enfocándose en su uso del grupo de subprocesos e implicaciones potenciales de rendimiento.

`Task.Run` y `Task.Factory.StartNew` se utilizan para operaciones asíncronas en .NET, pero difieren en su programador predeterminado y comportamiento del grupo de subprocesos. `Task.Run` es generalmente preferido, ya que es una abstracción de nivel superior diseñada específicamente para poner en cola el trabajo directamente en el grupo de subprocesos. Utiliza el `TaskScheduler.Default` predeterminado, que está respaldado por el grupo de subprocesos. `Task.Factory.StartNew`, por otro lado, ofrece más control. De forma predeterminada, también utiliza el grupo de subprocesos, pero le permite especificar un programador de tareas personalizado y configurar opciones como `TaskCreationOptions` (por ejemplo, `LongRunning`).

La diferencia clave con `Task.Factory.StartNew` es su flexibilidad. Puede, por ejemplo, usar `TaskCreationOptions.LongRunning` para indicar al programador que la tarea podría tomar un tiempo, lo que podría llevar a la creación de un nuevo subproceso fuera del grupo de subprocesos. Usar `Task.Run` es más simple y generalmente suficiente para la mayoría de las operaciones asíncronas basadas en el grupo de subprocesos, promoviendo una mejor gestión del grupo de subprocesos y rendimiento. Si necesita un control más preciso o necesita ejecutar tareas realmente de larga duración fuera del grupo de subprocesos para evitar la inanición, `Task.Factory.StartNew` se puede usar con precaución.

3. Explique el concepto de middleware en ASP.NET Core y cómo implementaría un middleware personalizado para manejar la autenticación o el registro de solicitudes.

En ASP.NET Core, los middleware son componentes que forman una tubería para manejar las solicitudes HTTP. Cada componente de middleware en la tubería puede inspeccionar y modificar la solicitud y la respuesta. Se ejecutan en el orden en que se agregan a la tubería en el método Configure del archivo Startup.cs.

Para implementar un middleware personalizado, crea una clase con un método InvokeAsync. Este método recibe el HttpContext y un RequestDelegate que representa el siguiente middleware en la tubería. Dentro de InvokeAsync, puedes realizar operaciones antes y después de llamar a await _next(context);. Por ejemplo, para el registro, registrarías los detalles de la solicitud antes de _next y los detalles de la respuesta después. Para la autenticación, verificarías los tokens de autenticación y establecerías el HttpContext.User en consecuencia. Aquí está el código de ejemplo:

public class RequestLoggingMiddleware { private readonly RequestDelegate _next; private readonly ILogger _logger; public RequestLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory) { _next = next; _logger = loggerFactory.CreateLogger<RequestLoggingMiddleware>(); } public async Task InvokeAsync(HttpContext context) { _logger.LogInformation($"Request: {context.Request.Method} {context.Request.Path}"); await _next(context); _logger.LogInformation($"Response: {context.Response.StatusCode}"); } } public static class RequestLoggingMiddlewareExtensions { public static IApplicationBuilder UseRequestLogging(this IApplicationBuilder builder) { return builder.UseMiddleware<RequestLoggingMiddleware>(); } } //En Startup.cs public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { app.UseRequestLogging(); // Otro middleware app.UseEndpoints(endpoints => { endpoints.MapControllers(); }); }

4. ¿Cómo puedes implementar estrategias de almacenamiento en caché eficientes en aplicaciones .NET Core, considerando tanto las opciones de almacenamiento en caché en memoria como distribuidas?

El almacenamiento en caché eficiente en .NET Core implica el aprovechamiento tanto del almacenamiento en caché en memoria como distribuido. Para el almacenamiento en caché en memoria, utiliza IMemoryCache. Puedes establecer políticas de caducidad (absoluta, deslizante) y prioridades. La inyección de dependencias facilita su uso. El almacenamiento en caché distribuido, ideal para entornos de múltiples servidores, se puede implementar utilizando Redis o SQL Server. Usa la interfaz IDistributedCache. La serialización (por ejemplo, JSON) es a menudo necesaria cuando se utiliza IDistributedCache porque los datos deben transferirse a través de la red.

Para elegir entre ellos: Si la aplicación se ejecuta en un solo servidor o si el almacenamiento en caché de datos pequeños y de acceso frecuente es suficiente, el almacenamiento en caché en memoria es una buena opción. Si la aplicación se ejecuta en múltiples servidores o si se necesita el almacenamiento en caché de grandes conjuntos de datos, el almacenamiento en caché distribuido es una mejor opción. Puedes usar ambos en conjunto. Por ejemplo, implementar un patrón Cache-Aside, donde verificas primero en memoria, luego distribuido y, finalmente, el origen.

5. Discute el papel de la inyección de dependencias en .NET Core y cómo promueve el acoplamiento débil y la capacidad de prueba en tus aplicaciones.

La Inyección de Dependencias (DI) en .NET Core es un patrón de diseño que te permite desarrollar aplicaciones con bajo acoplamiento y que se pueden probar. En lugar de que las clases creen sus dependencias, estas dependencias se 'inyectan' en la clase, generalmente a través de la inyección de constructor. .NET Core tiene soporte incorporado para DI a través de su contenedor de servicios (IServiceCollection).

DI promueve el acoplamiento débil porque las clases no tienen dependencias directas de implementaciones concretas; dependen de abstracciones (interfaces). Esto facilita el intercambio de implementaciones sin modificar la clase dependiente. Para la capacidad de prueba, DI le permite inyectar objetos simulados o dobles de prueba en las clases en prueba, aislando la unidad que se está probando y facilitando la verificación de su comportamiento de forma aislada. Por ejemplo, si una clase depende de una IUserRepository, puede inyectar un IUserRepository simulado durante las pruebas para controlar los datos devueltos y verificar las interacciones con el repositorio sin acceder a una base de datos real.

public class MyService { private readonly IRepository _repository; public MyService(IRepository repository) //Inyección de constructor { _repository = repository; } }

6. Explique cómo usar las comprobaciones de estado en ASP.NET Core para supervisar el estado de su aplicación y sus dependencias.

Las comprobaciones de estado de ASP.NET Core proporcionan una forma de supervisar el estado de su aplicación y sus dependencias (como bases de datos, servicios externos, etc.). Para usarlas, primero agregue el paquete Microsoft.AspNetCore.HealthChecks. Luego, en Startup.cs, configure las comprobaciones de estado en ConfigureServices usando services.AddHealthChecks(). Registre comprobaciones de estado individuales para las dependencias (por ejemplo, builder.AddSqlServer(...) para una base de datos SQL Server). Finalmente, en Configure, exponga el punto final de comprobación de estado usando app.UseEndpoints(endpoints => { endpoints.MapHealthChecks("/health"); });. Esto crea un punto final (por ejemplo, /health) que devuelve una respuesta JSON que indica el estado de salud de cada comprobación configurada. La respuesta indicará el estado Healthy (Sano), Degraded (Degradado) o Unhealthy (No sano).

Puede personalizar las comprobaciones de estado implementando la interfaz IHealthCheck. Esto le permite realizar una lógica personalizada para determinar el estado de una dependencia específica. El punto final de comprobación de estado también se puede personalizar con opciones, como especificar códigos de estado permitidos o usar un escritor de respuesta personalizado para cambiar el formato de la respuesta. Aquí hay un ejemplo de cómo agregar una comprobación de estado básica:

services.AddHealthChecks() .AddCheck("Example", () => HealthCheckResult.Healthy("¡La comprobación es correcta!"));

7. ¿Cuáles son los beneficios de usar Kestrel como servidor web en .NET Core, y cuándo podría elegir usar un proxy inverso como Nginx o IIS delante de él?

Kestrel es un servidor web multiplataforma para ASP.NET Core. Es ligero y está diseñado para el rendimiento. Los beneficios clave incluyen: ser multiplataforma, su velocidad inherente y su capacidad de ser utilizado como un servidor perimetral expuesto directamente a Internet en algunos escenarios.

Aunque Kestrel puede servir peticiones directamente, a menudo es beneficioso usar un proxy inverso como Nginx o IIS delante de él. Las razones para esto incluyen: Equilibrio de carga: Distribuir el tráfico entre múltiples instancias de Kestrel, Seguridad: Proporcionar una capa de defensa contra ataques (DDoS, etc.), Terminación SSL: Gestionar el cifrado/descifrado SSL para descargar a Kestrel, Servir archivos estáticos: Los proxies inversos son generalmente mejores para servir archivos estáticos, y Gestión centralizada: Gestionar el enrutamiento, el almacenamiento en caché y otras funciones del servidor web en un solo lugar. Normalmente se elegiría un proxy inverso en entornos de producción para aprovechar estas funciones.

8. Describe cómo manejarías los errores y las excepciones en una aplicación .NET Core, incluyendo el manejo global de excepciones y estrategias de registro.

En .NET Core, manejo los errores y las excepciones utilizando una combinación de bloques try-catch, middleware de manejo global de excepciones y registro. Para operaciones específicas que podrían fallar, envuelvo el código en bloques try-catch para manejar las excepciones con elegancia, como errores de conexión a la base de datos o problemas de acceso a archivos. Luego registro los detalles de la excepción usando un framework de registro como Serilog o NLog. Para el manejo global de excepciones, usaría middleware en la canalización de ASP.NET Core, este middleware captura cualquier excepción no manejada y las registra. Esto evita que la aplicación se bloquee y presenta un mensaje de error amigable para el usuario. La implementación se vería así:

public class ExceptionHandlingMiddleware { private readonly RequestDelegate _next; private readonly ILogger<ExceptionHandlingMiddleware> _logger; public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger) { _next = next; _logger = logger; } public async Task InvokeAsync(HttpContext httpContext) { try { await _next(httpContext); } catch (Exception ex) { _logger.LogError(ex, "Se produjo una excepción no controlada."); // Handle the exception and return an appropriate response. httpContext.Response.StatusCode = 500; // Or other appropriate status code await httpContext.Response.WriteAsync("Ocurrió un error. Por favor, inténtelo de nuevo más tarde."); } } }

Registro este middleware en Startup.cs así: app.UseMiddleware<ExceptionHandlingMiddleware>(); Esto asegura que todas las excepciones sean capturadas y manejadas eficazmente, y que la aplicación continúe funcionando.

9. ¿Cómo se puede proteger una API de .NET Core utilizando JWT (JSON Web Tokens), y cuáles son algunas de las mejores prácticas para almacenar y administrar tokens?

Para proteger una API de .NET Core con JWT, normalmente se utiliza un middleware como Microsoft.AspNetCore.Authentication.JwtBearer. Primero, configure la autenticación en Startup.cs para usar la autenticación JWT Bearer, especificando el emisor, la audiencia y la clave de firma. Luego, proteja sus endpoints de API agregando el atributo [Authorize] a los controladores o acciones. El cliente se autentica con nombre de usuario/contraseña y si es válido la API devuelve un JWT. El cliente luego incluye este JWT en el encabezado Authorization de las solicitudes subsiguientes utilizando el esquema Bearer. La API valida este token para cada solicitud. Aquí hay un ejemplo de cómo se usaría la autorización.

[Authorize] [ApiController] [Route("[controller]")] public class MyController : ControllerBase { [HttpGet] public IActionResult Get() { return Ok("¡Autorizado!"); } }

Las mejores prácticas para almacenar JWTs incluyen:

  • Nunca almacene JWTs en el almacenamiento local o cookies. Estos son vulnerables a ataques XSS.
  • Utilice cookies HTTP-only: Almacene los JWTs en cookies HTTP-only con un tiempo de expiración corto. Esto mitiga los riesgos de XSS.
  • Tokens de actualización: Implemente tokens de actualización para obtener nuevos tokens de acceso sin requerir que el usuario se reautentique con frecuencia. Almacene los tokens de actualización de forma segura en la base de datos y rótelos regularmente.
  • Revocación de tokens: Proporcione un mecanismo para revocar tokens, como invalidar el token al cerrar sesión o restablecer la contraseña.
  • Considere el patrón BFF (Backend For Frontend): Use un servicio backend seguro como proxy para manejar la autenticación y autorización en nombre del frontend.

10. Explique el concepto de programación asíncrona en .NET Core usando async y await, y cómo mejora la capacidad de respuesta de sus aplicaciones.

La programación asíncrona en .NET Core con async y await le permite realizar operaciones sin bloquear el subproceso principal. La palabra clave async marca un método como asíncrono, permitiendo el uso de la palabra clave await dentro de él. Cuando se encuentra await, la ejecución del método se suspende hasta que la tarea esperada se completa, devolviendo el control al que llama. Fundamentalmente, el subproceso no está bloqueado; es libre de manejar otras tareas.

Este enfoque mejora significativamente la capacidad de respuesta de la aplicación. En las aplicaciones de interfaz de usuario, evita que la interfaz de usuario se congele durante operaciones de larga duración (como solicitudes de red o E/S de archivos). En las aplicaciones del lado del servidor, permite que el servidor maneje más solicitudes concurrentes, ya que los subprocesos no están atados esperando que se completen las operaciones de E/S. En cambio, se liberan para atender otras solicitudes. Ejemplo: public async Task<string> DownloadDataAsync(string url) { using (HttpClient client = new HttpClient()) { return await client.GetStringAsync(url); } }

11. Discuta las ventajas de usar gRPC sobre las API REST en .NET Core, considerando factores como el rendimiento, la eficiencia y la generación de código.

gRPC ofrece varias ventajas sobre las API REST en .NET Core, principalmente en rendimiento y eficiencia. gRPC utiliza Protocol Buffers como su lenguaje de definición de interfaz y formato de mensaje. Esto resulta en tamaños de mensaje más pequeños y una serialización/deserialización más rápida en comparación con JSON utilizado por REST. gRPC aprovecha HTTP/2, lo que permite funciones como la transmisión bidireccional, la compresión de encabezados y la multiplexación a través de una única conexión TCP, lo que mejora aún más el rendimiento.

Otra ventaja significativa es la generación de código. gRPC utiliza Protocol Buffers para definir el contrato del servicio, y las herramientas generan automáticamente stubs de cliente y servidor en varios idiomas, incluido C# para .NET Core. Esto reduce el código repetitivo, mejora la seguridad de tipos y simplifica el desarrollo. Por el contrario, las API REST a menudo requieren la creación manual de bibliotecas de clientes o la dependencia de la serialización basada en la reflexión, lo que puede ser menos eficiente y propenso a errores. Aquí hay un ejemplo simple que demuestra una definición proto:

sintaxis = "proto3"; servicio Greeter { rpc SayHello (HelloRequest) returns (HelloReply) {} } mensaje HelloRequest { cadena nombre = 1; } mensaje HelloReply { cadena mensaje = 1; }

12. ¿Cómo implementaría una cola de mensajes utilizando .NET Core y cuáles son algunas tecnologías de cola de mensajes populares que podría considerar (por ejemplo, RabbitMQ, Kafka)?

Para implementar una cola de mensajes en .NET Core, podría usar una cola en memoria (útil para escenarios más simples) o integrarse con un agente de mensajes dedicado. Para el enfoque en memoria, normalmente usaría una ConcurrentQueue<T> para manejar el almacenamiento de mensajes e implementar patrones de productor/consumidor utilizando hilos o tareas para encolar y desencolar mensajes de forma asíncrona.

Para soluciones más robustas, las tecnologías de cola de mensajes populares incluyen:

  • RabbitMQ: Un agente de mensajes de código abierto ampliamente utilizado que admite varios protocolos de mensajería como AMQP.
  • Kafka: Una plataforma de transmisión distribuida adecuada para tuberías de datos de alto rendimiento y transmisión de eventos.
  • Azure Service Bus: Un servicio de mensajería basado en la nube ofrecido por Microsoft Azure.
  • Amazon SQS (Simple Queue Service): Un servicio de cola de mensajes totalmente administrado de AWS.

La elección depende de factores como las necesidades de escalabilidad, el volumen de mensajes, las funciones requeridas (por ejemplo, enrutamiento de mensajes, persistencia) y la infraestructura existente. Bibliotecas como RabbitMQ.Client para RabbitMQ o Confluent.Kafka para Kafka simplifican la integración dentro de una aplicación .NET Core. Ejemplo usando RabbitMQ:

//Publicando un mensaje using RabbitMQ.Client; using System.Text; var factory = new ConnectionFactory() { HostName = "localhost" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare(queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null); string message = "¡Hola Mundo!"; var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "", routingKey: "hello", basicProperties: null, body: body); Console.WriteLine(" [x] Enviado {0}", message); }

13. Explique cómo usar la CLI de .NET Core para construir, probar e implementar sus aplicaciones, y ¿cuáles son algunos comandos comunes de la CLI que usa?

La CLI de .NET Core es una herramienta poderosa para construir, probar e implementar aplicaciones .NET. Para construir, se usa dotnet build, que compila el código y produce los ensamblados de salida. Para probar, dotnet test descubre y ejecuta las pruebas definidas en su proyecto. La implementación implica crear una implementación autocontenida o dependiente del framework usando dotnet publish. Este comando empaqueta la aplicación y sus dependencias para la distribución.

Algunos comandos CLI comunes que uso con frecuencia incluyen:

  • dotnet new: Crea un nuevo proyecto o solución .NET.
  • dotnet restore: Restaura las dependencias especificadas en el archivo del proyecto.
  • dotnet run: Ejecuta la aplicación directamente desde el código fuente.
  • dotnet add package: Agrega un paquete NuGet al proyecto.
  • dotnet ef migrations add: Agrega una nueva migración para Entity Framework Core.
  • dotnet ef database update: Actualiza la base de datos a la última migración.

El uso de la CLI ofrece flexibilidad y permite la automatización a través de secuencias de comandos, lo que la hace ideal para las canalizaciones de CI/CD.

14. Describe los diferentes modelos de alojamiento disponibles en ASP.NET Core (por ejemplo, InProcess, OutOfProcess) y sus implicaciones en el rendimiento y la implementación.

ASP.NET Core ofrece dos modelos de alojamiento principales: InProcess y OutOfProcess.

  • InProcess (IIS): La aplicación ASP.NET Core se ejecuta dentro del mismo proceso que el proceso de trabajo de IIS (w3wp.exe o iisexpress.exe). Esto ofrece importantes beneficios de rendimiento porque las solicitudes no necesitan ser enviadas a través de un proxy a un proceso separado. La implementación es más sencilla, ya que IIS gestiona directamente la aplicación.
  • OutOfProcess (Kestrel): La aplicación ASP.NET Core se ejecuta en un proceso separado, normalmente utilizando el servidor Kestrel. IIS (u otro proxy inverso como Nginx o Apache) actúa como un proxy inverso, reenviando las solicitudes a Kestrel. Este modelo proporciona un mayor aislamiento y flexibilidad, lo que le permite actualizar o reiniciar la aplicación sin afectar a IIS. El rendimiento es generalmente ligeramente inferior debido a la sobrecarga del proxy inverso. Esto también incluye el alojamiento propio donde Kestrel actúa como el servidor web de borde/público.

15. ¿Cómo se optimiza el rendimiento en las aplicaciones .NET Core, específicamente en lo que respecta a la asignación de memoria y el uso de la CPU?

Para optimizar las aplicaciones .NET Core, especialmente en lo que respecta a la asignación de memoria y el uso de la CPU, considere varias estrategias. Para la asignación de memoria, minimice la creación de objetos, especialmente en las rutas de código ejecutadas con frecuencia. Utilice la agrupación de objetos para objetos reutilizables, aproveche las estructuras para estructuras de datos de tipo valor pequeñas para evitar asignaciones de montón y considere el uso de Span<T> y Memory<T> para trabajar directamente con regiones de memoria, minimizando las copias. Profile su aplicación con herramientas como el Monitor de rendimiento de .NET para identificar fugas de memoria y asignaciones excesivas.

Para el uso de la CPU, optimice algoritmos y estructuras de datos para la eficiencia. Utilice programación asíncrona (async/await) para evitar bloquear el hilo principal, mejore la concurrencia con la clase Parallel o ThreadPool. Reduzca la contención de bloqueos usando bloqueo más fino o estructuras de datos sin bloqueos. Emplee estrategias de almacenamiento en caché para evitar cálculos redundantes. Perfile su aplicación con herramientas como PerfView o dotnet-trace para identificar cuellos de botella y puntos calientes de la CPU. Asegúrese de un uso eficiente de LINQ; evite iteraciones y asignaciones innecesarias. Por ejemplo, prefiera .ToArray() o .ToList() para ejecutar consultas inmediatamente cuando utilice los resultados varias veces.

16. ¿Cuáles son las diversas formas de configurar una aplicación .NET Core y cómo se gestionan las configuraciones específicas del entorno?

La configuración en .NET Core es flexible y se puede lograr a través de varios proveedores. Los métodos comunes incluyen:

  • appsettings.json: El archivo de configuración principal para almacenar la configuración general.
  • appsettings.{Environment}.json: Configuración específica del entorno, como appsettings.Development.json o appsettings.Production.json, que anulan el appsettings.json base en el entorno respectivo. La variable de entorno ASPNETCORE_ENVIRONMENT determina qué archivo específico del entorno se carga.
  • Variables de entorno: Pueden anular la configuración de appsettings.json y, a menudo, se utilizan para información confidencial o configuración que varía en gran medida entre las implementaciones.
  • Argumentos de la línea de comandos: Pueden anular la configuración, útil para configuraciones únicas o para pasar valores específicos durante el inicio de la aplicación.
  • Secretos de usuario: Se utilizan solo en desarrollo para almacenar información confidencial, evitando que se envíe al control de código fuente.
  • Azure Key Vault: Puede recuperar la configuración directamente desde Azure Key Vault en entornos de Azure, incluidos los secretos.

Las configuraciones específicas del entorno se gestionan mediante la convención de nomenclatura (appsettings.{Environment}.json) y aprovechando la variable de entorno ASPNETCORE_ENVIRONMENT. El tiempo de ejecución de .NET carga automáticamente el archivo de configuración apropiado basándose en esta variable. Podemos acceder a los valores de configuración utilizando la interfaz IConfiguration. Por ejemplo, Configuration["SettingName"] o a través de clases de opciones fuertemente tipadas configuradas mediante services.Configure<MyOptions>(Configuration.GetSection("MyOptions")).

17. ¿Cómo maneja el tiempo de ejecución de .NET Core la compatibilidad multiplataforma, y cuáles son algunos de los posibles desafíos al desplegar en diferentes sistemas operativos?

.NET Core logra la compatibilidad multiplataforma principalmente a través de .NET Runtime implementando la Biblioteca .NET Standard y construyendo implementaciones específicas de la plataforma. .NET Standard define un conjunto consistente de APIs que se pueden usar en diferentes implementaciones de .NET (como .NET Framework, .NET Core y Xamarin). Cuando construyes una aplicación .NET Core, esta apunta a una versión específica de .NET Standard o a una plataforma específica (como net6.0-windows). El .NET Runtime contiene los componentes para la recolección de basura, la compilación JIT y las bibliotecas de clases base y proporciona los servicios necesarios para ejecutar la aplicación.

Los desafíos potenciales al implementar en diferentes sistemas operativos incluyen: dependencias específicas de la plataforma (por ejemplo, bibliotecas solo para Windows), diferencias en las rutas del sistema de archivos (por ejemplo, / vs \), diferentes llamadas al sistema y la necesidad de instalar el .NET Runtime apropiado en la máquina de destino. También es posible que deba considerar diferentes arquitecturas (x86, x64, ARM). La resolución de dependencias nativas a menudo implica la compilación condicional o paquetes NuGet específicos de la plataforma. La utilización de la contenedorización (como Docker) puede aliviar las inconsistencias de implementación.

18. ¿Qué son Span<T> y Memory<T> en .NET Core, y qué problemas resuelven al tratar con la gestión de memoria y el procesamiento de datos?

Span y Memory son estructuras de tipo valor introducidas en .NET Core para proporcionar una forma segura y eficiente de trabajar con regiones contiguas de memoria. Span es una estructura similar a ref que representa una región contigua de memoria arbitraria, mientras que Memory es una estructura que puede envolver tanto memoria administrada como no administrada. Ayudan a evitar asignaciones y copias de memoria innecesarias al trabajar con matrices, cadenas y otras estructuras de datos.

Estos tipos abordan problemas como:

  • Rendimiento: Permiten el acceso directo a la memoria sin la sobrecarga de crear nuevas matrices o cadenas.
  • Asignación de memoria: Reducen la necesidad de asignaciones de memoria frecuentes y la recolección de basura, lo que conduce a un mejor rendimiento.
  • Seguridad: Hacen cumplir la comprobación de límites y evitan la corrupción de la memoria mediante el uso de la semántica ref y restricciones sobre cómo se pueden usar.
  • Flexibilidad: Pueden representar diferentes fuentes de memoria, incluidas matrices, cadenas y memoria no administrada, lo que permite un enfoque unificado para la manipulación de la memoria. Por ejemplo:

ReadOnlySpan<byte> bytes = new byte[] { 1, 2, 3, 4, 5 }; ReadOnlySpan<byte> slice = bytes.Slice(1, 3); // slice ahora representa {2, 3, 4} sin copiar los datos subyacentes

19. Describa el papel de los marcos de registro (por ejemplo, Serilog, NLog) en .NET Core y cómo configuraría el registro estructurado en sus aplicaciones.

Los marcos de registro como Serilog y NLog proporcionan una forma estandarizada y configurable de registrar eventos e información de diagnóstico en las aplicaciones .NET Core. Ofrecen características como:

  • Registro estructurado: Registro de datos como pares clave-valor en lugar de texto sin formato, lo que facilita la consulta y el análisis de los registros.
  • Múltiples sumideros: Escritura de registros en varios destinos (consola, archivo, base de datos, servicios en la nube).
  • Niveles de registro: Asignación de niveles de gravedad (por ejemplo, Depuración, Información, Advertencia, Error, Fatal) para controlar qué eventos se registran.
  • Extensibilidad: Permitiendo formateadores, filtros y sumideros personalizados.

Para configurar el registro estructurado, normalmente instalaría los paquetes NuGet relevantes (por ejemplo, Serilog.AspNetCore, Serilog.Sinks.Console). Luego, en Program.cs o Startup.cs, configuraría el registrador, especificando los sumideros, el nivel mínimo de registro y las plantillas de salida. Por ejemplo, con Serilog:

Log.Logger = new LoggerConfiguration() .MinimumLevel.Information() .WriteTo.Console(outputTemplate: "{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} [{Level:u3}] {Message:lj}{NewLine}{Exception}") .WriteTo.File("log.txt", rollingInterval: RollingInterval.Day) .CreateLogger(); builder.Host.UseSerilog();

Esto configura Serilog para registrar en la consola y un archivo, utilizando una plantilla de salida especificada para el registro estructurado y archivos rotativos diarios.

20. ¿Cómo implementa las pruebas unitarias y las pruebas de integración en .NET Core, y qué marcos de pruebas prefiere (por ejemplo, xUnit, NUnit)?

En .NET Core, las pruebas unitarias típicamente implican el uso de un marco de pruebas como xUnit o NUnit junto con una biblioteca de simulación como Moq. Escribiría pruebas para verificar métodos o clases individuales de forma aislada. Por ejemplo, usando xUnit, instalaría los paquetes NuGet xunit y xunit.runner.visualstudio. Una prueba se vería algo así:

[Fact] public void MyMethod_ShouldReturnTrue() { // Arrange var myObject = new MyClass(); // Act bool result = myObject.MyMethod(); // Assert Assert.True(result); }

Las pruebas de integración verifican la interacción entre diferentes partes de la aplicación o sistemas externos. También pueden usar xUnit o NUnit. Sin embargo, en lugar de simular dependencias externas, normalmente se trabaja con los componentes reales o una base de datos de prueba. Generalmente prefiero xUnit por su simplicidad y enfoque en los hechos en lugar de las teorías, pero NUnit también es una opción viable que ofrece más características de forma predeterminada. Ambos están bien soportados en el ecosistema .NET Core.

21. Explique el concepto de las API mínimas en .NET 6+ y cómo difieren de las API tradicionales basadas en controladores.

Las API mínimas en .NET 6+ ofrecen un enfoque optimizado para construir API HTTP con menos código repetitivo en comparación con las API tradicionales basadas en controladores. En lugar de definir controladores y acciones, se mapean directamente las rutas a funciones de manejo dentro del archivo Program.cs (o una configuración similar). Esto resulta en una estructura de código más concisa y enfocada, especialmente adecuada para API más pequeñas o microservicios.

Las diferencias clave residen en:

  • Volumen de código: Las API mínimas reducen significativamente la cantidad de código requerido.

  • Estructura: Eliminan la necesidad de clases de controlador separadas, integrando el manejo de rutas directamente en el inicio de la aplicación.

  • Flexibilidad: Ambos enfoques ofrecen flexibilidad, pero las API mínimas pueden ser más rápidas para escenarios simples, mientras que los controladores brindan una mejor estructura para proyectos más grandes y complejos. Aquí hay un ejemplo de una ruta de API mínima:

app.MapGet("/hello", () => "¡Hola Mundo!");

22. Describa cómo implementaría tareas en segundo plano en una aplicación .NET Core, considerando opciones como IHostedService y Hangfire.

Para implementar tareas en segundo plano en una aplicación .NET Core, consideraría algunas opciones. IHostedService es un enfoque ligero adecuado para tareas simples en proceso. Crearía una clase que implemente IHostedService y la registraría en el método ConfigureServices de Startup.cs. El método StartAsync contendría la lógica para iniciar el proceso en segundo plano (por ejemplo, usando Task.Run o un Timer), y StopAsync manejaría el apagado correcto. Para escenarios más complejos o tareas que requieran persistencia y confiabilidad, optaría por Hangfire. Proporciona características como la programación de trabajos, mecanismos de reintento y un panel para el monitoreo. Implementarlo implica instalar el paquete NuGet de Hangfire, configurar el almacenamiento (por ejemplo, SQL Server) y luego programar trabajos usando BackgroundJob.Enqueue o RecurringJob.AddOrUpdate. Hangfire se encarga de la ejecución y persistencia de estos trabajos fuera del proceso.

23. ¿Cómo puedes usar la reflexión en .NET Core para inspeccionar y manipular dinámicamente tipos y miembros en tiempo de ejecución?

La reflexión en .NET Core te permite examinar y modificar tipos, propiedades, métodos, eventos y otros miembros en tiempo de ejecución. Puedes usar el espacio de nombres System.Reflection para cargar ensamblados, descubrir tipos dentro de ellos y luego crear instancias de esos tipos. Por ejemplo, Assembly.LoadFrom("MiEnsamblado.dll") carga un ensamblado. Luego, assembly.GetType("MiNombreDeEspacio.MiClase") recupera un tipo específico. Activator.CreateInstance(type) crea una instancia de la clase. Luego puedes usar type.GetMethod("MiMetodo") para obtener un método, y method.Invoke(instance, null) para invocarlo.

La reflexión es útil para escenarios como arquitecturas de plugins, mapeadores objeto-relacional (ORMs), contenedores de inyección de dependencias y generación dinámica de código. Debe usarse con prudencia ya que puede afectar el rendimiento debido a la sobrecarga de la resolución de tipos en tiempo de ejecución y también reduce la seguridad de tipos en tiempo de compilación. Usa los BindingFlags apropiados en los métodos Get (por ejemplo, GetMethods, GetProperties, GetFields) para filtrar según la accesibilidad (pública, privada, etc.) y los miembros de instancia vs. estáticos. Por ejemplo:

Type myType = typeof(MiClase); PropertyInfo myProperty = myType.GetProperty("MiPropiedad", BindingFlags.Public | BindingFlags.Instance);

24. Discute las diversas opciones para desplegar aplicaciones .NET Core en plataformas en la nube como Azure y AWS.

Para implementar aplicaciones .NET Core en plataformas en la nube como Azure y AWS, existen varias opciones. Azure ofrece opciones como Azure App Service (Plataforma como Servicio, PaaS), Azure Kubernetes Service (AKS) para la orquestación de contenedores, Azure Virtual Machines (Infraestructura como Servicio, IaaS) y Azure Functions (sin servidor). Cada opción proporciona un nivel diferente de control y responsabilidad de gestión. Del mismo modo, AWS proporciona Elastic Beanstalk (PaaS), Elastic Container Service (ECS) y Elastic Kubernetes Service (EKS) para la contenerización, instancias EC2 (IaaS) y AWS Lambda (sin servidor).

La elección depende de factores como la complejidad de la aplicación, las necesidades de escalabilidad, el nivel de control deseado y las consideraciones de costos. Las soluciones PaaS como App Service y Elastic Beanstalk son más fáciles de gestionar, pero ofrecen menos control, mientras que las soluciones IaaS como las VM y EC2 proporcionan control total, pero requieren más gastos de gestión. La contenerización a través de ECS, EKS o AKS permite la portabilidad y la escalabilidad. Las funciones sin servidor (Azure Functions o AWS Lambda) son adecuadas para aplicaciones basadas en eventos. Considere también factores como la integración CI/CD con servicios como Azure DevOps o AWS CodePipeline para implementaciones automatizadas.

25. ¿Cómo implementaría un patrón CQRS (Separación de Responsabilidad de Comandos y Consultas) en una aplicación .NET Core?

Implementar CQRS en una aplicación .NET Core implica separar las operaciones de lectura (consulta) y escritura (comando) en modelos distintos. Primero, defina interfaces y clases separadas para comandos (por ejemplo, CreateProductCommand, UpdateProductCommand) y consultas (por ejemplo, GetProductByIdQuery, GetAllProductsQuery). Estos comandos y consultas deben encapsular los datos requeridos para sus respectivas operaciones. Luego, implemente manejadores de comandos para ejecutar comandos y manejadores de consultas para recuperar datos. La inyección de dependencias es crucial para registrar estos manejadores. Por ejemplo: services.AddScoped<ICommandHandler<CreateProductCommand>, CreateProductCommandHandler>(); y services.AddScoped<IQueryHandler<GetProductByIdQuery, Product>, GetProductByIdQueryHandler>();. Finalmente, use un patrón mediador (por ejemplo, usando la biblioteca MediatR) para enrutar comandos y consultas a sus manejadores correspondientes. Esto permite desacoplar las capas de la aplicación. El acceso a datos para lecturas puede optimizarse para consultas, potencialmente utilizando una réplica de base de datos de solo lectura o una estructura de datos desnormalizada. Las escrituras deben enfocarse en mantener la integridad y la consistencia de los datos en el almacén de datos primario. Esta separación permite el escalado y la optimización independientes de las operaciones de lectura y escritura.

Ejemplo usando MediatR:

public class CreateProductCommand : IRequest<Guid> { public string Name { get; set; } public decimal Price { get; set; } } public class CreateProductCommandHandler : IRequestHandler<CreateProductCommand, Guid> { private readonly IProductRepository _productRepository; public CreateProductCommandHandler(IProductRepository productRepository) { _productRepository = productRepository; } public async Task<Guid> Handle(CreateProductCommand request, CancellationToken cancellationToken) { var product = new Product { Id = Guid.NewGuid(), Name = request.Name, Price = request.Price }; await _productRepository.AddAsync(product); return product.Id; } }

26. Explique el propósito del método ConfigureAwait(false) en código asíncrono de .NET Core.

ConfigureAwait(false) instruye al operador await a evitar intentar devolver la continuación al contexto de sincronización original o al programador de tareas. Esto es crucial en bibliotecas o aplicaciones que no son de interfaz de usuario para prevenir interbloqueos o cuellos de botella de rendimiento. Al usar ConfigureAwait(false), el código después de await se ejecutará en un hilo del grupo de hilos, en lugar de intentar reanudar en el contexto original (como un hilo de interfaz de usuario). Esto evita posibles interbloqueos donde el hilo de la interfaz de usuario está esperando a que la operación asíncrona se complete, mientras que la operación asíncrona está tratando de publicar de nuevo en el hilo de la interfaz de usuario.

En esencia, ConfigureAwait(false) mejora el rendimiento y evita bloqueos al desacoplar la continuación del contexto capturado. Por ejemplo:

await DoSomethingAsync().ConfigureAwait(false); // El código aquí se ejecutará en un hilo del grupo de subprocesos.

27. Describe las diferencias entre autorización y autenticación en ASP.NET Core y cómo implementar políticas de autorización personalizadas.

La autenticación verifica quién es un usuario, mientras que la autorización determina qué se le permite hacer. La autenticación confirma la identidad del usuario (por ejemplo, a través de nombre de usuario/contraseña o OAuth), y la autorización luego usa esa identidad para decidir si el usuario tiene permiso para acceder a un recurso específico o realizar una determinada acción.

Las políticas de autorización personalizadas en ASP.NET Core se pueden implementar usando AuthorizationPolicyBuilder. Define los requisitos (por ejemplo, una reclamación específica, un rol) y los manejadores que evalúan si el usuario cumple con esos requisitos. Las políticas luego se pueden aplicar globalmente o a controladores/acciones específicos usando el atributo [Authorize]. Por ejemplo:

services.AddAuthorization(options => { options.AddPolicy("AdminOnly", policy => policy.RequireRole("Admin")); });

Y luego, [Authorize(Policy = "AdminOnly")].

28. ¿Cómo se gestionan las migraciones de datos en .NET Core usando Entity Framework Core?

Las migraciones de datos en .NET Core con Entity Framework Core se gestionan típicamente mediante las herramientas de línea de comandos dotnet ef migrations. Primero, asegúrese de tener instaladas las herramientas de Entity Framework Core: dotnet tool install --global dotnet-ef. Luego, cree una migración con dotnet ef migrations add MigrationName. Esto crea una nueva migración que contiene los cambios en su modelo de datos. La migración incluye los métodos Up() y Down() para aplicar y revertir los cambios, respectivamente.

Para aplicar la migración a su base de datos, use el comando dotnet ef database update. Este comando ejecuta cualquier migración pendiente. También puede especificar una migración de destino para aplicar hasta un punto específico. En producción, las migraciones se aplican a menudo durante el despliegue, asegurando que el esquema de la base de datos esté sincronizado con el modelo de datos de la aplicación. Podría considerar usar scripts idempotentes para cambios de esquema críticos para evitar problemas si se interrumpe una migración.

29. ¿Cuáles son los beneficios de usar generadores de código fuente en .NET Core, y cómo pueden mejorar el rendimiento y reducir el código repetitivo?

Los generadores de código fuente en .NET Core ofrecen varios beneficios. Permiten generar código en tiempo de compilación, lo que puede mejorar el rendimiento al trasladar ciertos cálculos del tiempo de ejecución al tiempo de compilación. Esto reduce la sobrecarga en tiempo de ejecución, lo que lleva a un inicio y ejecución de la aplicación más rápidos. Los generadores de código fuente también permiten analizar el código y generar código adicional basado en el análisis.

Reducen el código repetitivo al crear automáticamente segmentos de código repetitivos. Por ejemplo, puede generar código para implementar INotifyPropertyChanged o crear DTOs basados en esquemas de bases de datos. Esto reduce la cantidad de código que necesita escribir manualmente, mejorando la productividad del desarrollador y reduciendo el riesgo de errores. Esto también promueve bases de código más mantenibles y limpias. El uso de generadores de código fuente es mejor que la reflexión en tiempo de ejecución porque el código se genera en tiempo de compilación. Además, los generadores de código fuente pueden utilizar el análisis de código y Árboles de Sintaxis para obtener información sobre el código, que podría no estar disponible en tiempo de ejecución.

30. Explique cómo usar OpenTelemetry en .NET Core para el rastreo y monitoreo distribuido.

Para usar OpenTelemetry en .NET Core para el rastreo y monitoreo distribuido, normalmente instalará los paquetes NuGet necesarios como OpenTelemetry.Exporter.Jaeger, OpenTelemetry.Extensions.Hosting, OpenTelemetry.Instrumentation.AspNetCore y OpenTelemetry.Instrumentation.SqlClient. Luego, en su archivo Program.cs, configure los servicios OpenTelemetry. Esto implica agregar OpenTelemetry a la colección de servicios, configurar un proveedor de rastreo y configurar exportadores como Jaeger o Zipkin para enviar los datos de telemetría. Las bibliotecas de instrumentación recopilan automáticamente datos de bibliotecas como ASP.NET Core y SqlClient.

Por ejemplo:

builder.Services.AddOpenTelemetryTracing(tracerProviderBuilder => { tracerProviderBuilder .AddSource("MiAplicación") .AddAspNetCoreInstrumentation() .AddSqlClientInstrumentation() .AddJaegerExporter(); });

Después de la configuración, OpenTelemetry captura automáticamente rastreos, métricas y registros de su aplicación, proporcionando información sobre el flujo de solicitudes, el rendimiento y los errores. Recuerde configurar el punto final de su exportador para que apunte a su backend de rastreo.

.NET Core MCQ

Pregunta 1.

En .NET, ¿cuál es la diferencia clave entre usar async Task y async void como el tipo de retorno de un método asíncrono?

Opciones:

`async Task` permite que el llamador espere la finalización del método y maneje excepciones, mientras que `async void` no lo hace.

`async void` es más eficiente porque no crea un objeto `Task`.

Tanto `async Task` como `async void` pueden ser esperados por el llamador, pero `async void` es preferido para los manejadores de eventos de la interfaz de usuario.

`async Task` se usa para los manejadores de eventos, mientras que `async void` se usa para operaciones asíncronas regulares.

Pregunta 2.

En .NET, ¿cuál es la principal diferencia entre IEnumerable e IQueryable cuando se usan con LINQ?

Opciones:

`IEnumerable` ejecuta la consulta en el lado del servidor, mientras que `IQueryable` la ejecuta en el lado del cliente.

`IEnumerable` es adecuado para consultar datos en memoria, mientras que `IQueryable` está diseñado para consultar fuentes de datos como bases de datos donde la consulta se ejecuta en la fuente de datos.

`IEnumerable` admite la ejecución diferida, mientras que `IQueryable` se ejecuta inmediatamente.

No hay una diferencia significativa; son intercambiables.

Pregunta 3.

¿Cuál de las siguientes opciones describe mejor la relación entre la Inyección de Dependencias (DI) y la Inversión de Control (IoC) en .NET Core?

Opciones:

DI es un patrón de diseño donde los módulos de alto nivel no deben depender de los módulos de bajo nivel. Ambos deben depender de abstracciones, mientras que IoC es una forma específica de implementar DI.

IoC es un patrón de diseño donde los módulos de alto nivel no deben depender de los módulos de bajo nivel. Ambos deben depender de abstracciones, mientras que DI es una forma específica de implementar IoC.

DI e IoC son términos intercambiables que se refieren al mismo concepto.

DI es una técnica para crear objetos, mientras que IoC es una técnica para administrar el ciclo de vida de los objetos.

Pregunta 4.

En .NET, ¿cuál es la principal diferencia entre el método Dispose() (que implementa IDisposable) y el método Finalize() (destructor)?

  • A) El recolector de basura llama a Dispose(), mientras que el usuario llama explícitamente a Finalize().
  • B) Dispose() se utiliza para la limpieza determinista de recursos, mientras que Finalize() se utiliza para la limpieza no determinista y como último recurso.
  • C) Dispose() se llama automáticamente cuando un objeto sale del ámbito, mientras que Finalize() requiere una invocación explícita.
  • D) Dispose() se utiliza para liberar memoria, mientras que Finalize() se utiliza para liberar recursos no administrados.

Opciones:

`Dispose()` es llamado por el recolector de basura, mientras que `Finalize()` es llamado explícitamente por el usuario.

`Dispose()` se utiliza para la limpieza determinista de recursos, mientras que `Finalize()` se utiliza para la limpieza no determinista y como último recurso.

`Dispose()` se llama automáticamente cuando un objeto sale del ámbito, mientras que `Finalize()` requiere una invocación explícita.

`Dispose()` se utiliza para liberar memoria, mientras que `Finalize()` se utiliza para liberar recursos no administrados.

Pregunta 5.

¿Cuál es la principal diferencia entre los delegados Action y Func en .NET?

Opciones:

`Action` los delegados solo se pueden usar para operaciones asíncronas, mientras que los delegados `Func` son para operaciones síncronas.

Los delegados `Action` no devuelven un valor, mientras que los delegados `Func` deben devolver un valor.

Los delegados `Func` solo pueden aceptar un máximo de 4 parámetros de entrada, mientras que los delegados `Action` no tienen tal limitación.

Los delegados `Action` están diseñados específicamente para el manejo de eventos, mientras que los delegados `Func` son para referencias de métodos de propósito general.

Pregunta 6.

¿Cuál es la diferencia clave entre una clase abstracta y una interfaz en C#?

Opciones:

Una clase abstracta puede tener constructores, mientras que una interfaz no puede.

Una clase abstracta puede tener campos, mientras que una interfaz no puede.

Una interfaz puede proporcionar una implementación completa para sus miembros, mientras que una clase abstracta no puede.

Una clase abstracta admite herencia múltiple, mientras que una interfaz no.

Pregunta 7.

¿Cuál es la diferencia clave entre usar var, dynamic y object al declarar una variable en C#?

Opciones:

`var` le permite omitir la verificación de tipo en tiempo de compilación, mientras que `dynamic` y `object` exigen una verificación de tipo estricta.

`var` usa inferencia de tipo en tiempo de compilación, `dynamic` omite la verificación de tipo en tiempo de compilación y resuelve los tipos en tiempo de ejecución, y `object` es el tipo base para todos los tipos, lo que requiere conversión explícita.

`dynamic` usa inferencia de tipo en tiempo de compilación, `var` omite la verificación de tipo en tiempo de compilación y resuelve los tipos en tiempo de ejecución, y `object` infiere el tipo en tiempo de ejecución.

No hay ninguna diferencia; todos son intercambiables y se pueden usar en cualquier situación.

Pregunta 8.

¿Cuál es la diferencia clave entre usar Task.Run() y Task.Factory.StartNew() en .NET?

Opciones:

`Task.Run()` usa de forma predeterminada el grupo de subprocesos y `Task.Factory.StartNew()` requiere una configuración explícita del programador para el uso del grupo de subprocesos.

`Task.Run()` permite especificar un CancellationToken, mientras que `Task.Factory.StartNew()` no lo hace.

`Task.Run()` está diseñado para tareas de larga duración, mientras que `Task.Factory.StartNew()` está optimizado para operaciones de corta duración.

`Task.Factory.StartNew()` es un envoltorio más simple alrededor de `Task.Run()`, que ofrece menos opciones de configuración.

Pregunta 9.

¿Cuál es la diferencia clave entre usar FirstOrDefault() y SingleOrDefault() en consultas LINQ?

  • A) FirstOrDefault() devuelve el primer elemento o un valor predeterminado si la secuencia está vacía, mientras que SingleOrDefault() lanza una excepción si la secuencia está vacía.
  • B) FirstOrDefault() lanza una excepción si la secuencia contiene más de un elemento, mientras que SingleOrDefault() devuelve el primer elemento o un valor predeterminado si la secuencia está vacía o contiene solo un elemento.
  • C) FirstOrDefault() devuelve el primer elemento o un valor predeterminado si la secuencia está vacía, mientras que SingleOrDefault() devuelve el único elemento o un valor predeterminado si la secuencia está vacía, pero lanza una excepción si la secuencia contiene más de un elemento.
  • D) FirstOrDefault() y SingleOrDefault() son funcionalmente equivalentes y se pueden usar indistintamente en todos los escenarios.

Pregunta 10.

En C#, ¿cuál es la diferencia clave entre usar el operador == y el método .Equals() al comparar dos objetos?

Opciones:

El operador == compara las referencias de los objetos (direcciones de memoria) de forma predeterminada, mientras que .Equals() compara el contenido de los objetos.

El operador `==` compara el contenido de los objetos por defecto, mientras que `.Equals()` compara las referencias a los objetos (direcciones de memoria).

Tanto `==` como `.Equals()` siempre comparan las referencias a los objetos (direcciones de memoria).

Tanto `==` como `.Equals()` siempre comparan el contenido de los objetos.

Pregunta 11.

¿Cuál es la principal diferencia entre HttpClient y WebClient en .NET?

Opciones:

`HttpClient` es más antiguo y se considera obsoleto, mientras que `WebClient` es el enfoque recomendado para el desarrollo moderno de .NET.

`HttpClient` se basa en el modelo de programación asíncrona y permite un mejor control sobre el ciclo de vida de la solicitud/respuesta, mientras que `WebClient` es síncrono y ofrece una API más simple para escenarios básicos.

`WebClient` solo admite solicitudes GET, mientras que `HttpClient` admite todos los métodos HTTP.

`WebClient` maneja la autenticación automáticamente, mientras que `HttpClient` requiere una configuración de autenticación manual.

Pregunta 12.

En la programación asíncrona de .NET, ¿cuál es el principal beneficio de usar .ConfigureAwait(false)?

Opciones:

Fuerza a la operación asíncrona a ejecutarse en un hilo diferente del grupo de subprocesos.

Evita que la continuación intente volver a alinearse con el contexto de sincronización original.

Garantiza que la operación asíncrona siempre se ejecutará más rápido.

Asegura que cualquier excepción lanzada durante la operación asíncrona siempre se maneje.

Pregunta 13.

En ASP.NET Core, ¿cuál es la diferencia clave entre los atributos [Authorize] y [AllowAnonymous]?

Opciones:

`[Authorize]` requiere que un usuario esté autenticado, mientras que `[AllowAnonymous]` permite el acceso independientemente del estado de autenticación.

`[Authorize]` permite que todos los usuarios accedan a un recurso, mientras que `[AllowAnonymous]` restringe el acceso solo a los usuarios autenticados.

`[Authorize]` se utiliza para la autenticación, mientras que `[AllowAnonymous]` se utiliza para la autorización.

`[Authorize]` solo se puede aplicar globalmente, mientras que `[AllowAnonymous]` solo se puede aplicar a acciones específicas.

Pregunta 14.

En ASP.NET Core, ¿cuál es la diferencia clave entre usar IActionResult y ActionResult<T> como tipo de retorno para una acción de controlador?

Opciones:

`IActionResult` permite devolver cualquier tipo de resultado, mientras que `ActionResult<T>` proporciona comprobación en tiempo de compilación y enlace de modelo automático para el tipo especificado `T`.

`ActionResult<T>` se usa para operaciones asíncronas, mientras que `IActionResult` se usa para operaciones síncronas.

`IActionResult` se usa para devolver códigos de estado HTTP, mientras que `ActionResult<T>` se usa para devolver datos.

`IActionResult` es una clase base para `ActionResult<T>`, lo que significa que son funcionalmente equivalentes e intercambiables.

Pregunta 15.

En ASP.NET Core, ¿cuál es la principal diferencia entre IMemoryCache e IDistributedCache?

Opciones:

`IMemoryCache` es para almacenar datos en la memoria del servidor, mientras que `IDistributedCache` es para almacenar datos en una caché compartida (por ejemplo, Redis, SQL Server) accesible a través de múltiples servidores o procesos.

`IMemoryCache` admite la expiración de datos, mientras que `IDistributedCache` no.

`IMemoryCache` solo se usa para almacenar datos de sesión, mientras que `IDistributedCache` se usa para almacenar datos de perfil de usuario.

`IMemoryCache` sincroniza automáticamente los datos entre múltiples servidores, mientras que `IDistributedCache` requiere sincronización manual.

Pregunta 16.

En ASP.NET Core, ¿cuál es la principal diferencia entre usar services.AddTransient(), services.AddScoped() y services.AddSingleton() al registrar servicios en el método ConfigureServices?

Opciones:

`AddTransient()` crea una nueva instancia del servicio para cada solicitud y cada inyección, `AddScoped()` crea una nueva instancia para cada solicitud HTTP, y `AddSingleton()` crea una única instancia para la vida útil de la aplicación.

`AddTransient()` crea una única instancia para la vida útil de la aplicación, `AddScoped()` crea una nueva instancia para cada solicitud HTTP, y `AddSingleton()` crea una nueva instancia del servicio para cada solicitud y cada inyección.

`AddTransient()` crea una nueva instancia para cada transacción de base de datos, `AddScoped()` crea una nueva instancia para cada sesión de usuario, y `AddSingleton()` crea una única instancia para la clase actual.

`AddTransient()` se usa para servicios sin estado, `AddScoped()` se usa para servicios con estado, y `AddSingleton()` se usa para servicios que requieren acceso a la base de datos.

Pregunta 17.

¿Cuál es la principal diferencia entre usar las clases string y StringBuilder para la manipulación de cadenas en .NET, y cuándo preferiría una sobre la otra?

Opciones:

`string` es mutable, creando nuevos objetos para cada modificación, mientras que `StringBuilder` es inmutable, modificando el objeto existente en su lugar. Use `string` para modificaciones frecuentes.

`string` es inmutable, creando nuevos objetos para cada modificación, mientras que `StringBuilder` es mutable, modificando el objeto existente en su lugar. Use `StringBuilder` para modificaciones frecuentes.

`string` usa una cantidad fija de memoria, mientras que `StringBuilder` asigna memoria dinámicamente según sea necesario. Use `string` cuando no sepa el tamaño de la cadena de antemano.

`string` es seguro para subprocesos, mientras que `StringBuilder` no lo es. Use `StringBuilder` en aplicaciones multiproceso.

Pregunta 18.

¿Cuál es la principal diferencia entre usar ToList() y AsEnumerable() en LINQ?

Opciones:

`ToList()` ejecuta la consulta inmediatamente y almacena los resultados en una nueva lista en la memoria, mientras que `AsEnumerable()` solo cambia el tipo en tiempo de compilación a `IEnumerable<T>` sin ejecutar la consulta.

`AsEnumerable()` ejecuta la consulta inmediatamente y almacena los resultados en una nueva lista en memoria, mientras que `ToList()` difiere la ejecución hasta que la lista se utiliza realmente.

Tanto `ToList()` como `AsEnumerable()` ejecutan la consulta inmediatamente y almacenan los resultados en una nueva lista en memoria, pero `ToList()` es más eficiente.

Tanto `ToList()` como `AsEnumerable()` difieren la ejecución de la consulta, pero `AsEnumerable()` permite operaciones de consulta adicionales, mientras que `ToList()` finaliza el resultado.

Pregunta 19.

¿Cuál es la diferencia clave entre llamar a un método `async` y llamar a un método síncrono en .NET?

Opciones:

Un método `async` siempre se ejecuta en un nuevo hilo, mientras que un método síncrono siempre se ejecuta en el hilo principal.

Un método `async` permite que el hilo que llama continúe ejecutándose mientras la operación esperada está en curso, mientras que un método síncrono bloquea el hilo que llama hasta que la operación se completa.

Un método `async` no puede devolver un valor, mientras que un método síncrono siempre debe devolver un valor.

Un método `async` maneja automáticamente las excepciones, mientras que un método síncrono requiere bloques try-catch explícitos.

Pregunta 20.

¿Cuál es la diferencia clave entre usar `yield return` y `return` dentro de un método iterador en C#?

Opciones:

`return` permite devolver múltiples valores, mientras que `yield return` devuelve solo un valor.

`yield return` preserva el estado del método para la siguiente llamada, mientras que `return` sale completamente del método.

`return` solo se puede usar en métodos `async`, mientras que `yield return` no puede.

No hay una diferencia significativa; son intercambiables.

Pregunta 21.

En .NET, ¿cuál es la principal diferencia entre usar Thread y Task para operaciones asíncronas?

Opciones:

`Thread` es una abstracción de alto nivel sobre `Task` que simplifica la gestión de hilos.

`Task` representa una operación que puede o no ejecutarse en un hilo separado, mientras que `Thread` siempre crea y gestiona un nuevo hilo del sistema operativo.

`Thread` usa el grupo de hilos de forma predeterminada, mientras que `Task` requiere la creación manual de hilos.

`Task` es específico para operaciones enlazadas a la interfaz de usuario, mientras que `Thread` está diseñado para el procesamiento en segundo plano.

Pregunta 22.

¿Cuál es la diferencia clave entre un Semaphore y un Mutex en .NET?

Opciones:

Un `Semaphore` es una primitiva de sincronización ligera para bloqueos de corta duración, mientras que un `Mutex` está diseñado para bloqueos de larga duración.

Un `Semaphore` puede ser liberado por cualquier hilo, mientras que un `Mutex` solo puede ser liberado por el hilo que lo adquirió.

Un `Mutex` se utiliza para sincronizar el acceso a los recursos dentro de un único dominio de aplicación, mientras que un `Semaphore` se utiliza para sincronizar recursos entre múltiples dominios de aplicación.

Un `Semaphore` proporciona acceso exclusivo a un recurso, mientras que un `Mutex` permite que múltiples hilos accedan a un recurso simultáneamente hasta un límite especificado.

Pregunta 23.

¿Cuál es la diferencia clave entre un Delegate y un Event en C#?

Opciones:

Un `Delegate` es un puntero a función seguro para tipos, mientras que un `Event` es un mecanismo para que una clase u objeto notifique a otras clases u objetos cuando sucede algo de interés.

Un `Delegate` solo puede usarse con métodos estáticos, mientras que un `Event` solo puede usarse con métodos de instancia.

Un `Event` es un tipo especial de `Delegate` que puede ejecutar métodos directamente, mientras que un `Delegate` solo puede almacenar referencias de métodos.

Un `Delegate` se utiliza para operaciones asíncronas, mientras que un `Event` se utiliza para operaciones síncronas.

Pregunta 24.

En ASP.NET Core MVC, ¿cuál es la diferencia clave entre `ViewBag`, `ViewData` y `TempData` para pasar datos de un controlador a una vista?

Opciones:

`ViewBag` y `ViewData` son de tipado dinámico y persisten datos solo durante la solicitud actual, mientras que `TempData` es de tipado fuerte y persiste datos durante una solicitud subsiguiente.

`ViewBag` es de tipado dinámico y `ViewData` es un diccionario de objetos; ambos persisten datos solo durante la solicitud actual. `TempData` persiste datos durante una solicitud subsiguiente.

`ViewBag` y `ViewData` ambos usan el estado de sesión, mientras que `TempData` utiliza cookies para persistir datos.

`ViewBag` es de tipado fuerte, `ViewData` es de tipado dinámico y `TempData` es accesible a través de múltiples sesiones.

Pregunta 25.

¿Cuál es la principal diferencia entre usar una declaración `using` e implementar directamente la interfaz `IDisposable` en C#?

Opciones:

La declaración `using` llama automáticamente a `Dispose()` al final de su bloque, mientras que implementar `IDisposable` requiere llamar manualmente a `Dispose()`.

Implementar `IDisposable` maneja excepciones de referencia nula, lo cual la declaración `using` no puede manejar.

La declaración `using` solo se puede usar con flujos de archivos, mientras que `IDisposable` se puede implementar para cualquier recurso.

Implementar `IDisposable` garantiza la recolección de basura, mientras que la declaración `using` solo la sugiere.

¿Qué habilidades de .NET Core debería evaluar durante la fase de entrevista?

No se puede medir completamente la destreza de un candidato en .NET Core en una sola entrevista. Sin embargo, centrarse en algunas habilidades clave le dará una sólida comprensión de sus capacidades. Estas habilidades representan las competencias básicas necesarias para tener éxito en un puesto de .NET Core.

¿Qué habilidades de .NET Core debería evaluar durante la fase de entrevista?

Fundamentos de C#

Evalúe la competencia en C# con una prueba en línea. La prueba de C# de Adaface incluye preguntas sobre sintaxis, estructuras de datos y conceptos comunes de C#.

Para probar su comprensión de los fundamentos de C#, plantee una pregunta sobre la herencia.

Explique la diferencia entre clases abstractas e interfaces en C# y cuándo usaría una en lugar de la otra.

Busque una clara comprensión del propósito de cada construcción. El candidato debe explicar que una clase abstracta puede tener implementaciones de métodos y estado, mientras que una interfaz solo define un contrato.

ASP.NET Core

Mida las habilidades de los candidatos en ASP.NET Core con preguntas de opción múltiple (MCQ) específicas. Puede utilizar la prueba de ASP.NET de Adaface para filtrar a los candidatos en función de sus conocimientos de los conceptos de ASP.NET Core.

Para evaluar su comprensión de ASP.NET Core, pregunte sobre el middleware.

Describa qué es el middleware en ASP.NET Core y proporcione un ejemplo de un middleware personalizado que podría crear.

El candidato debe ser capaz de explicar que los componentes de middleware se encuentran en el pipeline de solicitudes HTTP. También deben ser capaces de dar un ejemplo plausible de middleware personalizado, como el registro o la autenticación.

Inyección de Dependencias .NET Core

Puede evaluar eficientemente la comprensión de un candidato sobre la ID (Inyección de Dependencias) utilizando una prueba de evaluación de habilidades. Si bien Adaface no tiene una prueba dedicada de ID de .NET Core, las preguntas relacionadas con los principios de ID podrían estar presentes en nuestra prueba de C#/.NET.

Una buena pregunta para hacer es sobre los beneficios de la ID.

¿Cuáles son los beneficios de usar la Inyección de Dependencias en las aplicaciones .NET Core?

El candidato debe mencionar una mejor capacidad de prueba, un acoplamiento suelto y una mayor capacidad de mantenimiento. También deben demostrar una comprensión de cómo la ID promueve los principios SOLID.

3 Consejos para usar preguntas de entrevista de .NET Core

Antes de comenzar a utilizar estas preguntas de entrevista de .NET Core, aquí hay algunos consejos para ayudarlo a maximizar su efectividad. Estos conocimientos lo ayudarán a refinar su enfoque y garantizar que obtenga el mayor valor de sus entrevistas.

1. Aproveche las evaluaciones de habilidades para una mejor selección de candidatos

Las evaluaciones de habilidades son herramientas invaluables para evaluar objetivamente la competencia de un candidato. Incorporarlas al principio de su proceso de contratación agiliza significativamente el proceso de selección, ayudándole a concentrarse en los candidatos con los conjuntos de habilidades más prometedores.

Para los roles de .NET Core, considere usar evaluaciones que evalúen C#, .NET y tecnologías relacionadas como Entity Framework o ASP.NET MVC. Adaface ofrece una gama de pruebas en línea de .NET, incluyendo una prueba en línea de .NET, una prueba en línea de C# y una prueba en línea de Entity Framework para evaluar estas habilidades.

Al usar estas evaluaciones de habilidades, puede identificar fácilmente las áreas donde los candidatos sobresalen o necesitan mejorar. Esto le permite adaptar las preguntas de la entrevista para enfocarse en fortalezas y debilidades específicas, lo que lleva a una conversación más perspicaz y productiva.

2. Delinear estratégicamente preguntas clave de la entrevista

El tiempo es esencial durante las entrevistas, así que concéntrese en hacer un conjunto seleccionado de preguntas de alto impacto. Compilar la combinación correcta de preguntas le ayuda a evaluar eficientemente a los candidatos en los aspectos más importantes del rol.

Considera complementar tus preguntas de .NET Core con preguntas sobre tecnologías relacionadas como SQL o frameworks front-end. Puede que nuestra página de preguntas de entrevista de C# sea útil, así como nuestra página de preguntas de entrevista de Javascript para explorar las habilidades relacionadas de los candidatos.

Al elegir estratégicamente tus preguntas de entrevista, podrás evaluar rápidamente la idoneidad de un candidato y tomar decisiones de contratación bien informadas. Esto maximiza el tiempo de tu entrevista y ayuda a evitar pasar por alto habilidades cruciales.

3. Domina el arte de hacer preguntas de seguimiento

Simplemente hacer preguntas de entrevista no siempre es suficiente para descubrir las verdaderas habilidades de un candidato. Hacer las preguntas de seguimiento correctas es crucial para validar sus conocimientos y comprender la profundidad de su experiencia.

Por ejemplo, si un candidato explica el concepto de inyección de dependencias, una pregunta de seguimiento podría ser: "¿Puedes describir un escenario en el que el uso de la inyección de dependencias mejoraría significativamente el mantenimiento de una aplicación .NET Core?" Esto va más allá del conocimiento teórico y revela habilidades de aplicación práctica y la profundidad del candidato.

Evalúa a los candidatos de .NET con precisión: pruebas de habilidades y preguntas de entrevista específicas

¿Busca contratar a los mejores talentos de .NET? Asegurarse de que los candidatos posean las habilidades necesarias es primordial. La forma más efectiva de medir con precisión sus habilidades es a través de pruebas de habilidades dedicadas. Explore la gama de evaluaciones de .NET de Adaface, incluida nuestra Prueba en línea de .NET y Prueba en línea de C#, para identificar a los candidatos con experiencia comprobada.

Una vez que haya identificado a los solicitantes prometedores mediante pruebas de habilidades, agilice su proceso de contratación centrándose en las personas más cualificadas. Preseleccione a los mejores y invítelos a entrevistas específicas. ¿Listo para empezar? Regístrese y transforme su contratación de .NET hoy mismo.

Prueba en línea de .NET

40 minutos | 10 preguntas de opción múltiple y 1 pregunta de codificación

La prueba en línea de Dot Net utiliza preguntas de opción múltiple basadas en escenarios para evaluar a los candidatos en su dominio del trabajo con las tecnologías de Microsoft .NET, incluyendo el framework .NET, C# y ASP.NET. La prueba evalúa la capacidad de los candidatos para escribir código .NET, crear y administrar proyectos .NET, utilizar bibliotecas y frameworks .NET, y desarrollar aplicaciones web utilizando ASP.NET.

[

Realizar la prueba en línea de .NET

](https://www.adaface.com/assessment-test/dot-net-online-test)

Descargue la plantilla de preguntas de entrevista de .NET Core en múltiples formatos

Descarga la plantilla de preguntas para entrevistas de .NET Core en formato PNG, PDF y TXT

Las preguntas comunes para los recién graduados podrían cubrir conceptos básicos como el framework .NET Core, la sintaxis de C# y los principios de la programación orientada a objetos.

Para los desarrolladores experimentados, concéntrese en preguntas relacionadas con los patrones de arquitectura, la optimización del rendimiento, la inyección de dependencias y su experiencia con varias bibliotecas y herramientas de .NET Core.

Las áreas clave incluyen la comprensión de ASP.NET Core, Entity Framework Core, la inyección de dependencias, el middleware y la experiencia con estrategias de prueba e implementación.

Algunos consejos son usar una combinación de preguntas teóricas y prácticas, hacer que los candidatos escriban código y preguntar sobre su experiencia con proyectos del mundo real.

Las pruebas de habilidades proporcionan una forma estandarizada de evaluar las habilidades de codificación y resolución de problemas de un candidato, lo que le ayuda a comparar objetivamente a los candidatos e identificar a los mejores talentos.