ITCA_API_SAP_WMS (.NET) — build, publish y despliegue en IIS

API de integración WMS ↔ SAP Business One (Service Layer + HANA directo), ASP.NET Core 3.1. Para contexto de por qué este proyecto sigue activo (hay una reescritura en Python en paralelo) ver CLAUDE.md.

Requisitos para compilar

  • .NET Core 3.1 SDK.
  • Cliente HANA .NET instalado en C:\Program Files\sap\hdbclient\dotnetcore\v2.1\Sap.Data.Hana.Core.v2.1.dll (ruta hardcodeada vía HintPath en los .csproj de Net.Data y Net.Business.Services — sin esto no compila ningún proyecto que dependa de HANA).
  • Compilar desde macOS/Linux (forma simple): pasar la ruta de la DLL con -p:HanaDll=<ruta>/Sap.Data.Hana.Core.v2.1.dll a dotnet build/publish (los .csproj usan esa propiedad si está definida). Forma alternativa: el HintPath es relativo (6 niveles hacia arriba + Program Files\sap\...). Se puede compilar copiando el repo a <raiz>/a/b/c/d/repo/ y poniendo la DLL en <raiz>/Program Files/sap/hdbclient/dotnetcore/v2.1/ — así el HintPath resuelve sin tocar los .csproj. (Pasar AssemblySearchPaths por línea de comandos NO sirve: rompe la resolución del framework.)

Configuración de HANA (appsettings.json, sección Hana)

Las credenciales y el esquema de HANA ya no están fijos en el código; hay un único lugar, LocalData.Configure(...) (Net.Data/LocalData.cs), que se llama desde Startup:

"Hana": {
  "server": "192.168.0.13:30015",
  "user": "<usuario>",
  "password": "<password>",
  "schema": "<opcional>"
}
  • schema es opcional: si no está, se usa SapServiceLayer:company (si no hay ninguno de los dos la app no arranca, no hay valor por defecto), de modo que lecturas por HANA (CALL "<esquema>"."ITCA_...") y escrituras por Service Layer apunten siempre a la misma compañía.
  • Si falta la sección Hana la app no arranca (InvalidOperationException clara en LocalData.Configure). Al desplegar sobre un sitio existente hay que agregarla a su appsettings.json antes de iniciar el pool.

Correr localmente

dotnet run --project Net.Business.Services

Swagger queda en la raíz (RoutePrefix = "" en Startup.cs): http://localhost:<puerto>/.

Generar el publish para IIS

dotnet publish Net.Business.Services/Net.Business.Services.csproj -c Release -r win-x64 --self-contained false -o <carpeta-salida>
  • -r win-x64 --self-contained false: genera un .exe nativo (apphost) de 64 bits que no incluye el runtime — depende de que el servidor ya tenga el ASP.NET Core 3.1 Hosting Bundle instalado (confirmarlo con dotnet --list-runtimes en el servidor: debe listar Microsoft.AspNetCore.App 3.1.x y Microsoft.NETCore.App 3.1.x).
  • El .xml de comentarios (ITCA_API_SAP_WMS.xml, que Swagger necesita vía IncludeXmlComments en Startup.cs) ya se genera solo en Release desde que se sacó la condición Debug|AnyCPU del .csproj — si en algún momento vuelve a faltar en el output del publish, revisar que esa propiedad (DocumentationFile) siga sin estar condicionada a Debug.
  • dotnet publish transforma automáticamente el processPath del web.config para que apunte al .exe publicado — no copiar el web.config del código fuente (ese apunta a bin\Debug\..., es el de desarrollo) a una carpeta de publish.

Versión y script de publish

  • La versión sale de <Version>/<AssemblyVersion>/<FileVersion> en Net.Business.Services/Net.Business.Services.csproj (actual: 2.1.7.0); súbela en cada publish.
  • publicar.ps1 (solo Windows) genera dist\ITCA_API_SAP_WMS_v<versión>.zip sin appsettings.json. Desde macOS se hace el mismo dotnet publish a mano con -p:HanaDll=..., se borran appsettings.json/appsettings.Development.json de la salida y se comprime.
  • Control de versiones: rama main y etiquetas vX.Y.Z.W por versión publicada (ver CLAUDE.md).

Logs de integración

  • B_Log (controllers): en cada llamada guarda en ITC_WMS_SAP.ITCA_LOG_INTEGRACION el request del WMS (TRAMA_ORIGEN) y la respuesta de la API (TRAMA_RESPUESTA), con PROCESO (Picking, Recibo...), NRO_ORDEN, DOCENTRY, DOCNUMSAP y DOCENTRYSAP.
  • Log de errores del Service Layer (desde 2.1.5.0): cuando SAP rechaza un envío con cuerpo JSON (PostAsync, PatchAsyncSBA, PatchNoContentAsync) se guarda en esa misma tabla el JSON enviado y el mensaje de SAP, con PROCESO = 'ServiceLayer Error', NRO_ORDEN = ruta del recurso y DOCENTRY = BaseEntry del documento base. Solo en error; no cambia la respuesta de la API.
  • Ambos usan el esquema fijo ITC_WMS_SAP (columnas PROCESO, NRO_ORDEN y DOCENTRY son VARCHAR(100)).
  • Consulta de ejemplo: SELECT * FROM "ITC_WMS_SAP"."ITCA_LOG_INTEGRACION" WHERE "PROCESO" = 'ServiceLayer Error' ORDER BY "FECHA" DESC, "HORA" DESC

Desplegar/actualizar un sitio en IIS

Si el sitio YA corre desde una carpeta de publish (actualización de versión)

  1. Detener el Application Pool del sitio (libera los locks de los .dll/.exe).
  2. Copiar el contenido del nuevo publish sin tocar appsettings.json ni web.config existentes — esos quedan tal cual están configurados en ese servidor/ambiente (pueden tener valores distintos a los del repo, ej. SapServiceLayer:company apuntando a una base SAP distinta de QA/prod).
  3. Iniciar el Application Pool.

Si el sitio corre directo desde el código fuente (bin\Debug\...)

Así corre al menos un ambiente real (CLONE-SRV-WEB, ruta física ...\BackEnd\Desarrollo\BackEnd\Net.Business.Services, web.config con processPath="bin\Debug\netcoreapp3.1\ITCA_API_SAP_WMS.exe") — ahí no se usa dotnet publish, se compila in situ:

  1. Detener el Application Pool primero (si no, falla la compilación por archivos en uso).
  2. Copiar los .cs/.csproj que cambiaron a las mismas rutas relativas dentro de la solución en el servidor (no hace falta tocar ningún .csproj para agregar archivos nuevos — son proyectos SDK-style con glob automático de **/*.cs).
  3. Compilar la solución ahí (Visual Studio → Build Solution en Debug, o dotnet build desde la carpeta de la solución).
  4. Iniciar el Application Pool.

Checklist de configuración del Application Pool (IIS Manager, una sola vez por pool nuevo)

  • .NET CLR Version: Sin código administrado (No Managed Code).
  • Configuración avanzada → Habilitar aplicaciones de 32 bits: False (el .exe/DLLs son de 64 bits — con esto en True da 500.32 Failed to load .NET Core host, bitness mismatch).
  • Configuración avanzada → Cargar perfil de usuario (Load User Profile): True — sin esto, arranque falla con ErrorCode '0x8007023e' (excepción no manejada al iniciar el proceso in-process).
  • Permisos de carpeta: IIS AppPool\<NombreDelPool> con Lectura y ejecución sobre toda la carpeta del sitio, y Modificar sobre la subcarpeta logs\ (para que stdoutLogEnabled pueda escribir si hace falta diagnosticar).

Diagnóstico de errores de arranque

  1. Visor de eventos de Windows → Registros de Windows → Aplicación → buscar el evento de IIS AspNetCoreModule V2 más reciente — casi siempre trae el error real.
  2. Si no alcanza, poner stdoutLogEnabled="true" en el web.config de esa carpeta y revisar .\logs\stdout_*.log después de reciclar el pool.

Editar appsettings.json de un sitio ya desplegado

No hace falta detener el Application Pool para editarlo (no queda bloqueado como los binarios) — pero conviene reciclar el pool después de guardar, para garantizar que el valor nuevo se relea (el host usa Host.CreateDefaultBuilder, que ya trae reloadOnChange: true para appsettings.json, pero no vale la pena depender de eso para un cambio puntual).

El nombre de la base SAP (CompanyDB) se configura en SapServiceLayer:company dentro de appsettings.json — lo lee ConnectionServiceLayer.cs (_company = configuration["SapServiceLayer:company"]) para armar el body del Login contra el Service Layer.

Riesgos de seguridad heredados (documentados, no corregidos sin coordinar antes)

  • appsettings.json tiene credenciales reales en texto plano (SAP Service Layer, HANA B1ADMIN, semilla JWT). Está en .gitignore y no se versiona (solo appsettings.example.json); no subirlo a ningún repositorio.
  • B1ADMIN es un usuario administrador de SAP B1; la API solo necesita ejecutar los ITCA_* y leer algunas tablas. Conviene un usuario HANA de permisos mínimos y rotar la contraseña (estuvo en texto plano en el código y en el historial git del repo antiguo archivado).
  • ValidarCertificado en ConnectionServiceLayer.cs acepta cualquier certificado TLS (return true; siempre) — bypass de validación de certificado hacia el Service Layer, igual criterio que SERVICE_LAYER_VERIFY_SSL=false en la reescritura Python.
S
Description
No description provided
Readme
547 KiB
0 Stars 1 Watchers 0 Forks
Languages
C# 99.5%
PowerShell 0.5%