在单独的线程中执行操作以取消阻止用户界面 [英] Execute an Action in separate thread to unblock the UI

查看:76
本文介绍了在单独的线程中执行操作以取消阻止用户界面的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个用于生成报告的表格.我们正在使用RDLC报告,并且该报告已加载到aspx页面中.

I have a form which is used to generate a Report. We are using RDLC reports and the Report is loaded in an aspx page.

这是Form的代码,表单目标设置为_blank,并在新标签页中打开.

So this is the code for the Form, form target is set to _blank, and opens in new Tab.

@using (Html.BeginForm("AssetReports", "AssetReports", FormMethod.Post, new { target = "_blank" }))
{
    <div class="row mt-15">
        <div class="col-md-12 text-center">
            <input type="submit" class="btn btn-primary" value="Show Report" />
        </div>
    </div>
}

这是Controller动作,它重定向到Report aspx页面,在该页面上处理和显示报告.

This is the Controller action which redirects to the Report aspx page, where the Report is processed and displayed.

[HttpPost]
public void AssetReports(AssetReportsDTO model, AssetReportParametersDTO reportParameters)
{
    SessionHandler.AssetReport = model;
    SessionHandler.AssetReportParameters = reportParameters;

    switch (model.SelectedReportType)
    {
        case AssetReportTypesEnum.ExcessiveIdleReport:
            Response.Redirect("~/Reports/AssetReports/ExcessiveIdleReport/ExcessiveIdleReport.aspx");
            break;
    }
}

在某些情况下,生成报告需要3.4分钟.在这段时间内,用户界面被阻止了,

The Reports take 3,4 minutes to generate in some cases. and during this time the UI is blocked,

我们希望报表在单独的线程上生成,以便用户可以在生成报表时使用UI.

We want the report to generate on a separate thread so that user can use the UI while the report is generated.

MVC C#中是否有一种方法可以在单独的线程中执行此操作?

Is there a way in MVC C# to Execute this Action in a separate Thread?

我尝试使用以下内容,但是上下文和会话为NULL

I have tried using the following, but the Context and Session are then NULL

Task.Factory.StartNew(() =>
{
    switch (model.SelectedReportType)
    {
        case AssetReportTypesEnum.ExcessiveIdleReport:
            Response.Redirect("~/Reports/AssetReports/ExcessiveIdleReport/ExcessiveIdleReport.aspx");
            break;
    }
});

还有:

new Thread(() =>
{
    switch (model.SelectedReportType)
    {
        case AssetReportTypesEnum.ExcessiveIdleReport:
            Response.Redirect("~/Reports/AssetReports/ExcessiveIdleReport/ExcessiveIdleReport.aspx");
            break;
    }
}).Start();

编辑

用于生成报告的代码-这需要3到4分钟的代码ExcessiveIdleReport.aspx

Code to generate the Report in - This is the code that takes 3 to 4 minutes ExcessiveIdleReport.aspx

public partial class ExcessiveIdleReport1 : Page
    {
        private IReportsProvider _reportsProvider;

        protected void Page_Load(object sender, EventArgs e)
        {
            _reportsProvider = new ReportsProvider();
            if (!IsPostBack)
            {
                try
                {
                    var reportDetails = SessionHandler.AssetReport;
                    var reportParams = SessionHandler.AssetReportParameters;



                    var sPath = Server.MapPath("../ExcessiveIdleReport/ExcessiveIdleReport.rdlc");
                    var dsExcessiveReport =
                        _reportsProvider.GetExcessiveIdleReport(reportDetails.CompanyId, reportDetails.AssetId, reportDetails.StartDate,
                                                                reportDetails.EndDate, reportParams.SelectedIdleTime * 60);

                    ExcessiveIdleReportViewer.ProcessingMode = ProcessingMode.Local;
                    ExcessiveIdleReportViewer.LocalReport.EnableHyperlinks = true;
                    ExcessiveIdleReportViewer.HyperlinkTarget = "_blank";
                    ExcessiveIdleReportViewer.LocalReport.DataSources.Add(new ReportDataSource("ExcessiveIdleReport", dsExcessiveReport.Tables[0]));
                    ExcessiveIdleReportViewer.LocalReport.DataSources.Add(new ReportDataSource("ReportHeaderDetails", dsExcessiveReport.Tables[1]));
                    ExcessiveIdleReportViewer.LocalReport.DataSources.Add(new ReportDataSource("ReportSummary", dsExcessiveReport.Tables[2]));
                    ExcessiveIdleReportViewer.LocalReport.ReportPath = sPath;

                    ExcessiveIdleReportViewer.LocalReport.EnableExternalImages = true;
                    ExcessiveIdleReportViewer.LocalReport.SetParameters(param);

                    ExcessiveIdleReportViewer.LocalReport.Refresh();

                }
                catch (Exception ex)
                {
                    ErrorDiv.InnerText = string.Format("An error occured while generating the ExcessiveIdleReport, Please contact Support with following Message: [{0}] - [{1}]", ex.Message, ex.StackTrace);
                    ReportContentDiv.Visible = false;
                    ErrorDiv.Visible = true;
                }
            }
        }
    }

我也尝试过使用Ajax.BeginForm

 @using (Ajax.BeginForm("AssetReports", "AssetReports", new AjaxOptions() { HttpMethod = "POST", OnSuccess = "OpenReport"}, new { target = "_blank" }))
            {

            <div class="row mt-15">
                <div class="col-md-12 text-center">
                    <input type="submit" class="btn btn-primary" value="Show Report" />
                </div>
            </div>
}

JS:

function OpenReport(response) {
    var popup = window.open("about:blank", "_blank"); // the about:blank is to please Chrome, and _blank to please Firefox
    popup.location = '/TBReports/AssetReports/ExcessiveIdleReport/ExcessiveIdleReport.aspx';
}

我使用Ajax加载所有其他页面:

I load all other Pages using Ajax:

这是执行操作的资产报告"页面显示报告"按钮的图像:

Here is an image of the Asset Reports page 'Show Report' button which executes the action:

但是,一旦单击此按钮,其他UI元素就会被阻止.例如在生成报告之前,无法使用Group Reports加载View.

But once this button is clicked other UI Elements are Blocked. e.g. I can't load View with Group Reports until the Report has been generated.

推荐答案

ASP.NET MVC倾向于序列化同一会话的请求,除非您指定该会话为只读.

ASP.NET MVC tends to serialize requests for the same session unless you specify that session is readonly.

在Microsoft的这篇文章中, https://msdn.microsoft.com/zh-cn/library/ms178581.aspx ,其中指出:

In this article by Microsoft, https://msdn.microsoft.com/en-us/library/ms178581.aspx, it states:

并发请求和会话状态

每个会话对ASP.NET会话状态的访问是独占的,这意味着 如果两个不同的用户同时发出请求,则可以访问每个 并发地授予单独的会话.但是,如果两个并发 对同一会话发出请求(通过使用相同的SessionID 值),则第一个请求将获得对该会话的独占访问权限 信息.第二个请求仅在第一个请求之后执行 完成. (如果独占,第二个会话也可以访问 因为第一个请求超过了,所以释放了对信息的锁定 锁定超时.)如果@页面中的EnableSessionState值 指令设置为ReadOnly,这是对只读会话的​​请求 信息不会导致会话数据互斥锁定. 但是,对会话数据的只读请求可能仍然需要等待 通过读写请求设置的锁定来清除会话数据.

Access to ASP.NET session state is exclusive per session, which means that if two different users make concurrent requests, access to each separate session is granted concurrently. However, if two concurrent requests are made for the same session (by using the same SessionID value), the first request gets exclusive access to the session information. The second request executes only after the first request is finished. (The second session can also get access if the exclusive lock on the information is freed because the first request exceeds the lock time-out.) If the EnableSessionState value in the @ Page directive is set to ReadOnly, a request for the read-only session information does not result in an exclusive lock on the session data. However, read-only requests for session data might still have to wait for a lock set by a read-write request for session data to clear.

您可能希望将会话状态设置为只读,或者使用更明智的技术(例如node.js). (只是在开玩笑...)

You might want to look into making the session state readonly or use a more sensible technology like node.js. (just kidding about the last bit...)

有关约翰·库尔维纳(John Culviner)的文章,请参见此处: http://johnculviner.com/asp-net-concurrent-ajax-requests-and-session-state-blocking/,他说:

See here for John Culviner's article: http://johnculviner.com/asp-net-concurrent-ajax-requests-and-session-state-blocking/, where he says:

MVC 3解决方案

A Solution for MVC 3

幸运的是,Microsoft已在以下位置提供了ENUM值: 允许我们放弃的System.Web.SessionState.SessionStateBehavior 排他会话锁的权限.主要值:

Luckily Microsoft has provided ENUM values in System.Web.SessionState.SessionStateBehavior that allow us to give up rights to an exclusive session lock. Mainly the values:

ReadOnly –不阻止其他请求,因为该请求无法 更新会话已禁用–无法阻止,您最好的选择是 StateServer&中的性能SQL模式,因为不需要序列化 发生.请记住,所有会话都已序列化和反序列化 每次用户.不仅是您正在访问的特定键.

ReadOnly – Doesn’t block other requests because this request can’t update session Disabled – Can’t block, and your best option for performance in StateServer & SQL modes because no serialization needs to occur. Remember that all of session is serialized and de-serialized per user every time. Not just particular keys your are accessing.

在MVC 3属性上添加新属性,并在其中添加所需的Enum值 这样的控制器类:

Throw a new for MVC 3 attribute with your desired Enum value on your Controller class as such:

[SessionState(System.Web.SessionState.SessionStateBehavior.ReadOnly)]
public class TestController : Controller
{
    public ActionResult Index()
    {
        System.Threading.Thread.Sleep(10000);
        return new EmptyResult();
    }
}

这篇关于在单独的线程中执行操作以取消阻止用户界面的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆