優雅的在WinForm/WPF/控制台 中使用特性封裝WebApi 說明 ` 在C/S端作為Server,建立HTTP請求,方便快捷。 ` 1.使用到的類庫 ` Newtonsoft.dll ` 2.封裝 HttpListener HttpApi類 特性類 ActionName 特性類 HttpMe ...
優雅的在WinForm/WPF/控制台 中使用特性封裝WebApi
說明
在C/S端作為Server,建立HTTP請求,方便快捷。
1.使用到的類庫
Newtonsoft.dll
2.封裝 HttpListener
HttpApi類
public class HttpApi
{
private static List<HttpListener> HttpListenerList = new List<HttpListener>();
/// <summary>
/// 初始化服務
/// </summary>
public static void InitService()
{
//獲取程式集下麵的所有的類
Type[] types = System.Reflection.Assembly.GetExecutingAssembly().GetTypes();
foreach (Type item_type in types)
{
//定義是否有類的特性標識
bool IsHasFormApi = false;
//取類上的自定義特性
object[] objs = item_type.GetCustomAttributes(typeof(FromApi), true);
foreach (object obj in objs)
{
FromApi fromApi = obj as FromApi;
if (fromApi != null)
{
IsHasFormApi = true;
break;
}
}
if (IsHasFormApi)
{
// 獲取完全名稱
String className = item_type.FullName;
// 根據命名空間反射類的Type
Type type = Type.GetType(className);
object objInstance = type.Assembly.CreateInstance(className);
// 獲取所有的方法
MethodInfo[] info = type.GetMethods();
// 遍歷所有的方法
foreach (MethodInfo item in info)
{
// 獲取Http請求方法
HttpMethod httpMethod = item.GetCustomAttribute<HttpMethod>();
// 獲取Action
ActionName actionName = item.GetCustomAttribute<ActionName>();
// 判斷有沒有特性
if (httpMethod != null || actionName != null)
{
HttpListener listerner = new HttpListener();
listerner.AuthenticationSchemes = AuthenticationSchemes.Anonymous;//指定身份驗證 Anonymous匿名訪問
string url = "http://127.0.0.1:8011";
if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["httpserver"]))
{
url = "http://" + ConfigurationManager.AppSettings["httpserver"];
}
listerner.Prefixes.Add(url + actionName.URL + "/");
//開啟服務
if (!listerner.IsListening)
{
listerner.Start();
AsyncCallback ac = new AsyncCallback(GetContextAsyncCallback);
CallbackObject callback = new CallbackObject() { Listerner = listerner, MethodItem = item, ClassInstance = objInstance, HttpMethod = httpMethod.method };
listerner.BeginGetContext(ac, callback);
HttpListenerList.Add(listerner);
}
}
}
}
}
}
/// <summary>
/// 收到監聽請求回調
/// </summary>
/// <param name="ia"></param>
private static void GetContextAsyncCallback(IAsyncResult ia)
{
CallbackObject state = ia.AsyncState as CallbackObject;
if (ia.IsCompleted)
{
HttpListenerContext ctx = state.Listerner.EndGetContext(ia);
var request = ctx.Request;
HttpListenerResponse response = ctx.Response;
try
{
//判斷 請求 方式
if (request.HttpMethod.ToUpper() == state.HttpMethod.ToString().ToUpper() || Method.All.ToString().ToUpper() == state.HttpMethod.ToString().ToUpper())
{
string rawData;
using (var reader = new StreamReader(request.InputStream, request.ContentEncoding))
{
rawData = reader.ReadToEnd();
}
//獲取方法參數列表
ParameterInfo[] parameterInfos = state.MethodItem.GetParameters();
//參數
// List<object> paramters = new List<object>();
object[] paramters = new object[parameterInfos.Length];
for (int i = 0; i < parameterInfos.Length; i++)
{
ParameterInfo item = parameterInfos[i];
if (item.ParameterType == typeof(string) || item.ParameterType == typeof(int) || item.ParameterType == typeof(bool))
{
paramters[i] = JsonHelper.GetJsonValue(rawData, item.Name);
}
else
{
Type t = item.ParameterType;
paramters[i] = JsonConvert.DeserializeObject(rawData, t);
}
}
object resobj = state.MethodItem.Invoke(state.ClassInstance, paramters);
if (typeof(string) == resobj.GetType())
{
ResponseWrite(response, resobj.ToString());
}
else
{
ResponseWrite(response, JsonConvert.SerializeObject(resobj));
}
}
else
{
ResponseWrite(response, $"不支持{request.HttpMethod.ToUpper()}方法請求!");
}
}
catch (Exception ex)
{
ResponseWrite(response, $"服務出現異常,異常信息:{ex.Message}");
}
}
//重新監聽 不寫的話只能調用一次
AsyncCallback ac = new AsyncCallback(GetContextAsyncCallback);
state.Listerner.BeginGetContext(ac, state);
}
/// <summary>
/// 回寫響應
/// </summary>
/// <param name="response"></param>
/// <param name="Content"></param>
private static void ResponseWrite(HttpListenerResponse response, string Content)
{
//使用Writer輸出http響應代碼
using (System.IO.StreamWriter writer = new System.IO.StreamWriter(response.OutputStream, new UTF8Encoding()))
{
response.ContentType = "application/json; charset=utf-8";
writer.WriteLine(Content);
writer.Close();
response.Close();
}
}
}
public enum Method
{
All, Post, Get
}
public class CallbackObject
{
/// <summary>
/// 監聽
/// </summary>
public HttpListener Listerner { get; set; }
/// <summary>
/// 方法
/// </summary>
public MethodInfo MethodItem { get; set; }
/// <summary>
/// 調用者 對象
/// </summary>
public object ClassInstance { get; set; }
/// <summary>
/// 調用方式 Get Post
/// </summary>
public Method HttpMethod { get; set; }
}
特性類 ActionName
[AttributeUsage(AttributeTargets.Method)]
class ActionName : Attribute
{
public string URL { get; set; }
public ActionName()
{
}
public ActionName(string url)
{
this.URL = url;
}
}
特性類 HttpMethod
[AttributeUsage(AttributeTargets.Method)]
public class HttpMethod : Attribute
{
public Method method { get; set; }
public HttpMethod()
{
this.method = Method.All;
}
public HttpMethod(Method _method)
{
this.method = _method;
}
}
特性類 FromApi
[AttributeUsage(AttributeTargets.Class)]
public class FromApi : Attribute
{
//窗體里的具體方法忽略
}
幫助類 JsonHelper
public static class JsonHelper
{
public static string GetJsonValue(string json, string key)
{
string value = "";
if (string.IsNullOrEmpty(json)) { return ""; }
JObject jo = (JObject)JsonConvert.DeserializeObject(json);
if (jo.ContainsKey(key))
{
if (jo[key] != null)
{
value = jo[key].ToString();
}
}
return value;
}
public static List<string> GetJsonList(string json, string key)
{
List<string> value = new List<string>();
if (string.IsNullOrEmpty(json)) { return new List<string>(); }
JObject jo = (JObject)JsonConvert.DeserializeObject(json);
if (jo.ContainsKey(key))
{
if (jo[key] != null)
{
foreach (var item in jo[key])
{
value.Add(item.ToString());
}
}
}
return value;
}
}
3.在Web.config中增加
<appSettings>
<add key="httpserver" value="127.0.0.1:8022"/>
</appSettings>
4.使用方法
- 4.1在窗體類上增加 [FromApi] 特性
[FromApi]
public partial class ScoketForm : Form
{
}
- 4.2Program.cs 中增加 這種初始化方式會對程式集中所有帶有 [FromApi] 特性的類進行初始化
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
//服務初始化
HttpApi.InitService(); //這裡是增加初始化的代碼
Application.Run(new SocketTest.gg.ScoketForm());
- 4.3具體使用方法 HttpMethod 後面可以不寫,不寫的話代表 支持兩種請求方式 POST,GET 需要註意命名空間的導入
/// <summary>
/// 方法說明
/// </summary>
/// <returns></returns>
[HttpMethod(Method.Post), ActionName("/api/index")]
public HttpResult Index(List<string> Ids)
{
HttpResult httpResult = new HttpResult();
//具體方法內容
return httpResult;
}