asp.net应用程序_如何在ASP.NET中为聊天应用程序构建键入指示器

asp.net应用程序

by Neo Ighodaro

由新Ighodaro

如何在ASP.NET中为聊天应用程序构建键入指示器 (How to build a typing indicator for your chat app in ASP.NET)

A basic understanding of ASP.NET and jQuery is needed to follow this tutorial.
要学习本教程,需要对ASP.NET和jQuery有基本的了解。

When you’re using a chat app, knowing when the person you are chatting with is typing a message can improve your user experience. It gives you some feedback that you’re not alone in the conversation, and that a message is coming your way.

当您使用聊天应用程序时,知道与您聊天的人何时键入消息可以改善您的用户体验。 它为您提供了一些反馈,表明您并不孤单,并且有消息在向您发送。

In this tutorial, we will go through some simple steps to create this feature using C#, .NET, and Pusher.

在本教程中,我们将通过一些简单的步骤使用C#、. NET和Pusher创建此功能。

At the end of this tutorial we will have something like this:

在本教程的最后,我们将提供以下内容:

This tutorial assumes prior knowledge of:

本教程假定您具有以下先验知识:

  • C#

    C#
  • .NET MVC

    .NET MVC
  • JavaScript (jQuery)

    JavaScript(jQuery)

When you’re ready, let’s begin.

准备就绪后,就开始吧。

设置我们的项目 (Setting up our project)

We’ll be using Visual Studio, which is an IDE popularly used for building .NET projects. Visual Studio 2017 is free and available for most Operating Systems. You can view installation details here.

我们将使用Visual Studio ,这是一个广泛用于构建.NET项目的IDE。 Visual Studio 2017是免费的,适用于大多数操作系统。 您可以在此处查看安装详细信息。

After installing Visual Studio, launch it and create a new project by clicking New Project from the dashboard. Following the New Project wizard we:

安装Visual Studio之后,启动它并通过从仪表板上单击“ 新建项目”来创建一个新项目。 遵循“ 新建项目”向导,我们:

  • Set C# as our language

    将C#设置为我们的语言
  • Select .NET MVC Project as the template

    选择.NET MVC Project作为模板
  • Fill in the Project name (for example “HeyChat” — but any name would do)

    填写项目名称(例如“ HeyChat”,但可以使用任何名称)
  • Fill in the Solution name (that is, the application name — “HeyChat” or any name would do).

    填写解决方案名称(即应用程序名称-“ HeyChat”或任何名称)。

编写服务器端(C)代码 (Writing the server-side (C) code)

To display a typing indicator, our chat app needs to be able to recognize who is typing at any given time. For this, we will add some limited form of identification. We’re not doing any authentication at all, because this tutorial does not require it.

要显示打字指示符,我们的聊天应用程序需要能够在任何给定时间识别谁在打字。 为此,我们将添加一些有限形式的身份证明。 我们根本不进行任何身份验证,因为本教程不需要它。

? For the purpose of this tutorial, we will assume that this chat is open to all users. All that will be required is that our users specify their names on first entry.

就本教程而言,我们假定此聊天对所有用户开放。 所需要做的就是让我们的用户在第一次输入时指定他们的姓名。

路线定义 (Route definition)

We can define some of the routes that we need to make this feature, which are:

我们可以定义实现此功能所需的一些路线,这些路线是:

  • A home route which renders the first page that takes the user’s name.

    一个家庭路线,该路线显示使用用户名的第一页。
  • A login route which accepts a POST request of the user’s name.

    接受用户名的POST请求的登录路由。

  • A chat route which renders the chat view.

    提供聊天视图的聊天路径。

? We may need some other routes as we go along, but this is enough for starters.

我们可能会需要一些其他路线,但这对初学者来说足够了。

To add these routes, we open the RouteConfig.cs file in the App_Start directory of our application. And in it, we add the routes we have defined.

要添加这些路由,我们在应用程序的App_Start目录中打开RouteConfig.cs文件。 然后在其中添加我们定义的路由。

routes.MapRoute(        name: "Home",        url: "",        defaults: new { controller = "Home", action = "Index" }    );
routes.MapRoute(        name: "Login",        url: "login",        defaults: new { controller = "Login", action = "Index" }    );
routes.MapRoute(        name: "ChatRoom",        url: "chat",        defaults: new {controller = "Chat", action="Index"}    );

Using the Home route as a sample, the route definition states that / requests will be handled by the HomeController which is found in the Controllers/HomeController.cs file and the Index method of that controller. Next, we will create the controllers we’ll need.

使用Home路由作为示例,路由定义指出/请求将由HomeController处理,该请求可在Controllers/HomeController.cs文件和该Controllers/HomeController.csIndex方法中找到。 接下来,我们将创建所需的控制器。

创建控制器和动作方法 (Creating controllers and action methods)

To create a new controller, right-click the Controller directory and select Add → Controller. In the resulting form, we type in the name of our controller and select the empty template.

要创建新的控制器,请右键单击Controller目录,然后选择Add → Controller 。 在生成的表单中,我们输入控制器的名称,然后选择空模板。

? When our application is created, it includes a HomeController with an Index action method by default, so we’ll perform the above steps to create our LoginController and ChatController.

创建我们的应用程序时,默认情况下它包括带有Index操作方法的HomeController,因此我们将执行上述步骤来创建LoginController和ChatController。

In our LoginController class, we create the Index action method specifying [HttpPost] at the top of the action method to indicate that it handles POST requests.

在我们的LoginController类中,我们创建Index操作方法,在该操作方法的顶部指定[HttpPost] ,以指示它处理POST请求。

public class LoginController : Controller    {        [HttpPost]        public ActionResult Index()        {
}    }

The Index action of the LoginController will receive the request payload, read the username from the payload, and assign it to the current user session. Then it will redirect our user to the chat page. When we add this to our action method, we’ll have:

LoginController的Index操作将接收请求有效负载,从有效负载中读取用户名,并将其分配给当前用户会话。 然后它将把我们的用户重定向到聊天页面。 将其添加到操作方法时,将具有:

public class LoginController : Controller    {        [HttpPost]        public ActionResult Index()        {            string user = Request.Form["username"];            if (user.Trim() == "") {                return Redirect("/");            }            Session["user"] = user;            return Redirect("/chat");        }    }

? In a real-world chat app, we would add the user to a database and mark the user as logged in so that other users could see the available chat options. But that is beyond the scope of this tutorial, so adding to a session will suffice.

在实际的聊天应用程序中,我们会将用户添加到数据库中,并将该用户标记为已登录,以便其他用户可以看到可用的聊天选项。 但这超出了本教程的范围,因此添加一个会话就足够了。

In our ChatController class, we will add the Index action method. The Index action of the ChatController will render our chat view and pass along the current user to the view.

在我们的ChatController类中,我们将添加Index操作方法。 ChatController的Index操作将呈现我们的聊天视图,并将当前用户传递到该视图。

public class ChatController : Controller    {        public ActionResult Index()        {            if (Session["user"] == null) {                return Redirect("/");            }
ViewBag.currentUser = Session["user"];
return View ();        }    }

? By default, action methods handle GET requests, so we will not need to add [HttpGet] to the top of our method. We’ve also added a simple check to prevent access to the chat page if there is no logged in user.

默认情况下,操作方法处理G ET请求,因此我们无需在方法顶部添加[ HttpGet] 我们还添加了一个简单的检查,以防止在没有登录用户的情况下访问聊天页面。

Let’s not forget about our Home route. In the HomeController, we’ll add the code to render the front page.

让我们不要忘记我们的回家路线。 在HomeController中,我们将添加代码以呈现首页。

public class HomeController : Controller    {        public ActionResult Index()        {            if ( Session["user"] != null ) {                return Redirect("/chat");            }
return View();        }    }

? We’ve also added a small check to prevent multiple logins in the same user session.

我们还添加了一个小检查,以防止在同一用户会话中多次登录。

At this point, we’ve created the Controllers and methods to serve our views (which we haven’t created yet), so trying to run this will give you some errors! Let’s fix that.

至此,我们已经创建了Controllers和方法来服务于我们的视图(尚未创建),因此尝试运行它会给您一些错误! 让我们修复它。

实施应用程序的视图 (Implementing the application’s views)

Based on the routes we’ve defined so far, we will need two views:

根据到目前为止我们定义的路线,我们将需要两个视图:

  • The front page view with the login form — served by the Indexaction method of the HomeController class

    具有登录表单的首页视图—由HomeController类的Index action方法提供服务

  • The chat view where the typing indicator feature will be seen — served by ChatController class’ Index action method

    可以看到键入指示符功能的聊天视图-由ChatController类的Index操作方法提供

主页/登录页面 (Front page/login page)

For our front page, we’ll create a page with a form that asks for the user’s username and shows them a button to submit for login. Referring to our controller code:

对于我们的首页,我们将创建一个带有表单的页面,该表单要求用户的用户名,并向他们显示一个提交登录的按钮。 参考我们的控制器代码:

public class HomeController : Controller    {        public ActionResult Index()        {            if ( Session["user"] != null ) {                return Redirect("/chat");            }            return View();        }    }

? The View function creates a view response which we return. When View() is invoked, C# looks for the default view of the calling controller class. This default view is the index.cshtml file found in the Views directory, in a directory with the same name as the Controller. That is, the default view of the HomeController class will be the Views/Home/index.cshtml file.

V iew函数创建一个视图响应,我们将其返回。 调用V iew()时 ,C#查找调用控制器类的默认视图。 该默认视图是在Views目录中的i ndex.cshtml文件,该目录与Controller的名称相同。 也就是说,HomeController类的默认视图将是iews/Home/index.cshtml文件。

To create our HomeController default view, we:

要创建我们的HomeController默认视图,我们:

  • Right-click on the Views directory and select Add New Folder,

    右键点击Views目录,然后选择Add New Folder

  • Fill in Home as the folder name,

    填写首页作为文件夹名称,

  • Right click the newly created Home folder and select Add New View,

    右键点击新创建的文件夹,然后选择Add New View

  • Fill in the view name (in our case index), select Razor as the view engine, and click OK.

    填写视图名称(在本例中为索引 ),选择Razor作为视图引擎,然后单击“确定”。

Now that we’ve created our front page view file, we’ll add the markup for the login form.

现在,我们已经创建了首页视图文件,我们将为登录表单添加标记。

<div class="container">      <div class="row">        <div class="col-md-5 col-md-offset-4">          <div class="panel panel-default">            <div class="panel-body">              <form action="/login" method="post" style="margin:0">                <div class="form-group">                  <input type="text" name="username" id="username"                       placeholder="Enter Username" class="form-control"                       required minlength="3" maxlength="15" />                </div>                <button type="submit" class="btn btn-primary btn-block">                  Enter Chat                </button>              </form>            </div>          </div>        </div>      </div>    </div>
聊天页面 (The chat page)

We’ll create the view for the chat page following the same steps as above, but using Chat as our folder name rather than Home.

我们将按照与上述相同的步骤为聊天页面创建视图,但是使用“ Chat作为我们的文件夹名称而不是“ Home

In the chat view, we add markup up to give us a sidebar of available users and an area for chatting.

在聊天视图中,我们添加了标记,以便为我们提供可用用户的侧边栏和一个聊天区域。

<!DOCTYPE html>    <html>    <head>      <title>pChat — Private Chatroom</title>      <link rel="stylesheet" href="@Url.Content("~/Content/app.css")">    </head>    <body>            @{                var currentUser = ViewBag.currentUser;            }        <!-- Navigation Bar -->        <nav class="navbar navbar-inverse">          <div class="container-fluid">            <div class="navbar-header">              <a class="navbar-brand" href="#">pChat</a>            </div>            <ul class="nav navbar-nav navbar-right">              <li><a href="#">Log Out</a></li>            </ul>          </div>        </nav>        <!-- / Navigation Bar -->        <div class="container">          <div class="row">            <div class="col-xs-12 col-md-3">              <aside class="main">                <div class="row">                  <div class="col-xs-12">                    <div class="panel panel-default users__bar">                      <div class="panel-heading users__heading">                        Online Users (1)                      </div>                      <div class="panel-body users__body">                        <ul class="list-group">                        @if( @currentUser == "Daenerys" ) {                            <li class="user__item">                                <div class="avatar"></div> <a href="#">Jon</a>                            </li>                        } else if( @currentUser == "Jon") {                            <li class="user__item">                                <div class="avatar"></div> <a href="#">Daenerys</a>                            </li>                        }                        </ul>                      </div>                    </div>                  </div>                </div>              </aside>            </div>            <div class="col-xs-12 col-md-9 chat__body">              <div class="row">                <div class="col-xs-12">                  <ul class="list-group chat__main">                    <div class="row __chat__par__">                      <div class="__chat__ from__chat">                        <p>Did you see Avery's sword???</p>                      </div>                    </div>                    <div class="row __chat__par__">                      <div class="__chat__ receive__chat">                        <p>Err Looked normal to me...</p>                      </div>                    </div>                    <div class="row __chat__par__">                      <div class="__chat__ receive__chat">                        <p>maybe I'm a hater</p>                      </div>                    </div>                    <div class="row __chat__par__">                      <div class="__chat__ from__chat">                        <p>Lmaooo</p>                      </div>                    </div>                  </ul>                </div>                <div class="chat__type__body">                  <div class="chat__type">                    <textarea id="msg_box" placeholder="Type your message"></textarea>                  </div>                </div>                <div class="chat__typing">                  <span id="typerDisplay"></span>                </div>              </div>            </div>          </div>        </div>        <script src="@Url.Content("~/Content/app.js")"></script>        </body>    </html>

We’re using the razor template engine, which gives us the ability to read data passed from the C# code and assign them to variables that can be used in our frontend. Using @{ var currentUser = ViewBag.currentUser } we have passed in the name of the current user, which will come in handy shortly.

我们使用的是razor模板引擎 ,它使我们能够读取从C#代码传递的数据,并将其分配给可在前端使用的变量。 使用@{ var currentUser = ViewBag.currentUser }我们传入了当前用户的名称,这很快就会派上用场。

? To keep things quick and simple, we have assumed that there are only two possible users: Daenerys or Jon. So using the razor @if{ } condition, we are showing who is available to chat with.

为了使事情变得简单快捷,我们假设只有两个可能的用户:D aenerys或J on。 因此,使用剃刀@ if{ }条件,我们正在显示可以与谁聊天。

Now that we have our views in place, we can move on to our typing indicator feature!

现在我们已经有了自己的视图,我们可以继续使用打字指示器功能!

实施打字指示器 (Implementing the typing indicator)

聆听打字事件 (Listening for the typing event)

In most chat applications, the feature becomes visible when someone is typing. To implement it, we’ll start off by listening for the typing event in the chat text area using jQuery. We’ll also pass the currentUser variable we defined earlier with razor to our script.

在大多数聊天应用程序中,当有人键入内容时,该功能将变为可见。 为了实现它,我们将从使用jQuery聊天文本区域中的键入事件开始。 我们还将把之前用剃刀定义的currentUser变量传递给脚本。

var currentUser = @currentUser;
$('#msg_box').on('keydown', function () {      //stub    });

We added a listener to the keydown event in our typing area to help us monitor when someone is typing.

我们在键入区域的keydown事件中添加了一个侦听器,以帮助我们监视某人何时键入。

Now that we’ve created our listeners, we’ll make them send a message that someone is typing to the other members of the chat. To do this, we’ll create an endpoint in our C# code to receive this request and broadcast it via Pusher.

现在,我们已经创建了侦听器,我们将使他们向聊天的其他成员发送一条消息,指出有人正在键入消息。 为此,我们将在C#代码中创建一个端点,以接收此请求并通过Pusher广播该请求。

We’ll implement all the client code (assuming that our C# endpoint exists, then we’ll actually create the endpoint later).

我们将实现所有客户端代码(假设我们的C#端点存在,然后稍后再实际创建该端点)。

? To prevent excessive requests to our C# code, that is sending a request as every key on the keypad is pressed or released, we’ll throttle the sending of the requests using a debounce function. This debounce function just ignores a function for a while if it keeps occurring.

为防止对C#代码的过多请求(即在按下或释放键盘上的每个键时发送请求),我们将使用反跳功能来限制请求的发送。 如果该反跳功能持续发生,则会暂时忽略该功能。

// Debounce function    // Credit: https://davidwalsh.name/javascript-debounce-function
// Returns a function, that, as long as it continues to be invoked, will not    // be triggered. The function will be called after it stops being called for    // N milliseconds. If `immediate` is passed, trigger the function on the    // leading edge, instead of the trailing.    function debounce(func, wait, immediate) {        var timeout;        return function() {            var context = this, args = arguments;            var later = function() {                timeout = null;                if (!immediate) func.apply(context, args);            };            var callNow = immediate && !timeout;            clearTimeout(timeout);            timeout = setTimeout(later, wait);            if (callNow) func.apply(context, args);        };    };

Now that we have a debounce function, we’ll create the callback function for our keydown event:

现在我们有了一个去抖动功能,我们将为keydown事件创建回调函数:

var isTypingCallback = debounce( function() {        $.post('/chat/typing', {            typer: currentUser,        });    }, 600, true);

and pass the callback to our event listeners.

并将回调传递给我们的事件监听器。

$('#msg_box').on('keydown',isTypingCallback);
创建由键入事件触发的端点 (Creating the endpoint triggered by the typing event)

Earlier, we had our event listeners send a POST request to the /chat/typing Route on the client side. Now we’ll create this Route, which will transmit the typing event to other client users using Pusher.

之前,我们让事件监听器将POST请求发送到客户端的/chat/typing Route。 现在,我们将创建此Route,它将使用Pusher将键入事件传输给其他客户端用户。

First, we’ll create the route for the endpoint in our RouteConfig.cs file.

首先,我们将在RouteConfig.cs文件中为端点创建路由。

...    routes.MapRoute(        name: "UserTyping",        url: "chat/typing",        defaults: new { controller = "Chat", action = "Typing" }    );

? We’ve created this endpoint to be handled by the Typing action method of the ChatController.

我们创建了此端点,以使用C hatController的T yping action方法进行处理

Next, we’ll create our Typing action method in the ChatController:

接下来,我们将在ChatController创建Typing action方法:

[HttpPost]    public ActionResult Typing()    {        //stub    }

使用Pusher实时更新我们的应用程序 (Using Pusher to make our application update in realtime)

Our /`chat/typing` endpoint will receive a post payload of the user who is doing the typing. We’re going to use Pusher to transmit this to everyone else.

我们的/`聊天/打字”端点将收到正在进行打字的用户的帖子负载。 我们将使用Pusher将其传输给其他人。

On our Pusher dashboard, we’ll create a new app filling out the information requested — app name, frontend tech, and so on. You can register for free if you don’t have an account. Next, we’ll install the Pusher Server package in our C# code using NuGet, a packer manager for .NET.

在Pusher 仪表板上 ,我们将创建一个新应用,填写所需的信息-应用名称,前端技术等。 如果您没有帐户,可以免费注册 。 接下来,我们将使用.NET的打包程序管理器NuGet将Pusher Server软件包安装在C#代码中。

? To install the package, we right-click the Packages directory, select the add Package option, and select the Pusher Server package.

要安装该软件包,我们右键单击P ackages目录,选择dd软件包选项,然后选择P 服务器服务器软件包。

Then we’ll add the Pusher broadcasting to our Typing action event. To use Pusher, we’ll have to import the Pusher Server namespace into our code.

然后,我们将Pusher广播添加到我们的Typing action事件中。 要使用Pusher,我们必须将Pusher Server名称空间导入我们的代码中。

...    using PusherServer;
namespace HeyChat.Controllers    {        public class ChatController : Controller        {          ...
[HttpPost]          public ActionResult Typing()          {              string typer        = Request.Form["typer"];              string socket_id    = Request.Form["socket_id"];
var options = new PusherOptions();              options.Cluster = "PUSHER_APP_CLUSTER";
var pusher = new Pusher(              "PUSHER_APP_ID",              "PUSHER_APP_KEY",              "PUSHER_APP_SECRET", options);
pusher.TriggerAsync(              "chat",              "typing",              new { typer = typer },              new TriggerOptions() { SocketId = socket_id });
return new HttpStatusCodeResult(200);          }         ...

We initialized Pusher using our PUSHER_APP_ID, PUSHER_APP_KEY, PUSHER_APP_SECRET, and PUSHER_APP_CLUSTER (be sure to replace these with the actual values from your dashboard). Then we broadcast an object containing the typer — which is the person typing — on the typing event via the chat channel.

我们使用PUSHER_APP_IDPUSHER_APP_KEYPUSHER_APP_SECRETPUSHER_APP_CLUSTER初始化了Pusher(请确保将其替换为仪表板上的实际值)。 然后,我们广播一个包含 导电型测量仪 -这是人打字-typing通过事件chat通道。

? We’ve added new TriggerOptions() { SocketId = socket_id } to our Pusher triggerAsync function. This is to prevent the sender of the broadcast from receiving the broadcast as well. To do this, we’ve assumed we’re receiving socket_id in our payload along with typer, so on our client side, we’ll add it to the payload sent.

我们在Pusher t riggerAsync函数中添加了ew TriggerOptions() { SocketId = socket_id } 这是为了防止广播的发送者也接收广播。 为此,我们假设我们在负载中收到了s ocket_idyper,因此在客户端,我们将其添加到发送的负载中。

Now, whenever there’s a typing event, our C# code broadcasts it on Pusher. All that is left is to listen to that broadcast and display the ‘xxxx is typing…’ feature.

现在,每当发生打字事件时,我们的C#代码都会在Pusher中广播该事件。 剩下的就是收听广播并显示“ xxxx正在输入...”功能。

First, we’ll initialize Pusher in the script section of our chat page using our PUSHER_APP_KEY and PUSHER_APP_CLUSTER (once again, replace these with the values from your dashboard).

首先,我们将在聊天页面的脚本部分中使用PUSHER_APP_KEYPUSHER_APP_CLUSTER初始化Pusher(再次将它们替换为仪表板中的值)。

var pusher = new Pusher('PUSHER_APP_KEY', {        cluster:'PUSHER_APP_CLUSTER'    });

To implement the broadcaster exemption we mentioned earlier, we’ll get the socket id from our client pusher instance and amend our payload for the typing request to the server to include it.

为了实现我们前面提到的广播商豁免,我们将从客户端pusher实例中获取套接字ID,并修改向服务器的键入请求的有效负载以将其包括在内。

var socketId = null;    pusher.connection.bind('connected', function() {      socketId = pusher.connection.socket_id;    });
var isTypingCallback = debounce( function() {        $.post('/chat/typing', {            typer: currentUser,            socket_id: socketId // pass socket_id parameter to be used by server        });    }, 600, true);

Now that Pusher is initialized on our client side, we’ll subscribe to the chat channel and implement our feature using the typer passed.

现在,在客户端初始化了Pusher,我们将订阅聊天频道并使用传递的typer来实现我们的功能。

var channel = pusher.subscribe('chat');
channel.bind('typing', function(data) {        $('#typerDisplay').text( data.typer + ' is typing...');
$('.chat__typing').fadeIn(100, function() {            $('.chat__type__body').addClass('typing_display__open');        }).delay(1000).fadeOut(300, function(){            $('.chat__type__body').removeClass('typing_display__open');        });    });

结论 (Conclusion)

In this tutorial, we’ve walked through implementing the popular typing indicator feature using Pusher, .NET, C# code and some jQuery. We’ve also seen how to broadcast messages and avoid the sender responding to a message they sent.

在本教程中,我们逐步使用了Pusher,.NET,C#代码和一些jQuery实现了流行的打字指示器功能。 我们还看到了如何广播消息以及如何避免发件人对他们发送的消息作出响应。

This post was first published to Pusher.

该帖子最初发布给Pusher

翻译自: https://www.freecodecamp.org/news/how-to-build-a-typing-indicator-for-your-chat-app-in-asp-net-2b008680a69a/

asp.net应用程序

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值