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プロジェクトなので、少しだけそれを応援し、毎秒タイマーを試してリピーターを再作成することを考えました...しかし成功せず、それは賢明な解決策ではないと思います:

まず第一に、私のリピーターウィンドウに影響を与えるタイマーは、ユーザーがメッセージを読むために上にスクロールすることを不可能にしました。

第二に、私はとにかくそれを動作させることができませんでした、これは私が私のタイマーのために試したイベントです:

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

しかし、ええ、成功しません。

これが私が今このチャットをしているところです:メッセージがうまくポップアップするのを見ることができますが、他のユーザーが新しいメッセージを入力した場合に、他のユーザーがメッセージを入力したときにウィンドウを更新する方法を理解する必要がありますメッセージを入力します。彼らのメッセージを表示するには、自分のメッセージを送信する必要があります。

私は少しの間Webを閲覧していて、Signal Rについていくつか読んでいますが、誰かがこれをどこに行けばいいのか、メッセージウィンドウにリアルタイム更新を実装する方法についてもっと簡単なアイデアがあるのではないかと思っていました。

4

4 に答える 4

2

SignalRを調べることをお勧めします-http ://nuget.org/packages/signalr

SignalRは、永続的な接続を開いたままにし、サーバーがデータをクライアントに「プッシュ」できるようにするライブラリです。

また、SignalRの適切な概要としてhttp://www.slideshare.net/adammokan/introduction-to-signalr-10082193を参照することもできます。

それ

于 2012-08-30T15:47:54.660 に答える
1

One option is to do this outside of the ASP.Net lifecycle and makea manual AJAX request to the server. The server method can hold on to the connection for a max of 30 secs, returning any new messages as soon as they arrive. This is then returned to the client and handled in JS, and they then open another connection and wait again. I've heard this called the reverse AJAX poll.

However you detect new messages is up to you, you could poll the DB every second, or maintain in memory message etc.

Note that this can cause problems if thousands of clients are holding open connections to the server.

于 2012-08-30T15:38:06.973 に答える
1

SignalRは良いオプションです。

ただし、何らかの理由で自分でやりたい場合は、この方法で対処する必要があります。

asp.netでチャットを構築する最も効率的な方法は、IHttpAsyncHandlerとajaxリクエストを使用することです。

非同期リクエストを使用すると、外部イベントが発生するまでリクエストの応答を遅らせることができます。
ユーザーはこのハンドラーを呼び出し、誰かが彼にメッセージを送信するまで待ちます。
メッセージは、ユーザーに送信するとすぐに配信されます。

メッセージを受信すると、クライアントは別の要求を行い、次のメッセージを待ちます。これは、持続的接続を開いたままにして、サーバーがデータをクライアントにプッシュできるようにする方法です。

これは、メッセージが到着したかどうかを確認するためにサイトをポーリングするよりもはるかに効率的です。
非同期ハンドラーを使用すると、ユーザーがメッセージの送信を待機している間、asp.netスレッドが無駄になることもありません。タイマーを使用してポーリングすると、asp.netで要求を処理するためのスレッドがすぐに不足します。

これにより、サイトのユーザー数が増えてもチャットを適切に拡張できます。

これは、ajaxとともにこれを実装する完全に機能するプロジェクトです。

于 2012-08-30T16:53:22.987 に答える
1

私はKingPancakeに同意します。SignalRはこのようなものにアプローチするための非常に良い方法です。データを永続化したい場合は、SignalRと組み合わせた新しい.NetWebAPIのようなものでこれを「バックエンド」することができます。

あなたを助けるかもしれないブラッドウィルソンによるこのプレゼンテーションをチェックしてください:

于 2012-08-30T15:56:04.483 に答える