asp.net Blazor Pages中的取消令牌?

gt0wga4j  于 2022-11-19  发布在  .NET
关注(0)|答案(2)|浏览(202)

在生活在岩石下2年就业明智的,我现在面临着Blazor在我的新工作场所,并有很多赶上做后,主要是做ASP .netframeworkmvc之前的2年。
尝试自己在Blazor服务器端,我试图应用我过去的知识,其中包括异步操作的cancellationtoken,我找不到太多的信息,他们结合Blazor。
它们仍然是最佳实践还是在某个时候过时了?我确实发现了this previously asked question,它建议在OnInitializedAsync()方法上创建一个tokensource,并在Dispose()上取消它,老实说,我觉得有点粗糙。(我需要在每个页面上实现这个,你知道...干)
我还找到了this Article about advanced Scenarios on Microsoft Docs,它解释了如何实现电路处理程序,老实说,这有点超出了我现在的能力范围,很可能超出了我的小家庭项目的范围。
相比之下,在asp.net框架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);
        }
    }
}

CancellationToken将由asp.net Framework / Core注入,并直接链接到当前上下文连接管道。因此,如果用户关闭连接,令牌将变为无效。
我本以为对于asp.net core和blazor来说,依赖注入是其中很大的一部分,这里也是如此,但是我在这里找不到任何关于这方面的文档。
那么,在这一点上,cancellationtoken是否应该继续使用,或者微软是否在后台为异步任务做了一些魔术?如果是的话,最好的实现是什么?

**EDIT:**以下是我得设置,以便澄清:

Blazor组件:

@page "/Index"
@inject IIndexService Service

@* Some fancy UI stuff *@

@code {
    private IEnumerable<FancyUiValue> _uiValues;

    protected override async Task OnInitializedAsync()
    {
        _uiValues = await Service.FetchCostlyValues();
    }
}

注入式服务级别执行繁重得工作:

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;
    }
}

我的问题是,在代码的特定部分获得令牌的最佳方式是什么,或者它是无关紧要的,因为服务器会在连接(例如)结束时杀死所有正在运行的任务?

brgchamk

brgchamk1#

在使用Blazor两年之后,我发现将CancellationToken传递给更长生命周期的对象(例如Singleton或Scoped Service)中的任务的唯一可靠方法是IDisposeableCancellationTokenSource的组合

@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
}

在重复使用或仅为了遵守DRY规则时,您也可以从ComponentBase类继承,然后将该类用于需要传递CancellationToken的组件:
第一次
我还发现,虽然您可以注入IHttpContextAccessor并使用HttpContext.RequestAborted标记(与ASP.NET MVC方法调用中生成和注入的标记相同),但从当前的.Net6版本开始,它永远不会触发,即使与客户端的连接被切断,并且提供的HttpContext被释放。
这可能是Github上的开发团队的一个案例,因为我确实看到了它的用例,其中用户被允许退出组件,而任务继续进行,直到用户完全离开网站。
(For在这种情况下,我建议的解决方法是编写您自己的CircuitHandler,它将为您提供删除电路时的事件。)

k97glaaz

k97glaaz2#

您可以创建一个公开CancellationToken的基本组件,并在项目的所有组件中自动使用此基本组件,而不是手动将CancellationTokenSource添加到所有组件
实现应用程序组件库

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;
        }
    }
}

然后将@inherits ApplicationComponentBase添加到_Imports.razor文件
高翔听差一叫:

await Task.Delay(50000, CancellationToken);

然后尝试导航到另一个页面,您调用的任务将被取消

相关问题