ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

CodeGo.net>如何在ASP MVC中实现“用户交互”依赖注入

2019-11-11 17:17:34  阅读:135  来源: 互联网

标签:dependency-injection asp-net c asp-net-mvc


我有一个完整的引擎,该引擎依赖于基于用户交互的抽象.这对WPF / Xamarin应用程序非常有效,因为我可以使用window / form来实现这种抽象.

将此引擎移植到ASP MVC时遇到一些问题.

这样可以显示一个简单的示例.

抽象接口(简体)

public interface IQuestionBox
{
    Task<bool> ShowYesNoQuestionBox(string message);
}

对于WPF,这确实非常简单,我通过调用ShowDialog()将此接口实现为返回窗口的结果.

在一个简单的业务类中,我可以进行这种调用(简化):

public async Task<string> GetValue(IQuestionBox qbox)
{
    if(await qbox.ShowYesNoQuestionBox("Question ?"))
    {
        return "Ok";
    }
    return "NOk";
}

由于HTTP处于无状态状态,我真的看不到如何在ASP中实现这种行为,因为我知道这种调用可以随域/业务需求的变化而变化.我认为应该这样做是通过返回PartialView注入弹出窗口来实现的,但是在不中断所有过程的情况下,我不知道如何做到这一点.

有人做过吗?

解决方法:

您可以创建从客户端到服务器端的Web套接字连接.并通过Web套接字请求处理前端内容.它可以实现如下:

客户端:

$app = {
    uiEventsSocket : null,
    initUIEventsConnection : function(url) {
        //create a web socket connection
        if (typeof (WebSocket) !== 'undefined') {
                this.uiEventsSocket = new WebSocket(url);
            } else if (typeof (MozWebSocket) !== 'undefined') {
                this.uiEventsSocket = new MozWebSocket(url);
            } else {
                console.error('WebSockets unavailable.');
            }

            //notify if there is an web socket error
            this.uiEventsSocket.onerror = function () {
                console.error('WebSocket raised error.');
            }

            this.uiEventsSocket.onopen = function () {
                console.log("Connection to " + url + " established");
            }

            //handling message from server side
            this.uiEventsSocket.onmessage = function (msg) {
                this._handleMessage(msg.data);
            };
    },

    _handleMessage : function(data){
        //the message should be in json format
        //the next line fails if it is not
        var command = JSON.parse(data);

        //here is handling the request to show prompt
        if (command.CommandType == 'yesNo') {
            var message = command.Message;

            var result = confirm(message);
            //not sure that bool value will be successfully converted
            this.uiEventsSocket.send(result ? "true" : "false");
        }
    }
}

并从ready或load事件初始化它:

window.onload = function() { $app.initUIEventsConnection(yourUrl); }

请注意,您的url应该以ws://而不是http://和wss://而不是https://开头(Web套接字和Web套接字安全).

服务器端.

Here是一篇有关如何在asp.net核心应用程序上设置Web套接字的好文章,或者您可以找到另一个.请注意,您应该将单个用户的Web套接字连接分组,如果要向具体用户发送消息,则应该为该用户的每个连接发送消息.

您应该通过AcceptWebSocketAsync()方法调用接受的每个Web套接字,然后将此Web套接字的实例添加到singleton,其中包含一组按用户分组的Web套接字连接.

以下类将用于操作命令:

public class UICommand
{
    public string CommandType { get; set; }
    public string Message { get; set; }
    public Type ReturnType { get; set; }
}

以及用于处理套接字的完整单例代码

public class WebSocketsSingleton
{
    private static WebSocketsSingleton _instance = null;
    //here stored web sockets groupped by user
    //you could use user Id or another marker to exactly determine the user
    private Dictionary<string, List<WebSocket>> _connectedSockets;

    //for a thread-safety usage
    private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();

    public static WebSocketsSingleton Instance {
        get {
            if (this._instance == null)
            {
                this._instance = new WebSocketsSingleton();
            }

            return this._instance;
        }
    }

    private WebSocketsSingleton()
    {
        this._connectedSockets = new Dictionary<string, List<WebSocket>>();
    }

    /// <summary>
    /// Adds a socket into the required collection
    /// </summary>
    public void AddSocket(string userName, WebSocket ws)
    {
        if (!this._connectedSockets.ContainsKey(userName))
        {
            Locker.EnterWriteLock();
            try
            {
                this._connectedSockets.Add(userName, new List<WebSocket>());
            }
            finally
            {
                Locker.ExitWriteLock();
            }
        }

        Locker.EnterWriteLock();
        try
        {
            this._connectedSockets[userName].Add(ws);
        }
        finally
        {
            Locker.ExitWriteLock();
        }
    }

    /// <summary>
    /// Sends a UI command to required user
    /// </summary>  
    public async Task<string> SendAsync(string userName, UICommand command)
    {
        if (this._connectedSockets.ContainsKey(userName))
        {
            var sendData = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(command));

        foreach(var item in this._connectedSockets[userName])
        {
            try
            {
                await item.SendAsync(new ArraySegment<byte>(sendData), WebSocketMessageType.Text, true, CancellationToken.None);
            }
            catch (ObjectDisposedException)
            {
                //socket removed from front end side
            }
        }

            var buffer = new ArraySegment<byte>(new byte[1024]);
            var token = CancellationToken.None;         
            foreach(var item in this._connectedSockets[userName])
            {
                await Task.Run(async () => {
                    var tempResult = await item.ReceiveAsync(buffer, token);
                    //result received
                    token = new CancellationToken(true);
                });
            }

            var resultStr = Encoding.Utf8.GetString(buffer.Array);

            if (command.ReturnType == typeof(bool))
            {
                return resultStr.ToLower() == "true";
            }

            //other methods to convert result into required type

            return resultStr;
        }

        return null;
    }
}

说明:

>在通过Web套接字建立连接时,将添加
AddSocket方法
>在发送请求以显示消息时,所需的命令将传递到SendAsync方法中
>该命令将被序列化为JSON(使用Json.Net,但是您可以以您的方式进行序列化)并发送到与所需用户相关的所有套接字
>发送命令后,应用程序将等待前端方的响应
>结果将转换为所需的类型,并发送回您的IQuestionBox

在处理Web套接字时,应添加以下代码:

app.Use(async (http, next) =>
{
    if (http.WebSockets.IsWebSocketRequest)
    {
        var webSocket = await http.WebSockets.AcceptWebSocketAsync();
        var userName = HttpContext.Current.User.Identity.Name;
        WebSocketsSingleton.Instance.AddSocket(userName, webSocket);

        while(webSocket.State == WebSocketState.Open)
        {
            //waiting till it is not closed         
        }

        //removing this web socket from the collection
    }
});

而且,ShowYesNoQuestionBox的方法实现应如下所示:

public async Task<bool> ShowYesNoQuestionBox(string userName, string text)
{
    var command = new UICommand
    {
        CommandType = "yesNo",
        Message = text,
        ReturnType = typeof(bool)
    };

    return await WebSocketsSingleton.Instance.SendAsync(string userName, command);
}

请注意,应该添加userName以防止向所有连接的用户发送相同的消息.

WebSocket应该在服务器和客户端之间创建持久连接,因此您可以简单地以两种方式发送命令.

我是Asp.Net Core的新手,所以最终的实现可能与此有所不同.

标签:dependency-injection,asp-net,c,asp-net-mvc
来源: https://codeday.me/bug/20191111/2021402.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有