Uzyskiwanie dostępu do folderów współdzielonych na innych serwerach z poziomu aplikacji ASP.NET Core (wersja programu połączonego z siecią)

Strona zaktualizowana :
Data utworzenia strony :

Środowisko weryfikacji działania

Visual Studio
  • informacji o wersji Visual Studio 2022
ASP.NET Rdzeń
  • 8 (strony brzytwy, MVC)
Serwer z systemem Windows
  • 2022 (ASP.NET podstawowe wymagania systemowe)
  • 2019 (serwer wdrażania folderów współdzielonych)
Usługi IIS
  • 10.0

Środowisko pracy

Nie przetestowaliśmy go we wszystkich przypadkach, ale powinien działać ogólnie w następujących warunkach:

Visual Studio
  • Wszystko, co może rozwinąć projekt ASP.NET Core
ASP.NET Rdzeń
  • Dowolna wersja (MVC, Razor Pages, API)
Serwer z systemem Windows
  • Windows Server 2008 lub nowszy
Usługi IIS
  • 7.0 lub nowszy

Warunek wstępny

  • ASP.NET Podstawowe aplikacje są przeznaczone do uruchamiania w usługach IIS.
  • Ponieważ używa interfejsów API systemu Windows do uwierzytelniania, nie działa w systemach innych niż Windows.

środowisko

Jest on weryfikowany w następującym środowisku.

Cel korzystania z komputerów PC i serwerów
Windows 11 (lokalny) Środowisko do tworzenia programów.
Test SV2022 Środowisko, w którym działają usługi IIS i ASP.NET Core. Uzyskaj dostęp do folderu współdzielonego SV2019Test z tego miejsca
Test SV2019 Serwery z folderami udostępnionymi

Ponadto różne ustawienia są następujące.

Nazwa parametru Wartość
Uzyskaj dostęp do nazwy użytkownika Współdzielony użytkownik
Nazwa folderu udostępnionego Folder współdzielony

Budowanie serwera folderów współdzielonych

Tworzenie użytkownika

Utwórz użytkownika, aby uzyskać dostęp do wspólnego folderu. W takim przypadku utworzymy konto lokalne, ale jeśli masz do czynienia z serwerami i kontami w domenie takiej jak Active Directory, możesz również z niego skorzystać.

Proces tworzenia użytkownika wykracza poza zakres tych wskazówek, więc nie będziemy wchodzić w szczegóły.

SharedUser W takim przypadku utworzymy go pod nazwą . Ponieważ ten użytkownik nie obsługuje ekranu ani nie zmienia ustawień, nie można zmienić hasła.

Jeśli pozostawisz ustawienie domyślne, możesz zalogować się za pomocą tego użytkownika za pomocą Pulpitu zdalnego itp., więc usuń go z grupy Users .

Tworzenie folderu udostępnionego

Nie ma znaczenia, gdzie go utworzysz. Dzieje się tak, ponieważ inne serwery nie dbają o lokalizację folderu fizycznego. W takim przypadku utworzymy folder o nazwie bezpośrednio pod SharedFolder dyskiem C i udostępnimy go.

Otwórz właściwości i skonfiguruj ustawienia udostępniania.

Nazwa folderu udostępnionego powinna być następująca SharedFolder . Ta nazwa będzie widoczna dla innych serwerów. Dodaj SharedUser uprawnienia.

Everyone Usuń istniejący plik .

Potwierdź za pomocą uprawnienia "Zmień".

Ponieważ dodaliśmy tylko uprawnienia, do których można uzyskać dostęp z zewnątrz, ustawimy je wewnętrznie SharedUser , aby mogły działać w tym folderze.

Potwierdź za pomocą uprawnienia "Zmień".

Utwórz plik, aby sprawdzić operację. W tym programie kodowanie jest przetwarzane w UFT-8, więc zapisz je w UTF-8.

Nie ma nic złego w tym, że możesz uzyskać dostęp do Eksploratora z \\<サーバー名>\ innego komputera, zalogowaćSharedUser się za pomocą i wyświetlić plik.

Tworzenie programu do odczytu i zapisu plików z folderu udostępnionego z aplikacji ASP.NET Core

Operacja Mr./Ms. polega na kliknięciu przycisku.

  • Załaduj pliki do folderu udostępnionego i wyświetl je na ekranie
  • Zapisywanie nowego pliku w folderze udostępnionym

proces.

Razor Pages i kod MVC są tego przykładami, ale program, który uzyskuje dostęp do folderu udostępnionego, jest taki sam dla obu. To samo dotyczy internetowych interfejsów API. Jeśli już, to powinien działać również w programie klienckim.

Proces, który łączy się z siecią na czas trwania określonego procesu

Utwórz następujący kod w dowolnym miejscu w projekcie. Nazwa klasy to SharedFolderAccessor , ale nazwa jest dowolna. SharedFolderAccessor Dostęp do folderu udostępnionego można uzyskać do momentu utworzenia instancji Dispose klasy . using Umożliwia określenie okresu, w którym dostęp do programu Access może być uzyskiwany w jawnym zakresie.

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

Ponieważ korzysta z interfejsów API Win32 i WNetAddConnection2 WNetCancelConnection2 , działa tylko w środowisku Windows. Na razie mam komentarz, ale jeśli chcesz dowiedzieć się więcej, poszukaj go w Internecie. Oprócz folderów udostępnionych można również wykonywać operacje w celu uzyskania dostępu do zasobów sieciowych.

Jest łatwy w użyciu, a jeśli napiszesz następujące informacje, możesz using uzyskać dostęp do folderu udostępnionego podczas zakresu.

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

Jednak w rzeczywistości WNetCancelConnection2 połączenie nie jest natychmiast rozłączane w momencie wywołania , dzięki czemu using możesz uzyskać dostęp do folderu współdzielonego nawet po zasięgu.

Testowanie kodu przy użyciu SharedFolderAccessor

Ponieważ proces uzyskiwania dostępu do folderu współdzielonego nie zależy od struktury, tworzymy wspólną metodę testowania, która odczytuje i zapisuje pliki. Pazor Pages i MVC powinny nazywać się tak samo.

Zawartość jest procesem, który zapisuje tekst przekazany do argumentu do folderu udostępnionego, odczytuje plik tekstowy znajdujący się już w folderze udostępnionym i zwraca tekst.

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

Strony brzytwy

W Razor Pages umieszczamy przycisk w pliku Index.cshtml, klikamy go, uruchamiamy kod testowy i wyświetlamy wyniki na ekranie. W niektórych przypadkach folder udostępniony może być niedostępny, więc jest on ujęty w 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 (Kodeks Zarządzania

Podobnie w przypadku MVC Index.cshtml przycisk jest umieszczany w , a po kliknięciu wywołuje kod testowy folderu współdzielonego.

Kontrolery/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>
@* ここまで追加 *@

Potwierdzenie działania

Debuguj i sprawdź, czy możesz pomyślnie uzyskać dostęp do folderu udostępnionego.

Budowanie serwera aplikacji

Ponieważ potwierdziliśmy, że dostęp do folderu współdzielonego można uzyskać, uruchamiając program, następny krok jest niepotrzebny. Jeśli chcesz sprawdzić działanie na serwerze IIS, możesz to zrobić, wykonując poniższe czynności.

Stąd jest to dodatek, więc nie będę tego zbyt szczegółowo wyjaśniał, ale głównie wyjaśnię obraz.

Instalowanie usług IIS

Zainstaluj go domyślnie z poziomu Menedżera serwera. Nie będę wchodził w szczegóły procedury.

Nie są wymagane żadne dodatkowe funkcje.

Obecnie nie są wymagane żadne dodatkowe usługi usług IIS.

Instalacja pakietu hostingowego ASP.NET Core Runtime

Ponieważ używamy ASP.NET Core 8, musimy odpowiednio zainstalować środowisko uruchomieniowe. Pobierz go z następującego adresu URL:

Aby uruchomić ASP.NET Core w usługach IIS, potrzebujesz czegoś, co nazywa się "Hosting Bundle". Pobierz "Hosting Bundle" z ASP.NET Core Runtime.

Po pobraniu uruchom go na serwerze.

Postępuj zgodnie z instrukcjami kreatora, aby go zainstalować.

Opublikuj swój program

Dane wyjściowe programu, który chcesz wdrożyć w usługach IIS jako plik z programu Visual Studio.

Zmodyfikuj go dla systemu Windows.

Opublikuj, gdy skończysz.

Jeśli klikniesz lokalizację docelową, możesz otworzyć folder, w którym znajduje się opublikowany plik.

Nie musisz zabierać ich wszystkich, ale jeśli nie jesteś pewien, możesz je wszystkie na razie zabrać. W tym momencie wszystko, co musisz zrobić, to upewnić się, że plik istnieje.

Tworzenie i wdrażanie aplikacji internetowych

W narzędziach administracyjnych systemu Windows otwórz Menedżera Internetowych usług informacyjnych (IIS).

Stworzymy witrynę, ale tym razem użyjemy "Domyślnej witryny internetowej", która jest tam od samego początku.

Po wybraniu opcji Domyślna witryna sieci Web kliknij przycisk Eksplorator, aby otworzyć folder. Skopiuj opublikowany program tutaj. Możesz usunąć oryginalny plik.

Otwórz stronę za pomocą łącza usług IIS i sprawdź, czy pojawi się ekran. Możesz najpierw otworzyć przeglądarkę internetową i bezpośrednio wprowadzić adres URL.

Potwierdzenie działania

Kliknij przycisk, aby sprawdzić, czy działa bez żadnych problemów. W powyższym przypadku dostęp do niego uzyskuje się z poziomu serwera WWW, ale ponieważ jest to serwer WWW, powinno być możliwe sterowanie nim z innych komputerów.