Åtkomst till delade mappar på andra servrar från ett ASP.NET Core-program (version av nätverksanslutet program)

Sidan uppdaterad :
Datum för skapande av sida :

Miljö för verifiering av åtgärder

Visuell studio
  • Visual Studio 2022
ASP.NET kärna
  • 8 (Razor Pages, MVC)
Windows Server
  • 2022 (ASP.NET grundläggande systemkrav)
  • 2019 (distributionsserver för delade mappar)
IIS (IIS)
  • 10.0

Omvärld

Vi har inte testat det i alla fall, men det bör fungera generellt under följande förhållanden:

Visuell studio
  • Allt som kan utveckla ett ASP.NET Core-projekt
ASP.NET kärna
  • Vilken version som helst (MVC, Razor Pages, API)
Windows Server
  • Windows Server 2008 eller senare
IIS (IIS)
  • 7.0 eller senare

förutsättning

  • ASP.NET Core-program är avsedda att köras på IIS.
  • Eftersom den använder Windows-API:er för autentisering fungerar den inte på icke-Windows.

miljö

Det verifieras i följande miljö.

Syfte med användning av datorer och servrar
Windows 11 (lokalt) En miljö för att utveckla program.
SV2022Test En miljö som kör IIS och ASP.NET Core. Öppna den delade mappen SV2019Test härifrån
SV2019Test Servrar med delade mappar

Dessutom är de olika inställningarna följande.

Parameternamn Värde
Åtkomst till användarnamn DeladUser
Namn på delad mapp DeladFolder

Bygga en server för delade mappar

Skapa en användare

Skapa en användare för att få åtkomst till den gemensamma mappen. I det här fallet kommer vi att skapa ett lokalt konto, men om du har att göra med servrar och konton i en domän som Active Directory kan du använda det också.

Processen att skapa en användare ligger utanför ramen för dessa tips, så vi kommer inte att gå in på för mycket detaljer.

SharedUser I det här fallet skapar vi den med namnet . Eftersom den här användaren inte använder skärmen eller ändrar inställningarna kan lösenordet inte ändras.

Om du lämnar standardinställningen kan du logga in med den här användaren med Fjärrskrivbord osv., så ta bort från gruppen Users .

Skapa en delad mapp

Det spelar ingen roll var du skapar den. Detta beror på att andra servrar inte bryr sig om platsen för den fysiska mappen. I det här fallet kommer vi att skapa en mapp med namnet direkt under SharedFolder C-enheten och dela den.

Öppna egenskaperna och konfigurera delningsinställningarna.

Namnet på den delade mappen ska SharedFolder vara . Det här namnet kommer att vara synligt för andra servrar. Lägg till SharedUser behörigheterna.

Everyone Ta bort den befintliga .

Bekräfta med behörigheten "Ändra".

Eftersom vi bara har lagt till behörigheter som kan nås utifrån, kommer vi att ställa in det internt SharedUser så att det kan fungera i den här mappen.

Bekräfta med behörigheten "Ändra".

Skapa en fil för att kontrollera åtgärden. I det här programmet bearbetas kodningen i UFT-8, så spara den i UTF-8.

Det är OK om du kan komma åt i Utforskaren från \\<サーバー名>\ en annan dator, logga inSharedUser med och visa filen.

Skapa ett program för att läsa och skriva filer från en delad mapp från ett ASP.NET Core-program

Herr/Fröken-funktionen är att klicka på knappen.

  • Ladda filer i en delad mapp och visa dem på skärmen
  • Skriva en ny fil till en delad mapp

process.

Razor Pages och MVC-kod är exempel på detta, men programmet som kommer åt den delade mappen är detsamma för båda. Samma sak gäller för webb-API:er. Om något borde det fungera i klientprogrammet också.

En process som ansluter till ett nätverk under en viss process

Skapa följande kod var som helst i projektet. Klassnamnet är SharedFolderAccessor , men namnet är godtyckligt. SharedFolderAccessor Du kan komma åt den delade mappen tills du skapar en Dispose instans av . using Gör att du kan ange den tidsperiod under vilken åtkomst kan nås i ett explicit omfång.

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

Eftersom den använder Win32-API:erna och WNetAddConnection2 WNetCancelConnection2 fungerar den bara i Windows-miljön. Jag har en kommentar tills vidare, men om du vill veta mer, slå upp den på Internet. Förutom delade mappar kan du även utföra åtgärder för att komma åt nätverksresurser.

Det är lätt att använda, och om du skriver följande kan du using komma åt den delade mappen under omfattningen.

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

Men i verkligheten WNetCancelConnection2 kopplas anslutningen inte omedelbart bort vid tidpunkten för anropet, så using du kan komma åt den delade mappen även efter omfånget.

Testa kod med SharedFolderAccessor

Eftersom processen för att komma åt den delade mappen inte är beroende av ramverket skapar vi en gemensam metod för testning som läser och skriver filer. Pazor Pages och MVC bör kallas likadana.

Innehållet är en process som skriver texten som skickas till argumentet till den delade mappen, läser textfilen som redan finns i den delade mappen och returnerar texten.

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

Razor Sidor

I Razor Pages placerar vi en knapp i Index.cshtml, klickar på den, kör testkoden och visar resultaten på skärmen. I vissa fall kanske den delade mappen inte är tillgänglig, så den är innesluten i en 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

På samma sätt, när det gäller MVC, Index.cshtml placeras en knapp i , och när du klickar på den anropar den testkoden för den delade mappen.

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

Bekräftelse av drift

Felsök och kontrollera att du har åtkomst till den delade mappen.

Skapa en programserver

Eftersom vi har bekräftat att den delade mappen kan nås genom att köra programmet är nästa steg onödigt. Om du vill kontrollera åtgärden på IIS-servern kan du göra det genom att följa stegen nedan.

Härifrån är det ett tillägg, så jag kommer inte att förklara det för mycket i detalj, utan kommer främst att förklara bilden.

Installera IIS

Installera det som standard från Serverhanteraren. Jag kommer inte att gå in på detaljerna i proceduren.

Inga ytterligare funktioner krävs.

Inga ytterligare IIS-tjänster krävs just nu.

ASP.NET Core Runtime Hosting Bundle Installation

Eftersom vi använder ASP.NET Core 8 måste vi installera körningen därefter. Ladda ner den från följande URL:

För att kunna köra ASP.NET Core i IIS behöver du något som kallas "Hosting Bundle". Ladda ned "Hosting Bundle" från ASP.NET Core Runtime.

När du har laddat ner kör du den på servern.

Följ guiden för att installera den.

Publicera ditt program

Mata ut det program som du vill distribuera till IIS som en fil från Visual Studio.

Ändra den för Windows.

Publicera när du är klar.

Om du klickar på målplatsen kan du öppna mappen där den publicerade filen finns.

Du behöver inte ta med dem alla, men om du inte är säker kan du ta dem alla för tillfället. Vid det här laget är allt du behöver göra att se till att filen finns.

Skapa och distribuera webbprogram

Öppna IIS-hanteraren (Internet Information Services) i Windows Administrationsverktyg.

Vi kommer att skapa en webbplats, men den här gången kommer vi att använda "Standardwebbplatsen" som finns där från början.

När du har valt Standardwebbplats klickar du på Utforskaren för att öppna mappen. Kopiera det publicerade programmet här. Du kan ta bort originalfilen.

Öppna sidan från IIS-länken och se om skärmen visas. Du kan öppna en webbläsare först och ange URL:en direkt.

Bekräftelse av drift

Klicka på knappen för att verifiera att det fungerar utan problem. I ovanstående nås den från webbservern, men eftersom det är en webbserver bör det vara möjligt att använda den från andra datorer.