Accés a carpetes compartides d'altres servidors des d'una aplicació ASP.NET Core (versió Network Connected Program)

Pàgina actualitzada :
Data de creació de la pàgina :

Entorn de verificació d'operacions

Estudi visual
  • Estudi visual 2022
ASP.NET Nucli
  • 8 (Navalles d'afaitar, MVC)
Windows Server
  • 2022 (ASP.NET requisits bàsics del sistema)
  • 2019 (Servidor compartit de desplegament de carpetes)
IIS
  • 10.0

Entorn operatiu

No l'hem provat en tots els casos, però hauria de funcionar generalment sota les condicions següents:

Estudi visual
  • Qualsevol cosa que pugui desenvolupar un projecte ASP.NET Core
ASP.NET Nucli
  • Qualsevol versió (MVC, Razor Pages, API)
Windows Server
  • Windows Server 2008 o posterior
IIS
  • 7.0 o posterior

Precondició

  • ASP.NET aplicacions bàsiques estan pensades per executar-se en IIS.
  • Com que utilitza API de Windows per a l'autenticació, no funciona en persones que no siguin Windows.

entorn

Es verifica en el següent entorn.

Finalitat de l'ús de PCs i servidors
Windows 11 (local) Un entorn per al desenvolupament de programes.
Test SV2022 Un entorn que executa IIS i ASP.NET Core. Accediu a la carpeta compartida SV2019Test des d'aquí
SV2019Test Servidors amb carpetes compartides

A més, els diversos paràmetres són els següents.

Valor del nom del paràmetre
Nom d'usuari d'accés Usuari compartit
Nom de la carpeta compartida Carpeta compartida

Creació d'un servidor de carpetes compartit

Crear un usuari

Creeu un usuari per accedir a la carpeta comuna. En aquest cas, crearem un compte local, però si esteu tractant amb servidors i comptes en un domini com l'Active Directory, també podeu utilitzar-lo.

El procés de creació d'un usuari està fora de l'abast d'aquests consells, de manera que no entrarem en massa detalls.

SharedUser En aquest cas, el crearem amb el nom . Com que aquest usuari no opera la pantalla ni canvia la configuració, la contrasenya no es pot canviar.

Si deixeu el valor per defecte, podeu iniciar sessió amb aquest usuari amb Escriptori remot, etc., així que elimineu-lo del grup Users .

Creació d'una carpeta compartida

No importa on el creeu. Això es deu al fet que a altres servidors no els importa la ubicació de la carpeta física. En aquest cas, crearem una carpeta anomenada directament sota SharedFolder la unitat C i la compartirem.

Obriu les propietats i configureu els paràmetres per compartir.

El nom de la carpeta compartida ha SharedFolder de ser . Aquest nom serà visible per a altres servidors. Afegiu SharedUser els permisos.

Everyone Suprimiu l'existent .

Confirmeu amb el permís "Canvia".

Com que només hem afegit permisos als quals es pot accedir des de l'exterior, ho configurarem internament SharedUser perquè pugui funcionar en aquesta carpeta.

Confirmeu amb el permís "Canvia".

Creeu un fitxer per comprovar l'operació. En aquest programa, la codificació es processa en UFT-8, així que deseu-la en UTF-8.

És correcte si podeu accedir a l'Explorer des d'un \\<サーバー名>\ altre PC, iniciar sessióSharedUser amb , i veure el fitxer.

Crear un programa per llegir i escriure arxius des d'una carpeta compartida des d'una aplicació ASP.NET Core

L'operació Sr./Sra. és clicar el botó.

  • Carregar arxius en una carpeta compartida i mostrar-los a la pantalla
  • Escriure un arxiu nou a una carpeta compartida

procés.

Razor Pages i codi MVC en són exemples, però el programa que accedeix a la carpeta compartida és el mateix per a tots dos. El mateix passa amb les API web. En tot cas, també hauria de funcionar en el programa client.

Un procés que es connecta a una xarxa durant la durada d'un procés específic

Crea el següent codi en qualsevol lloc del teu projecte. El nom de la classe és SharedFolderAccessor , però el nom és arbitrari. SharedFolderAccessor Pots accedir a la carpeta compartida fins que creïs una Dispose instància de . using Permet especificar el període de temps durant el qual es pot accedir a l'accés en un àmbit explícit.

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,
  }
}

Com que utilitza les API de Win32 i WNetAddConnection2 WNetCancelConnection2 , només funciona en l'entorn Windows. Tinc un comentari de moment, però si voleu saber-ne més, si us plau busqueu-lo a Internet. A més de les carpetes compartides, també pots fer operacions per accedir als recursos de xarxa.

És fàcil d'utilitzar i, si escriviu el següent, podeu using accedir a la carpeta compartida durant l'abast.

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

No obstant això, en realitat WNetCancelConnection2 , la connexió no es desconnecta immediatament en el moment de la trucada, de manera que using podeu accedir a la carpeta compartida fins i tot després de l'abast.

Codi de prova mitjançant SharedFolderAccessor

Com que el procés d'accés a la carpeta compartida no depèn del marc, creem un mètode comú per provar que llegeix i escriu arxius. Pazor Pages i MVC s'haurien d'anomenar igual.

El contingut és un procés que escriu el text passat a l'argument a la carpeta compartida, llegeix l'arxiu de text que ja és a la carpeta compartida i retorna el text.

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));
    }
  }
}

Navalles d'afaitar

A Razor Pages, col·loquem un botó a Index.cshtml, feu-hi clic, executeu el codi de prova i mostrem els resultats a la pantalla. En alguns casos, és possible que la carpeta compartida no sigui accessible, de manera que s'inclou en un intent.

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

De la mateixa manera, en el cas de MVC, Index.cshtml es col·loca un botó en , i en fer clic, crida al codi de prova de la carpeta compartida.

Controladors/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ó de l'operació

Depura i verifica que puguis accedir correctament a la carpeta compartida.

Construcció d'un servidor d'aplicacions

Com que hem confirmat que es pot accedir a la carpeta compartida executant el programa, el següent pas no és necessari. Si voleu comprovar el funcionament al servidor IIS, podeu fer-ho seguint els passos següents.

A partir d'aquí, és un suplement, així que no ho explicaré amb massa detall, sinó que explicaré principalment la imatge.

Instal·lació d'IIS

Instal·leu-lo per defecte des del Gestor de servidors. No entraré en els detalls del procediment.

No es requereixen funcions addicionals.

No es requereixen serveis IIS addicionals en aquest moment.

ASP.NET Instal·lació del paquet d'allotjament en temps d'execució bàsic

Com que estem utilitzant ASP.NET Core 8, hem d'instal·lar el temps d'execució en conseqüència. Descarrega-te-la des de la següent URL:

Per executar ASP.NET Core a IIS, necessiteu una cosa anomenada "Hosting Bundle". Baixeu el "Hosting Bundle" des del ASP.NET Core Runtime.

Un cop descarregat, executeu-lo al servidor.

Seguiu l'assistent per instal·lar-lo.

Publica el teu programa

Sortiu el programa que voleu implementar a IIS com a fitxer des del Visual Studio.

Modifiqueu-lo per a Windows.

Publica quan hagis acabat.

Si feu clic a la ubicació de destinació, podeu obrir la carpeta on es troba el fitxer publicat.

No cal que els portis tots, però si no n'estàs segur, pots portar-los tots de moment. En aquest punt, tot el que heu de fer és assegurar-vos que el fitxer existeix.

Creació i desplegament d'aplicacions web

Des de Windows Administrative Tools, obriu Internet Information Services (IIS) Manager.

Crearem un lloc, però aquesta vegada utilitzarem el "Lloc web per defecte" que hi ha des del principi.

Amb l'opció Lloc web per defecte seleccionada, feu clic a Explorador per obrir la carpeta. Copieu el programa publicat aquí. Podeu suprimir el fitxer original.

Obriu la pàgina des de l'enllaç IIS i comproveu si apareix la pantalla. Podeu obrir primer un navegador web i introduir l'URL directament.

Confirmació de l'operació

Feu clic al botó per verificar que funcioni sense cap problema. En l'anterior, s'accedeix des de dins del servidor web, però com que es tracta d'un servidor web, hauria de ser possible operar-lo des d'altres PC.