从队列中的所有用户运行方法

我的设置:用户有一个页面,他执行一些操作和数据转换。
我将这些操作存储在数据集中(在会话中)。
然后,在按钮单击时,我需要执行一些更多转换并调用自定义数据库函数,该函数将每个数据表中的每一行插入到数据库中。 我已经解决了所有问题并且效果很好。

但是,现在,我需要做的是修改按钮单击事件不要立即运行,而是将该操作放入队列(这是所有用户的公共队列)。 因此,如果user1单击该按钮,则user2单击该按钮,然后我们需要获取user1数据集并在其上运行方法,并且仅在此之后获取user2数据集并运行方法。 所有的一个队列。

private void btnclick() { DataSet ds = Session["test"] as DataSet; PerformFinalTransformation(ds); foreach (DataTable dt in ds.Tables) { foreach (DataRow dr in dt.Rows) { CallCustomSqlFunction(dr); } } } 

如果可能的话,我想避免将数据集存储在数据库中,因为它们对于每个用户(表/列的数量)并不相同。 我正在寻找关于如何在asp.net / c#中完成此任务的任何指示。 (石英网是我应该考虑的吗?)。 我应该寻找什么概念? 并行编程? 还是asp.net队列? 或者是其他东西? 甚至无法启动,因为不知道该从什么开始。 顺便说一句,如果有所帮助,我会在我的应用程序中使用最新的DotNetNuke。

从架构的角度来看,您的解决方案很好。 队列是要走的路。 但是,解决方案并非易事。 要考虑的一些事情:

  1. 弹性:如果系统崩溃或重启会怎么样? 队列是否被保留?
  2. 你将如何从这个队列消费? 你的ASP.Net应用程序中的一个线程(丑陋)? Windows服务?
  3. 并发性怎么样?

根据你的答案,我给你一些选择:

  1. 内存中的队列,使用[ConcurrentQueue][1] ,在线程中上升。 可能使用Singleton来启用对队列的访问。 我建议你不要这样做。

  2. 创建服务,通过WCF公开接口并从ASP.Net应用程序访问它。 该服务也应该持有[ConcurrentQueue][2] ,访问数据库等将是服务职责(您仍然会遇到崩溃和数据丢失的问题)。

  3. 使用MSMQ 。 还有一些服务来封装从ASP.Net接收调用的function(如果你不想让ASP.Net直接访问MSMQ)并访问数据库(MSMQ调用这个服务)。

这些只是我的头脑。 请随时发表评论,我会尽可能回答(我现在正在工作)。

  1. 要重新启动,您必须将队列存储在数据库中。 您可以通过将每个数据集序列化为xml并将生成的xml存储在nvarchar(max)列中来克服数据不相似性。

  2. 运行队列的最佳方法是使用单独的Windows服务,一次选择一个项目并对其进行处理。 您可以使用IIS执行相同的操作(只需在Application_Start启动另一个线程),但我不建议将其视为不可扩展(并且需要重新启动IIS,池回收等)。

而不是为每一行调用一个函数将其插入数据库,是否可以使用表值参数提交数据? 这是SQL Server 2008及更高版本的一项function,它允许您在单个语句中完全提交表。

使用这种解决方案,您可能不需要队列。 我发现当我切换到表参数时,我的代码性能提高了很多,因此没有必要批处理语句。

以下是您的代码的工作方式:

 private void btnclick() { DataSet ds = Session["test"] as DataSet; PerformFinalTransformation(ds); using (SqlConnection conn = new SqlConnection(my_connection_string)) { conn.Open(); using (SqlCommand cmd = new SqlCommand("insert_multiple_tables", conn)) { cmd.CommandType = CommandType.StoredProcedure; SqlParameter param = new SqlParameter("@table0", SqlDbType.Structured); param.Value = ds.Tables[0]; cmd.Parameters.Add(param); SqlParameter param = new SqlParameter("@table1", SqlDbType.Structured); param.Value = ds.Tables[1]; cmd.Parameters.Add(param); cmd.ExecuteNonQuery(); } } } 

然后,您可以像这样定义存储过程:

 CREATE TYPE udt_mytable0 AS TABLE ( col1 int, col2 varchar(255), col3 datetime, -- and so on ) CREATE TYPE udt_mytable1 AS TABLE ( col1 bigint ) CREATE PROCEDURE insert_multiple_tables @mytable0 udt_mytable0 READONLY, @mytable1 udt_mytable1 READONLY AS INSERT INTO mydatabase0 (col1, col2, col3) SELECT col1, col2, col3 FROM @mytable0 INSERT INTO mydatabase1 (col1) SELECT col1 FROM @mytable1 

由于我对这些问题知之甚少,WCF和MSMQ都是很好的解决方案,在你的场景中肯定会有所帮助。 如果你做得好,写一个你想要的数据库实现并不是很糟糕。 您可以在每次插入后将字段设置为AutoIncrement ,将数据添加到数据库中。

但是 ,要使用队列解决此问题,下面是一些指南和示例:

  • 在WCF中排队

  • 在ASP.NET应用程序中利用MSMQ 。

一些示例项目实现:

  • 如何使用ASP.NET,MSMQ和Windows进行异步编程
    服务,用于长时间运行的流程
  • 在ASP.NET,VB中使用Queue发送电子邮件
  • WCF排队消息

希望你发现它们有用。 祝好运。

如果我应该这样做,我可能最终会采用以下方式:

队列存储

如果您不想将队列保留在内存中(这可能是一个坏主意,请参阅其他答案)您需要在服务器上安装某种数据库或其他存储器,这些存储器在服务器重置时不会被清除那。 为此,您当然可以使用像SQL Server这样的传统数据库,但也可以使用其他选项。

如果您已经在服务器上没有SQL Server或类似的商业数据库,我建议使用像RavenDB这样的文档数据库,或者只是将队列存储为一系列带有时间戳的文件(XML序列化)(记得使用某种排序)文件名中的随机性,所以你不会得到两个具有相同时间戳的文件,这是不太可能的,但它会发生)。 这两种情况都存在问题,但我认为没有完美的解决方案,因此可以归结为您期望用户使用您的服务的频率。

清空队列

根据您使用的队列的存储类型,我只需将控制台应用程序设置为每5分钟运行一次的服务器上的计划任务或运行所需的频率。 计划任务检查队列中是否有新作业,并继续处理前一个作业。

结论

以上描述是“简单”的方法。 它不需要很多技能,也不需要你进入一种全新的框架和类似的东西。

如果是我的话,我会选择文件和计划任务的解决方案,因为它很容易实现和测试。 如果您遇到大量流量,您可以随时更改存储队列的方式,使其更具性能。

作为最后一点:记住在从队列处理作业时进行日志记录以帮助您进行调试;)

我想你应该看看并行库中的“任务”……

http://msdn.microsoft.com/en-us/library/dd537609.aspx

处理asinc队列非常好。

虽然我建议你使用某种持久性来避免数据丢失,但是在db中的另一个表中,或者在文件或任何其他方法中序列化。

你不应该只信任内存存储。 IIS重置或Windows重启,即使在appPool中回收也会破坏未处理的数据。

我认为你可以通过使用缓存来实现这一点。 创建一个包含每个会话数据的队列,并将队列存储在缓存中。 然后使用缓存执行自定义数据库操作。 当您使用队列时,它将是FCFS。 因此,只有在使用用户1之后才会使用用户2的数据。