Acceso a carpetas compartidas en otros servidores desde una aplicación ASP.NET Core (versión del programa conectado a la red)

Actualización de la página :
Fecha de creación de la página :

Entorno de verificación de la operación

Visual Studio
  • Visual Studio 2022
ASP.NET Núcleo
  • 8 (Razor Pages, MVC)
Servidor de Windows
  • 2022 (ASP.NET requisitos básicos del sistema)
  • 2019 (servidor de implementación de carpetas compartidas)
IIS
  • 10.0

Entorno operativo

No lo hemos probado en todos los casos, pero debería funcionar generalmente bajo las siguientes condiciones:

Visual Studio
  • Cualquier cosa que pueda desarrollar un proyecto ASP.NET Core
ASP.NET Núcleo
  • Cualquier versión (MVC, Razor Pages, API)
Servidor de Windows
  • Windows Server 2008 o posterior
IIS
  • 7.0 o posterior

precondición

  • ASP.NET aplicaciones principales están pensadas para ejecutarse en IIS.
  • Dado que usa las API de Windows para la autenticación, no funciona en equipos que no sean de Windows.

medio ambiente

Se verifica en el siguiente entorno.

Finalidad de uso de los ordenadores y servidores
Windows 11 (local) Un entorno para el desarrollo de programas.
Prueba SV2022 Un entorno que ejecuta IIS y ASP.NET Core. Acceda a la carpeta compartida SV2019Test desde aquí
SV2019Prueba Servidores con carpetas compartidas

Además, los distintos ajustes son los siguientes.

parámetro
Valor del nombre del
Acceder al nombre de usuario SharedUser
Nombre de la carpeta compartida SharedFolder

Creación de un servidor de carpetas compartidas

Crear un usuario

Cree un usuario para acceder a la carpeta común. En este caso, crearemos una cuenta local, pero si está tratando con servidores y cuentas en un dominio como Active Directory, también puede usarla.

El proceso de creación de un usuario está más allá del alcance de estos consejos, por lo que no entraremos en demasiados detalles.

SharedUser En este caso, lo crearemos con el nombre . Dado que este usuario no opera la pantalla ni cambia la configuración, la contraseña no se puede cambiar.

Si deja el valor predeterminado, puede iniciar sesión con este usuario con Escritorio remoto, etc., así que elimínelo del grupo Users .

Creación de una carpeta compartida

No importa dónde lo crees. Esto se debe a que a otros servidores no les importa la ubicación de la carpeta física. En este caso, crearemos una carpeta nombrada directamente debajo SharedFolder de la unidad C y la compartiremos.

Abra las propiedades y configure los ajustes de uso compartido.

El nombre de la carpeta compartida debe SharedFolder ser . Este nombre será visible para otros servidores. Agregue SharedUser los permisos.

Everyone Elimine el archivo .

Confirme con el permiso "Cambiar".

Dado que solo hemos agregado permisos a los que se puede acceder desde el exterior, lo configuraremos internamente SharedUser para que pueda operar en esta carpeta.

Confirme con el permiso "Cambiar".

Cree un archivo para comprobar la operación. En este programa, la codificación se procesa en UFT-8, así que guárdela en UTF-8.

Está bien si puede acceder al Explorador desde \\<サーバー名>\ otra PC, iniciar sesiónSharedUser con y ver el archivo.

Crear un programa para leer y escribir archivos desde una carpeta compartida desde una aplicación ASP.NET Core

La operación Sr./Sra. es hacer clic en el botón.

  • Cargue archivos en una carpeta compartida y muéstrelos en la pantalla
  • Escribir un nuevo archivo en una carpeta compartida

proceso.

Razor Pages y el código MVC son ejemplos de esto, pero el programa que accede a la carpeta compartida es el mismo para ambos. Lo mismo ocurre con las API web. En todo caso, también debería funcionar en el programa cliente.

Un proceso que se conecta a una red durante la duración de un proceso específico

Cree el siguiente código en cualquier parte del proyecto. El nombre de la clase es SharedFolderAccessor , pero el nombre es arbitrario. SharedFolderAccessor Puede acceder a la carpeta compartida hasta que cree una Dispose instancia de . using Permite especificar el período de tiempo durante el cual se puede acceder al acceso en un ámbito explícito.

using System.ComponentModel;
using System.Net;
using System.Runtime.InteropServices;

/// <summary>
/// 共有フォルダにユーザー名とパスワードでアクセスするためのクラスです。
/// using を使用すればそのスコープの間、共有フォルダにアクセスできます。
/// </summary>
public class SharedFolderAccessor : IDisposable
{
  private readonly string _networkName;

  /// <summary>
  /// コンストラクタです。
  /// </summary>
  /// <param name="networkName">共有フォルダのあるサーバーを「\\&lt;サーバー名&gt;」形式で指定します。</param>
  /// <param name="credentials">共有フォルダにアクセスするための資格情報です。</param>
  /// <exception cref="Win32Exception"></exception>
  public SharedFolderAccessor(string networkName, NetworkCredential credentials)
  {
    _networkName = networkName;

    // 接続するネットワークの情報を設定
    var netResource = new NetResource
    {
      Scope = ResourceScope.GlobalNetwork,
      ResourceType = ResourceType.Disk,
      DisplayType = ResourceDisplaytype.Share,
      RemoteName = networkName,
    };

    // ドメインがある場合はドメイン名も指定、ない場合はユーザー名のみ
    var userName = string.IsNullOrEmpty(credentials.Domain)
        ? credentials.UserName
        : $@"{credentials.Domain}\{credentials.UserName}";

    // 共有フォルダにユーザー名とパスワードで接続
    var result = WNetAddConnection2(netResource, credentials.Password, userName, 0);

    if (result != 0)
    {
      throw new Win32Exception(result, $"共有フォルダに接続できませんでした。(エラーコード:{result})");
    }

    // 正常に接続できれば WNetCancelConnection2 を呼び出すまではプログラムで共有フォルダにアクセス可能
  }

  ~SharedFolderAccessor()
  {
    // Dispose を呼び忘れたときの保険
    WNetCancelConnection2(_networkName, 0, true);
  }

  public void Dispose()
  {
    WNetCancelConnection2(_networkName, 0, true);
    GC.SuppressFinalize(this);  // Dispose を明示的に呼んだ場合はデストラクタの処理は不要
  }

  /// <summary>
  /// ネットワーク リソースへの接続を確立し、ローカル デバイスをネットワーク リソースにリダイレクトできます。
  /// </summary>
  /// <param name="netResource">ネットワーク リソース、ローカル デバイス、ネットワーク リソース プロバイダーに関する情報など。</param>
  /// <param name="password">ネットワーク接続の作成に使用するパスワード。</param>
  /// <param name="username">接続を確立するためのユーザー名。</param>
  /// <param name="flags">接続オプションのセット。</param>
  /// <returns></returns>
  [DllImport("mpr.dll")]
  private static extern int WNetAddConnection2(NetResource netResource, string password, string username, int flags);

  /// <summary>
  /// 既存のネットワーク接続を取り消します。
  /// </summary>
  /// <param name="name">リダイレクトされたローカル デバイスまたは切断するリモート ネットワーク リソースの名前。</param>
  /// <param name="flags">接続の種類。</param>
  /// <param name="force">接続に開いているファイルまたはジョブがある場合に切断を行う必要があるかどうか。</param>
  /// <returns></returns>
  [DllImport("mpr.dll")]
  private static extern int WNetCancelConnection2(string name, int flags, bool force);

  /// <summary>
  /// NETRESOURCE 構造体を定義しています。
  /// </summary>
  [StructLayout(LayoutKind.Sequential)]
  private class NetResource
  {
    public ResourceScope Scope;
    public ResourceType ResourceType;
    public ResourceDisplaytype DisplayType;
    public int Usage;
    public string LocalName = "";
    public string RemoteName = "";
    public string Comment = "";
    public string Provider = "";
  }

  /// <summary>
  /// ネットワークリソースのスコープ。
  /// </summary>
  private enum ResourceScope : int
  {
    /// <summary>ネットワークリソースへの現在の接続。</summary>
    Connected = 1,
    /// <summary>すべてのネットワークリソース。</summary>
    GlobalNetwork = 2,
    Remembered = 3,
    Recent = 4,
    /// <summary>ユーザーの現在および既定のネットワークコンテキストに関連付けられているネットワークリソース。</summary>
    Context = 5,
  };

  /// <summary>
  /// リソースの種類。
  /// </summary>
  private enum ResourceType : int
  {
    /// <summary>印刷リソースとディスクリソースの両方のコンテナー、または印刷またはディスク以外のリソースなど。</summary>
    Any = 0,
    /// <summary>共有ディスクボリューム。</summary>
    Disk = 1,
    /// <summary>共有プリンター。</summary>
    Print = 2,
    Reserved = 8,
  }

  /// <summary>
  /// ユーザーインターフェイスで使用する必要がある表示の種類。
  /// </summary>
  private enum ResourceDisplaytype : int
  {
    /// <summary>リソースの種類を指定しないネットワークプロバイダーによって使用されます。</summary>
    Generic = 0x0,
    /// <summary>サーバーのコレクション。</summary>
    Domain = 0x01,
    /// <summary>サーバー。</summary>
    Server = 0x02,
    /// <summary>共有ポイント。</summary>
    Share = 0x03,
    File = 0x04,
    Group = 0x05,
    /// <summary>ネットワークプロバイダー。</summary>
    Network = 0x06,
    Root = 0x07,
    Shareadmin = 0x08,
    /// <summary>ディレクトリ。</summary>
    Directory = 0x09,
    Tree = 0x0a,
    Ndscontainer = 0x0b,
  }
}

Dado que utiliza las API de Win32 y WNetAddConnection2 WNetCancelConnection2 , solo funciona en el entorno de Windows. Tengo un comentario por el momento, pero si quieres saber más, búscalo en Internet. Además de las carpetas compartidas, también puede realizar operaciones para acceder a los recursos de red.

Es fácil de usar y, si escribe lo siguiente, using puede acceder a la carpeta compartida durante el ámbito.

using (new SharedFolderAccessor($@"\\{serverName}", credentials))
{
  // この間は共有フォルダにアクセスできる
}

Sin embargo, en realidad WNetCancelConnection2 , la conexión no se desconecta inmediatamente en el momento de la llamada , por lo que using puede acceder a la carpeta compartida incluso después del ámbito.

Probar el código mediante SharedFolderAccessor

Dado que el proceso de acceso a la carpeta compartida no depende del marco, creamos un método común para las pruebas que lee y escribe archivos. Pazor Pages y MVC deberían llamarse de la misma manera.

El contenido es un proceso que escribe el texto pasado al argumento en la carpeta compartida, lee el archivo de texto que ya está en la carpeta compartida y devuelve el texto.

using System.Net;

public static class Util
{
  public static string ReadAndWrite(string text)
  {
    var serverName = "ServerName";
    var folderName = "SharedFolder";
    var inputFileName = "Input.txt";
    var outputFileName = "Output.txt";
    var username = "SharedUser";
    var password = "password";

    var credentials = new NetworkCredential(username, password);
    using (new SharedFolderAccessor($@"\\{serverName}", credentials))
    {
      // ファイルの書き出し
      System.IO.File.WriteAllText(Path.Combine($@"\\{serverName}\{folderName}", outputFileName), text);

      // ファイルの読み込み
      return System.IO.File.ReadAllText(Path.Combine($@"\\{serverName}\{folderName}", inputFileName));
    }
  }
}

Páginas de afeitado

En Razor Pages, colocamos un botón en Index.cshtml, hacemos clic en él, ejecutamos el código de prueba y mostramos los resultados en la pantalla. En algunos casos, es posible que no se pueda acceder a la carpeta compartida, por lo que se incluye en un try-catch.

Index.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace SharedFolderAccessRazorPages.Pages
{
  public class IndexModel : PageModel
  {
    private readonly ILogger<IndexModel> _logger;
    public string Message { get; set; } = "";

    public IndexModel(ILogger<IndexModel> logger)
    {
      _logger = logger;
    }

    public void OnPost()
    {
      try
      {
        Message = Util.ReadAndWrite($"プログラムからの書き込み ({DateTime.Now})");
      }
      catch (Exception ex)
      {
        Message = ex.ToString();
      }
    }
  }
}

Index.cshtml

@page
@model IndexModel
@{
  ViewData["Title"] = "Home page";
}

<div class="text-center">
  <h1 class="display-4">Welcome</h1>
  <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

@* ここから追加 *@
<form method="post">
  <button type="submit">サブミット</button>
</form>

<div>
  @Model.Message
</div>
@* ここまで追加 *@

MVC (en inglés)

Del mismo modo, en el caso de MVC, Index.cshtml se coloca un botón en , y cuando se hace clic, llama al código de prueba de la carpeta compartida.

Controladores/HomeController.cs

// 省略

namespace SharedFolderAccessMvc.Controllers
{
  public class HomeController : Controller
  {
    // 省略

    public IActionResult Index()
    {
      return View();
    }

    // ここから追加
    [HttpPost]
    public IActionResult Index(string dummy)
    {
      try
      {
        ViewData["Message"] = Util.ReadAndWrite($"プログラムからの書き込み ({DateTime.Now})");
      }
      catch (Exception ex)
      {
        ViewData["Message"] = ex.ToString();
      }
      return View();
    }
    // ここまで追加

    public IActionResult Privacy()
    {
      return View();
    }

    // 省略
  }
}

Index.cshtml

@{
  ViewData["Title"] = "Home Page";
}

<div class="text-center">
  <h1 class="display-4">Welcome</h1>
  <p>Learn about <a href="https://learn.microsoft.com/aspnet/core">building Web apps with ASP.NET Core</a>.</p>
</div>

@* ここから追加 *@
<form method="post">
  <button type="submit">サブミット</button>
</form>

<div>
  @ViewData["Message"]
</div>
@* ここまで追加 *@

Confirmación de funcionamiento

Depurar y comprobar que puede acceder correctamente a la carpeta compartida.

Creación de un servidor de aplicaciones

Dado que hemos confirmado que se puede acceder a la carpeta compartida ejecutando el programa, el siguiente paso es innecesario. Si desea comprobar la operación en el servidor IIS, puede hacerlo siguiendo los pasos que se indican a continuación.

A partir de aquí, es un suplemento, por lo que no lo explicaré con demasiado detalle, sino que explicaré principalmente la imagen.

Instalación de IIS

Instálelo de forma predeterminada desde el Administrador del servidor. No voy a entrar en los detalles del procedimiento.

No se requieren funciones adicionales.

En este momento, no se requieren servicios adicionales de IIS.

Instalación del paquete de alojamiento de tiempo de ejecución ASP.NET Core

Dado que estamos usando ASP.NET Core 8, necesitamos instalar el tiempo de ejecución en consecuencia. Descárgalo desde la siguiente URL:

Para ejecutar ASP.NET núcleo en IIS, necesita algo llamado "Paquete de alojamiento". Descargue el "Paquete de alojamiento" de ASP.NET Core Runtime.

Una vez descargado, ejecútelo en el servidor.

Siga las instrucciones del asistente para instalarlo.

Publique su programa

Genere el programa que desea implementar en IIS como un archivo de Visual Studio.

Modifícalo para Windows.

Publique cuando haya terminado.

Si hace clic en la ubicación de destino, puede abrir la carpeta donde se encuentra el archivo publicado.

No es necesario que los traigas todos, pero si no estás seguro, puedes llevarlos todos por ahora. En este punto, todo lo que necesita hacer es asegurarse de que el archivo existe.

Creación e implementación de aplicaciones web

En Herramientas administrativas de Windows, abra el Administrador de Internet Information Services (IIS).

Crearemos un sitio, pero esta vez usaremos el "Sitio Web por defecto" que está ahí desde el principio.

Con la opción Sitio web predeterminado seleccionada, haga clic en el Explorador para abrir la carpeta. Copie el programa publicado aquí. Puede eliminar el archivo original.

Abra la página desde el vínculo IIS y vea si aparece la pantalla. Primero puede abrir un navegador web e ingresar la URL directamente.

Confirmación de funcionamiento

Haga clic en el botón para verificar que funciona sin ningún problema. En el caso anterior, se accede desde dentro del servidor web, pero al tratarse de un servidor web, debería ser posible operarlo desde otros PC.