0

我正在我的网站上构建一个非常简单的聊天页面,这是我目前所拥有的:

聊天

这是代码:

<asp:Content ID="Content2" ContentPlaceHolderID="maincontent" Runat="Server">
    <script language="javascript" type="text/javascript">
        var prm = Sys.WebForms.PageRequestManager.getInstance();
        prm.add_endRequest(EndRequestHandler);

        function EndRequestHandler(sender, args) {
            document.getElementById('<%=FormView1.FindControl("chattxt").ClientID%>').focus(); 
        }
    </script>
    <div id="chatbg">
    <asp:UpdatePanel ID="UpdatePanel1" runat="server">
    <ContentTemplate>
<div id="chatmessages">
    <asp:Repeater ID="Repeater1" runat="server" DataSourceID="SqlDataSource1">
    <ItemTemplate>
        <asp:Literal ID="Literal1" runat="server" Text='<%# Eval("Username") %>'></asp:Literal>: <asp:Literal ID="Literal2" runat="server" Text='<%# Eval("Message") %>'></asp:Literal><br />
    </ItemTemplate>
    </asp:Repeater>
</div>
    <asp:ListBox ID="ListBox1" runat="server" Rows="16" CssClass="memberlist"></asp:ListBox>
    </ContentTemplate>
    </asp:UpdatePanel>
        <asp:UpdatePanel ID="UpdatePanel2" runat="server" UpdateMode="Conditional">
        <ContentTemplate>
        <asp:FormView ID="FormView1" runat="server" DefaultMode="Insert"
        OnItemInserted="fv_ItemInserted" RenderOuterTable="False" 
            DataSourceID="SqlDataSource1">
        <InsertItemTemplate>
            <asp:Panel ID="Panel1" runat="server" DefaultButton="Button1">
            <asp:TextBox ID="chattxt" runat="server" CssClass="chattxtbox"
            Text='<%# Bind("Message") %>' autocomplete="off"></asp:TextBox>
        <asp:Button ID="Button1" runat="server" CommandName="insert" style="display:none" Text="Button"/>
            </asp:Panel>
        </InsertItemTemplate>
        </asp:FormView>
        </ContentTemplate>
        </asp:UpdatePanel>
</div>
    <asp:SqlDataSource ID="SqlDataSource1" runat="server" 
        ConnectionString="<%$ ConnectionStrings:orangefreshConnectionString1 %>" 
        InsertCommand="INSERT INTO [Chat] ([Username], [Message]) VALUES (@Username, @Message)" 
        SelectCommand="SELECT [Id], [Username], [Message], [Date] FROM [Chat] ORDER BY [Id]" >
        <InsertParameters>
            <asp:Parameter Name="Message" Type="String" />
            <asp:Parameter Name="Date" Type="DateTime" /> 
            <asp:SessionParameter Name="Username" SessionField="Username" Type="String" />
        </InsertParameters>
    </asp:SqlDataSource>
    <script type="text/javascript">
        function scrollpos() {
            var objDiv = document.getElementById("chatmessages");
            objDiv.scrollTop = objDiv.scrollHeight;
        }


</script>
</asp:Content>
  • 页面顶部的脚本在回发后将焦点重新放在我的文本框上。
  • 页面底部的脚本通过回发确保消息窗口上的滚动始终位于底部。

这是我的代码隐藏:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.Security;
using orangefreshModel;

public partial class chat : BasePage
{

    protected void Page_Load(object sender, EventArgs e)
    {
        Session["Username"] = User.Identity.Name;
        ListBox1.Items.Clear();
        foreach (MembershipUser myuser in Membership.GetAllUsers())
            if (myuser.IsOnline == true)
            {
                ListBox1.Items.Add(myuser.ToString());

            }

        ScriptManager.RegisterStartupScript(
                            UpdatePanel1,
                            this.GetType(),
                            "ScrollPos",
                            "scrollpos();",
                            true);
    }

    protected void fv_ItemInserted(object sender, FormViewInsertedEventArgs e)
    {
        this.FormView1.DataBind();
    }
}

所以这一切工作得很好,UpdatePanel 确保我的消息立即弹出,现在的问题是看到其他用户消息。这是我的第一个 ASP.NET 项目,所以我考虑过一点,并尝试每秒尝试一个 Timer 来重新填充我的中继器......但没有成功,我认为这根本不是一个明智的解决方案:

首先,影响我的中继器窗口的计时器使用户无法向上滚动以阅读消息,因为它每秒刷新一次滚动是不可能的。

其次,无论如何我从来没有让它工作,这是我为我的计时器尝试的事件:

 protected void Timer1_Tick(object sender, EventArgs e)
        {
            this.Repeater1.DataSource = SqlDataSource1;
            this.Repeater1.DataBind();
        }

但是,是的,没有成功。

这就是我现在与这个聊天的地方:我可以看到我的消息弹出很好,但现在我需要想办法让我的窗口在其他用户输入他们的消息时更新,如果其他用户输入一个新的消息,我需要发送自己的消息才能看到他们的消息。

我一直在浏览网页,阅读了一些关于 Signal R 的内容,但我想知道是否有人对我应该去哪里有更简单的想法,如何在我的消息窗口上实现实时更新?

4

4 回答 4

2

我建议研究 SignalR - http://nuget.org/packages/signalr

SignalR 是一个保持持久连接打开并允许服务器将数据“推送”到客户端的库。

您还可以查看http://www.slideshare.net/adammokan/introduction-to-signalr-10082193作为 SignalR 的一个不错的概述

于 2012-08-30T15:47:54.660 回答
1

SignalR是一个不错的选择。

但是,如果您出于某种原因确实想自己做,那么您应该这样做。

在 asp.net 中构建聊天的最有效方法是使用IHttpAsyncHandler和 ajax 请求。

异步请求允许您延迟请求的响应,直到发生外部事件。
用户调用此处理程序并等待有人向他发送消息。
一旦您将消息发送给用户,它们就会被传递。

收到消息后,客户端发出另一个请求并等待下一条消息。这就是保持持久连接打开并允许服务器将数据推送到客户端的方式。

这比轮询站点以检查消息是否到达要有效得多。
使用异步处理程序还可以确保在用户等待消息到来时不会浪费任何 asp.net 线程。使用计时器轮询您将很快用完线程来处理 asp.net 中的请求。

这可以确保即使网站用户数量增加,您的聊天也可以很好地扩展。

这是一个与 ajax 一起实现这个的完全工作的项目。

于 2012-08-30T16:53:22.987 回答
1

一种选择是在 ASP.Net 生命周期之外执行此操作,并向服务器发出手动 AJAX 请求。服务器方法最多可以保持连接 30 秒,并在新消息到达后立即返回。然后将其返回给客户端并在 JS 中处理,然后他们打开另一个连接并再次等待。我听说这叫reverse AJAX poll.

但是,您是否检测到新消息取决于您,您可以每秒轮询 DB,或在内存中维护消息等。

请注意,如果成千上万的客户端保持与服务器的打开连接,这可能会导致问题。

于 2012-08-30T15:38:06.973 回答
1

我同意 KingPancake 的观点,SignalR 将是处理此类问题的一种非常好的方法。如果您想完全保留数据,您可以使用新的 .Net Web API 和 SignalR 等“后端”

查看Brad Wilson 的此演示文稿,它可能会对您有所帮助:

于 2012-08-30T15:56:04.483 回答