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.cs
的Index
方法中找到。 接下來,我們將創建所需的控制器。
創建控制器和動作方法 (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 G
ET
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
Index
action method of theHomeController
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 i
ndex.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_ID , PUSHER_APP_KEY , PUSHER_APP_SECRET和PUSHER_APP_CLUSTER初始化了Pusher(請確保將其替換為儀表板上的實際值)。 然后,我們廣播一個包含 導電型測量儀 -這是人打字-對typing
通過事件chat
通道。
? We’ve added n
ew 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 }
。 這是為了防止廣播的發送者也接收廣播。 為此,我們假設我們在負載中收到了socket_id
和yper,
因此在客戶端,我們將其添加到發送的負載中。
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_KEY和PUSHER_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應用程序