Trampas de las unidades de red y las rutas UNC — la gestión práctica de servidores de archivos (carpetas compartidas) en aplicaciones empresariales

· Actualizado el: · · Unidad de red, Ruta UNC, SMB, Uso compartido de archivos, Servicio de Windows, Servidor de archivos, C#, .NET, Red, Investigación de fallos, Desarrollo en Windows, Consultoría técnica

«Funcionaba en la máquina de desarrollo, pero en el entorno del cliente dicen que no encuentra “Z:\“», «en cuanto lo pusimos en el Programador de tareas, la salida a la carpeta compartida empezó a fallar», «al convertirlo en un servicio de Windows, dejó de ver el servidor de archivos» — en las consultas sobre aplicaciones empresariales, los problemas relacionados con el servidor de archivos (la carpeta compartida) son de lo más habitual. La importación de datos de pedidos, la salida de informes y archivos CSV, la monitorización de los archivos que genera un equipo: en los sistemas empresariales on-premise, la carpeta compartida sigue siendo hoy una infraestructura de integración en pleno uso.

Lo complicado es que la mayoría de estos problemas no son «errores en el código», sino que están arraigados en el propio funcionamiento de Windows: la relación entre las letras de unidad y las sesiones de inicio de sesión, la cuenta de ejecución y la autenticación de los servicios, la gestión de conexiones de SMB. Por más que se siga con el depurador, no se llega a la causa, y el tiempo se consume mientras «en mi PC no se reproduce».

Este artículo se dirige a los desarrolladores de aplicaciones empresariales (WinForms/WPF/servicios de Windows) que implementan la salida, la importación y la monitorización de archivos hacia carpetas compartidas. Analizamos desde su funcionamiento las trampas de las unidades de red y las rutas UNC, y resumimos las reglas prácticas del oficio en una tabla de decisión.

Entorno previsto

Como las respuestas sobre la autenticación cambian según las condiciones de partida, dejamos claro de antemano el entorno que suponemos.

Elemento Supuesto
SO Windows 10 / 11, Windows Server (versiones actualmente compatibles)
Protocolo de recurso compartido SMB (el mecanismo estándar de uso compartido de archivos de Windows)
Base de autenticación Se supone principalmente un entorno de dominio de Active Directory. Cuando se trate de un entorno de grupo de trabajo sin dominio o de una cuenta propia de un NAS, se advertirá explícitamente cada vez con la frase “en un grupo de trabajo” para distinguirlo
Forma de ejecución de la app Aplicación de escritorio (WinForms / WPF), servicio de Windows, aplicación de consola iniciada desde el Programador de tareas
Ejemplos de código C# / .NET 6 o posterior (se usan File.WriteAllBytesAsync y la coincidencia de patrones is ... or ...)

Si su entorno es un dominio o un grupo de trabajo es la bifurcación que más afecta a este artículo. Las opciones de cuenta de ejecución del capítulo 3 (cuenta de equipo o gMSA) solo son viables si existe un dominio; en un entorno sin dominio, la solución se orienta hacia el enfoque de “pasar credenciales explícitamente” del capítulo 4. Confirme primero cuál es el caso de su empresa antes de continuar leyendo.

Abreviaturas usadas en este artículo

Abreviatura Lectura / nombre completo En pocas palabras
Ruta UNC Universal Naming Convention (convención de nomenclatura universal) Formato \\nombre-del-servidor\nombre-del-recurso\.... La dirección auténtica de una carpeta compartida
SMB Server Message Block El protocolo de comunicación que usa el uso compartido de archivos de Windows
Sesión de inicio de sesión El “contexto de ejecución” que el sistema operativo crea cuando un usuario inicia sesión o cuando se arranca un servicio. Las letras de unidad se administran por esta unidad (capítulo 2)
Kerberos El protocolo de autenticación estándar de un dominio de Active Directory. Verifica la identidad intercambiando tickets
SPN Service Principal Name (nombre principal de servicio) En Kerberos, el nombre que identifica de forma única al servicio de destino. El cliente construye el SPN a partir del nombre de host de destino para solicitar el ticket (capítulo 4)
gMSA group Managed Service Account (cuenta de servicio administrada por grupo) Una cuenta de servicio de dominio cuya contraseña genera y actualiza automáticamente el sistema operativo (capítulo 3)1

1. Ante todo, la conclusión

  • Las letras de unidad (como Z:) no son un recurso de todo el sistema, sino algo que existe por sesión de inicio de sesión. Como a cada sesión de inicio de sesión se le asigna su propio conjunto de letras de la A a la Z, un proceso de otro usuario o un servicio que se ejecuta en otra sesión de inicio de sesión no puede ver la unidad que el usuario asignó.2
  • Con UAC habilitado, un administrador tiene dos sesiones de inicio de sesión enlazadas —una con privilegios normales y otra elevada— y la asignación de unidades (los enlaces simbólicos de DosDevices) es independiente para cada sesión. Por eso ocurre que “Z: solo deja de verse desde la aplicación elevada”. Existe una solución alternativa mediante el valor de registro EnableLinkedConnections, que comparte la asignación entre ambas sesiones, pero Microsoft la documenta explícitamente como una configuración no compatible que “puede hacer que el sistema sea menos seguro” y que “no es compatible”.34
  • La directriz oficial es que un servicio (o un proceso que se ejecuta en un contexto de seguridad distinto) acceda a los recursos remotos mediante la ruta UNC (\\server\share\...). Implementar la asignación de una letra de unidad desde dentro de un servicio, ya sea con net use o con las API de la familia WNet, no se recomienda por el riesgo de fuga de credenciales y de interferencia entre servicios.2
  • A quién hay que otorgarle permisos en el recurso compartido lo determina la cuenta de ejecución del servicio. LocalSystem y NetworkService se autentican en la red como “las credenciales del equipo”, mientras que LocalService usa credenciales anónimas, por lo que no es apto para el acceso a recursos compartidos. Un servicio con una cuenta de usuario local no puede acceder a recursos de red. En la práctica, la opción principal es una cuenta de dominio o la gMSA (group Managed Service Account, cuenta de servicio administrada por grupo), que permite delegar la gestión de la contraseña al sistema operativo. Ahora bien, la gMSA exige como requisito previo un entorno de dominio y tener preparada la clave raíz de KDS (capítulo 3).567819
  • No es posible mantener conexiones simultáneas con el mismo servidor usando varias credenciales distintas. La segunda conexión falla con el error 1219 (ERROR_SESSION_CREDENTIAL_CONFLICT), y esto es un comportamiento intencionado (by design).1011
  • Que la carpeta compartida “sea lenta, se desconecte y a veces no esté disponible” es su comportamiento normal. Una conexión inactiva se desconecta desde el lado del servidor a los 15 minutos de forma predeterminada (se reconecta en el siguiente acceso). File.Exists devuelve false sin lanzar una excepción incluso cuando faltan permisos o se produce un error, por lo que no permite distinguir entre “el archivo no existe” y “no se puede llegar al servidor”.1213
  • FileSystemWatcher admite la monitorización de unidades de red y de equipos remotos, pero hay que diseñar contando con que se pierdan eventos. Puede perder eventos si el búfer se desborda, y cuando la monitorización es a través de la red, el límite del búfer interno queda restringido a 64 KB. La regla del oficio es combinarlo con sondeo (escaneo completo, polling).14

2. La relación entre las letras de unidad y las rutas UNC — Z: pertenece a “su sesión de inicio de sesión”

Cuando en el Explorador de archivos se asigna \\fileserver\share a Z:, da la impresión de que ha aparecido una “unidad Z:” en toda la máquina. Ese es el primer malentendido.

La documentación oficial lo dice con claridad. Las letras de unidad no son globales para todo el sistema: a cada sesión de inicio de sesión se le asigna su propio conjunto de la A a la Z. Las unidades redirigidas (unidades de red) no se pueden compartir entre procesos que se ejecutan con cuentas de usuario distintas, y un servicio que se ejecuta en otra sesión de inicio de sesión no puede acceder a las letras de unidad establecidas en otra sesión.2 El sistema administra las asignaciones de unidad basándose en el SID de inicio de sesión, que identifica de forma unívoca a cada sesión de inicio de sesión.2

En otras palabras, Z: es solo “un conjunto de símbolos abreviados de ruta por cada sesión de inicio de sesión”; la entidad real siempre es la ruta UNC. Si lo representamos en un diagrama, queda así:

Relación entre las letras de unidad y las sesiones de inicio de sesiónDiagrama que muestra que la sesión A tiene la letra Z asignada al recurso compartido, que la sesión B (un servicio) no tiene esa letra asignada, y que ambas sesiones solo alcanzan de forma fiable la carpeta compartida mediante la ruta UNCSesión de inicio de sesión B — servicio / Programador de tareasSesión de inicio de sesión A — usuario con inicio de sesión interactivoSe alcanza con Z:Z: no existe. Se alcanza con la ruta UNCServicio de WindowsTarea por lotes programadaConjunto de letras de unidad de esta sesiónZ: no está asignadaExplorador de archivosAplicación iniciada desde el escritorioConjunto de letras de unidad de esta sesiónZ: ya está asignada al recurso compartidoEntidad real de la carpeta compartidaRuta UNC — share en fileserver01

Figura 1: cada sesión de inicio de sesión tiene su propio conjunto de letras de unidad, pero la ruta UNC real es única

Lo que conviene tener presente es que esta separación no se debe a que “el usuario sea distinto”. Aunque configure el servicio para que se ejecute con la misma cuenta de usuario que la sesión A, el sistema crea una nueva sesión de inicio de sesión para el servicio, de modo que la asignación hecha en la sesión A no se hereda.2 La consulta de “configuré el servicio con mi propio usuario y aun así no encuentra Z:” tiene su origen en confundir este punto.

A partir de aquí se pueden explicar, encadenados, los síntomas que se repiten con frecuencia sobre el terreno.

Síntoma Razón según el mecanismo
Al ejecutar con otro usuario, no aparece Z: Las letras de unidad son por sesión de inicio de sesión. No se ve la asignación de otra persona2
Al “ejecutar como administrador”, no aparece Z: UAC crea dos sesiones de inicio de sesión, una normal y otra elevada, y la asignación no se comparte3
Al ponerlo en el Programador de tareas o en un servicio, no aparece Z: Porque se ejecuta en otra sesión de inicio de sesión. Aunque el servicio se configure con una cuenta de usuario, el sistema crea una nueva sesión de inicio de sesión para el servicio2

Vale la pena profundizar un poco más en el caso de UAC. Cuando un usuario del grupo de administradores inicia sesión, el sistema crea dos sesiones de inicio de sesión enlazadas: una con un token de privilegios limitados y otra con el token de administrador completo. La entidad real de la asignación de unidad es un objeto de enlace simbólico (DosDevices) que asocia la letra de unidad con la ruta UNC, y este objeto es específico de cada sesión de inicio de sesión, sin compartirse entre sesiones.3 Como el script de inicio de sesión se ejecuta en el lado de privilegios normales, la lógica es que esa asignación no es visible desde un proceso elevado.

Si se establece en 1 el valor EnableLinkedConnections (un valor DWORD en HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System), el enlace simbólico se escribe en las dos sesiones enlazadas, y este síntoma desaparece. Sin embargo, la documentación oficial indica explícitamente: “esta solución alternativa puede hacer que el sistema sea menos seguro. Microsoft no admite esta solución alternativa. Úsela bajo su propia responsabilidad”.4 Proponer incrustar una configuración no compatible en el registro del entorno del cliente es una mala solución para una aplicación empresarial. El camino correcto es que la aplicación trabaje con rutas UNC. Incluso la guía oficial de solución de problemas de redirección de carpetas indica que “se recomienda usar siempre la ruta UNC en lugar de la letra de unidad”.4

A nivel de implementación es sencillo: basta con guardar en el archivo de configuración la ruta en formato UNC.

// appsettings.json -- se guarda en UNC, no con letra de unidad
{
  "FileTransfer": {
    "IncomingDir": "\\\\fileserver01\\edi\\incoming",
    "ProcessedDir": "\\\\fileserver01\\edi\\processed"
  }
}

Si se trata de una aplicación en la que el usuario puede seleccionar una ruta bajo Z: mediante un cuadro de diálogo de selección de carpeta, normalizarla a UNC en el momento de guardarla evita que se rompa más adelante si cambia el contexto de ejecución. Para convertir de letra de unidad a UNC existe la API WNetGetUniversalName.15

3. Acceder a una carpeta compartida desde un servicio de Windows — UNC obligatorio, y “como quién” se accede

Como se explicó en el capítulo anterior, un servicio no puede usar una unidad asignada. La documentación oficial establece que un servicio (y un proceso que se ejecuta en un contexto de seguridad distinto) debe acceder a los recursos remotos mediante el nombre UNC, y desaconseja explícitamente implementar, dentro de un servicio, la asignación de una letra de unidad en tiempo de ejecución con net use o con las API de la familia WNet. Los motivos que se citan son que la asignación queda visible para otros servicios que se ejecutan en el mismo contexto, que las credenciales pasadas a net use pueden filtrarse fuera de los límites del servicio, y que varios servicios que intentan establecer la misma asignación interfieren entre sí con el error “ya conectado”.2

Una vez que se usa la ruta UNC, el siguiente problema es la autenticación. ¿”Como quién” accede el servicio al servidor de archivos? Esto lo determina la cuenta de ejecución, y también determina a quién hay que otorgarle los permisos en el lado del recurso compartido.

Cuenta de ejecución Identidad en la red Concesión de permisos en el recurso compartido Valoración
LocalSystem Credenciales del equipo5 En un entorno de dominio, permisos de uso compartido y NTFS para la cuenta de equipo (DOMAIN\MACHINE$) Funciona, pero con permisos excesivos. Al sustituir la máquina hay que rehacer la configuración de permisos
NetworkService Credenciales del equipo6 Igual que la anterior Privilegios locales mínimos, pero en la red tiene la misma identidad que LocalSystem
LocalService Credenciales anónimas7 No hay forma de otorgarle permisos No es apto para el acceso a recursos compartidos
Usuario local No puede acceder a recursos de red8
Usuario de dominio Esa cuenta Se otorgan a esa cuenta El estándar en la práctica. El cambio de contraseña es un problema operativo
gMSA Esa cuenta Se otorgan a esa cuenta El sistema operativo administra la contraseña automáticamente (la cambia sola cada 30 días). La opción principal si el entorno lo permite116

Que LocalSystem y NetworkService salgan a la red “como el equipo” es un comportamiento documentado oficialmente.56 Como consecuencia de esto, la documentación de BITS recoge directamente estas advertencias prácticas: “si la ACL del archivo de origen restringe el acceso a una cuenta de usuario, el servicio (que se autentica con las credenciales del equipo) recibirá acceso denegado” y “las cuentas del sistema no deberían usar unidades asignadas”.17

De aquí se pueden extraer estas tres directrices prácticas.

  • El primer paso para diagnosticar “al convertirlo en servicio, da acceso denegado” es comprobar la cuenta de ejecución. Cuando se ejecutaba en el escritorio, la comprobación de acceso se hacía con “sus” propios permisos; en un servicio, se hace con la identidad de la tabla anterior. Compruebe tanto los permisos de uso compartido como la ACL de NTFS para esa identidad.
  • Si se va a operar a largo plazo en un entorno de dominio, use como cuenta de ejecución una cuenta de dominio o una gMSA. Como la gMSA usa una contraseña aleatoria de 240 bytes que el sistema operativo actualiza automáticamente cada 30 días, se elimina estructuralmente el tipo de incidente en el que “todo se detuvo el lunes por la mañana porque caducó la contraseña de la cuenta de servicio”.16
  • En un entorno de grupo de trabajo (sin dominio), la autenticación con las credenciales del equipo no es viable, así que entra en juego el paso de credenciales explícitas del siguiente capítulo.

Esa gMSA tiene requisitos previos. La hemos llamado “la opción principal”, pero no es algo que se pueda usar el mismo día que se decide. La gMSA es, en origen, una extensión de la funcionalidad de la sMSA (standalone Managed Service Account, para un único servidor) para que pueda usarse en varios servidores a la vez; es una cuenta de dominio que ofrece administración automática de contraseñas y simplificación de la gestión de SPN.1 Antes de introducirla, compruebe lo siguiente.

Requisito previo Contenido
Dominio de Active Directory La gMSA es una cuenta de dominio. No es una opción en un entorno de grupo de trabajo. Tampoco se aplica a versiones de Windows anteriores a Windows Server 20121
Clave raíz de KDS El controlador de dominio necesita la clave raíz del Key Distribution Service (KDS) para generar la contraseña de la gMSA. Se crea ejecutando una sola vez en el bosque Add-KdsRootKey -EffectiveImmediately9
Tiempo de espera tras la creación No se puede crear una gMSA hasta que, como máximo 10 horas después de crear la clave raíz, converja la replicación de AD en todos los controladores de dominio. Es una medida de seguridad para evitar que se genere la contraseña antes de que todos los DC puedan atender las solicitudes de la gMSA; que “no se pueda usar justo después de crearla” es el comportamiento previsto9
Equipo de administración Ejecutar los comandos de Windows PowerShell que administran la gMSA requiere una arquitectura de 64 bits19
Tipo de cifrado La gMSA depende de los tipos de cifrado admitidos por Kerberos. Si en el host se ha deshabilitado RC4 y no existe el atributo msDS-SupportedEncryptionTypes, la autenticación fallará siempre, por lo que se recomienda configurar siempre AES en las MSA1

Como se trata de puntos que requieren coordinación con el administrador de dominio, el orden correcto es confirmar antes con el responsable de infraestructura estos cinco puntos, si se va a proponer un diseño basado en gMSA. Si no se puede obtener esa confirmación, o si el tiempo de espera de 10 horas no encaja en el cronograma, lo más realista es construir primero la solución con una cuenta de dominio normal, dejando el cambio a gMSA de forma que solo requiera modificar la cuenta de ejecución.

La forma de crear el propio servicio (la configuración de la cuenta de ejecución, las opciones de recuperación, una detención segura) se explica en «Cómo crear y operar un servicio de Windows», y el mecanismo de las sesiones y el inicio de sesión se organiza en «Cómo entender el aislamiento de sesiones de Windows».

4. El manejo de las credenciales — net use, el Administrador de credenciales y el error 1219

Cuando no se puede otorgar permisos en el recurso compartido directamente a la cuenta de ejecución (por ejemplo, en un grupo de trabajo, o cuando el NAS usa su propio sistema de cuentas), hay que conectarse pasando las credenciales de forma explícita. Hay principalmente tres formas de hacerlo.

  • net use \\server\share /user:... — establece la conexión en esa sesión de inicio de sesión. Resulta cómodo para comprobaciones interactivas, pero, como se vio en el capítulo anterior, no se recomienda ejecutarlo dentro de un servicio.2
  • El Administrador de credenciales (cmdkey) — si se guardan las credenciales con cmdkey /add:server /user:svc-file /pass:..., a partir de ese momento se usarán automáticamente en la autenticación con ese servidor.1819 El guardado es por perfil de usuario, así que la trampa está en que, si se va a usar desde un servicio, hay que registrarlas “en el contexto de la cuenta de ejecución del servicio”.
  • Conexión desde el código (WNetAddConnection2) — permite establecer una conexión a un recurso de red especificando las credenciales del cliente. La documentación oficial también la menciona como una de las estrategias para que un proceso de servidor acceda a recursos de red.20 Si se hace como una “conexión sin dispositivo” (deviceless), sin asignar una letra de unidad, se puede seguir accediendo con la ruta UNC.

Y en este terreno, la trampa más conocida es el error 1219.

Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. (ERROR_SESSION_CREDENTIAL_CONFLICT, 1219)11

No se pueden establecer varias conexiones al mismo servidor, desde la misma sesión de inicio de sesión, con nombres de usuario distintos. Si intenta conectarse al mismo servidor de archivos con dos tipos de credenciales —por ejemplo, “el recurso de ventas con mi propia cuenta, y el recurso de integración de sistemas con una cuenta dedicada”—, la segunda conexión fallará con el error 1219. La documentación oficial afirma explícitamente que esto es “by design” (comportamiento intencionado), y las soluciones alternativas que menciona son “conectarse por dirección IP” o “crear otro alias DNS y conectarse a través de él” — es decir, formas de hacer que parezca otro servidor distinto.10

En la práctica, la primera opción es evitar de entrada un diseño en el que se usan varias credenciales distintas contra un único servidor. Conviene consolidar en una sola cuenta de integración y otorgarle a esa cuenta permisos en todos los recursos compartidos necesarios. Solo cuando existan circunstancias que lo impidan, se separan las rutas mediante un alias.

Sin embargo, un alias no es algo que se resuelva “añadiendo una línea CNAME en el DNS y ya está”. En un entorno con autenticación Kerberos, el cliente SMB intenta autenticarse con el SPN (nombre principal de servicio) correspondiente al nombre de destino de la conexión, por lo que si no hay un SPN registrado para el alias, el propio acceso a través del CNAME puede fallar. La guía oficial de solución de problemas también menciona esta falta de SPN como una de las causas, y recomienda configurar el alias no como un CNAME de DNS, sino como un alias de nombre de equipo con netdom computername <nombre-del-servidor> /add:<alias>.21 Antes de incorporar al diseño una conexión mediante alias como medida contra el error 1219, valide siempre su funcionamiento en el entorno de destino.

Cabe señalar que un requisito avanzado como “queremos que el servicio acceda al servidor de archivos con los permisos del usuario cliente que se ha conectado” no pertenece al terreno de reutilizar credenciales, sino al de la suplantación (impersonation). La documentación oficial también recomienda la suplantación antes que hacer que el servicio acumule credenciales propias.2 Para conocer la forma correcta de escribir la suplantación y las consideraciones adicionales que exigen los recursos remotos, consulte «Cómo manejar correctamente los tokens de suplantación de Windows».

Diagnosticar su propio entorno — los comandos que hay que ejecutar primero

Todo lo dicho hasta ahora solo se vuelve práctico cuando se puede comprobar el estado en el entorno donde aparece el síntoma. El punto de partida del diagnóstico es como quién se está ejecutando ese proceso y qué conexiones tiene. Ejecute los tres comandos siguientes en el mismo contexto de ejecución en el que aparece el síntoma.

Comando Qué revela Puntos a observar
whoami Como quién se está ejecutando en ese momento (se muestra en el formato nombre-de-dominio\nombre-de-usuario) Si coincide con la cuenta de ejecución prevista. Si es un servicio, a qué fila de la tabla del capítulo 3 corresponde
net use (sin argumentos) La lista de conexiones de red que tiene esa sesión de inicio de sesión22 Si la Z: que se supone que no debería verse aparece en la lista. Si no aparece, queda confirmado que “no existe en esa sesión”
net use \\fileserver01\share El estado de la conexión indicada22 Si la conexión en sí no se ha podido establecer, o si se estableció y luego se rechazó por permisos

Lo esencial es ejecutarlo en el mismo contexto. Ejecutar net use en su propio escritorio no dice nada sobre las conexiones que tiene el servicio. Cuando quiera comprobarlo con la cuenta de ejecución del servicio, lo más fiable es registrar temporalmente en el Programador de tareas una tarea como cmd /c "whoami > C:\temp\who.txt & net use >> C:\temp\who.txt", con la misma cuenta y la misma configuración de privilegios, y revisar después el archivo de salida.

Reproducir el error 1219 en su propio entorno

Con el error 1219, entenderlo cuesta menos si se produce una vez uno mismo que leyendo la explicación. En un equipo unido al dominio, intente conectarse con credenciales distintas a dos recursos compartidos del mismo servidor de archivos.

:: 1) Conectarse al primer recurso compartido con su propia cuenta (la contraseña se pide con *)
net use \\fileserver01\share1 * /user:CONTOSO\tanaka

:: 2) Intentar conectarse a otro recurso compartido del mismo servidor con otra cuenta
net use \\fileserver01\share2 * /user:CONTOSO\svc-file
::    -> Aqui se devuelve el error 1219 citado arriba y no se puede conectar

:: Limpieza: cerrar todas las conexiones de red de esta sesion
net use * /delete

El punto clave es que el conflicto se produce si el servidor es el mismo, aunque el recurso compartido sea distinto. No importa que el primero sea share1 y el segundo share2, porque la restricción es por servidor. Al contrario, si primero se cierra la conexión con net use \\fileserver01\share1 /delete y después se establece la segunda, esta tendrá éxito — es decir, según el orden en que se hagan las cosas, puede llegar a funcionar, lo que produce el desagradable efecto de que no se reproduce durante el desarrollo y aparece por primera vez en producción. Si usa una dirección IP o un alias como solución alternativa, no olvide el requisito de SPN mencionado justo antes.1021

5. Diseñar partiendo de la base de que el recurso “es lento, se desconecta y a veces no está disponible”

El código escrito con la misma mentalidad que para un disco local acaba fallando en algún momento cuando el destino es una carpeta compartida. Hay tres realidades que hay que dar por sentadas.

En primer lugar, es normal que la conexión se desconecte. Una conexión inactiva se desconecta de forma predeterminada tras un tiempo de espera de 15 minutos, para evitar el desperdicio de recursos del servidor. Este es el conocido fenómeno de la cruz roja que aparece en la unidad de red del Explorador de archivos, y en el siguiente acceso se reconecta rápidamente.12 Es decir, tanto que “una aplicación empresarial que accede solo de vez en cuando sufra una breve espera cada vez que accede” como que “una herramienta de monitorización se alarme diciendo ‘¡se desconectó!’ sin que haya un daño real” son comportamientos conforme al diseño. En lugar de vigilar la existencia de la conexión, hay que decidir en función de si la E/S real tiene éxito.

Este tiempo de espera se puede cambiar. Sin embargo, tenga en cuenta que hay temporizadores en dos sitios, en el servidor y en el cliente, y gana el que sea más corto.12

Dónde Configuración Contenido
Lado del servidor (comando) net config server /autodisconnect:<minutos> Minutos hasta la desconexión por inactividad. El valor máximo es 65535. La trampa es que asignar 0 no la deshabilita, sino que hace que se desconecte tras unos segundos de inactividad
Lado del servidor (comando) net config server /autodisconnect:-1 Deshabilita la propia función de autodisconnect
Lado del servidor (registro) autodisconnect (REG_DWORD) en HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters Solo permite cambiar el tiempo de espera. Con este método no se puede deshabilitar la función
Lado del cliente (registro) KeepConn (REG_DWORD, de 1 a 65535 segundos) en HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parameters El tiempo de retención por inactividad en el lado del cliente. El valor predeterminado es 600 segundos (10 minutos)

Lo que se pasa por alto con facilidad es la última fila. El valor predeterminado del lado del cliente es de 10 minutos, más corto que los 15 minutos predeterminados del lado del servidor, así que extender solo el lado del servidor no cambia el comportamiento de la desconexión. Esto se debe a que la sesión se desconecta según el valor más corto entre autodisconnect y KeepConn.12

Dicho esto, cambiar estos valores no es la primera opción. La desconexión es un comportamiento conforme al diseño y, como se reconecta en el siguiente acceso, normalmente no causa ningún daño real. Toque estos valores solo cuando tenga circunstancias como una aplicación antigua que se cae cada vez que se desconecta y que no se puede tocar, y hágalo siempre de acuerdo con el administrador del servidor, teniendo en cuenta que es una configuración que también afecta a otros sistemas. Lo correcto para la aplicación es orientarse hacia “reintentar dando por hecho que se va a desconectar”.

En segundo lugar, la forma en que se manifiestan los errores no es nada amigable. File.Exists devuelve false sin lanzar una excepción tanto si la ruta no es válida, como si faltan permisos, como si hay un fallo de disco.13 En local, “si es false es que no existe” casi nunca da problemas, pero contra un recurso compartido, “el archivo no existe” y “no se puede llegar al servidor / no hay permisos” quedan todos aplastados en false, lo que produce el desagradable fallo de que un código que toma decisiones de negocio ramificando sobre Exists termina, ante un fallo de red, finalizando con normalidad como si «el objeto no existiera». Un diseño que abre directamente el archivo, sin comprobar antes su existencia, y distingue los casos mediante excepciones, es más fácil de diagnosticar cuando el destino es un recurso compartido.

En tercer lugar, es posible que el otro extremo todavía no esté disponible. Justo después de arrancar la máquina, el inicio del servicio puede adelantarse a la preparación de la red, y también es posible que el servidor de archivos esté reiniciándose. Como la conexión persistente (persistent connection) es un mecanismo que se restaura al iniciar sesión el usuario23, en el mundo de los servicios, que no pasan por un inicio de sesión, no hay ninguna garantía de que “en cuanto arranque, el recurso compartido sea visible”. El comportamiento correcto no es comprobar la conectividad una sola vez al arrancar y terminar si falla, sino esperar reintentando.

Incorporando estos tres puntos, el esqueleto del lado de escritura queda así.

// Reintentar los errores de red temporales; hacer fallar de inmediato los errores de negocio
private static async Task WriteToShareAsync(string finalPath, byte[] content, CancellationToken ct)
{
    var dir = Path.GetDirectoryName(finalPath)!;
    var tempPath = Path.Combine(dir, $"~{Guid.NewGuid():N}.tmp");

    try
    {
        for (var attempt = 1; ; attempt++)
        {
            try
            {
                await File.WriteAllBytesAsync(tempPath, content, ct);
                File.Move(tempPath, finalPath); // Publicar el "completado" mediante un rename dentro del mismo directorio
                return;
            }
            catch (IOException ex) when (attempt < 5 && IsRetryable(ex))
            {
                // Reintentar solo los fallos de red temporales con backoff exponencial (con un límite)
                _logger.LogWarning(ex, "Fallo al escribir en el recurso compartido (intento {Attempt}). Reintentando", attempt);
                await Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt)), ct);
            }
        }
    }
    catch
    {
        // Si se propaga la excepción tras desistir, limpiar el archivo temporal en el mejor esfuerzo posible
        try { File.Delete(tempPath); } catch { /* se ignora un fallo en la limpieza */ }
        throw;
    }
}

// IOException llega con el mismo tipo tanto para "desconexión de red" como para "ya existe un archivo con el mismo nombre en el destino" o "disco lleno".
// Con los 16 bits inferiores de HResult (el código de error de Win32) se seleccionan solo los fallos temporales para los que tiene sentido reintentar
private static bool IsRetryable(IOException ex)
{
    var win32 = ex.HResult & 0xFFFF;
    return win32 is 53   // ERROR_BAD_NETPATH: no se encuentra la ruta de red
              or 59   // ERROR_UNEXP_NET_ERR: error de red inesperado
              or 64   // ERROR_NETNAME_DELETED: el nombre de red dejó de estar disponible
              or 121; // ERROR_SEM_TIMEOUT: tiempo de espera agotado (el llamado semaphore timeout)
}

También es importante no escribir a la ligera algo como “si es IOException, reintentar”. Fallos que no cambian de resultado por más veces que se intenten —como que ya exista un archivo con el mismo nombre en el destino, que la ruta sea demasiado larga o que el disco esté lleno— llegan igualmente como IOException, así que si se decide solo por el tipo de excepción, se acaba reintentando cinco veces un error permanente y esperando en vano con el backoff. Como en el ejemplo anterior, seleccione mediante el código de error de Win32 (53/59/64/121, entre otros, relacionados con desconexiones y tiempos de espera del acceso a recursos compartidos24) solamente los “fallos para los que tiene sentido reintentar”. Lo más realista es ir añadiendo, sobre la marcha, los códigos que se observen en los registros del entorno real.

El punto clave no es tanto añadir el reintento en sí, sino combinarlo con un protocolo de entrega seguro incluso si se reintenta (temp -> rename, idempotencia). Si la conexión se corta a mitad de la escritura, queda un archivo a medio terminar. Si se establece la norma de que el nombre final solo puede aparecer mediante un “rename después de cerrar”, se evita el accidente de que el receptor lea un archivo a medio cocinar. Además, como una caída del proceso o un corte de energía impiden que se ejecute la propia limpieza del código, conviene preparar también en la carpeta de entrega una limpieza periódica que “elimine los archivos ~*.tmp que no se hayan actualizado en un tiempo determinado”, para no atascarse con la acumulación de basura. La visión de conjunto de este diseño de entrega está recogida en «Conocimientos básicos sobre el control de exclusión en la integración de archivos».

Hay otra precaución específica cuando el destino es la red. Un resultado de “fallo” no garantiza que realmente haya fallado. Si la conexión se corta justo después de que el rename se complete en el servidor, puede darse la situación de que el cliente reciba una excepción mientras que el archivo con el nombre final ya está publicado. Si en ese estado se reintenta sin más consideración, o bien se atasca con el error de que “ya existe un archivo con ese nombre en el destino”, o bien, si el receptor ya había recogido el primero, se acaba publicando la misma información por duplicado. La medida correcta es, antes de reintentar el paso del rename que falló, comprobar y cotejar el estado del destino. Si el nombre final incluye un identificador de procesamiento (un número de albarán o un GUID de ejecución), se puede determinar que “ya existe un archivo final con ese mismo ID, es decir, que el rename anterior en realidad tuvo éxito” y salir tratándolo como un éxito; y el receptor también puede rechazar la doble importación por la duplicidad del ID.

6. Control de exclusión a través de SMB y la fiabilidad de FileSystemWatcher

6.1. No confíe ciegamente en los bloqueos

Una carpeta compartida puede recibir acceso simultáneo de varios clientes. Si se abre con FileShare.None, la exclusión mientras el archivo permanece abierto funciona incluso a través de SMB, pero un diseño que se apoya en la idea de que “si se consiguió el bloqueo, es seguro” se viene abajo cuando se pierde el handle por una desconexión, o cuando se mezcla algún actor que no toma el bloqueo (una copia manual, otro sistema). El núcleo de la exclusión no debe residir en el bloqueo del sistema operativo, sino en el propio protocolo de entrega: temp -> rename, una reclamación atómica (claim, donde solo el que gana el rename de incoming a processing procesa el archivo) e idempotencia. Los detalles de este planteamiento se dejan al artículo sobre control de exclusión mencionado arriba.

6.2. La realidad de usar FileSystemWatcher en un recurso compartido remoto

FileSystemWatcher está documentado oficialmente como compatible con la monitorización de archivos no solo en local, sino también en unidades de red y equipos remotos.14 Usarlo por sí mismo es legítimo. Pero hay dos condiciones que afectan a su fiabilidad.

  • Las notificaciones llegan a través de un búfer, y si se desborda, se pierden. Si los cambios se concentran en poco tiempo, los eventos que superan el tamaño del búfer se pierden.14
  • Cuando la monitorización es a través de la red, el límite de InternalBufferSize queda restringido a 64 KB. Está documentada explícitamente esta limitación, más estricta que en local, de que “no se puede ampliar tanto”.14

Además, hemos visto repetidamente, en investigaciones de fallos sobre el terreno, el síntoma de que, cuando se produce un reinicio o un corte al otro lado del recurso compartido, la monitorización simplemente muere en silencio y deja de llegar ninguna notificación. La conclusión práctica es asumir que el FileSystemWatcher sobre un recurso remoto es solo “una pista para darse cuenta antes”, y convertir en la fuente de verdad el escaneo completo periódico (sondeo, polling) al iniciar, ante errores y de forma regular. El patrón de diseño, incluyendo el tratamiento de los eventos duplicados y del desorden en la secuencia, se detalla en la «Guía práctica de FileSystemWatcher».

7. Reglas prácticas del oficio (tabla de decisión)

Resumimos todo lo anterior en una tabla de decisión, organizada por cada punto que suele generar dudas al diseñar.

Punto Opciones Criterio de decisión
Cómo mantener la ruta Letra de unidad / Ruta UNC La ruta que maneja la aplicación siempre debe ser UNC. La letra de unidad se asume como una comodidad de pantalla para el usuario2
Escritura en el recurso compartido Escritura directa / temp -> rename La escritura directa no garantiza que “no se lea un archivo a medio terminar”. La base es la promesa de que el nombre final equivale a completado
Detección de archivos nuevos Solo FileSystemWatcher / Sondeo (polling) / Combinación de ambos En un recurso compartido remoto, se da por hecho que se pierden eventos. Si un intervalo de varios minutos es aceptable, usar solo sondeo es más simple y robusto. Si se necesita inmediatez, combinar ambos14
Cuenta de ejecución del servicio LocalSystem / Cuenta de dominio / gMSA Si hay acceso a recursos compartidos, use una cuenta de dominio o una gMSA. Si el entorno admite gMSA, se elimina también toda la gestión operativa de la contraseña1
Cuando hacen falta credenciales aparte Ejecutar net use desde el código / WNetAddConnection2 / registro previo con cmdkey No se recomienda net use dentro de un servicio. Como varias credenciales contra el mismo servidor chocan con el error 1219, evítelo desde la fase de diseño consolidando cuentas o usando un alias DNS210
Acceso directo desde muchos clientes Cada equipo accede directamente por UNC / A través de un servicio intermedio (API) Cuando el número de equipos multiplicado por las credenciales y el acceso simultáneo deje de ser manejable, consolide el acceso al recurso compartido en un único servicio y haga que los clientes hablen mediante una API

Conviene ampliar la última fila. La integración mediante carpeta compartida es cómoda, pero cuantos más orígenes de acceso hay, más difícil se vuelve, de forma exponencial, gestionar “quién tiene qué permisos” y “quién compite con quién”. Superada cierta escala, conviene consolidar en un único servicio de Windows el proceso que toca el servidor de archivos, y que cada cliente hable con él mediante HTTP o gRPC. Degradar la carpeta compartida de ser “la interfaz entre sistemas” a ser “un detalle de implementación interno de ese servicio” es, a largo plazo, la forma más fácil de mantener.

8. Resumen

  • Las letras de unidad no son más que un símbolo por sesión de inicio de sesión. Que no sean visibles para otro usuario, un proceso elevado o un servicio es el comportamiento previsto, y el camino correcto es que la aplicación trabaje con rutas UNC. EnableLinkedConnections es una solución alternativa no compatible.
  • El acceso a un recurso compartido desde un servicio exige UNC. Como quién se autentica lo determina la cuenta de ejecución: LocalSystem y NetworkService usan las credenciales del equipo, y LocalService, credenciales anónimas. En la práctica se otorgan los permisos del recurso compartido a una cuenta de dominio o a una gMSA.
  • Las conexiones simultáneas con varias credenciales al mismo servidor fallan con el error 1219 (comportamiento previsto). Se evita desde la fase de diseño consolidando cuentas o usando un alias DNS.
  • El comportamiento normal de un recurso compartido es “lento, se desconecta y a veces no está disponible”. La desconexión por inactividad (15 minutos de forma predeterminada) no es una anomalía, y el false de File.Exists no se puede distinguir de un fallo de red. Incorpore juntos los reintentos, el patrón temp -> rename y la idempotencia.
  • FileSystemWatcher admite la monitorización remota, pero, como existe la posibilidad de perder eventos por desbordamiento del búfer y un límite de 64 KB, la regla del oficio es combinarlo con un escaneo completo.
  • Si tiene dudas, consulte la tabla de decisión del capítulo 7. Si la escala crece, considere también consolidar en un servicio intermedio el proceso que toca el recurso compartido.

Artículos relacionados

Áreas de consultoría relacionadas

KomuraSoft LLC se encarga del diseño e implementación de sistemas de integración de archivos a través de carpetas compartidas, del estudio de la configuración de permisos de acceso y autenticación al convertir una aplicación en servicio de Windows, y de la investigación de fallos como “al convertirlo en servicio deja de verse el recurso compartido” o “falla solo en un entorno concreto”.

Referencias

  1. Microsoft Learn, Group Managed Service Accounts overview. Sobre que la gMSA es una cuenta de dominio que ofrece administración automática de contraseñas y simplificación de la gestión de SPN, permitiendo delegar la gestión de la contraseña al sistema operativo Windows.  2 3 4 5 6 7 8

  2. Microsoft Learn, Services and Redirected Drives. Sobre que las letras de unidad no son globales para el sistema sino que se asignan por cada sesión de inicio de sesión, que un servicio no puede acceder a las letras de unidad de otra sesión y debe usar el nombre UNC, los motivos por los que se desaconseja la asignación de unidades dentro de un servicio mediante net use o las funciones WNet (fuga de credenciales, interferencia entre servicios, etc.), que incluso un servicio configurado con una cuenta de usuario obtiene una nueva sesión de inicio de sesión, y que se recomienda la suplantación del cliente en lugar de que el servicio acumule credenciales.  2 3 4 5 6 7 8 9 10 11 12

  3. Microsoft Learn, Mapped drives are not available from an elevated prompt when UAC is configured to Prompt for credentials. Sobre que, con UAC habilitado, se crean dos sesiones de inicio de sesión enlazadas, que la entidad real de la asignación de unidad es un objeto de enlace simbólico (DosDevices) específico de cada sesión de inicio de sesión y que no se comparte entre sesiones, y que EnableLinkedConnections fuerza a escribir el enlace simbólico en ambas sesiones.  2 3

  4. Microsoft Learn, Folder Redirection fails to apply when redirected to mapped drive letter, instead of UNC path. Sobre que, al iniciar sesión un administrador, la LSA crea dos tokens de acceso y la unidad se asigna con el token estándar, el procedimiento para configurar el valor de registro EnableLinkedConnections junto con la advertencia de que “puede hacer que el sistema sea menos seguro y Microsoft no lo admite”, y que siempre se recomienda usar la ruta UNC en lugar de la letra de unidad.  2 3

  5. Microsoft Learn, LocalSystem Account. Sobre que LocalSystem tiene amplios privilegios en local y presenta las credenciales del equipo a los servidores remotos en la red.  2 3

  6. Microsoft Learn, NetworkService Account. Sobre que NetworkService tiene privilegios mínimos en local y presenta las credenciales del equipo a los servidores remotos en la red.  2 3

  7. Microsoft Learn, LocalService Account. Sobre que LocalService presenta credenciales anónimas en la red.  2

  8. Microsoft Learn, About Service Logon Accounts. Sobre que la cuenta de inicio de sesión del servicio determina el contexto de seguridad en tiempo de ejecución, y que un servicio que se ejecuta con el contexto de seguridad de una cuenta de usuario local no puede acceder a recursos de red.  2

  9. Microsoft Learn, Create a Key Distribution Service (KDS) Root Key. Sobre que el controlador de dominio necesita la clave raíz de KDS para generar la contraseña de la gMSA, que se crea con Add-KdsRootKey -EffectiveImmediately, que no se puede crear una gMSA hasta un máximo de 10 horas después de la creación, mientras no converja la replicación de AD en todos los controladores de dominio (una medida de seguridad para evitar la generación de la contraseña antes de que todos los DC puedan atender las solicitudes de gMSA), y que ejecutar los comandos de administración de gMSA requiere una arquitectura de 64 bits.  2 3 4

  10. Microsoft Learn, The network folder specified is currently mapped using a different user name and password error. Sobre que el error al intentar establecer varias conexiones al mismo servidor con credenciales distintas es un comportamiento intencionado (by design), y que las soluciones alternativas son conectarse por dirección IP o crear otro alias DNS.  2 3 4

  11. Microsoft Learn, System Error Codes (1000-1299). Sobre la definición y el mensaje del error 1219 (ERROR_SESSION_CREDENTIAL_CONFLICT).  2

  12. Microsoft Learn, Mapped drive connection to network share may be lost. Sobre que una conexión inactiva se desconecta de forma predeterminada tras un tiempo de espera de 15 minutos (autodisconnect), que aparece la conocida cruz roja en el icono de la unidad en el Explorador de archivos pero se reconecta rápidamente al acceder, que net config server /autodisconnect:<minutos> permite cambiar el tiempo de espera con un valor máximo de 65535, que asignar 0 no deshabilita la función sino que hace que se desconecte tras unos segundos de inactividad, que -1 deshabilita la función, que en el registro del lado del servidor, autodisconnect en HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanserver\parameters, solo permite cambiar el tiempo de espera y no deshabilitar la función, que existe KeepConn (REG_DWORD, de 1 a 65535 segundos, 600 segundos de forma predeterminada) en el registro del lado del cliente en HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\lanmanworkstation\parameters, y que la sesión se desconecta según el valor más corto entre autodisconnect y KeepConn.  2 3 4

  13. Microsoft Learn, File.Exists(String) Method. Sobre que devuelve false sin lanzar una excepción cuando no hay permiso de lectura, y que también devuelve false cuando se produce algún error durante la comprobación de existencia (ruta no válida, fallo de disco, falta de permisos, etc.).  2

  14. Microsoft Learn, FileSystemWatcher Class. Sobre que admite la monitorización de archivos en el equipo local, en unidades de red y en equipos remotos, que puede perder eventos cuando se supera el tamaño del búfer, y que el valor máximo de InternalBufferSize es de 64 KB cuando la monitorización es a través de la red.  2 3 4 5

  15. Microsoft Learn, WNet Functions. Sobre que WNetGetUniversalName es la función que obtiene el nombre en formato universal (UNC) a partir de una ruta basada en letra de unidad. 

  16. Microsoft Learn, Secure group managed service accounts. Sobre que la contraseña de la gMSA es una generación aleatoria de 240 bytes que el sistema operativo cambia automáticamente cada 30 días, eliminando la necesidad de planificar el cambio de contraseña o detener el servicio por parte del administrador.  2

  17. Microsoft Learn, Service Accounts and BITS. Sobre que la autenticación en red de LocalSystem/NetworkService se realiza con las credenciales del equipo y la de LocalService con credenciales anónimas, que se produce acceso denegado cuando la ACL está limitada a una cuenta de usuario, y que las cuentas del sistema no deberían usar unidades asignadas. 

  18. Microsoft Learn, cmdkey. Sobre que el comando cmdkey permite crear, listar y eliminar nombres de usuario y contraseñas (credenciales) guardados. 

  19. Microsoft Learn, Credentials processes in Windows authentication. Sobre que el Administrador de credenciales guarda las credenciales en el contenedor de credenciales de Windows y las presenta automáticamente en autenticaciones posteriores. 

  20. Microsoft Learn, Client Access to Network Resources. Sobre que, como estrategia para que un proceso de servidor acceda a recursos de red, se menciona el establecimiento de una conexión mediante WNetAddConnection2 especificando las credenciales del cliente. 

  21. Microsoft Learn, SMB file server share access is unsuccessful through DNS CNAME alias. Sobre que una de las causas de que el acceso SMB a través de un CNAME falle es la falta de un SPN registrado para el alias, y que se recomienda definir el alias con el comando netdom computername en lugar de con un CNAME de DNS.  2

  22. Microsoft Learn, Net use. Sobre que, ejecutado sin parámetros, muestra la lista de conexiones de red, que net use <nombre-de-dispositivo> muestra la información de una conexión concreta, que se puede especificar * en la contraseña para que se solicite de forma interactiva, que /user permite indicar otro nombre de usuario, y que /delete con * desconecta todas las conexiones de red.  2

  23. Microsoft Learn, Windows Networking Operations. Sobre que la conexión persistente (persistent connection) es una conexión de red que el sistema restaura automáticamente al iniciar sesión el usuario. 

  24. Microsoft Learn, System Error Codes (0-499). Sobre las definiciones de ERROR_BAD_NETPATH (53), ERROR_UNEXP_NET_ERR (59), ERROR_NETNAME_DELETED (64) y ERROR_SEM_TIMEOUT (121). 

Artículos recientes con las mismas etiquetas para profundizar en temas cercanos.

Estas páginas sitúan el tema en un contexto más amplio de servicios y decisiones.

El artículo está directamente relacionado con los siguientes servicios.

Preguntas frecuentes

Preguntas habituales en las consultas sobre el tema del artículo.

¿Por qué un servicio de Windows no puede acceder a una unidad de red (Z:)?
Porque la letra de unidad no es un recurso del sistema en su conjunto, sino algo que existe por cada sesión de inicio de sesión. La Z: que un usuario asigna desde el Explorador de archivos es solo un símbolo que pertenece a la sesión de inicio de sesión de ese usuario, y no es visible para un servicio que se ejecuta en una sesión de inicio de sesión distinta. Aunque el servicio se ejecute con la misma cuenta de usuario, el sistema crea una nueva sesión de inicio de sesión para el servicio, de modo que la asignación hecha en el escritorio no se hereda, ni siquiera con la misma cuenta. La forma correcta de acceder desde un servicio es usar la ruta UNC \\server\share.
¿Cómo puede un servicio que se ejecuta como LocalSystem acceder a una carpeta compartida?
En la red, LocalSystem se autentica con las credenciales del equipo. En un entorno de dominio, se puede conceder acceso otorgando permisos, en el lado del recurso compartido (tanto en los permisos de uso compartido como en la ACL de NTFS), a la cuenta de equipo de esa máquina (DOMAIN\MACHINE$). Sin embargo, este enfoque es poco práctico de operar, porque al sustituir la máquina hay que rehacer la configuración de permisos. En la práctica, se recomienda configurar la cuenta de ejecución del servicio como una cuenta de dominio o una gMSA (group Managed Service Account, cuenta de servicio administrada por grupo) y otorgar los permisos del recurso compartido a esa cuenta.
¿Es correcto monitorizar archivos en una carpeta compartida con FileSystemWatcher?
Se puede usar, pero no confíe en él por sí solo. FileSystemWatcher admite la monitorización de unidades de red y de equipos remotos, pero las notificaciones de cambio llegan a través de un búfer, así que si las notificaciones se concentran en poco tiempo, el búfer se desborda y se pierden eventos. Además, cuando la monitorización es a través de la red, el límite del búfer queda restringido a 64 KB. La regla del oficio es tratar las notificaciones como un simple «disparador para volver a escanear» y combinarlas siempre con un escaneo completo periódico (sondeo, o polling) al iniciar, ante errores y de forma regular.
¿Cómo se diseña una integración de archivos resistente a los cortes de red?
Se diseña partiendo de la base de que «el recurso compartido es lento, se desconecta y a veces no está disponible» como comportamiento normal. En concreto: escribir con un nombre de archivo temporal y publicarlo renombrándolo después de cerrarlo (temp -> rename), envolver las operaciones de lectura y escritura en reintentos, y distinguir entre errores de red temporales y errores de negocio. Tenga en cuenta que File.Exists también devuelve false cuando no se puede acceder al recurso, por lo que no permite distinguir entre «el archivo no existe» y «no se puede llegar al servidor»; la última línea de defensa es diseñar un procesamiento idempotente que no se rompa aunque se vuelva a ejecutar.

Perfil del autor

Página de presentación del autor del artículo.

Go Komura

Representante de KomuraSoft LLC

Especializado en desarrollo de software para Windows, consultoría técnica e investigación de fallos, sobre todo en proyectos con sistemas existentes y errores difíciles de reproducir.

Volver al blog