如何绕过 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 的路由系统?
更新:
- 我正在使用 Identity 作为后备存储(尽管这与我遇到的问题无关)。
- 我使用基本控制器
Url.Action("actionName", "controllerName", actionParam, Request.Scheme);
中的 Url 属性 生成 link。 link,现在看起来像
https://localhost:5001/api/user/confirmaemail?confirmationtoken=xyz&useremail=abc
- 该操作是一个 post 操作。
- 当 blazor 尝试重定向到页面时,它显然不能,因为我没有包含这样路由的页面。因此显示
<NotFound />
组件(App.razor 文件)中的内容。
注:
这不是错误。这是 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;
}
}
我有一个 blazor wasm 托管应用程序,用户可以在其中通过填写表格来创建帐户。创建帐户后,将向用户发送一封电子邮件,其中必须遵循 link s/he 以确认 his/her 对电子邮件地址的所有权。 link 指向我服务器中的一个操作方法。同一台服务器托管 blazor wasm 应用程序和 API。
问题是,当用户单击 link 时,请求不会发送到服务器。相反,blazor 拦截调用并尝试路由到页面。
我怎样才能完成这项工作?我怎样才能使 link 指向服务器中的某个操作,在单击时实际上将其发送到服务器?换句话说,如果可能的话,如何绕过 blazor 的路由系统?
更新:
- 我正在使用 Identity 作为后备存储(尽管这与我遇到的问题无关)。
- 我使用基本控制器
Url.Action("actionName", "controllerName", actionParam, Request.Scheme);
中的 Url 属性 生成 link。 link,现在看起来像https://localhost:5001/api/user/confirmaemail?confirmationtoken=xyz&useremail=abc
- 该操作是一个 post 操作。
- 当 blazor 尝试重定向到页面时,它显然不能,因为我没有包含这样路由的页面。因此显示
<NotFound />
组件(App.razor 文件)中的内容。
注:
这不是错误。这是 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;
}
}