简体   繁体   English

获取新创建的线程以将输出发送到ASP.NET C#中的asp:panel时出现问题

[英]Problems getting newly created thread to send outputs to asp:panel in ASP.NET C#

I'm creating a file processor for use in an intranet. 我正在创建用于Intranet的文件处理器。 I described it in another question - ERR_EMPTY_RESPONSE when processing a large number of files in ASP.Net using C# 我在另一个问题-ERR_EMPTY_RESPONSE中使用C#处理ASP.Net中的大量文件时对此进行了描述

Now, as suggested on above question's answer, I'm trying to use threads to execute the file processing task. 现在,如上述问题的答案所建议,我正在尝试使用线程执行文件处理任务。

But there is a problem. 但有一个问题。 I need the newly created thread to write feedbacks to a component in page (asp:panel, or div, or whatever). 我需要新创建的线程将反馈写入页面中的组件(asp:panel或div或其他)。 Those feedbacks would be results from several database operations. 这些反馈将是几个数据库操作的结果。

The application reads those txts, interprets each line of it, and insert data in database. 应用程序读取这些txt,解释其每一行,然后将数据插入数据库。 Each line inserted in database must return a feedback, like "registry 'regname' inserted successfully", or "i got problems inserting registry 'regname' in file 'filename', skipping to next registry". 插入数据库中的每一行都必须返回一个反馈,例如“注册表成功插入注册表名”,或者“我在将文件注册表名插入文件名时遇到问题,跳到下一个注册表”。

I did test with something very simple: 我做了一些非常简单的测试:

protected void DoImport()
{
    try
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "wait");

        int x = 0;
        while (x < 10000)
        {
            ReturnMessage(String.Format("Number {0}<hr />", x), ref pnlConfirms);
            x++;
        }
    }
    catch (Exception ex)
    {
        ReturnMessage(String.Format("<font style='color:red;'><b>FATAL ERROR DURING DATA IMPORT</b></font><br /><br /><font style='color:black;'><b>Message:</b></font><font style='color:orange;'> {0}</font><br />{1}", ex.Message, ex.StackTrace), ref pnlErrors);
    }
    finally
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "default");
    }
}

This function is called from Page_Load, and fills an asp:panel called "pnlConfirms" with a row of numbers, but all at once, on load. 从Page_Load调用此函数,并在加载时将一行数字填充一个名为“ pnlConfirms”的asp:panel。

I changed it to: 我将其更改为:

protected void DoImport()
{
    try
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "wait");
        ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
    }
    catch (Exception ex)
    {
        ReturnMessage(String.Format("<font style='color:red;'><b>FATAL ERROR DURING DATA IMPORT</b></font><br /><br /><font style='color:black;'><b>Message:</b></font><font style='color:orange;'> {0}</font><br />{1}", ex.Message, ex.StackTrace), ref pnlErrors);
    }
    finally
    {
        MainBody.Style.Add(HtmlTextWriterStyle.Cursor, "default");
    }
}

private void DoWork(Object stateInfo)
{
    int x = 0;
    while (x < 10000)
    {
        ReturnMessage(String.Format("Number {0}<hr />", x), ref pnlConfirms);
        x++;
    }
}

And both uses this function: 两者都使用此功能:

public void ReturnMessage(string message, ref Panel panel, bool reset = false)
{
    if (reset)
    {
        panel.Controls.Clear();
    }
    Label msg = new Label();
    msg.Attributes.Add("width", "100%");
    msg.Text = message;
    panel.Controls.Add(msg);
}

I need ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork)); 我需要ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork)); to fill those asp:panels with feedbacks - like insertion errors and warnings. 用反馈(例如插入错误和警告)填充这些asp:panel。

My code already has those feedbacks under try...catch statements, but they're not getting output to any asp:panel from threadpool (it works when invoked directly from DoImport() function, like in the first example I posted). 我的代码已经在try...catch语句下获得了这些反馈,但是它们并没有从DoImport()输出到任何asp:panel(当直接从DoImport()函数调用时,它可以工作,就像我发布的第一个示例一样)。

I'm doing something very wrong, but I can't find out what (and I'm researching this for almost 2 weeks). 我做错了什么,但是我找不到原因(而且我已经研究了将近2个星期)。 Please, help! 请帮忙!

In ASP.NET, when a browser requests a page, that page is rendered and sent to the browser as soon as its processing finishes, so the browser will show the page as it's finally rendered. 在ASP.NET中,当浏览器请求页面时,该页面将被渲染并在处理完成后立即发送到浏览器,因此浏览器将在最终渲染时显示该页面。

According to your code you're trying to render a page, show a wait cursor, and expect it's shown on the browser and then, the cursor is changed by a default cursor. 根据您的代码,您试图呈现页面,显示等待光标,并期望它显示在浏览器中,然后默认光标更改了该光标。 As I explained, independently from using or not additional threads, the page won't be sent to the browser until it's completely rendered. 正如我所解释的,无论是否使用其他线程,该页面在完全呈现之前都不会发送到浏览器。 So you'l never see the wait cursor on the client side. 因此,您永远不会在客户端看到等待游标。

The easiest wait to get what you're trying to do is to use web services (traditional .asmx or WCF) and AJAX (jquery os ASP.NET AJAX). 最简单的等待操作就是使用Web服务(传统的.asmx或WCF)和AJAX(jquery os ASP.NET AJAX)。

1) create a web service that does the processing 1)创建一个进行处理的Web服务

2) create a page which is sent to the browser, and, using javascript (jQuery or ASP.NET AJAX) make a call to the web service, and show something to let the user know that the request is being processed. 2)创建一个发送到浏览器的页面,并使用javascript(jQuery或ASP.NET AJAX)对Web服务进行调用,并显示一些内容以使用户知道请求正在处理中。 (a wait cursor, or even better an animated gif) (一个等待光标,甚至更好的动画gif)

3) when the process finishes, your javascript will get the responde from the web service, and you can update the page to let the user know the process has finished. 3)完成该过程后,您的JavaScript将从Web服务获取响应者,并且您可以更新页面以使用户知道该过程已完成。

if you don't have experience on javascript, you can make most of this task using: 如果您没有使用javascript的经验,则可以使用以下方法完成大部分任务:

  • ScriptManager which can be used to create a javascript web service proxy for your client side ( other interesting article ) and is required for the rest of the controls ScriptManager ,可用于为您的客户端创建javascript Web服务代理其他有趣的文章 ),其余控件则需要

  • some javascript (or jquery) which can be use to update the "process running/ process finished hints" on the client side. 一些javascript(或jquery),可用于在客户端更新“进程正在运行/进程已完成提示”。 Ie when the call to the web service ends, you can use javascript to update the page using DOM, or load a new page or the same page with an special parameter to show the result of the process 也就是说,当对Web服务的调用结束时,您可以使用javascript使用DOM更新页面,或者使用特殊参数加载新页面或同一页面以显示处理结果

In this way you can do what you want: 通过这种方式,您可以做自己想做的事情:

1) show a page in a state that shows the process is running 1)以显示进程正在运行的状态显示页面

2) show the same, or other page, in a state that shows the end of the process 2)在显示过程结束的状态下显示同一页面或其他页面

The trick is comunicating the browser with the server, and this can only be done using some of the available ajax techniques. 技巧是将浏览器与服务器进行通信,而这只能使用某些可用的ajax技术来完成。

Another typical technique is using jQuery.ajax, like explained in encosia.com 另一种典型的技术是使用jQuery.ajax,如encosia.com中所述

According to the OP message, the process of all the files would be so slow that it would tiemout the web service call. 根据OP消息,所有文件的处理将非常缓慢,以至于会阻塞Web服务调用。 If this is the case, you can use this solution: 在这种情况下,您可以使用以下解决方案:

1) Create a web service that process one (or a batch) of the pending files, and returns at least the number of pending files when it finishes the processing of the current file (or batch). 1)创建一个处理一个(或一批)待处理文件的Web服务,并在完成当前文件(或批处理)的处理后至少返回待处理文件的数量。

2) from the client side (javascript), call the web service. 2)从客户端(javascript)调用Web服务。 When it finishes, update the page showing the number of pending files, and, if this number is greater than zero, call the web service again. 完成后,更新显示挂起文件数量的页面,如果该数量大于零,请再次调用该Web服务。

3) when the call to the web service returns 0 pending files, you can update the page to show the work is finished, and don't call it any more. 3)当对Web服务的调用返回0个待处理文件时,您可以更新页面以显示工作已完成,并且不再调用它。

If you process all the files at once, there will be no feedback on the client side, and there will also be a timeout. 如果您一次处理所有文件,则客户端将没有反馈,并且还会有超时。 Besides, IIS can decide to stop the working thread which is making the work. 此外,IIS可以决定停止正在工作的工作线程。 IIS does this for several reasons. IIS这样做有几个原因。

A more reliable solution, but harder to implement, is: 一个更可靠但更难以实施的解决方案是:

1) implement a Windows Service, that does the file processing 1)实现Windows服务,该服务进行文件处理

2) implement a web service that returns the number of pending files (you can communicate the Windows Service and Web App indirectly using the file system, a database table or something like that) 2)实现一个返回未决文件数量的Web服务(您可以使用文件系统,数据库表或类似的东西间接地与Windows Service和Web App进行通信)

3) use a timer (ajax timer, or javascript setInterval) from your web page to poll the server every N seconds using the web service, until the number of pending files is 0. 3)使用您的网页上的计时器(ajax计时器,或javascript setInterval)使用Web服务每N秒轮询一次服务器,直到待处理文件的数量为0。

An even harder way to do this is hosting a WCF service in your Windows Service, instead of the indirect communication between your web app and windows service. 一种更困难的方法是在Windows服务中托管WCF服务,而不是在Web应用程序和Windows服务之间进行间接通信。 This case is much more complicated because you need to use threads to do the work, and attend the calls to the wcf service. 这种情况要复杂得多,因为您需要使用线程来完成工作,并参加对wcf服务的调用。 If you can use indirect communitacion it's much easier to implemente. 如果可以使用间接通信,则实现起来会容易得多。 The dtabse table is a simple and effective solution: your working process updates a row a table whenever it process a file, and the web service reads the progress state from this table. dtabse表是一种简单而有效的解决方案:您的工作进程在处理文件时都会更新表的一行,并且Web服务从该表读取进度状态。

There are many different soultions for a not so simple problem. 对于一个并非如此简单的问题,有很多不同的想法。

You are starting new thread (or more precise running your code on one of free threads in thread pool)and not waiting for results in main thread. 您正在启动新线程(或更精确地说,在线程池中的一个空闲线程上运行代码),而不是在等待主线程中的结果。 Something like Thread.Join (if you would use manual thread creation) or other synchronization mechanism as events need to be used if you want to go this route. 像Thread.Join之类的东西(如果您将使用手动线程创建)或其他同步机制,因为如果您想走这条路线,则需要使用事件。

The question you've linked to suggests using asynchronous pages which you are not doing. 您链接到的问题建议您使用未使用的异步页面。 You would start processing request, kick off the task and release the thread, when the task is finished you complete request. 您将开始处理请求,启动任务并释放线程,当任务完成时,您将完成请求。

Side note: consider simply doing all conversion on main thread that handles request. 旁注:考虑简单地在处理请求的主线程上进行所有转换。 Unless you expect slow I/O to complete the task moving CPU work from one thread to another may not produce significant gains. 除非您期望缓慢的I / O完成将CPU工作从一个线程转移到另一个线程的任务,否则可能不会带来明显的收益。 Please measure performance of your current solution and confirm that it does not meet performance goals you have set up for your application. 请评估您当前解决方案的性能,并确认它不满足您为应用程序设置的性能目标。 (this does not apply if you doing it for fun/educational purposes). (如果您出于娱乐/教育目的这样做则不适用)。

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

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