Kyt*_*yte 11 c# asp.net async-await .net-core blazor
在工作方面经历了两年的埋头苦干后,我现在在新的工作场所遇到了 Blazor,在这两年之前主要从事 ASP.NET Framework MVC 工作之后,我还有很多工作要做。
在 Blazor 服务器端尝试自己,我尝试应用我过去的知识,其中包括用于异步操作的取消令牌,但我找不到有关它们与 Blazor 结合的太多信息。
它们仍然是最佳实践还是在某个时候已经过时了?我确实发现了这个先前提出的问题,建议在该OnInitializedAsync()方法上创建一个令牌源并取消它,Dispose()老实说我觉得有点粗糙。(我需要为每个页面实现这个,你知道......干)
我还在Microsoft Docs 上找到了这篇关于高级方案的文章,其中解释了如何实现电路处理程序,老实说,这有点超出了我的能力范围,而且很可能超出了我的小型家庭项目的范围。
相比之下,在 asp.net Framework MVC 中我会构建一个像这样的控制器:
namespace SampleWebsite.Controllers
{
public class SampleController : ApiController
{
private readonly MyEntities _entities = new MyEntities();
public async Task<IHttpActionResult> MyAsyncApi(CancellationToken cancellationToken)
{
var result = _entities.MyModel.FirstOrDefault(e => e.Id == 1, cancellationToken: cancellationToken);
return OK(result);
}
}
}
Run Code Online (Sandbox Code Playgroud)
CancellationToken 将由 asp.net Framework / Core 注入,并直接链接到当前上下文连接管道。因此,如果用户关闭连接,令牌就会失效。
我本以为对于依赖注入占很大一部分的 asp.net core 和 blazor 来说,这里也是这种情况,但我在这里找不到任何关于此的文档。
那么,此时是否仍应使用取消令牌,或者微软是否在后台为异步任务做了一些魔法?如果是,最好的实施是什么?
编辑: 这是我的设置来澄清:
Blazor 组件:
@page "/Index"
@inject IIndexService Service
@* Some fancy UI stuff *@
@code {
private IEnumerable<FancyUiValue> _uiValues;
protected override async Task OnInitializedAsync()
{
_uiValues = await Service.FetchCostlyValues();
}
}
Run Code Online (Sandbox Code Playgroud)
以及执行繁重任务的注入服务类:
public interface IIndexService
{
Task<IEnumerable<FancyUiValue>> FetchCostlyValues();
}
public class IndexService : IIndexService
{
public async Task<IEnumerable<FancyUiValue>> FetchCostlyValues()
{
var uiValues = await heavyTask.ToListAsync(); // <-- Best way to get a cancellationtoken here?
return uiValues;
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,在代码的特定部分获取令牌的最佳方法是什么,或者它是否无关紧要,因为当连接(例如)结束时服务器会终止所有正在运行的任务?
Kyt*_*yte 11
经过 2 年的 Blazor 经验后,我认为将 an 传递CancellationToken给生命周期较长的对象(例如单例或作用域服务)中的任务的唯一可靠方法是IDisposeable和的组合CancellationTokenSource
@page "/"
@implements IDisposable
*@ Razor Stuff *@
@code
{
private CancellationTokenSource _cts = new();
protected override async Task OnInitializedAsync()
{
await BusinessLogicSingleton.DoExpensiveTask(_cts.Token);
}
#region IDisposable
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
#endregion
}
Run Code Online (Sandbox Code Playgroud)
在重复使用或只是为了遵守 DRY 规则时,您还可以从该类继承ComponentBase,然后将该类用于需要传递以下内容的组件CancellationToken:
public class CancellableComponent : ComponentBase, IDisposable
{
internal CancellationTokenSource _cts = new();
public void Dispose()
{
_cts.Cancel();
_cts.Dispose();
}
}
Run Code Online (Sandbox Code Playgroud)
@page "/"
@inherits CancellableComponent
@* Rest of the Component *@
Run Code Online (Sandbox Code Playgroud)
我还发现,虽然您可以注入IHttpContextAccessor并使用与HttpContext.RequestAbortedASP.Net MVC 方法调用中生成和注入的令牌相同的令牌,但从当前版本开始,即使与客户端的连接被切断,.Net6它也永远不会触发并且该提供HttpContext被处置。
这可能是 Github 上开发团队的情况,因为我确实看到了用例,其中允许用户退出组件,而任务继续进行,直到用户完全离开网站。
(对于这种情况,我建议的解决方法是编写您自己的解决CircuitHandler方法,以便在电路被删除时为您提供事件。)
CancellationTokenSource您可以创建一个公开 a 的基础组件,并CancellationToken在项目的所有组件中自动使用该基础组件,而不是手动将 a 添加到所有组件
实现您的ApplicationComponentBase
public abstract class ApplicationComponentBase: ComponentBase, IDisposable
{
private CancellationTokenSource? cancellationTokenSource;
protected CancellationToken CancellationToken => (cancellationTokenSource ??= new()).Token;
public virtual void Dispose()
{
if (cancellationTokenSource != null)
{
cancellationTokenSource.Cancel();
cancellationTokenSource.Dispose();
cancellationTokenSource = null;
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后添加@inherits ApplicationComponentBase到_Imports.razor文件中
在页面中调用:
await Task.Delay(50000, CancellationToken);
Run Code Online (Sandbox Code Playgroud)
然后尝试导航到另一个页面,您调用的任务将被取消
| 归档时间: |
|
| 查看次数: |
9739 次 |
| 最近记录: |