代码仅提供参考,已去掉业务内容,下载地址:http://download.csdn.net/detail/hel_wor/9596946
考虑:
1.请求方式
2.请求函数简洁直观
3.合理利用java/C#的类型推导
4.request,response对象的设计,考虑接口,抽象类带来的隐式多继承
5.服务异常,网络异常的封装
解决:
1:一般采用http请求的方式。请求url,请求体,请求头的构造,content-type,accept-type视后端服务而定。
2:请求方法应当简单明了,复杂的请求过程应当被封装,只暴露简单的接口。
3:能够做到类型自动推导的,不要让调用者使用强制转换或显式的声明请求以及返回对象类型--使用泛型。
4:为适应扩展性,当开放更多的请求接口后能不改动请求代码结构的情况下扩展请求及响应对象--使用接口,抽象类。
由于之前是做C#的,所以这次公司的开放平台C#版本SDK由本人编写。
一.请求方式采用http:
a:根据url创建httpwebrequest;
b:设置消息头;
c:设置消息体;
d:发送请求获取响应;
e:处理响应;
请求的构造:
/// <summary>
/// 请求头
/// </summary>
/// <param name="contentLength">内容长度</param>
/// <returns>HttpWebRequest</returns>
private void SetRequestHeader(int contentLength)
{
httpRequest.Method = request.GetMethod();
httpRequest.KeepAlive = true;
httpRequest.ProtocolVersion = HttpVersion.Version10;
httpRequest.ContentType = "application/x-www-form-urlencoded";
httpRequest.ContentLength = contentLength;
httpRequest.Timeout = this.timeout * 1000;
}
/// <summary>
/// 请求体
/// </summary>
/// <returns>请求体</returns>
private string SetRequestBody()
{
Dictionary<string, string> requestParams = request.GetParamMap();
//// 表单提交方式,构造post请求体内容
return WebHelper.GetPostBody(requestParams);
}
/// <summary>
/// 获取响应
/// </summary>
/// <returns>响应信息</returns>
public HttpWebResponse GetResponse() {
byte[] requestByte = Encoding.UTF8.GetBytes(this.SetRequestBody());
SetRequestHeader(requestByte.Length);
try
{
using (Stream requestStream = httpRequest.GetRequestStream())
{
requestStream.Write(requestByte, 0, requestByte.Length);
}
}
catch (Exception e) {
throw new WinxuanApiException(e.Message);
}
return (HttpWebResponse)httpRequest.GetResponse();
}
响应的处理:
/// <summary>
/// 获取响应内容并做处理
/// </summary>
/// <param name="t">请求</param>
/// <returns>响应内容</returns>
public T GetResponse(WinxuanHttpRequest<T> t)
{
string result = string.Empty;
using (HttpWebResponse httpResponse = t.GetResponse())
{
if (httpResponse.StatusCode == HttpStatusCode.OK)
{
using (StreamReader readStream = new StreamReader(httpResponse.GetResponseStream(), Encoding.UTF8))
{
result = readStream.ReadToEnd();
}
}
else
{
throw new WinxuanApiException("API请求响应的状态码:" + httpResponse.StatusCode);
}
result = JObject.Parse(result)["response"].ToString();
T baseResponse = JsonConvert.DeserializeObject<T>(result);
if (!baseResponse.isSuccess()) {
throw new WinxuanApiException(baseResponse.ResultCode.ToString(), baseResponse.ErrorMsg, baseResponse.ResultMessage);
}
return baseResponse;
}
}
二:保证扩展性所以使用接口,抽象类。
Request对象的定义:
namespace Winshare.Distribute.Sdk.Model
{
public interface IWinXuanRequest
{
string GetApiPath();
string GetMethod();
Dictionary<string, string> GetParamMap();
}
}
namespace Winshare.Distribute.Sdk.Model
{
public abstract class BaseRequest<T> : IWinXuanRequest where T : BaseResponse
{
protected string REQUEST_TOKEN = "/oauth2/authorize";
protected string ACCESS_TOKEN = "/oauth2/accessToken";
protected string REFRESH_TOKEN = "/oauth2/refreshToken";
//业务部分接口地址省略
public abstract string GetMethod();
public abstract string GetApiPath();
public abstract Dictionary<string, string> GetParamMap();
}
}
需要扩展的请求类都需要继承BaseRequest< T >类,并重写我们要求继承者实现的3个抽象方法。
Response对象的定义:
namespace Winshare.Distribute.Sdk.Model
{
public abstract class BaseResponse
{
/// <summary>
/// 请求处理成功返回true,请求处理失败返回false。
/// </summary>
[JsonProperty("result")]
private bool result;
/// <summary>
/// 状态码
/// </summary>
[JsonProperty("result_code")]
private int resultCode;
//// 部分属性省略
//// get,set方法省略
需要扩展的响应对象都需要继承BaseResponse类。
三.使用泛型做到类型自动推导
C#和Java都能利用泛型做到类型感知,自动推导,以下针对C#:
暴露给第三方使用的sdk接口:
namespace Winshare.Distribute.Sdk.Interact
{
public interface IWinxuanClient
{
T execute<T>(BaseRequest<T> t) where T : BaseResponse;
}
}
C#的泛型,如果类型参数多于1个,即使是相同类型的两个类型参数T,在使用泛型接口时都需要显式的声明两个参数的类型。所以把响应类型放在了请求类型中,而未采用下面的定义方式:
U execute<T, U>(T t)
where T : BaseRequest<U>
where U : BaseResponse;
最终的请求方式为:
AccessTokenResponse accessTokenResponse = client.execute(request);
而非:
AccessTokenResponse accessTokenResponse = client.execute<AccessTokenRequest ,AccessTokenResponse >(request);
使用泛型让我们无需强制转换,使用单个泛型参数让我们无需显式声明泛型类型,这是因为泛型在编译期间会推导类型信息。