C# 在Post操作发生后使用模型绑定更新文本框

C# 在Post操作发生后使用模型绑定更新文本框,c#,asp.net-mvc,razor,razor-pages,asp.net-core-3.1,C#,Asp.net Mvc,Razor,Razor Pages,Asp.net Core 3.1,我对Razor和.NETCore3.1的一个公认的非传统用例有一个问题。我为我的字段设置了一个带有模型绑定的Razor页面,当用户单击按钮时,它将路由到NoAction函数以执行一些可能很长的(用户定义的时间量)计算。当三个并行运行的任务中的任何一个发送消息时,我想向文本框发送消息,但我无法使用模型绑定在客户端更新文本框,并且我不想在每次modelstate更新时导致回发(因为并行任务可以在100ms到5000ms之间的任何位置发送消息) 我可能做错了,因为我对剃须刀还相当陌生。其思想是并行任务

我对Razor和.NETCore3.1的一个公认的非传统用例有一个问题。我为我的字段设置了一个带有模型绑定的Razor页面,当用户单击按钮时,它将路由到NoAction函数以执行一些可能很长的(用户定义的时间量)计算。当三个并行运行的任务中的任何一个发送消息时,我想向文本框发送消息,但我无法使用模型绑定在客户端更新文本框,并且我不想在每次modelstate更新时导致回发(因为并行任务可以在100ms到5000ms之间的任何位置发送消息)

我可能做错了,因为我对剃须刀还相当陌生。其思想是并行任务使用我的自定义ConcurrentQueue(因此我可以在消息进入队列时添加事件处理程序),并且每当进入队列的事件触发时,主线程都会更新文本框

以下是.cshtml文件:

@page
@using AMQSimNetCore.Pages;
@model AMQSimNetCore.Pages.Producer.ProducerModel
@{
    ViewData["Title"] = "Producer";
}

<h1>Producer</h1>

<div class="jumbotron">
    <h1>AMQ Producer</h1>
    @using (Html.BeginForm("OnPostRunSimulator_OnClickAsync", "Producer", FormMethod.Post))
    {
        <div class="container" id="dv_ctrlsContainer" style="border-color:grey; border-style:solid; border-width:thin; margin-bottom:10px">
            <div class="row">
                <div class="col-md-3">
                    <input type="checkbox" asp-for="TalkerSelected" />
                    <label ID="lbl_talker">Generate Talker Messages</label>
                </div>
                <div class="col-md-5">
                    <label ID="lbl_talkerTime">Time (in ms) between generated talker messages.</label>
                </div>
                <div class="col-md-3">
                    <input type="text" asp-for="TalkerTime" width="75" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <input type="checkbox" asp-for="PartInfoSelected" />
                    <label ID="lbl_partInfo">Generate PartInfo Messages</label>
                </div>
                <div class="col-md-5">
                    <label ID="lbl_partInfoTime">Time (in ms) between generated part info messages.</label>
                </div>
                <div class="col-md-3">
                    <input type="text" asp-for="PartInfoTime" Width="75" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <input type="checkbox" asp-for="ConfInfoSelected" />
                    <label ID="lbl_confInfo">Generate ConfInfo Messages</label>
                </div>
                <div class="col-md-5">
                    <label ID="lbl_confInfoTime">Time (in ms) between generated conf info messages.</label>
                </div>
                <div class="col-md-3">
                    <input type="text" asp-for="ConfInfoTime" Width="75" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <label ID="lbl_totalSimTime">Total Time (in ms) to run Simulator</label>
                </div>
                <div class="col-md-2">
                    <input type="text" asp-for="TotalConfTime" Width="75" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <label ID="lbl_numSimultaneousConfs">Number of Simulatenous Conferences</label>
                </div>
                <div class="col-md-2">
                    <input type="text" asp-for="NumSimultaneousConfs" Width="75" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <label ID="lbl_numParts">Number of participants.</label>
                </div>
                <div class="col-md-2">
                    <input type="text" asp-for="NumParts" Width="75" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <label ID="lbl_endpoint">Choose Endpoint</label>
                </div>
                <div class="col-md-5">                    
                    <select asp-for="EndpointString" class="form-control">
                        <option>xxxxxxxx</option>
                        <option>xxxxxxxx</option>
                        <option>xxxxxxxx</option>
                        <option>xxxxxxxx</option>
                    </select>
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <label ID="lbl_userName">Username</label>
                </div>
                <div class="col-md-5">
                    <input type="text" asp-for="UserName" Width="150" />
                </div>
            </div>
            <div class="row">
                <div class="col-md-3">
                    <label ID="lbl_password">Password</label>
                </div>
                <div class="col-md-5">
                    <input type="text" asp-for="Password" Width="150" />
                </div>
            </div>
        </div>
        <div class="container" style="border-color:grey; border-style:solid; border-width:thin; margin-bottom:10px">
            <div class="row">
                <div class="col-md-12">
                    <input type="text"style="height:auto; width:100% !important;" asp-for="Logger" />
                </div>
            </div>
        </div>
        <div>
            <input type="submit" ID="btn_run" asp-page-handler="RunSimulator_OnClick" Width="125" value="Run Simulator" />
        </div>
    }
</div>
@page
@使用AMQSimNetCore.Pages;
@型号AMQSimNetCore.Pages.Producer.ProducerModel
@{
ViewData[“标题”]=“制作人”;
}
制作人
AMQ生产商
@使用(Html.BeginForm(“OnPostRunSimulator\u OnClickAsync”,“Producer”,FormMethod.Post))
{
生成说话者消息
生成的通话器消息之间的时间(毫秒)。
生成PartInfo消息
生成零件信息消息之间的时间(毫秒)。
生成ConfInfo消息
生成的配置信息消息之间的时间(毫秒)。
运行模拟器的总时间(毫秒)
模拟会议次数
与会者人数。
选择端点
xxxxxxxx
xxxxxxxx
xxxxxxxx
xxxxxxxx
用户名
密码
}
以下是.cshtml.cs代码:

    using Apache.NMS;
using Apache.NMS.ActiveMQ;
using Apache.NMS.ActiveMQ.Commands;
using Common.Logging;
using ServiceStack.Text;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.UI;
using System.Threading;
using System.Threading.Tasks;
using System.Collections.Concurrent;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.Razor.TagHelpers;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using System.ComponentModel.DataAnnotations;
using ISession = Apache.NMS.ISession;
using static AMQSimNetCore.ConcurrentQueueWithEvents<string>;

namespace AMQSimNetCore.Pages.Producer
{
    [BindProperties]
    public class ProducerModel : PageModel
    {

        public string EndpointString { get; set; }

        public bool TalkerSelected { get; set; } = true;
        public int TalkerTime { get; set; } = 1000;

        public bool PartInfoSelected { get; set; } = true;
        public int PartInfoTime { get; set; } = 1000;

        public bool ConfInfoSelected { get; set; } = true;
        public int ConfInfoTime { get; set; } = 1000;

        public int TotalConfTime { get; set; } = 60000;
        public int NumSimultaneousConfs { get; set; } = 5;
        public int NumParts { get; set; } = 2;

        public string UserName { get; set; } = "xxxxxx";
        public string Password { get; set; } = "xxxxxx";

        public string Logger { get; set; }

        private readonly ConcurrentQueueWithEvents<string> loggerText = new ConcurrentQueueWithEvents<string>();
        private ConnectionFactory factory;
        private IConnection connection;
        private IMessageProducer producer;
        private ISession sessionProducer;
        private int msgNum = 0, loopTimes = 0;
        private List<int> ConfIds = new List<int>();
        private readonly string publishTopicName = "xxxxxxx";

        public void OnGet()
        {
            ConfIds = new List<int>(Enumerable.Range(1, NumSimultaneousConfs));
            HttpContext.Session.SetString("ConfIds", JsonSerializer.SerializeToString(ConfIds));
        }

        [NonAction]
        public async void OnPostRunSimulator_OnClickAsync(IFormCollection collection)
        {
            loggerText.OnEnqueuedMessage += MessageEnqueued;

            bool _config = await LoadConfig(collection);

            if (!_config)
            {
                this.Response.Redirect("/Error");
            }

            if(EndpointString.Contains("xxxxxxx"))
            {
                this.factory = new ConnectionFactory("ssl://" + EndpointString + "?wireFormat.maxInactivityDuration=30000");
            }
            else
            {
                this.factory = new ConnectionFactory("failover:(ssl://" + EndpointString + "?wireFormat.maxInactivityDuration=30000)");
            }

            this.factory.AsyncSend = true;

            this.connection = factory.CreateConnection(UserName, Password);
            ((Connection)this.connection).AsyncSend = true;
            this.connection.Start();
            this.sessionProducer = this.connection.CreateSession();

            Task pt = Task.Run(() => {
                Parallel.Invoke(
                    () =>
                    {
                        CalcLoop();
                    },
                    () =>
                    {
                        if (ConfInfoSelected)
                        {

                            GenerateConfInfo(ConfIds);
                        }
                    },
                    () =>
                    {
                        if (PartInfoSelected)
                        {

                            GeneratePartInfo(ConfIds);
                        }
                    },
                    () =>
                    {
                        if (TalkerSelected)
                        {

                            GenerateTalker(ConfIds);
                        }
                    }
                );
            });

            ModelState.Clear();
            Task.WhenAll(pt);
        }

        void MessageEnqueued()
        {
            if (loggerText.TryDequeue(out string _msg))
            {
                Logger += _msg + System.Environment.NewLine;
            }
        }

        private Task<bool> CalcLoop()
        {
            bool _finished = false;

            while (loopTimes < (this.TotalConfTime / 1000))
            {
                Thread.Sleep(1000);
                loopTimes++;
            }
            return Task.FromResult(_finished);
        }

        private Task<bool> GenerateConfInfo(List<int> confIds)
        {
            bool _finished = false;

            while (loopTimes < (this.TotalConfTime / 1000))
            {
                foreach (int confId in confIds)
                {
                    var conf = new ConfInfo()
                    {
                        ConfId = confId.ToString(),
                        Active = true,
                        TalkerNotify = true
                    };

                    using (var m = new MemoryStream())
                    {
                        ProtoBuf.Serializer.Serialize(m, conf);
                        ActiveMQBytesMessage msg = new ActiveMQBytesMessage();
                        msg.Content = m.ToArray();
                        msg.Properties.SetString("confid", confId.ToString());

                        Interlocked.Increment(ref msgNum);

                        msg.Properties.SetString("msgNum", msgNum.ToString());

                        msg.NMSDeliveryMode = MsgDeliveryMode.NonPersistent;

                        msg.NMSType = "confinfo";

                        msg.NMSTimeToLive = new TimeSpan(0, 0, 10);

                        msg.ReadOnlyBody = true;

                        var topic = new ActiveMQTopic(publishTopicName + "." + confId.ToString());

                        this.producer = this.sessionProducer.CreateProducer(topic);
                        this.producer.Send(msg);

                        loggerText.Enqueue(String.Format("{0} - MsgNum {1}: Sending ConfInfo message for ConfId {2}", DateTime.UtcNow.ToString(), msgNum.ToString(), confId.ToString()));
                    }

                    Thread.Sleep(ConfInfoTime);
                }
            }

            return Task.FromResult(_finished);
        }

        private Task<bool> GeneratePartInfo(List<int> confIds)
        {
            bool _finished = true;

            while (loopTimes < (this.TotalConfTime / 1000))
            {
                foreach (int confId in confIds)
                {
                    Random partId = new Random();
                    var part = new PartInfo()
                    {
                        ConfId = confId.ToString(),
                        Connected = true,
                        PartId = partId.Next().ToString()
                    };

                    using (var m = new MemoryStream())
                    {

                        ProtoBuf.Serializer.Serialize(m, part);
                        ActiveMQBytesMessage msg = new ActiveMQBytesMessage();
                        msg.Content = m.ToArray();
                        msg.Properties.SetString("confid", confId.ToString());

                        Interlocked.Increment(ref msgNum);
                        msg.Properties.SetString("msgNum", msgNum.ToString());

                        msg.NMSDeliveryMode = MsgDeliveryMode.NonPersistent;
                        msg.NMSType = "partinfo";
                        msg.NMSTimeToLive = new TimeSpan(0, 0, 10);

                        msg.ReadOnlyBody = true;

                        var topic = new ActiveMQTopic(publishTopicName + "." + confId.ToString());

                        this.producer = this.sessionProducer.CreateProducer(topic);
                        this.producer.Send(msg);

                        loggerText.Enqueue(String.Format("{0} - MsgNum {1}: Sending PartInfo message for ConfId {2}, PartId {3}", DateTime.UtcNow.ToString(), msgNum.ToString(), confId.ToString(), part.PartId));
                    }

                    Thread.Sleep(PartInfoTime);
                }
            }

            return Task.FromResult(_finished);
        }

        private Task<bool> GenerateTalker(List<int> confIds)
        {
            bool _finished = true;

            while (loopTimes < (this.TotalConfTime / 1000))
            {
                foreach (int confId in confIds)
                {
                    var talker = new Talker()
                    {
                        ConfId = confId.ToString(),
                        PartIds = new List<string> { "xxxxxxx" }
                    };

                    using (var m = new MemoryStream())
                    {
                        ProtoBuf.Serializer.Serialize(m, talker);
                        ActiveMQBytesMessage msg = new ActiveMQBytesMessage();
                        msg.Content = m.ToArray();
                        msg.Properties.SetString("confid", confId.ToString());

                        Interlocked.Increment(ref msgNum);
                        msg.Properties.SetString("msgNum", msgNum.ToString());

                        msg.NMSDeliveryMode = MsgDeliveryMode.NonPersistent;
                        msg.NMSType = "talker";
                        msg.NMSTimeToLive = new TimeSpan(0, 0, 10);

                        msg.ReadOnlyBody = true;

                        var topic = new ActiveMQTopic(publishTopicName + "." + confId.ToString());

                        this.producer = this.sessionProducer.CreateProducer(topic);
                        this.producer.Send(msg);

                        loggerText.Enqueue(String.Format("{0} - MsgNum {1}: Sending Talker message for ConfId {2}", DateTime.UtcNow.ToString(), msgNum.ToString(), confId.ToString()));
                    }

                    Thread.Sleep(TalkerTime);
                }
            }
            return Task.FromResult(_finished);
        }

        private Task<bool> LoadConfig(IFormCollection collection)
        {
            bool _success = false;

            try
            {
                if (collection.Keys.Contains("EndpointString"))
                {
                    this.EndpointString = collection["EndpointString"];
                }

                if (collection.Keys.Contains("TalkerSelected"))
                {
                    this.TalkerSelected = bool.Parse(collection["TalkerSelected"].ToArray()[0]);
                }

                if (collection.Keys.Contains("TalkerTime"))
                {
                    this.TalkerTime = Int32.Parse(collection["TalkerTime"]);
                }

                if (collection.Keys.Contains("PartInfoSelected"))
                {
                    this.PartInfoSelected = bool.Parse(collection["PartInfoSelected"].ToArray()[0]);
                }

                if (collection.Keys.Contains("PartInfoTime"))
                {
                    this.PartInfoTime = Int32.Parse(collection["PartInfoTime"]);
                }

                if (collection.Keys.Contains("ConfInfoSelected"))
                {
                    this.ConfInfoSelected = bool.Parse(collection["ConfInfoSelected"].ToArray()[0]);
                }

                if (collection.Keys.Contains("ConfInfoTime"))
                {
                    this.ConfInfoTime = Int32.Parse(collection["ConfInfoTime"]);
                }

                if (collection.Keys.Contains("TotalConfTime"))
                {
                    this.TotalConfTime = Int32.Parse(collection["TotalConfTime"]);
                }

                if (collection.Keys.Contains("NumSimultaneousConfs"))
                {
                    this.NumSimultaneousConfs = Int32.Parse(collection["NumSimultaneousConfs"]);
                    ConfIds = new List<int>(Enumerable.Range(1, NumSimultaneousConfs));
                    HttpContext.Session.SetString("ConfIds", JsonSerializer.SerializeToString(ConfIds));
                }

                if (collection.Keys.Contains("NumParts"))
                {
                    this.NumParts = Int32.Parse(collection["NumParts"]);
                }

                if (collection.Keys.Contains("UserName"))
                {
                    this.UserName = collection["UserName"];
                }

                if (collection.Keys.Contains("Password"))
                {
                    this.Password = collection["Password"];
                }

                if (collection.Keys.Contains("Logger"))
                {
                    this.Logger = collection["Logger"];
                }

                _success = true;
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            return Task.FromResult(_success);
        }
    }
使用Apache.NMS;
使用Apache.NMS.ActiveMQ;
使用Apache.NMS.ActiveMQ.Commands;
使用公共日志;
使用ServiceStack.Text;
使用制度;
使用System.Collections.Generic;
使用System.IO;
使用System.Linq;
使用System.Web.UI;
使用系统线程;
使用System.Threading.Tasks;
使用System.Collections.Concurrent;
使用Microsoft.AspNetCore.Mvc;
使用Microsoft.AspNetCore.Mvc.RazorPages;
使用Microsoft.AspNetCore.Razor.TagHelpers;
使用Microsoft.AspNetCore.Http;
使用Microsoft.Extensions.Primitives;
使用Microsoft.AspNetCore.Mvc.ViewFeatures;
使用System.ComponentModel.DataAnnotations;
使用ISession=Apache.NMS.ISession;
使用静态AMQSimNetCore.ConcurrentQueueWithEvents;
命名空间AMQSimNetCore.Pages.Producer
{
[BindProperties]
公共类ProducerModel:PageModel
{
公共字符串端点字符串{get;set;}
公共bool TalkerSelected{get;set;}=true;
公共整数通话时间{get;set;}=1000;
public bool partinfo selected{get;set;}=true;
公共int partinfo时间{get;set;}=1000;
public bool confinfo selected{get;set;}=true;
公共int confinfo时间{get;set;}=1000;
公共int TotalConfTime{get;set;}=60000;
public int NumSimultaneousConfs{get;set;}=5;
公共int NumParts{get;set;}=2;
公共字符串用户名{get;set;}=“xxxxxx”;
公共字符串密码{get;set;}=“xxxxxx”;
公共字符串记录器{get;set;}
private readonly ConcurrentQueueWithEvents loggerText=新建ConcurrentQueueWithEvents();
私人连接工厂;
专用i连接;
私营IMessageProducer;
私人会话制作人;
private int msgNum=0,loopTimes=0;
私有列表ConfIds=新列表();
私有只读字符串publishTopicName=“xxxxxxx”;
公共互联网
{
ConfIds=新列表(可枚举的范围(1,NumSimultaneousConfs));
HttpContext.Session.SetString(“ConfIds”,JsonSerializer.SerializeToString(ConfIds));
}
[不行动]
公共异步void OnPostRunSimulator\u OnClickAsync(IFormCollection集合)
{
loggerText.OnEnqueuedMessage+=MessageEnqueued;
bool\u config=await LoadConfig(集合);
如果(!\u配置)
{
this.Response.Redirect(“/Error”);
}
if(EndpointString.Contains(“xxxxxxx”))
{
this.factory=new Connec