简体   繁体   English

ASP.NET核心返回HTTP响应并继续具有相同上下文的后台工作者

[英]ASP.NET Core Return HTTP Response And Continue Background Worker With Same Context

Sorry ahead of time, this is a bit of a lengthy setup/question. 对不起,这是一个冗长的设置/问题。 I am currently working on an API using C# ASP.NET Core 2.1. 我目前正在使用C#ASP.NET Core 2.1开发API。 I have a POST endpoint which takes about 5-10 seconds to execute (which is fine). 我有一个POST端点,执行大约需要5-10秒(这很好)。 I need to add functionality which could take a considerable amount of time to execute. 我需要添加可能需要相当长时间才能执行的功能。 My current load testing takes an additional 3 minutes. 我目前的负载测试需要额外的3分钟。 To be honest production could take a bit longer because I can't really get a good answer as to how many of these things we can expect to have to process. 说实话,生产可能会花费更长的时间,因为我无法真正得到一个好的答案,我们可以期望处理多少这些事情。 From an UX perspective, it is not acceptable to wait this long as the front end is waiting for the results of the existing POST request. 从用户体验的角度来看,等待这一长时间是不可接受的,因为前端正在等待现有POST请求的结果。 In order to maintain an acceptable UX. 为了维持可接受的用户体验。

All services are set up as transient using the default ASP.NET Core DI container. 使用默认的ASP.NET Core DI容器将所有服务设置为瞬态。 This application is using EF Core and is set up in the same fashion as the services (sorry I am not at work right now and forgot the exact verbiage within the Setup file). 此应用程序使用EF Core并以与服务相同的方式设置(抱歉,我现在没有工作,忘记了安装文件中的确切措辞)。

I first tried to just create a background worker, but after the response was sent to the client, internal objects would start to be disposed (ie entity db context) and it would eventualy throw errors when continuing to try executing code using said context (which makes sense since they were being disposed). 我首先尝试创建一个后台工作程序,但是在将响应发送到客户端之后,内部对象将开始被处理(即实体数据库上下文),并且当继续尝试使用所述上下文执行代码时,它将最终抛出错误(因为他们被处置了所以有意义。

I was able to get a background worker mostly working by using the injected IServiceScopeFactory (default ASP.NET Core implementation). 我能够让一个后台工作者主要使用注入的IServiceScopeFactory(默认的ASP.NET Core实现)。 All my code executes successfully until I try saving to the DB. 我的所有代码都成功执行,直到我尝试保存到数据库。 We have overridden the SaveChangesAsync() method so that it will automatically update the properties CreatedByName, CreatedTimestamp, UpdatedByName, and UpdatedTimestamp to the currently tracked entities respectively. 我们重写了SaveChangesAsync()方法,以便它自动将属性CreatedByName,CreatedTimestamp,UpdatedByName和UpdatedTimestamp分别更新到当前跟踪的实体。 Since this logic is used by an object created from the IServiceScopeFactory, it seems like it does not share the same HttpContext and therefore, does not update the CreatedByName and UpdatedByName correctly (tries to set these to null but the DB column does not accept null). 由于此逻辑由从IServiceScopeFactory创建的对象使用,因此它似乎不共享相同的HttpContext,因此不会正确更新CreatedByName和UpdatedByName(尝试将这些设置为null但DB列不接受null) 。

Right before I left work, I created a something that seemed to work, but it seems very dirty. 就在我离开工作之前,我创造了一些似乎有用的东西,但它看起来很脏。 Instead of using the IServiceScopeFactory within my background worker to create a new scope, I created an impersonated request using the WebClient object which pointed to an endpoint within the same API that was currently being executed. 我没有在后台工作程序中使用IServiceScopeFactory来创建新作用域,而是使用WebClient对象创建了一个模拟请求,该对象指向当前正在执行的同一API中的端点。 This did allow the response to be sent back to the client in a timely manor, and this did continue executing the new functionality on the server (updating my entities correctly). 这确实允许响应以及时的方式发送回客户端,这确实继续在服务器上执行新功能(正确更新我的实体)。

I apologize, I am not currently at work and cannot provide code examples at this moment, but if it is required in order to fully answer this post, I will put some on later. 我道歉,我目前没有工作,目前无法提供代码示例,但如果要完全回答这篇文章是必需的,我稍后会介绍一些。

Ideally, I would like to be able to start my request, process the logic within the existing POST, send the response back to the client, and continue executing the new functionality using the same context (including the HttpContext which contains identity information). 理想情况下,我希望能够启动我的请求,处理现有POST中的逻辑,将响应发送回客户端,并使用相同的上下文(包括包含身份信息的HttpContext)继续执行新功能。 My question is, can this be done without creating an impersonated request? 我的问题是,这可以在不创建模拟请求的情况下完成吗? Can this be accomplished with a background worker using the same context as the original thread (I know that sounds a bit weird)? 这可以通过后台工作者使用与原始线程相同的上下文来完成(我知道这听起来有点奇怪)? Is their another approach that I am completely missing? 他们的另一种方法是我完全失踪了吗? Thanks ahead of time. 提前谢谢。

查看Hangfire非常易于使用的库来执行后台任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM