2.2 Creación del Proyecto en Visual Studio

Configura Visual Studio paso a paso para desarrollo de plugins

Con las herramientas instaladas, es hora de crear tu primer proyecto de plugins. Un proyecto bien configurado desde el principio te ahorrará dolores de cabeza cuando empieces a desarrollar y desplegar. Te guío paso a paso por la creación y configuración correcta.

Objetivos de aprendizaje

  • Crear un proyecto de Class Library correctamente configurado
  • Entender y configurar la firma del assembly
  • Instalar los paquetes NuGet necesarios
  • Organizar la estructura del proyecto para escalabilidad

Creando el proyecto: los detalles que importan

Abre Visual Studio y selecciona "Create a new project". En el buscador, escribe "Class Library". Verás varias opciones. Aquí está la primera trampa para principiantes.

Visual Studio mostrará "Class Library" a secas (que es para .NET Standard o .NET Core) y "Class Library (.NET Framework)". Necesitas la segunda. Si no la ves, significa que no instalaste el workload de .NET desktop development.

Selecciona "Class Library (.NET Framework)" y haz clic en Next.

Nomenclatura del proyecto

Para el nombre del proyecto, sigue una convención que tenga sentido para tu organización. Yo uso el patrón: [Empresa].[Producto].Plugins

Por ejemplo, si trabajo para Contoso en su proyecto de CRM, el proyecto se llamaría Contoso.CRM.Plugins. Este nombre será también el namespace por defecto y el nombre del DLL generado.

Para el nombre de la solución, puedes usar algo más genérico como Contoso.CRM si planeas tener múltiples proyectos (por ejemplo, uno para plugins, otro para tests, otro para Custom Workflow Activities).

Seleccionando el Framework correcto

En el selector de Framework, elige .NET Framework 4.7.2 si está disponible, o 4.6.2 como mínimo. No elijas nada más reciente que 4.8 (las versiones 5, 6, 7, 8 son .NET Core, no Framework).

Una vez creado el proyecto, verás un archivo Class1.cs generado automáticamente. Puedes eliminarlo, vamos a crear nuestros propios archivos.


La firma del assembly: requisito obligatorio

Los plugins de Dataverse deben estar firmados con una Strong Name Key. Esto no es opcional. Si intentas registrar un plugin sin firmar, el Plugin Registration Tool rechazará el assembly.

La firma garantiza la integridad del código y permite que Dataverse verifique que el assembly no ha sido modificado. También es necesaria para el versionado del assembly en el GAC del servidor.

Generando la clave de firma

Hay varias formas de generar una Strong Name Key. La más directa es usando la línea de comandos:


# Abre Developer Command Prompt for VS o PowerShell
# Navega a la carpeta de tu proyecto
cd C:\repos\Contoso.CRM\Contoso.CRM.Plugins

# Genera el archivo .snk
sn -k Contoso.CRM.Plugins.snk

Esto genera un archivo .snk que contiene las claves pública y privada. Este archivo es importante: si lo pierdes, no podrás actualizar el assembly registrado en Dataverse. Tendrías que eliminar el registro y volver a registrar desde cero, lo que puede ser problemático en producción.

Consejo de seguridad: Guarda el archivo .snk en un lugar seguro fuera del repositorio de código si trabajas en un proyecto empresarial. Algunos equipos lo almacenan en Azure Key Vault o en un share protegido. Lo importante es que esté accesible pero no expuesto.

Configurando la firma en el proyecto

Una vez tienes el archivo .snk, cópialo a la carpeta raíz del proyecto. Luego, haz clic derecho en el proyecto en Solution Explorer y selecciona Properties.

Ve a la pestaña "Signing" (Firma). Marca la casilla "Sign the assembly" y en el desplegable selecciona "Browse" para elegir tu archivo .snk.

Alternativamente, puedes editar el archivo .csproj directamente:


<PropertyGroup>
  <SignAssembly>true</SignAssembly>
  <AssemblyOriginatorKeyFile>Contoso.CRM.Plugins.snk</AssemblyOriginatorKeyFile>
</PropertyGroup>

Compila el proyecto para verificar que la firma funciona. Si ves errores relacionados con la firma, verifica que la ruta al archivo .snk es correcta.


Instalando los paquetes NuGet esenciales

Para desarrollar plugins necesitas referencias al SDK de Dataverse. Microsoft lo distribuye a través de paquetes NuGet.

Haz clic derecho en el proyecto y selecciona "Manage NuGet Packages". En la pestaña Browse, busca e instala:

Microsoft.CrmSdk.CoreAssemblies es el paquete principal. Contiene las interfaces como IPlugin, IOrganizationService, y las clases como Entity, EntityReference, etc.

Ese es el único paquete obligatorio. Sin embargo, hay otros que son útiles:

Microsoft.CrmSdk.XrmTooling.CoreAssembly te da clases helper para conectar con Dataverse desde aplicaciones de consola o tests. No lo usarás dentro del plugin, pero es útil para tests unitarios.

Microsoft.CrmSdk.Workflow si planeas crear Custom Workflow Activities además de plugins.

Para un proyecto de plugins básico, solo necesitas CoreAssemblies:


# Desde Package Manager Console en Visual Studio
Install-Package Microsoft.CrmSdk.CoreAssemblies -Version 9.0.2.*

El asterisco en la versión te da la última versión del rango 9.0.2.x. Te recomiendo fijar versiones específicas en proyectos de producción para evitar sorpresas cuando Microsoft publique actualizaciones.


Organizando la estructura del proyecto

Un proyecto pequeño puede tener todos los plugins en la carpeta raíz. Pero cuando empiezas a tener 10, 20, 50 plugins, necesitas estructura.

Esta es la organización que uso en proyectos reales:


Contoso.CRM.Plugins/
├── Base/
│   └── PluginBase.cs         # Clase base abstracta
├── Constants/
│   ├── EntityNames.cs        # Constantes de nombres de entidades
│   └── FieldNames.cs         # Constantes de nombres de campos
├── Plugins/
│   ├── Account/
│   │   ├── ValidateAccountPlugin.cs
│   │   └── SetAccountTerritoryPlugin.cs
│   ├── Contact/
│   │   └── SyncContactToExternalSystem.cs
│   └── Opportunity/
│       └── CalculateCommissionPlugin.cs
├── Services/
│   └── ExternalApiService.cs  # Servicios reutilizables
├── Contoso.CRM.Plugins.snk
└── Contoso.CRM.Plugins.csproj

La clase base: evitando código repetitivo

Cada plugin repite el mismo patrón: obtener servicios, obtener contexto, manejar excepciones, escribir traces. Una clase base abstract te permite centralizar esto:


namespace Contoso.CRM.Plugins.Base
{
    public abstract class PluginBase : IPlugin
    {
        public void Execute(IServiceProvider serviceProvider)
        {
            ITracingService trace = (ITracingService)
                serviceProvider.GetService(typeof(ITracingService));
            
            IPluginExecutionContext context = (IPluginExecutionContext)
                serviceProvider.GetService(typeof(IPluginExecutionContext));
            
            IOrganizationServiceFactory factory = (IOrganizationServiceFactory)
                serviceProvider.GetService(typeof(IOrganizationServiceFactory));
            
            IOrganizationService service = 
                factory.CreateOrganizationService(context.UserId);
            
            try
            {
                trace.Trace($"{GetType().Name}: Inicio de ejecución");
                trace.Trace($"Mensaje: {context.MessageName}, Entidad: {context.PrimaryEntityName}");
                
                ExecutePlugin(context, service, trace);
                
                trace.Trace($"{GetType().Name}: Fin de ejecución");
            }
            catch (InvalidPluginExecutionException)
            {
                throw; // Re-lanzar sin modificar
            }
            catch (Exception ex)
            {
                trace.Trace($"Error: {ex.Message}");
                trace.Trace(ex.StackTrace);
                throw new InvalidPluginExecutionException(
                    $"Error en {GetType().Name}: {ex.Message}", ex);
            }
        }
        
        protected abstract void ExecutePlugin(
            IPluginExecutionContext context,
            IOrganizationService service,
            ITracingService trace);
    }
}

Con esta base, cada plugin concreto solo necesita implementar el método ExecutePlugin:


public class ValidateAccountPlugin : PluginBase
{
    protected override void ExecutePlugin(
        IPluginExecutionContext context,
        IOrganizationService service,
        ITracingService trace)
    {
        // Tu lógica aquí, sin repetir el boilerplate
    }
}

Verificando la configuración

Antes de continuar, compila el proyecto (Ctrl+Shift+B). Deberías ver en la carpeta bin\Debug\net462 (o similar) el archivo DLL con el nombre de tu proyecto.

Verifica que el assembly está firmado. Puedes usar la herramienta sn:


sn -vf bin\Debug\net462\Contoso.CRM.Plugins.dll
# Debe mostrar: "Assembly 'Contoso.CRM.Plugins.dll' is valid"

Si ves un mensaje de error sobre firma, revisa la configuración de Signing en las propiedades del proyecto.


Puntos clave

  • Usa la plantilla "Class Library (.NET Framework)", no .NET Standard ni .NET Core
  • Target framework: 4.6.2 mínimo, 4.7.2 recomendado
  • La firma del assembly con Strong Name Key es obligatoria
  • Guarda el archivo .snk en un lugar seguro, perderlo es problemático
  • El único paquete NuGet obligatorio es Microsoft.CrmSdk.CoreAssemblies
  • Organiza el proyecto por carpetas cuando crezca: Base, Constants, Plugins, Services
  • Una clase base abstract reduce código repetitivo y estandariza el manejo de errores

Para profundizar

Inicia sesión e inscríbete para guardar tu progreso.
En este curso
¿Te ha resultado útil?