簡體   English   中英

如何使用 Blazor 從 .CS 文件而不是 .RAZOR 文件訪問在 Startup.cs 中注釋的范圍服務中的數據?

[英]How do I access data within a scoped service, annotated in Startup.cs, from a .CS file NOT a .RAZOR file using Blazor?

在我的 Blazor 應用程序中,我有一個范圍服務:

下載文件.cs

namespace MyNamespace {
    public class DownloadingFile
    {
        public byte[] theFile { get; set; }
    }
}

我在 Startup.cs 中對其進行了注釋:

啟動文件

services.AddScoped<DownloadingFile>();

我可以從 .RAZOR 文件成功訪問它:

我的文件.razor

<div @onclick="MyTask">Click Me</div>

@code {
    [Inject]
    private NavigationManager navigationManager { get; set; }

    [Inject]
    DownloadingFile downloadingFile { get; set; }

    private async Task MyTask(){
        APIResponse apiResponse = await APIResponse.getResponse();
        downloadingFile = apiResponse.data;
        navigationManager.NavigateTo("/api/Download/DownloadFile?filename=" + apiResponse.filename, true);
    }
}

我有一個下載控制器:

MyNamespace
`- Controllers
   `- DownloadController.cs

下載控制器.cs

namespace MyNamespace.Controllers {
    [Route("api/[controller]")]
    [ApiController]
    public class DownloadController : ControllerBase
    {
        [HttpGet("[action]")]
        public IActionResult DownloadFile(string filename)
        {
            byte[] theByteArray = new byte[] {1, 2, 3, 4, ... };
            return File(theByteArray, "application/zip", filename);
        }
    }
}

如果我按原樣運行 Blazor 應用程序,則一切正常。

但是,如您所料,我不能在theByteArray硬編碼,它需要是動態的。 如果我更改我的下載控制器:

namespace MyNamespace.Controllers {
    [Route("api/[controller]")]
    [ApiController]
    public class DownloadController : ControllerBase
    {
        // TO THIS
        private DownloadingFile downloadingFile;
        public DownloadController(DownloadingFile downloadingFile)
        {
            this.downloadingFile = downloadingFile;
        }

        // OR THIS
        private DownloadingFile downloadingFile;
        public DownloadController() {
            downloadingFile = new DownloadingFile();
        }

        [HttpGet("[action]")]
        public IActionResult DownloadFile(string filename)
        {
            return File(downloadingFile.theFile, "application/zip", filename);
        }
    }
}

DownloadingFileDownloadingFile始終為null


編輯:澄清一下,我通過在控制器中實例化 DownloadingFile 創建的對象不為空,它是我期望在那里的字節數組為空。


如果我可以將字節數組從 .RAZOR 文件獲取到 .CS 文件,一切都會好起來的。 我該怎么做?

讓我們看看你的代碼:

        APIResponse apiResponse = await APIResponse.getResponse();
        downloadingFile = apiResponse.data;
        navigationManager.NavigateTo("/api/Download/DownloadFile?filename=" + apiResponse.filename, true);

為什么將downloadingFile設置為APIResponse.data 這是一個注入的服務。 你不要重新分配它。

在控制器的第二個版本中

        private DownloadingFile downloadingFile;
        public DownloadController(DownloadingFile downloadingFile)
        {
            this.downloadingFile = downloadingFile;
        }

您正在注入DownloadingFile ,但這與 Blazor 會話中的實例不同。 它是為服務器端調用控制器而創建的新實例,並且downloadingFile.theFile為空。

您可以執行以下操作來跟蹤服務實例:

    public class ScopedService
    {
        public Guid ID => Guid.NewGuid();

        public ScopedService()
        {
            Debug.WriteLine($"New ScopedService ID:{ID}");
        }
    }

“我該怎么做?” 從您的代碼中看不出您實際下載的是什么以及從何處下載,因此很難回答。

正如MrC aka Shaun Curtis所說:由於客戶端和服務器是不同的范圍,並且您將DownloadingFile服務作為范圍服務注入,因此您設置downloadingFile = apiResponse.dataDownloadingFile實例與您嘗試檢索的實例不同這就是文件為NULL

在我看來,您的目標是向用戶提供文件下載。 現在(假設您的代碼有效)您正在前端下載一個文件並嘗試將其設置為后端服務,然后在 HTTP 響應中將其返回給用戶。 如果不首先實際發送 HTTP 請求,這顯然是不可能的。

相反,您應該簡單地導航到您想要的文件所在的 URL。 為此,您需要將按鈕換成瀏覽器的標簽以允許它。

<a class="btn" href="https://myapiurl.com/filename" role="button">Click Me</a>

嘗試安裝此擴展BlazorDownloadFile

然后注冊它的服務

builder.Services.AddBlazorDownloadFile(ServiceLifetime.Scoped);

如果在此階段您已經擁有文件字節:

APIResponse apiResponse = await APIResponse.getResponse();
downloadingFile = apiResponse.data;

假設您的文件是 pdf,您可以:

@inject IBlazorDownloadFileService _blazorDownloadFile

APIResponse apiResponse = await APIResponse.getResponse();

_blazorDownloadFile.DownloadFile("myFile.pdf", apiResponse.data, "application/pdf");

如果需要,您可以處理更多MIME 類型

冒着向這條破碎的記錄添加另一個跳過的風險:您的剃刀組件和您的控制器使用不同的范圍。 您可能在一個代碼庫中擁有所有內容,但框架的不同模塊對作用域的處理方式不同。

控制器的范圍僅限於單個 HTTP 請求。 每次發出請求時都會實例化和處理服務。 在 Blazor 服務器中,服務的范圍僅限於客戶端和服務器之間的 SignalR 連接/電路。

這些范圍不共享。 引用 Blazor 文檔中關於依賴注入的內容(粗體強調我的):

應用程序的 Razor 頁面或MVC 部分正常處理范圍服務,並在頁面或視圖之間導航或從頁面或視圖導航到組件時在每個 HTTP 請求上重新創建服務 在客戶端上的組件之間導航時,不會重建范圍服務,其中與服務器的通信是通過用戶電路的 SignalR 連接而不是通過 HTTP 請求進行的。

我仍然不確定您為什么要以這種方式做事,但我認為在 ASP.NET Core DI 基礎結構的上下文中您的要求是不可能的,除非您使您的服務成為單例。

我會遵循其他海報的建議,並將用戶指向 API,以與在組件中相同的方式獲取文件。 如果存在安全問題,是否將其設為受保護的端點?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM