zoukankan      html  css  js  c++  java
  • WCF 实例 —— Android 短信助手 (WCF + Android)

     (1)最近开始学习 Android,为了更快上手于是给自己找个小课题来练习一下: WCF作为服务端开放RESTful Service,Android作为客户端将手机上的短信传给服务端显示,并轮询服务端是否有发送的短信取回并发送。(在电脑前就可以浏览即时的短信并能快速回复,呵呵还是挺有意思的)。先上几张图:

    1. 客户端:(咦?怎么还用android1.5?没办法现在手机是1.5的,为了在真机上发布凑合用吧:))
     

    2. 服务端:


    其中涉及到的知识点如下:(恩文章标题有点跑偏了,其实大头在Android端。。。)

    1. 服务端:
    (1) RESTful WCF 如何作成 Winform Host
    (2) WCF 服务在 Winform Host 如何与服务端的UI进行数据交互
    2. 客户端:
    (1) Android Timer 的应用
    (2) Android Http 的交互
    (3) Android Json数据的序列化/反序列化
    (4) Android 短信拦截器的使用
    (5) Android Sqlite 查询


    --------------------------------------------------------------------------------

    服务端
    (1) RESTful WCF 如何作成 Winform Host

    首先Binding 选择 webHttpBinding 使用 WebGetAttribute 或 WebInvokeAttribute 特性对各个服务操作进行批注。这定义了从 URI 和 HTTP 方法到服务操作之间的映射,还定义了用于调用操作和返回结果的消息格式。

    view plaincopy to clipboardprint?
    <?xml version="1.0" encoding="utf-8" ?> 
    <configuration> 
      <system.web> 
        <compilation debug="true" /> 
      </system.web> 
      <system.serviceModel> 
        <services> 
          <service name="WCFRestHost.SmsService" behaviorConfiguration="default"> 
            <endpoint address="" binding="webHttpBinding" bindingConfiguration="" 
              contract="WCFRestHost.SmsService"> 
            </endpoint> 
            <host> 
              <baseAddresses> 
                <add baseAddress="http://localhost:8732/RestWcfSMSSvc" /> 
              </baseAddresses> 
            </host> 
          </service> 
        </services> 
        <behaviors> 
          <serviceBehaviors> 
            <behavior name="default"> 
              <serviceMetadata httpGetEnabled="True"/> 
              <serviceDebug includeExceptionDetailInFaults="False" /> 
            </behavior> 
          </serviceBehaviors> 
        </behaviors> 
      </system.serviceModel> 
    </configuration> 
    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.web>
        <compilation debug="true" />
      </system.web>
      <system.serviceModel>
        <services>
          <service name="WCFRestHost.SmsService" behaviorConfiguration="default">
            <endpoint address="" binding="webHttpBinding" bindingConfiguration=""
              contract="WCFRestHost.SmsService">
            </endpoint>
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost:8732/RestWcfSMSSvc" />
              </baseAddresses>
            </host>
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="default">
              <serviceMetadata httpGetEnabled="True"/>
              <serviceDebug includeExceptionDetailInFaults="False" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    (2) WCF 服务在 Winform Host 如何与服务端的UI进行数据交互

    服务端代码,没什么特别的。一开始考虑用socket,但是socket自己维护双工通信太麻烦了,于是想到了WCF,在Winform Host下发布一个RESTful WCF服务,而作为客户端的Android实现Http通信也不是什么难事,服务端直接反序列化成服务端对象编码很便利。
    WCF服务里公开一个static的BindingList<SmsData>作为短信容器(Tip:使用BindingList<T>可以使得数据源变化立即反映到UI上,相比之下List<T>可以说只是Oneway的容器),PC端可以通过UI往里添加要发送的短信,客户端则轮询取出要发送的短信进行发送;当客户端收到短信则通过WCF往容器里放入一条短信对象。流程比较简单,大家一看就明白啦。

    + expand sourceview plaincopy to clipboardprint?
    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Runtime.Serialization;  
    using System.ServiceModel;  
    using System.Text;  
    using System.ServiceModel.Web;  
    using System.ComponentModel;  
    namespace WCFRestHost  
    {  
        [ServiceContract]  
        [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]  
        public class SmsService  
        {  
            static SmsService()  
            {  
                SmsList = new BindingList<SmsData>();  
            }  
            public static BindingList<SmsData> SmsList  
            {  
                get;  
                private set;  
            }  
            public static event Action<SmsData> OnSmsRecieved;  
            public static void AddData(SmsData data)  
            {  
                lock (SmsList)  
                {  
                    SmsList.Add(data);  
                }  
            }  
            [OperationContract]  
            [WebInvoke(UriTemplate="SetData", Method="POST", RequestFormat=WebMessageFormat.Json)]  
            public void SetData(SmsData data)  
            {  
                var ctx = WebOperationContext.Current;  
                data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");  
                //SmsList.Add(data);  
                if (OnSmsRecieved != null)  
                    OnSmsRecieved(data);  
                ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;  
            }  
            [OperationContract]  
            [WebGet(UriTemplate = "GetData", ResponseFormat = WebMessageFormat.Json)]  
            public SmsData GetData()  
            {  
                var ctx = WebOperationContext.Current;  
                var data = SmsList.FirstOrDefault(sms => sms.State == 1);  
                if (data != null)  
                {  
                    data.State = 2;  
                    data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");  
                }  
                ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;  
                return data;  
            }  
        }  
        public class SmsData  
        {  
            public string Phone { get; set; }  
            public string Content { get; set; }  
            public string SmsTime { get; set; }  
            public string Name { get; set; }  
            // 0: recieved 1: presend 2: send  
            public int State { get; set; }  
        }  

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Runtime.Serialization;
    using System.ServiceModel;
    using System.Text;
    using System.ServiceModel.Web;
    using System.ComponentModel;
    namespace WCFRestHost
    {
        [ServiceContract]
        [ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
        public class SmsService
        {
            static SmsService()
            {
                SmsList = new BindingList<SmsData>();
            }
            public static BindingList<SmsData> SmsList
            {
                get;
                private set;
            }
            public static event Action<SmsData> OnSmsRecieved;
            public static void AddData(SmsData data)
            {
                lock (SmsList)
                {
                    SmsList.Add(data);
                }
            }
            [OperationContract]
            [WebInvoke(UriTemplate="SetData", Method="POST", RequestFormat=WebMessageFormat.Json)]
            public void SetData(SmsData data)
            {
                var ctx = WebOperationContext.Current;
                data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");
                //SmsList.Add(data);
                if (OnSmsRecieved != null)
                    OnSmsRecieved(data);
                ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
            }
            [OperationContract]
            [WebGet(UriTemplate = "GetData", ResponseFormat = WebMessageFormat.Json)]
            public SmsData GetData()
            {
                var ctx = WebOperationContext.Current;
                var data = SmsList.FirstOrDefault(sms => sms.State == 1);
                if (data != null)
                {
                    data.State = 2;
                    data.SmsTime = DateTime.Now.ToString("MM-dd HH:mm:ss");
                }
                ctx.OutgoingResponse.StatusCode = System.Net.HttpStatusCode.OK;
                return data;
            }
        }
        public class SmsData
        {
            public string Phone { get; set; }
            public string Content { get; set; }
            public string SmsTime { get; set; }
            public string Name { get; set; }
            // 0: recieved 1: presend 2: send
            public int State { get; set; }
        }
    }
     
    其次,ServiceHost 选择 WebServiceHost 类来承载利用 REST 编程模型的服务。即支持REST风格的Http Uri到服务方法的映射。另外,在 Winform 中 Host 为了让WCF 服务的通信不影响 UI 线程,需要为 WebServiceHost 单独创建线程。

    + expand sourceview plaincopy to clipboardprint?
    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Text;  
    using System.ServiceModel;  
    using System.Threading;  
    namespace WCFRestHost  
    {  
        public class ThreadedServiceHost<T> : IDisposable where T : ServiceHostBase  
        {  
            const int SleepTime = 100;  
            private ServiceHostBase _serviceHost = null;  
            private Thread _thread;  
            private bool _isRunning;  
            public ThreadedServiceHost(Type serviceType)  
            {  
                _serviceHost = (ServiceHostBase)Activator.CreateInstance(typeof(T), new object[] { serviceType });  
                _thread = new Thread(ThreadMethod);  
            }  
            void ThreadMethod()  
            {  
                try 
                {  
                    _isRunning = true;  
                    _serviceHost.Open();  
                    while (_isRunning)  
                    {  
                        Thread.Sleep(SleepTime);  
                    }  
                    _serviceHost.Close();  
                }  
                catch (Exception)  
                {  
                    if (_serviceHost != null)  
                    {  
                        _serviceHost.Close();  
                    }  
                }  
            }  
            public void Open()  
            {  
                _thread.Start();  
            }  
            public void Stop()  
            {  
                lock (this)  
                {  
                    _isRunning = false;  
                }  
            }  
            public void Dispose()  
            {  
                Stop();  
            }  
        }  

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.ServiceModel;
    using System.Threading;
    namespace WCFRestHost
    {
        public class ThreadedServiceHost<T> : IDisposable where T : ServiceHostBase
        {
            const int SleepTime = 100;
            private ServiceHostBase _serviceHost = null;
            private Thread _thread;
            private bool _isRunning;
            public ThreadedServiceHost(Type serviceType)
            {
                _serviceHost = (ServiceHostBase)Activator.CreateInstance(typeof(T), new object[] { serviceType });
                _thread = new Thread(ThreadMethod);
            }
            void ThreadMethod()
            {
                try
                {
                    _isRunning = true;
                    _serviceHost.Open();
                    while (_isRunning)
                    {
                        Thread.Sleep(SleepTime);
                    }
                    _serviceHost.Close();
                }
                catch (Exception)
                {
                    if (_serviceHost != null)
                    {
                        _serviceHost.Close();
                    }
                }
            }
            public void Open()
            {
                _thread.Start();
            }
            public void Stop()
            {
                lock (this)
                {
                    _isRunning = false;
                }
            }
            public void Dispose()
            {
                Stop();
            }
        }
    }
     

    服务端UI:
    + expand sourceview plaincopy to clipboardprint?
    using System;  
    using System.Collections.Generic;  
    using System.ComponentModel;  
    using System.Data;  
    using System.Drawing;  
    using System.Linq;  
    using System.Text;  
    using System.Windows.Forms;  
    using System.ServiceModel.Web;  
    namespace WCFRestHost  
    {  
        public partial class frmMain : Form  
        {  
            public frmMain()  
            {  
                InitializeComponent();  
            }  
            private ThreadedServiceHost<WebServiceHost> _threadHost;  
            private void frmMain_Load(object sender, EventArgs e)  
            {  
                _threadHost = new ThreadedServiceHost<WebServiceHost>(typeof(SmsService));  
                _threadHost.Open();  
                tssStatus.Text = "Listener is opening ...";  
                SmsService.OnSmsRecieved += new Action<SmsData>(SmsService_OnSmsRecieved);  
                DataBind();  
            }  
            void SmsService_OnSmsRecieved(SmsData obj)  
            {  
                Action<SmsData> addData = d => SmsService.AddData(d);  
                dgvSms.Invoke(addData, obj);  
            }  
            private void DataBind()  
            {  
                dgvSms.DataSource = SmsService.SmsList;  
                dgvSms.ClearSelection();  
                txtPhone.DataBindings.Add("Text", SmsService.SmsList, "Phone");  
                txtTime.DataBindings.Add("Text", SmsService.SmsList, "SmsTime");  
                txtContent.DataBindings.Add("Text", SmsService.SmsList, "Content");  
            }  
            private void frmMain_FormClosing(object sender, FormClosingEventArgs e)  
            {  
                if (_threadHost != null)  
                    _threadHost.Stop();  
            }  
            private void btnQuit_Click(object sender, EventArgs e)  
            {  
                this.Close();  
            }  
            private void btnSend_Click(object sender, EventArgs e)  
            {  
                var smsForm = new SendSms();  
                smsForm.ShowDialog();  
                //DataBind();  
            }  
            private void button1_Click(object sender, EventArgs e)  
            {  
                SmsService.SmsList.Add(new SmsData { Phone = "1" });  
            }  
        }  

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    using System.ServiceModel.Web;
    namespace WCFRestHost
    {
        public partial class frmMain : Form
        {
            public frmMain()
            {
                InitializeComponent();
            }
            private ThreadedServiceHost<WebServiceHost> _threadHost;
            private void frmMain_Load(object sender, EventArgs e)
            {
                _threadHost = new ThreadedServiceHost<WebServiceHost>(typeof(SmsService));
                _threadHost.Open();
                tssStatus.Text = "Listener is opening ...";
                SmsService.OnSmsRecieved += new Action<SmsData>(SmsService_OnSmsRecieved);
                DataBind();
            }
            void SmsService_OnSmsRecieved(SmsData obj)
            {
                Action<SmsData> addData = d => SmsService.AddData(d);
                dgvSms.Invoke(addData, obj);
            }
            private void DataBind()
            {
                dgvSms.DataSource = SmsService.SmsList;
                dgvSms.ClearSelection();
                txtPhone.DataBindings.Add("Text", SmsService.SmsList, "Phone");
                txtTime.DataBindings.Add("Text", SmsService.SmsList, "SmsTime");
                txtContent.DataBindings.Add("Text", SmsService.SmsList, "Content");
            }
            private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
            {
                if (_threadHost != null)
                    _threadHost.Stop();
            }
            private void btnQuit_Click(object sender, EventArgs e)
            {
                this.Close();
            }
            private void btnSend_Click(object sender, EventArgs e)
            {
                var smsForm = new SendSms();
                smsForm.ShowDialog();
                //DataBind();
            }
            private void button1_Click(object sender, EventArgs e)
            {
                SmsService.SmsList.Add(new SmsData { Phone = "1" });
            }
        }
    }
    注意:当收到短信时直接添加到BindingList<SmsData>中时会导致"跨线程更新UI的错误",因为WCF服务实际在子线程中,所以添加SmsData的操作必须使用Control.Invoke 进行调用,但是又不想把UI的引用直接交给WCF服务。。。呵呵,使用事件机制就可以很好的解决这一问题,让服务通知UI有新数据并让UI自己取添加数据。可以看到上面的服务代码中,公开了一个OnSmsRecieved事件。这样UI端监听这个事件,再使用 Control.Invoke 调用 AddData 方法。怎么样是不是很简单?不过每条短信是花1毛钱的T_T


    OK,接下来介绍下android端的代码。


    本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/fangxinggood/archive/2011/05/23/6438762.aspx

  • 相关阅读:
    Vue中事件委托的使用
    java提取每个汉字的首字母
    想把大脑存进电脑,我为什么要写博客
    CF 1606 D题题解
    js前端 音频波形图像展示
    js前端 仪表盘实现
    js前端 bootstrap select的使用
    UOS系统维护命令
    linux 打印机管理常用命令
    linux 调用shell命令
  • 原文地址:https://www.cnblogs.com/mistor/p/2334062.html
Copyright © 2011-2022 走看看