优雅的在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;
}
如有疑问欢迎加入QQ群:765907694 交流!

优雅的在WinForm/WPF/控制台 中使用特性封装WebApi的更多相关文章

  1. Winform/WPF中内嵌BeetleX的HTTP服务

    在新版本的BeetleX.FastHttpApi加入了对netstandard2.0支持,如果程序基于.NetFramework4.6.1来构建WinForm或WPF桌面程序的情况下可以直接把Beet ...

  2. 提供PPT嵌入Winform/WPF解决方案,Winform/WPF 中嵌入 office ppt 解决方案

    Winform/WPF 中嵌入 office ppt(powerpoint)解决方案示: 1. 在winform中操作ppt,翻页.播放.退出:显示 总页数.当前播放页数 2. 启动播放ppt时录制视 ...

  3. 在WinForm应用程序中嵌入WPF控件

    我们知道,在WPF界面上添加WinForm的控件需要使用WindowsFormHost类.而在WinForm界面上添加WPF控件该如何做呢?有没有类似的类呢?明显是有的,ElementHost就是为了 ...

  4. 把演讲人的桌面、头像、声音合成后推送到 指定的直播流平台上; 录制电脑桌面、摄像头头像、声音保存为本地视频; 适用于讲课老师、医生等演讲内容保存为视频; 提供PPT嵌入Winform/WPF解决方案,Winform/WPF 中嵌入 office ppt 解决方案

    提供PPT嵌入Winform/WPF解决方案,Winform/WPF 中嵌入 office ppt 解决方案 Winform/WPF 中嵌入 office ppt(powerpoint)解决方案示: ...

  5. 后续来啦:Winform/WPF中快速搭建日志面板

    后续来啦:Winform/WPF中快速搭建日志面板 继昨天发文ASP.NET Core 可视化日志组件使用(阅读文章,查看视频)后,视频下有朋友留言 "Winform客户端的程序能用它不?& ...

  6. 在WPF程序中打开网页:使用代理服务器并可进行JS交互

    本项目环境:使用VS2010(C#)编写的WPF程序,通过CefSharp在程序的窗体中打开网页.需要能够实现网页后台JS代码中调用的方法,从网页接收数据,并能返回数据给网页.运行程序的电脑不允许上网 ...

  7. 在C#代码中应用Log4Net(四)在Winform和Web中捕获全局异常

    毕竟人不是神,谁写的程序都会有bug,有了bug不可怕,可怕的是出错了,你却不知道错误在哪里.所以我们需要将应用程序中抛出的所有异常都记录起来,不然出了错,找问题就能要了你的命.下面我们主要讨论的是如 ...

  8. Winform/WPF国际化处理

    1.Winfrom国际化处理方式 ==> Winform中国际化支持可将UI页面和.cs文件分开处理 处理窗体方式如下:1.选择Form窗体设置其--Language(默认中文--Default ...

  9. 初识MFC,WinForm,WPF,Q't

    MFC和QT是C++中常见的GUI框架,而WinForm和WPF是C#中常用的框架,不过我们一般很少叫WinForm框架,可能直接叫图形控件类库更多点.反正只是个称呼罢了,爱咋叫就咋叫.另外WinFo ...

随机推荐

  1. Mybatis__模糊查询

    在一个Web工程中,查询功能几乎都要用到姓名模糊查询,,虽然学号,工号等可以最准确最快的定位,但如果清楚信息到连学号,工号都一个数不差,应该也没必要去查询了. 故需要用到一下语句实现模糊查询: sel ...

  2. Bzoj 2563: 阿狸和桃子的游戏 题解

    2563: 阿狸和桃子的游戏 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 970  Solved: 695[Submit][Status][Discu ...

  3. ~~在python中踩过的坑以及问题~~(不断更新)

    python说简单也不难,但是在这其中大大小小的点 真的是有够折磨人欸!  1.   input 输入的时候,即使输入的是数字,数据类型也是字符串   2.   字符串本质上来看可以看作有序数组  3 ...

  4. 【动态规划DP】传娃娃-C++

    传娃娃 描述 学习空闲之余,小信经常带着同学们做游戏,最近小信发明了一个好玩的新游戏:n 位同学围成一个圈,同学 A 手里拿着一个布娃娃.小信喊游戏开始,每位手里拿着娃娃的同学可以选择将娃娃传给左边或 ...

  5. centos7 linux下增加swap虚拟内存分区大小

    此方法不限于centos,linux均适用 最近在服务器上部署了一个java项目,java进程经常性莫名被自动Kill,首先java程序是没有报错的,那么我想可能是内存不足的原因,因为4G内存的服务上 ...

  6. 《ElasticSearch6.x实战教程》之复杂搜索、Java客户端(下)

    第八章-复杂搜索 黑夜给了我黑色的眼睛,我却用它寻找光明. 经过了解简单的API和简单搜索,已经基本上能应付大部分的使用场景.可是非关系型数据库数据的文档数据往往又多又杂,各种各样冗余的字段,组成了一 ...

  7. C#8.0 新增功能

    连载目录    [已更新最新开发文章,点击查看详细] C#8.0提供了许多增强功能 01 Readonly 成员 可将 readonly 修饰符应用于结构的任何成员. 它指示该成员不会修改状态. 这比 ...

  8. vscode在win10 / linux下的.vscode文件夹的配置 (c++/c)

    系统方面配置自行查找 linux: launch.json { // 使用 IntelliSense 了解相关属性. // 悬停以查看现有属性的描述. // 欲了解更多信息,请访问: https:// ...

  9. Spring cloud搭建Eureka高可用注册中心

    注册中心在微服务中是必不可少的一部分,主要用来实现服务自治的功能,本文则主要记载使用Netflix提供的Eureka作为注册中心,来实现服务自治的功能. 实际上Eureka的集群搭建方法很简单:每一台 ...

  10. jQuery 解析 url 参数

    应用场景: 三毛:我现在拿到一个 url 地址(https://www.google.com/search?dcr=&ei=5C&q=param),我现在要获取 location.se ...