作為沒有花很多時間轉java,把java當C#用的我,在做服務器端程序的時候,自然不想考慮java web,java需要學的框架太多了,看了一下Java Servlet,始終沒有編碼的沖動。經過幾天的試驗還是決定使用.net做服務器端。webservic很簡單也經常用,WCF也用過,感覺還是沒有web api來得輕量級,而且根據經驗一般商用傳統軟件會有一大群小白用戶和計算機能力不強的代理商,他們都要求軟件要部署安裝調試簡便,什么裝個新的Windows Server,新的MSSQL,設置IIS...最好是下一步下一步搞定這種,這就要求服務器端一般吧依賴IIS,這個要求也不過份。那么調研下來只有mvc webapi 2+.net 4.5(OWin.Net)可以自宿主host web服務。
一路趟坑下來,總算成功了。記錄下來給朋友們參考一下。
1、win7 64位系統裝不上vs2013,.net 4.5的限制
2、OWIN.NET + .net 4嘗試
3、web api 的路由把我坑慘了,路由機制跟mvc不一樣,在寫api的時候傳參遇到的問題
1、win7 64位系統裝不上vs2013,.net 4.5的限制
安裝vs2013需要IE10以上還需要安裝SP1,嘗試幾次安裝SP1都是在最后關頭失敗了,至今沒有解決,結果在公司的win2008上安裝vs2013成功。由於現在還是使用vs2010比較多,所以家里的電腦就不折騰了。還了解到.net 4.5支持的操作系統有: WIN7 SP1以上,WIN2008 SP1以上,WIN2012,Win8;后兩個系統都沒用過,貌似這個方案也不是很靠譜啊,客戶一般XP和WIN7,服務器WIN2003或者WIN2008比較多。勉強可以吧,服務器端程序要求Win7以上供應商應該能夠接受。
2、OWIN.NET + .net 4嘗試
這個嘗試是把.net 4.5和owin.net需要的全部dll添加到.net 4的解決方案里面,經過N次排錯之后編譯通過。這個比較奇怪在家里的電腦上(沒有安裝.net4.5)編譯通過,在公司的電腦上(vs2010和vs2013共存)編譯失敗,多出來N多錯誤,排除不了。這不是天方夜譚,也不是天馬行空的想法,因為之前有.net 2使用linq的經驗,所以想嘗試一下,結果死在了沙灘上。
owin.net依賴.net 4.5才有的一個方法,現在那個解決方案的源碼找不到了,忘記什么異常了。總之一時解決不了.net 4.5的依賴,失敗了。
3、web api 的路由把我坑慘了,路由機制跟mvc不一樣,在寫api的時候傳參遇到的問題
1)web api不是我想的那樣: web api就是沒有view的mvc!!!
之前學過點mvc用mvc 2做過項目,於是稍微查下資料就給web api下了個結論:"web api就是沒有view的mvc",就是這個結論讓我趟了許多坑,在寫api的時候調試遇到各種問題,比如多個參數,多種參數類型api返回json等問題,以前用mvc的JsonResult很順手,結果非常不習慣web api返回json(這是不了解web api機制導致的),原來web api支持xml和json兩種格式的返回,一番惡補之后,終於走上正途了。哎,基礎啊基礎,自作孽不可活啊,不要以為跟着一些簡單的例子操作一遍就掌握了,沒基礎沒有知其所以然就是不行啊。
2)web api的默認路由規則是省略了action的名稱,使用默認的路由“api/{controller}/{id}"我不明覺厲,發現api傳一個參數的時候可以接收到,但是多個參數不行,自定義路由參數方式好像可以,但是參數名和個數變化大,發現是沒有搞明白和mvc的路由之間的差異造成的。
api/{controller}/{id}這個看了N次解釋后才了解清楚 {controller}代表控制器的名稱,然后自己就傳參{id}了,{action}哪兒去了?讀書看帖不求甚解啊,罪過,這就是自以為是的苦果,一直都是先入為主,以為是那樣的,結果最基礎的特性都沒有了解清楚。總之將{action}加入變成“api/{controller}/{action}/{id}"之后一切都順利了。
最終成果及關鍵代碼分享
1)先截幾個圖吧
服務器端:



客戶端:





2)關鍵代碼,Win Service方式Host web api。
定制路由規則和json方式默認返回。
namespace SaunaWebApiHostService
{
public class RegisterRoutesStartup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host. 默認路由
HttpConfiguration config = new HttpConfiguration();
//config.Routes.MapHttpRoute(
// name: "DefaultApi",
// routeTemplate: "api/{controller}/{id}",
// defaults: new { id = RouteParameter.Optional }
//);
//自定義路由
config.Routes.MapHttpRoute(
name: "CustomApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
//只響應Json請求
var jsonFormatter = new JsonMediaTypeFormatter();
config.Services.Replace(typeof(IContentNegotiator), new JsonContentNegotiator(jsonFormatter));
appBuilder.UseWebApi(config);
}
}
}
Windows Service
/// <summary>
/// 啟動服務
/// </summary>
/// <param name="args"></param>
public new void OnStart(string[] args)
{
hostObject = WebApp.Start<RegisterRoutesStartup>(this.GetBaseAddress());
EventLog.WriteEntry("Web Api Host Success,請求基地址:" + this.GetBaseAddress() + "。", EventLogEntryType.Information);
//開始主線程
mainTaskThread = new Thread(SearchDataChangeEvent);
mainTaskThread.Start();
}
如果服務沒有其他事做但是host webapp,好像要被系統認為服務沒有任何事情可做會自動結束。所以開了個線程,輪詢管理系統的消費清單,如果發生變化udp發送udp廣播給終端和各消費點方便刷新顯示。
安卓客戶端:
@Override
protected Boolean doInBackground(String... params) {
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair("timestamp", String
.valueOf(System.currentTimeMillis())));
JSONHttpClient jsonHttpClient = new JSONHttpClient();
String strResult = jsonHttpClient.Get(ServiceUrl.getInstance("")
.get_Categary_URL(), nameValuePairs);
resultList = new GsonBuilder()
.enableComplexMapKeySerialization()
.create()
.fromJson(strResult,
new TypeToken<List<SaunaItemCategory>>() {
}.getType());
return resultList.size() > 0 ? true : false;
}
package com.aidpoint.sauna.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.zip.GZIPInputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import android.util.Log;
import com.aidpoint.sauna.util.ServiceUrl;
import com.google.gson.GsonBuilder;
public class JSONHttpClient {
public <T> T PostObject(final String url, final T object,
final Class<T> objectClass) throws Exception {
DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(url);
try {
String data = new GsonBuilder().create().toJson(object);
StringEntity stringEntity = new StringEntity(data);
Log.i(ServiceUrl.G_Log_Flag, "Post Request:" + data);
httpPost.setEntity(stringEntity);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
httpPost.setHeader("Accept-Encoding", "gzip");
HttpResponse httpResponse = defaultHttpClient.execute(httpPost);
Log.i(ServiceUrl.G_Log_Flag,
"Response Result Status:" + httpResponse.getStatusLine());
if (httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
InputStream inputStream = httpEntity.getContent();
org.apache.http.Header contentEncoding = httpResponse
.getFirstHeader("Content-Encoding");
if (contentEncoding != null
&& contentEncoding.getValue().equalsIgnoreCase(
"gzip")) {
inputStream = new GZIPInputStream(inputStream);
}
String resultString = convertStreamToString(inputStream);
inputStream.close();
return new GsonBuilder().create().fromJson(resultString,
objectClass);
}
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
throw e;
} catch (ClientProtocolException e) {
e.printStackTrace();
throw e;
} catch (IOException e) {
e.printStackTrace();
throw e;
}
return null;
}
public <T> T PostParams(String url, final List<NameValuePair> params,
final Class<T> objectClass) throws Exception {
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
return PostObject(url, null, objectClass);
}
private String convertStreamToString(InputStream inputStream) {
BufferedReader bufferedReader = new BufferedReader(
new InputStreamReader(inputStream));
StringBuilder stringBuilder = new StringBuilder();
String line = null;
try {
while ((line = bufferedReader.readLine()) != null) {
stringBuilder.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return stringBuilder.toString();
}
public <T> T Get(String url, List<NameValuePair> params,
final Class<T> objectClass) {
DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
Log.i(ServiceUrl.G_Log_Flag, "Send Request:" + url);
HttpGet httpGet = new HttpGet(url);
try {
httpGet.setHeader("Accept", "application/json");
HttpResponse httpResponse = defaultHttpClient.execute(httpGet);
Log.i(ServiceUrl.G_Log_Flag, "Response Result Status:"
+ httpResponse.getStatusLine());
if (httpResponse != null
&& httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
InputStream inputStream = httpEntity.getContent();
org.apache.http.Header contentEncoding = httpResponse
.getFirstHeader("Content-Encoding");
String resultString = convertStreamToString(inputStream);
inputStream.close();
return new GsonBuilder().enableComplexMapKeySerialization()
.create().fromJson(resultString, objectClass);
} else
return null;
} else
return null;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
} catch (ClientProtocolException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public String Get(String url, List<NameValuePair> params) {
DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
Log.i(ServiceUrl.G_Log_Flag, "Send Request:" + url);
HttpGet httpGet = new HttpGet(url);
try {
httpGet.setHeader("Accept", "application/json");
HttpResponse httpResponse = defaultHttpClient.execute(httpGet);
Log.i(ServiceUrl.G_Log_Flag, "Response Result Status:"
+ httpResponse.getStatusLine());
if (httpResponse != null
&& httpResponse.getStatusLine().getStatusCode() == 200) {
HttpEntity httpEntity = httpResponse.getEntity();
if (httpEntity != null) {
InputStream inputStream = httpEntity.getContent();
org.apache.http.Header contentEncoding = httpResponse
.getFirstHeader("Content-Encoding");
String resultString = convertStreamToString(inputStream);
inputStream.close();
return resultString;
} else
return null;
} else
return null;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
return null;
} catch (ClientProtocolException e) {
e.printStackTrace();
return null;
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
public boolean Delete(String url, final List<NameValuePair> params) {
DefaultHttpClient defaultHttpClient = new DefaultHttpClient();
String paramString = URLEncodedUtils.format(params, "utf-8");
url += "?" + paramString;
Log.i(ServiceUrl.G_Log_Flag, url);
HttpDelete httpDelete = new HttpDelete(url);
HttpResponse httpResponse = null;
try {
httpResponse = defaultHttpClient.execute(httpDelete);
return httpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_NO_CONTENT;
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}
