asp.net core blazor: Изображения / файлы на сетевом ресурсе работают в течение 1 минуты, затем перестают работать

#c# #asp.net-core #blazor-server-side #static-files #fileshare

Вопрос:

Мое приложение хранит и извлекает фотоизображения из общего сетевого ресурса. Моя машина разработки-Windows 2018 под управлением Visual Studio 2019 на VMware.

Изображения отлично подходят при первом открытии приложения. Затем, примерно через 1 минуту (или около того), изображения 404.

В принципе, я пытаюсь реализовать что-то вроде классического asp.net виртуальный каталог в IIS. Это позволяет читать/записывать файлы через общий сетевой ресурс. Насколько я понимаю, это asp.net ядро разбивает виртуальные каталоги старой школы…

Я пробовал много вещей, таких как изменение расположения изображений в сети (разные физические машины). Не повезло. Я также пробовал различные реализации NetworkConnection (см. Код ниже). Nada.

Я также попытался использовать UseStaticFiles вместо UseFileServer:

 app.UseStaticFiles(new StaticFileOptions
                {
                    FileProvider = new PhysicalFileProvider(
                    Path.Combine("\\DESKTOP-QRDNRCJ\Images\Photos2")),
                    RequestPath = new PathString("/Photos2")
                });
 

И, наконец, я попробовал IP-адрес вместо сетевого имени машины.


Чтобы упростить отладку для stackoverflow, я создал совершенно новое решение Blazor с одной страницей, на которой отображаются только 3 изображения. Он также выходит из строя примерно через 1 минуту.

Интересно: иногда 2 из 3 изображений визуализируются в течение некоторого времени. Но в конце концов все 3 идут по 404.

Кроме того, иногда, когда я сохраняю файл по сети (используя мое полное приложение, которого нет ниже), оно сохраняет имя файла, но размер файла = 0 к.

Это расстраивает, потому что приложение вроде как работает в течение короткого времени. Поэтому я не допускаю опечатки или другой ошибки (насколько мне известно).

Вот несколько рекомендаций, которые помогли мне начать:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-5.0amp;tabs=aspnetcore2x#serve-files-outside-of-web-root

https://thecodeblogger.com/2021/05/17/network-path-for-static-files-in-asp-net-core-web-applications/

https://www.c-sharpcorner.com/article/virtual-directory-inside-of-asp-net-core-app-in-iis/

И вот мой код:

Простая страница с 3 изображениями:

 @page "/index"
@page "/"
<img src="Photos2/birthday.gif" /><img src="Photos2/bo.jpg" /><img src="Photos2/dotnet.png" />
 

Startup.cs

 using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using WebApplication2.Data;
using System.Net;
using Microsoft.Extensions.FileProviders;
using System.IO;
using Microsoft.AspNetCore.Http;

namespace WebApplication2
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddRazorPages();
            services.AddServerSideBlazor();
            services.AddSingleton<WeatherForecastService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                app.UseExceptionHandler("/Error");
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            app.UseHttpsRedirection();
            app.UseStaticFiles();

            var sourceCredentials = new NetworkCredential { Domain = "192.168.1.162", UserName = "ImageManager", Password = "qwer1234)" };

            using (new NetworkConnection("\\192.168.1.162\Images\Photos2", sourceCredentials))
            {
                app.UseFileServer(new FileServerOptions()
                {
                    FileProvider = new PhysicalFileProvider(
                        Path.Combine("\\192.168.1.162\Images\Photos2")),
                    RequestPath = new PathString("/Photos2"),
                    EnableDirectoryBrowsing = true
                });

            }

            app.UseRouting();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapBlazorHub();
                endpoints.MapFallbackToPage("/_Host");
            });
        }
    }
}
 

Класс для подключения к сети.

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

public class NetworkConnection : IDisposable
{
    readonly string _networkName;

    public NetworkConnection(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
            : string.Format(@"{0}{1}", credentials.Domain, credentials.UserName);

        var result = WNetAddConnection2(
            netResource,
            credentials.Password,
            userName,
            0);

        if (result != 0)
        {
            throw new Win32Exception(result, "Error connecting to remote share");
        }
    }

    ~NetworkConnection()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        WNetCancelConnection2(_networkName, 0, true);
    }

    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(NetResource netResource,
        string password, string username, int flags);

    [DllImport("mpr.dll")]
    private static extern int WNetCancelConnection2(string name, int flags,
        bool force);

    [StructLayout(LayoutKind.Sequential)]
    public 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;
    }

    public enum ResourceScope : int
    {
        Connected = 1,
        GlobalNetwork,
        Remembered,
        Recent,
        Context
    };

    public enum ResourceType : int
    {
        Any = 0,
        Disk = 1,
        Print = 2,
        Reserved = 8,
    }

    public enum ResourceDisplaytype : int
    {
        Generic = 0x0,
        Domain = 0x01,
        Server = 0x02,
        Share = 0x03,
        File = 0x04,
        Group = 0x05,
        Network = 0x06,
        Root = 0x07,
        Shareadmin = 0x08,
        Directory = 0x09,
        Tree = 0x0a,
        Ndscontainer = 0x0b
    }
}
 

скриншоты рендеринга изображений, то нет..

Комментарии:

1. Переход от одного пути к другому. Объединять бессмысленно

2. Да, лол, замечание принято. Теперь о моем фактическом вопросе/проблеме …

Ответ №1:

Я думаю, что решил. Публикую на случай, если кто-нибудь споткнется о что-то подобное…

Мне нужно было удалить «использование». Итак, это …

     using (new NetworkConnection("\\192.168.1.162\Images\Photos2",sourceCredentials))
            {
                app.UseFileServer(new FileServerOptions()
                {
                    FileProvider = new PhysicalFileProvider(
                        Path.Combine("\\192.168.1.162\Images\Photos2")),
                    RequestPath = new PathString("/Photos2"),
                    EnableDirectoryBrowsing = true
                });

            }
 

стало это:

     new NetworkConnection("\\192.168.1.162\Images\Photos2", sourceCredentials);

   app.UseFileServer(new FileServerOptions()
   {
       FileProvider = new PhysicalFileProvider(
                Path.Combine("\\192.168.1.162\Images\Photos2")),
                RequestPath = new PathString("/Photos2"),
                EnableDirectoryBrowsing = true
   });
 

Единственное различие заключается в том, что «использование» и скобки удалены.

Почему это работает? Я предполагаю, что объект NetworkConnection должен быть сохранен. Если я использовал «использование», это не так. Это была моя проблема, через 30-60 секунд мое сетевое соединение не работало.

Просто жаль, что я не понял это простое решение быстрее!