Обновление TextBox с привязкой модели после выполнения действия Post - PullRequest
0 голосов
/ 12 марта 2020

У меня проблема с предположительно нетрадиционным вариантом использования Razor и. NET Core 3.1. У меня есть страница Razor с привязками моделей для моих полей, когда пользователь нажимает кнопку, он перенаправляет ее в функцию NonAction для выполнения некоторых потенциально длительных (определяемых пользователем промежуток времени) вычислений. Я хочу отправить сообщение в текстовое поле, когда любая из 3 параллельно выполняемых задач отправляет сообщение, но я не могу обновить текстовое поле на стороне клиента с помощью привязки модели, и я не хочу вызывать обратную передачу каждый раз, когда состояние модели обновления (поскольку параллельные задачи могут передавать сообщения от 100 мс до 5000 мс).

Я, вероятно, делаю это неправильно, поскольку я довольно новичок в Razor. Идея состоит в том, что параллельные задачи используют мой пользовательский ConcurrentQueue (чтобы я мог добавить обработчик событий, когда сообщение ставится в очередь), и всякий раз, когда событие в очереди запускает основной поток, обновляет текстовое поле.

Вот .cs html:

@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>

Вот код .cs html .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);
        }
    }

Любая помощь будет приветствоваться (даже если это сказать мне, что я идиот)!

1 Ответ

0 голосов
/ 25 марта 2020

Так что, как бы я ни хотел использовать привязку модели, пост-событие убивало меня, и это просто невозможно без каких-либо по-настоящему хакерских решений или чего-то вроде SignalR по сути обновлять текстовую область. Я решил пойти дальше и использовать JavaScript и setInterval, чтобы просто проверять модель данных каждую секунду.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...