使用RX方式模拟DoubanFm的登陆
WP7下的Get Post都是异步的
关于RX
http://www.cnblogs.com/yangecnu/archive/2012/11/03/Introducting_ReactiveExtensions.html
我初步理解的Rx,是观察者模式的一种实现
Url很简单,先来看看URL
-
URL:
http://www.douban.com/j/app/login
-
Method:
POST
-
Arguments:
-
app_name
:radio_desktop_win
-
version
:100
-
email
:用户帐号
-
password
:明文密码
-
-
Header:
Content-Type: application/x-www-form-urlencoded
-
Response (
application/json
)
在WP7下的Post过程大致如下(Get过程相对简单,只需要2步):
第一步:
1 public void PostMethod(string Url,string Postdata) 2 { 3 4 HttpWebRequest request; 5 request = (HttpWebRequest)WebRequest.Create(new Uri(Url)); 6 request.Method = "POST"; 7 request.ContentType = "application/x-www-form-urlencoded"; 8 request.BeginGetRequestStream(new AsyncCallback(RequestCallback), request);10 _postdata = Postdata; 11 }
第二步:
1 private void RequestCallback(IAsyncResult asyncResult) 2 { 3 HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState; 4 UTF8Encoding encoding = new UTF8Encoding(); 5 Stream _body = request.EndGetRequestStream(asyncResult); 6 byte[] formBytes = encoding.GetBytes(_postdata);//这是通过post方式传的 7 _body.Write(formBytes, 0, formBytes.Length); 8 _body.Close(); 9 request.BeginGetResponse(new AsyncCallback(ResponseCallback), request); 10 11 }
第三步:
1 private void ResponseCallback(IAsyncResult asyncResult) 2 { 3 HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState; 4 5 WebResponse httpwebresponse = request.EndGetResponse(asyncResult); 6 Stream stream= httpwebresponse.GetResponseStream(); 7 StreamReader reader = new StreamReader(stream); 8 string result=reader.ReadToEnd(); 9 10 // Deployment.Current.Dispatcher.BeginInvoke(_postret, result); 11 12 }
刚学习了Rx,想看看如果用Rx应该怎么做
先来回顾下Rx 如下
public interface IObservable<T> { IDisposable Subscribe(IObserver<T> observer); }
1 public interface IObserver<T> 2 { 3 void OnCompleted(); 4 void OnError(Exception exception); 5 void OnNext(T value); 6 }
在我的System.Reactive.Linq的Observable静态类下,定义了了IObservable<T>的很多扩展方法,
public static IObservable<TResult> Select<TSource, TResult>(this IObservable<TSource> source, Func<TSource, TResult> selector)
public static IObservable<TResult> SelectMany<TSource, TResult>(this IObservable<TSource> source, Func<TSource, IEnumerable<TResult>> selector)
这些扩展方法反映了我们可以像Linq一样获得一个IObservable<T>
下面是获得一个IObservable<T>的最简单的方法
public static IObservable<TResult> Return<TResult>(TResult value)
用这个方法得到的IObservable<T>后就可以注册了,在我的System.Reactive.Core.dll,System命名空间下的ObservableExtensions静态类扩展了IObservable<T>的注册方式:
1 public static IDisposable Subscribe<T>(this IObservable<T> source, Action<T> onNext) 2 { 3 if (source == null) 4 { 5 throw new ArgumentNullException("source"); 6 } 7 if (onNext == null) 8 { 9 throw new ArgumentNullException("onNext"); 10 } 11 return source.Subscribe(new AnonymousObserver<T>(onNext, Stubs.Throw, Stubs.Nop)); 12 }
具体实现我们不具体去关注,但是我们知道在11行,是New了一个匿名的观察者Observer了。
接下来看看FromAsyncPattern
public static Func<IObservable<TResult>> FromAsyncPattern<TResult>(Func<AsyncCallback, object, IAsyncResult> begin, Func<IAsyncResult, TResult> end)
这是个静态方法,返回一个返回值类型为IObservable<TResult>,无实参,的委托
先回顾用Rx实现的一个Get方法:
1 public LoginTest() 2 { 3 4 var func= Observable.FromAsyncPattern<HttpWebRequest,HttpWebResponse>(Webrequest,WebResponse); 5 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://www.baidu.com"); 6 7 var observable= func(request); 8 observable.Subscribe( 9 (result) => 10 { 11 var stream = result.GetResponseStream(); 12 var sr = new StreamReader(stream); 13 var baiduhttphtml = sr.ReadToEnd(); 14 }); 15 16 } 17 18 IAsyncResult Webrequest(HttpWebRequest request,AsyncCallback callbcak,object ob) 19 { 21 return request.BeginGetResponse(callbcak, request); 22 } 23 HttpWebResponse WebResponse(IAsyncResult result) 24 { 25 var request = result.AsyncState as HttpWebRequest; 26 return (HttpWebResponse)request.EndGetResponse(result); 27 }
这样的Get方式看起来很简洁
昨晚敲了一下,Post方式如下:(回去后在VS2013上用RX,发现他提示我最好用await,Task等新特性来做异步,今晚回去试试,实验室是VS2010)
1 class MyHttpRequest 2 { 3 string PostData; 4 AsyncCallback save;//用于中间传递 5 public IObservable<string> PostMethod(string URL, string PostData) 6 { 7 this.PostData = PostData; 8 var func = Observable.FromAsyncPattern<HttpWebRequest,string>(Webrequest, ResponseCallback);//直接返回string 9 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(URL); 10 request.Method = "POST"; 11 request.ContentType = "application/x-www-form-urlencoded"; 12 return func(request); 13 14 } 15 IAsyncResult Webrequest(HttpWebRequest request, AsyncCallback callbcak, object ob) 16 { 17 save = callbcak;//保存CallBack 18 return request.BeginGetRequestStream(act, request); 19 } 20 void act(IAsyncResult asyncResult) 21 { 22 HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState; 23 UTF8Encoding encoding = new UTF8Encoding(); 24 Stream _body = request.EndGetRequestStream(asyncResult); 25 byte[] formBytes = encoding.GetBytes(this.PostData);//这是通过post方式传的 26 _body.Write(formBytes, 0, formBytes.Length); 27 _body.Close(); 28 request.BeginGetResponse(save, request);//用保存的CallBack 29 30 } 31 string ResponseCallback(IAsyncResult asyncResult) 32 { 33 HttpWebRequest request = (HttpWebRequest)asyncResult.AsyncState; 34 WebResponse httpwebresponse = request.EndGetResponse(asyncResult); 35 Stream stream = httpwebresponse.GetResponseStream(); 36 StreamReader reader = new StreamReader(stream); 37 return reader.ReadToEnd(); 38 } 39 }
好了,现在很清楚了,来试试效果
1 public LoginTest() 2 { 3 //发出一个消息 跟MVVMLight Messenger有点像 4 var observable= new MyHttpRequest().PostMethod("http://www.douban.com/j/app/login", "app_name=radio_desktop_win&version=100&email=327442095@qq.com&password="); 5 6 7 //直接在这里订阅一个匿名接收者 8 observable.Subscribe((result) => 9 { 10 Debug.WriteLine(result); 11 }); 12 Debug.WriteLine("我比你先返回,哈哈"); 13 }
~OK。
可以使用这个方式做我的FM登陆了。