Xamarin.Android SignalR 实时消息接收发送示例

2017-01-04 10:32:14来源:作者:Design based .NET人点击

第七城市

SignalR 是一个开发实时 Web 应用的 .NET 类库,使用 SignalR 可以很容易的构建基于 ASP.NET 的实时 Web 应用。SignalR 支持多种服务器和客户端,可以 Host 在 7.0 以上的 IIS 服务器,或者通过 Owin Host 在桌面应用和 Windows 服务的进程中;支持的客户端有浏览器、桌面应用、Siliverlight、各种手机等。

本文将会带你做一个 WPF 应用 Host 的 SignalR 服务端,和一个 Xamarin.Android 的客户端,实现服务端和客户端的简单的消息接收发送。

服务端:

1、新建一个 WPF 应用,通过 Nuget 添加引用 SignalR.SelfHost 类库

Install-Package Microsoft.AspNet.SignalR.SelfHost

如果要支持跨域访问,还需要引用 Microsoft.Owin.Cors 类库

Install-Package Microsoft.Owin.Cors

2、做一个简单的界面,显示接收和发送的消息,在 MainWindow.xaml 中添加下面的代码:

<Grid> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Margin="10"> <Button Name="UxStart" Click="UxStart_Click" Width="80" Height="30" Content="启动" Margin="20,0"/> <Button Name="UxStop" Click="UxStop_Click" Width="80" Height="30" Content="停止"/> </StackPanel> <RichTextBox Name="UxInfo" Grid.Row="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Margin="10,0" IsReadOnly="True"/> <StackPanel Grid.Row="2" Orientation="Horizontal" Margin="10"> <TextBox Name="UxMessage" HorizontalAlignment="Stretch" Width="400" Height="30"/> <Button Name="UxSend" Click="UxSend_Click" Width="80" Height="30" HorizontalAlignment="Right" Content="发送"/> </StackPanel></Grid>

以上代码添加了一个启动按钮和一个停止按钮,用来启动和停止 SignalR 服务端,接着添加一个 RichTextBox 用来显示发送和收到的信息,然后是一个用来输入要发送的信息的 TextBox 和一个 发送按钮,最终界面如下:

主窗体的 C# 代码:

public partial class MainWindow : Window{ private IDisposable _signalrServer; private string _serverUrl = "http://192.168.0.102:8080"; public MainWindow() { InitializeComponent(); UxStop.IsEnabled = false; } private void UxStart_Click(object sender, RoutedEventArgs e) { StartServer(); UxStart.IsEnabled = false; } private void StartServer() { try { _signalrServer = WebApp.Start(_serverUrl); LogMessage("服务已启动:" + _serverUrl + "/r"); UxStop.IsEnabled = true; } catch (TargetInvocationException ex) { LogMessage(ex.Message); } } private void UxStop_Click(object sender, RoutedEventArgs e) { _signalrServer.Dispose(); Close(); } private void UxSend_Click(object sender, RoutedEventArgs e) { LogMessage("Server: " + UxMessage.Text + "/r"); var context = GlobalHost.ConnectionManager.GetHubContext<HubDemo>(); context.Clients.All.send("Server: ", UxMessage.Text); UxMessage.Text = ""; } public void LogMessage(string message) { if (UxInfo.CheckAccess()) { UxInfo.AppendText(message + "/r"); } else { Dispatcher.Invoke(() => { UxInfo.AppendText(message + "/r"); }); } }}

以上代码包含启动服务,向所有客户端发送消息,记录消息几个方法,代码非常简单,这里就不做过多的解释了。

3、添加一个 Startup 类,代码如下:

internal class Startup{ public void Configuration(IAppBuilder app) { app.UseCors(CorsOptions.AllowAll); app.MapSignalR(); }}

现在这里只有两句代码,第一句启用跨域支持,第二句映射 SignalR 的地址。

4、新建一个 Hub,这里命名为 HubDemo,继承 SignalR.Hub,代码如下:

public class HubDemo : Hub{ public void Send(string name, string message) { _repository.Log(name, message); Clients.All.Send(name, message); }}

这里只有一个 Send 方法,发送用户名和信息。

接着定义一个记录接收和发送的消息的接口:

public interface IMessageRepository{ void Log(string name, string message);}

接口中只定义了一个 Log 方法,带有两个 string 类型的参数,一个是发送消息的用户名,一个是消息内容。

接口的实现:

public class MessageRepository : IMessageRepository{ public void Log(string name, string message) { Application.Current.Dispatcher.Invoke(() => ((MainWindow)Application.Current.MainWindow).LogMessage(name + ": " + message)); }}

在这儿我们没有存储消息,只是简单的在窗体上显示出来。

5、将定义的 IMessageRepository 接口添加到 HubDemo 中,修改后的 HubDemo 代码:

public class HubDemo : Hub{ private IMessageRepository _repository; public HubDemo(IMessageRepository repository) { _repository = repository; } public void Send(string name, string message) { _repository.Log(name, message); Clients.All.Send(name, message); } public override Task OnConnected() { _repository.Log(Context.ConnectionId, "已连接。"); return base.OnConnected(); } public override Task OnDisconnected(bool stopCalled) { _repository.Log(Context.ConnectionId, "已断开。"); return base.OnDisconnected(stopCalled); }}

在 Startup 类的 Configuration 方法中注册 Hub:

GlobalHost.DependencyResolver.Register(typeof(HubDemo), () => new HubDemo(new MessageRepository())); 服务端编写完成;接下来写 Android 客户端的代码:

6、新建一个 Xamarin.Android 项目,选择 Blank App 模板

7、引用 SignalR 客户端类库,Xamarin.Android 项目中不能使用 Nuget 上的 SignalR 客户端类库,需要引用这里的类库 https://components.xamarin.com/view/signalr

引用方法:在项目里的 Components 上右键,在弹出菜单中点击 Get more components

在弹出的窗体中搜索 SignalR,双击搜索结果中的 SignalR,在打开的页面中单击 Add to app;也可以从上面的网址下载到本地解压后添加引用

8、做一个简单的发送和显示消息窗体,在 Main.axml 中添加下面的代码:

<LinearLayout android:orientation="horizontal" android:layout_gravity="center" android:layout_width="wrap_content" android:layout_height="wrap_content"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/UserName" /> <EditText android:id="@+id/UserName" android:layout_width="100dp" android:layout_height="wrap_content" /> <Button android:layout_height="wrap_content" android:layout_width="wrap_content" android:layout_gravity="center_vertical" android:text="@string/Connect" android:id="@+id/Connect" /></LinearLayout><LinearLayout android:orientation="horizontal" android:layout_height="wrap_content" android:layout_width="match_parent"> <EditText android:id="@+id/Message" android:layout_gravity="center_vertical" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" /> <Button android:id="@+id/Send" android:layout_gravity="center_vertical" android:layout_height="wrap_content" android:layout_width="wrap_content" android:text="@string/Send" /></LinearLayout><TextView android:id="@+id/Info" android:layout_height="match_parent" android:layout_width="match_parent" android:lines="20" />

上面的代码首先添加一个用户名输入框和一个连接按钮,接着添加一个消息输入框和一个发送按钮,最后是一个消息显示框。输入用户名后点击“连接”,就会连接到 SignalR 服务端;输入消息后点击“发送”按钮向服务端发送消息。

MainActivity 中的 C# 代码:

public class MainActivity : Activity{ private IHubProxy _hubProxy; private HubConnection _connection; private string _serverUrl = "http://192.168.0.102:8080"; private EditText _message, _userName; private TextView _info; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); // Set our view from the "main" layout resource SetContentView(Resource.Layout.Main); _message = FindViewById<EditText>(Resource.Id.Message); _userName = FindViewById<EditText>(Resource.Id.UserName); _info = FindViewById<TextView>(Resource.Id.Info); var connectButton = FindViewById<Button>(Resource.Id.Connect); connectButton.Click += ConnectButton_Click; var sendButton = FindViewById<Button>(Resource.Id.Send); sendButton.Click += SendButton_Click; } private void SendButton_Click(object sender, System.EventArgs e) { // 调用服务端的 Send _hubProxy.Invoke("Send", _userName.Text, _message.Text); _message.Text = ""; } private void ConnectButton_Click(object sender, System.EventArgs e) { if (string.IsNullOrWhiteSpace(_userName.Text)) { _userName.RequestFocus(); Toast.MakeText(this, "请输入用户名。", ToastLength.Short); return; } _userName.Enabled = false; _connection = new HubConnection(_serverUrl, true); _connection.Closed += Connection_Closed; _hubProxy = _connection.CreateHubProxy("HubDemo"); // 匿名方法 Send _hubProxy.On<string, string>("Send", (n, s) => { Application.SynchronizationContext.Post(_ => { AppendText(n + ": " + s); }, null); }); try { _connection.Start().Wait(); } catch (HttpRequestException ex) { AppendText(ex.Message); } AppendText("已连接到:" + _serverUrl + "/r"); } private void Connection_Closed() { AppendText("连接已断开。/r"); } private void AppendText(string txt) { _info.Text += txt + "/n"; } protected override void OnDestroy() { base.OnDestroy(); if (_connection == null) return; _connection.Stop(); _connection.Dispose(); }}

上面的代码也很简单,不需要多做说明,至此服务端和客户端编写完成。

下面是测试运行的结果

如果对本文或本文所写的技术有什么观点,欢迎留言讨论。

代码下载: https://github.com/WaltChen/musical-octo-engine SignalR_Demo

还没人发表观点. 您对本文的观点?

0 我踩

0 我顶

0 超赞

0 困惑

0 新奇

0 思考

0 失望

第七城市

最新文章

123

最新摄影

微信扫一扫

第七城市微信公众平台