Se mueve de CreditNotesRepository a ConnectionServiceLayer (PostAsync, PatchAsyncSBA, PatchNoContentAsync) con un hook asignado en Startup. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
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íaHintPathen los.csprojdeNet.DatayNet.Business.Services— sin esto no compila ningún proyecto que dependa de HANA). - Compilar desde macOS/Linux: el
HintPathes 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í elHintPathresuelve sin tocar los.csproj. (PasarAssemblySearchPathspor 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>"
}
schemaes opcional: si no está, se usaSapServiceLayer: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
Hanala app no arranca (InvalidOperationExceptionclara enLocalData.Configure). Al desplegar sobre un sitio existente hay que agregarla a suappsettings.jsonantes 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.exenativo (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 condotnet --list-runtimesen el servidor: debe listarMicrosoft.AspNetCore.App 3.1.xyMicrosoft.NETCore.App 3.1.x).- El
.xmlde comentarios (ITCA_API_SAP_WMS.xml, que Swagger necesita víaIncludeXmlCommentsenStartup.cs) ya se genera solo en Release desde que se sacó la condiciónDebug|AnyCPUdel.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 publishtransforma automáticamente elprocessPathdelweb.configpara que apunte al.exepublicado — no copiar elweb.configdel código fuente (ese apunta abin\Debug\..., es el de desarrollo) a una carpeta de publish.
Desplegar/actualizar un sitio en IIS
Si el sitio YA corre desde una carpeta de publish (actualización de versión)
- Detener el Application Pool del sitio (libera los locks de los
.dll/.exe). - Copiar el contenido del nuevo publish sin tocar
appsettings.jsonniweb.configexistentes — esos quedan tal cual están configurados en ese servidor/ambiente (pueden tener valores distintos a los del repo, ej.SapServiceLayer:companyapuntando a una base SAP distinta de QA/prod). - 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:
- Detener el Application Pool primero (si no, falla la compilación por archivos en uso).
- Copiar los
.cs/.csprojque cambiaron a las mismas rutas relativas dentro de la solución en el servidor (no hace falta tocar ningún.csprojpara agregar archivos nuevos — son proyectos SDK-style con glob automático de**/*.cs). - Compilar la solución ahí (Visual Studio → Build Solution en Debug, o
dotnet builddesde la carpeta de la solución). - 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 da500.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 subcarpetalogs\(para questdoutLogEnabledpueda escribir si hace falta diagnosticar).
Diagnóstico de errores de arranque
- Visor de eventos de Windows → Registros de Windows → Aplicación → buscar
el evento de
IIS AspNetCoreModule V2más reciente — casi siempre trae el error real. - Si no alcanza, poner
stdoutLogEnabled="true"en elweb.configde esa carpeta y revisar.\logs\stdout_*.logdespué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.jsontiene credenciales reales en texto plano (SAP Service Layer, HANAB1ADMIN, semilla JWT) — no haygiten esta carpeta; si alguna vez se versiona o se sube a un remoto compartido, hay que decidir qué hacer con ese archivo primero.B1ADMINes un usuario administrador de SAP B1; la API solo necesita ejecutar losITCA_*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).ValidarCertificadoenConnectionServiceLayer.csacepta cualquier certificado TLS (return true;siempre) — bypass de validación de certificado hacia el Service Layer, igual criterio queSERVICE_LAYER_VERIFY_SSL=falseen la reescritura Python.