C# 在Post操作发生后使用模型绑定更新文本框
我对Razor和.NETCore3.1的一个公认的非传统用例有一个问题。我为我的字段设置了一个带有模型绑定的Razor页面,当用户单击按钮时,它将路由到NoAction函数以执行一些可能很长的(用户定义的时间量)计算。当三个并行运行的任务中的任何一个发送消息时,我想向文本框发送消息,但我无法使用模型绑定在客户端更新文本框,并且我不想在每次modelstate更新时导致回发(因为并行任务可以在100ms到5000ms之间的任何位置发送消息) 我可能做错了,因为我对剃须刀还相当陌生。其思想是并行任务使用我的自定义ConcurrentQueue(因此我可以在消息进入队列时添加事件处理程序),并且每当进入队列的事件触发时,主线程都会更新文本框 以下是.cshtml文件: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之间的任何位置发送消息) 我可能做错了,因为我对剃须刀还相当陌生。其思想是并行任务
@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