2016-05-13 81 views
1

因此,我有一个SPA(单页应用程序),AngularJS作为前端,.NET Web API作为后端(C#)。我需要在某些用户操作时生成SQL Server Reporting Services(SSRS)报告,即选择一些数据并按下按钮。这里是我现有的架构的一个粗略的说明:RabbitMQ与AngularJS/.NET Web API应用程序的架构

FRONT END     BACK END     SSRS Report 
==========    =========     =========== 
**AngularJS Web page**-->**.NET Web API controller**-->**Intermediary class (passes arguments to report)** -->**Generate report and save to file** 

这工作,但问题是,而正在生成报表的应用程序必须坐在那里,等待他们完成并在此期间,用户可以”不要做任何事情。如果有很多报告需要创建,例如100多个报告,则可能需要一两分钟的时间,这对我来说是不可接受的。

所以这就是RabbitMQ进来的地方。我想到的是.NET Web API控制器向服务器发送消息,一旦服务器收到它,就会对上面的中间类执行一个调用,报告,然后回复给客户,让他们知道报告已经生成。我想我需要使用RPC方案,所以我已经在RabbitMQ网站上完成了相应的教程,看起来很简单。

虽然我不知道,但这就是我的问题所在,就是如何从.NET Web API应用程序启动客户端和服务器。坦率地说,我现在有点失落,因为这是我第一次使用任何类型的消息传递的真实体验,我不太清楚如何处理它,架构明智。如果我可以在头脑中详细了解整个事情的工作方式,我可以从那里编写代码,但是现在我很难想象如何构建应用程序。

所以,问题:

  1. 我如何开始从.NET Web API控制器的RabbitMQ服务器和客户端?服务器和客户端应该是类库还是控制台应用程序,还是其他的东西?

  2. 我设想的体系结构会起作用还是有更好的方法?

  3. 任何关于如何接近我试图完成的一般建议将不胜感激。

回答

3
  1. 的RabbitMQ服务器之前引入的新HostingEnvironment.QueueBackgroundWorkItem是不是你从控制器开始的东西 - 它始终运行。从控制器发送消息到rabbitmq服务器。另一方面,另一个应用程序(Windows服务,控制台应用程序或者Linux上的单声道服务)会监听这些消息并处理它们。 RabbitMQ服务器仅管理端点之间的发送消息。在你的情况下,处理来自你的控制器的消息的应用程序也一直在运行(使它成为windows服务是合理的)。

  2. 这样的架构将工作是的。 RabbitMQ虽然可能是一种矫枉过正的情况 - 它对于多服务器,高负载情况更是如此。如果负载较低,并且所有应用程序都在同一台服务器上,则可以使用其他工具(如hangfire.io,MSMQ,或者甚至只是在Web服务器进程中运行后台任务,如另一个答案所示)。如果简单的工具可以做你的工作 - 为什么不。

  3. 生成报告时,不要始终保持客户端(浏览器)与服务器之间的连接。只需将任务放入兔子队列进行处理(或以其他方式开始生成报告)并返回。然后,如果作业已完成,则定期从客户端进行轮询,或(更好地)通过websocket连接通知客户端。这当然是报告生成可能需要一些时间(超过30秒)。

更新:更多关于整体架构。

  • RabbitMQ服务器作为Windows服务运行,与Windows一起启动。
  • 当您通过web api接收到报告生成请求时 - 您将GenerateReport消息与所有需要的信息一起放入,然后返回(不等待报告生成)。如果您将报告存储在数据库中,那么它们是持久的 - 在数据库中创建关于报告请求的记录。否则 - 在内存中保存关于待处理报告的信息(以便您知道当前正在生成X报告)。在理想情况下,您也可以通过Web套接字在客户端和服务器之间建立持久连接。如果是这种情况 - 您将实时通知用户有关报告生成状态。否则 - 用户将不得不频繁轮询服务器。
  • 另一方面是由您编写的Windows服务,它也与Windows服务器一起启动。它监听GenerateReport消息并开始生成。可以有多个这样的服务,或者你可以在一个服务中有多个订阅 - 这将均匀地在多个服务之间分配工作负载。报告生成期间 - 发布ReportProgress消息。完成后 - 更新数据库中的报告(如果持续存在)并发布ReportDone消息。 Web Api服务中的后台线程侦听此类消息。如果你有websockets连接 - 你只需将这些消息传递给客户端,这样他就可以实时查看报告生成进度。否则 - 更新数据库或内存中的结构,以便下次客户端将轮询报告状态时 - 您将返回一些内容。
  • 如果出现问题 - 没有问题(如果你坚持报告数据库)。在启动时,您的生成服务将检查数据库中是否有未决报告并生成它们。如果客户端在报告生成过程中断开连接(从网站) - 仍然没有问题,当他返回报告时就会准备就绪,并可以从数据库提供服务。如果web api服务崩溃 - 仍然没有问题。
+0

1. @Evk,你所描述的与远程过程调用(RPC)模式相当,其中有一个客户端和一个服务器,前者向后者发送消息,然后接收消息(结果)?这在这里有更详细的描述:https://www.rabbitmq.com/tutorials/tutorial-six-dotnet.html。 – lukegf

+0

2.如果是这样,您称为“另一个应用程序侦听这些消息并处理它们”对应于RPC模式中的客户端吗?另外,您说RabbitMQ服务器始终在运行,即使它不应该从控制器启动,也必须启动它。这是如何运作的?谁启动服务器?换句话说,假设我编码服务器,就像上面的RabbitMQ站点上的示例一样。那之后我该怎么处理它?我假设我必须将它部署在某处并以某种方式对其进行配置,以便它始终处于运行状态。客户同样的问题。 – lukegf

+1

@ user452103兔子只是一个或多个应用程序之间的消息总线(中介,代理)。在你的情况下,一个应用程序是你的asp.net web api服务。另一个应用程序生成报告(例如 - 单独的控制台或Windows服务应用程序)。如果使用RPC模式,则应用程序A(web api)会向应用程序B(windows服务)发送消息,要求生成报告。然后它会等待,直到应用程序B将返回一条带有操作结果的消息。至于谁开始兔子。在Windows上,您可以将兔子作为服务运行 - 然后与Windows一起启动。 – Evk

2

您是否尝试过使用在.NET 4.5切换到RabbitMQ的

HostingEnvironment.QueueBackgroundWorkItem(cancellationToken => 
{ 
    return Task.Factory.StartNew(() => 
    { 
     // Generate report and save to file 
    }, cancellationToken); 
}); 
+0

不,我没有。这是我第一次听说它。它究竟做了什么? – lukegf

+1

“安排可在后台运行的任务,与任何请求无关。”和[这里是博客文章](https://blogs.msdn.microsoft.com/webdev/2014/06/04/queuebackgroundworkitem-to-reliably-schedule-and-run-background-processes-in-asp-net/ )与更多细节。 – Nasreddine

+0

听起来像它有一些严重的限制,但。例如:“如果排队的项目太多,无法在90秒内完成,ASP.NET运行时将卸载AppDomain而不等待工作项完成。”这对我来说是一种破坏,因为我可能会有这么多的报告,他们很容易就会花费超过90秒的时间来生成。 – lukegf