如何绕过 blazor wasm 路由系统并调用服务器

How to bypass blazor wasm routing system and make calls to the server

我有一个 blazor wasm 托管应用程序,用户可以在其中通过填写表格来创建帐户。创建帐户后,将向用户发送一封电子邮件,其中必须遵循 link s/he 以确认 his/her 对电子邮件地址的所有权。 link 指向我服务器中的一个操作方法。同一台服务器托管 blazor wasm 应用程序和 API。

问题是,当用户单击 link 时,请求不会发送到服务器。相反,blazor 拦截调用并尝试路由到页面。

我怎样才能完成这项工作?我怎样才能使 link 指向服务器中的某个操作,在单击时实际上将其发送到服务器?换句话说,如果可能的话,如何绕过 blazor 的路由系统?

更新:

注: 这不是错误。这是 balzor wasm 的正常行为。如果一个应用程序托管在 www.foo.com,那么所有对 foo.com 的调用(例如 www.foo.com/bar)实际上不会对 foo.com 进行,但会被 blazor 和拦截被视为应用程序中页面的路由。但是,这阻止了我,因为我的 API 与应用程序具有相同的基地址(应用程序目前位于 localhost:5001/,API 位于 localhost:5001/api/xyz),因此,blazor 正在阻止调用单击 link 时发送到服务器。问题是如何解决这个问题?如果不可能,我还有哪些其他选择来实施此流程?

所以我通过将 Action 方法设为 GET 方法而不是 POST 来解决问题。仔细想想这是很合乎逻辑的:当用户单击通过电子邮件收到的 link s/he 时,将发出 GET,而不是 POST.

我还了解到,只有当您在地址栏中输入地址时,blazor 才会将您路由到某个页面。如果单击 link,将发出请求。我认为 blazor 拦截请求的原因是因为单击 link 将我重定向到一个页面,但实际上,这只是一种回退机制。您可以在 configure 方法中看到它:

app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
            endpoints.MapControllers();

            // the link clicked issues a GET. My action is a POST.
            // So no action is found. It falls back to the index.html
            // which is the entery point of my app. Blazor takes over 
            // from here and tries to find a page for the url requested.
            endpoints.MapFallbackToFile("index.html");
        });

我遇到了同样的问题。我使用 JS Interop 来修复它。显示了代码。

在 /wwwroot/index.html 添加以下脚本。

<script>
        function downloadfile(filename, fileContent) {
            var element = document.createElement('a');
            element.setAttribute('href', fileContent);
            element.setAttribute('download', filename);
            document.body.appendChild(element);
            element.click();
            document.body.removeChild(element);
        }
</script>

在 Blazor WASM Razor 组件中,在@code 中添加以下函数。

private async void DownloadFile(string fileName)
{
    //Get the file from the Server Side
    //Convert fileName string to String Content
    var response = await httpService.PostAsync(
       url:"/api/download", content:fileNameStringContent);

    if (response.IsSuccessStatusCode)
    {
       var content = await response.Content.ReadAsStringAsync();
       await JSRuntime.InvokeVoidAsync("downloadfile", fileName, content);
    }
}  

在服务器中添加以下 Controller.Action

[HttpPost("download")]
public async Task<string> Download(string fileName)
{
    var fileContent = GetFileAsBytes(fileName);
    
    var base64String = "data:application/pdf;base64," + Convert.ToBase64String(fileContent);
    
    return base64String;
}

private async Task<byte[]> GetFileAsBytes(string fileName)
{
    try
    {
        var folderPath = Path.Combine(_env.ContentRootPath, "folder");\
        if (!Directory.Exists(folderPath))
            return null;

        var filePath = Path.Combine(folderPath, fileName);
        if (!File.Exists(filePath))
            return null;

        var fileBytes = await File.ReadAllBytesAsync(filePath);
        return fileBytes;
    }
    catch
    {
        return null;
    }
}