.Net FrameWork4.5 已经是行将就木的老技术了,当时我刚开始工作的时候就用,现在得有6.7年了,
这次想用它来写个api接口
HttpSelfHostConfiguration 自宿主服务
宿主一词我们不会陌生,它可以看作是一个基础设施,它为一些服务和功能提供最底层的支持,如你的web应用程序可以运行在iis或者apache上,而这两个东西就是web应用程序的宿主,而今天说的自主宿主SelfHost就是说,它可以自己去监听自己的服务,如你可以把一个web应用程序宿主到一个console控制台程序上,或者把一个webApi宿主到一个console或者windowService上,这都是可以的。(这段话是抄的,大家理解一下就好)
下面是我的自宿主程序代码
api接口流程图
api接口的设计流程图如下
项目目录结构如下
后面有各个类的具体代码
使用控制台创建自宿主项目 + 绑定全局过滤器
使用自宿主服务,项目要引用几个dll,如果没有的话大家可以去拷贝下载
using Newtonsoft.Json;
using Robot2.OpenApi.V2.Filter;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
using System.Web.Http.Cors;
using System.Web.Http.SelfHost;
namespace ConsoleApp2
{
internal class Program
{
static void Main(string[] args)
{
try
{
string url = string.Format("http://localhost:20100");
var config = new HttpSelfHostConfiguration(url);
config.Formatters.XmlFormatter.SupportedMediaTypes.Clear();
config.Formatters.Add(new System.Net.Http.Formatting.JsonMediaTypeFormatter());
HttpSelfHostServer _hostServer = new HttpSelfHostServer(config);
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
config.EnableCors(new EnableCorsAttribute("*", "*", "GET, POST, PUT, DELETE, OPTIONS") { SupportsCredentials = true });
config.Filters.Add(new AuthorFilter());
config.Filters.Add(new ExceptionFilter());
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}",
defaults: new
{
controller = "Home",
action = "Index",
id = RouteParameter.Optional
});
_hostServer.OpenAsync().Wait();
Console.WriteLine("服务端口打开成功");
}
catch (Exception ex)
{
Console.WriteLine("服务端口打开异常:" + JsonConvert.SerializeObject(ex));
}
Console.ReadKey();
}
}
}
.Net FrameWork4.5 中的过滤器
过滤器的知识基本做2年的后端工程师都会懂,就不做赘述了,但是不同于.net core更好的AOP思想
.net framework里内置的过滤器种类就少了很多,常用的基本就只有一两种,这次的api接口中
使用以下两种过滤器
- System.Web.Http.Filters.IAuthorizationFilter (权限过滤器)
- System.Web.Http.Filters.IExceptionFilter (异常过滤器)
过滤器代码如下
using Microsoft.SqlServer.Server;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Web.Http.Controllers;
using System.Web.Http.Filters;
using System.Web.Http.Results;
namespace Robot2.OpenApi.V2.Filter
{
/// <summary>
/// 请求过滤器(日志记录)
/// </summary>
public class AuthorFilter : System.Web.Http.Filters.IAuthorizationFilter
{
public class Message
{
public string Title { get; set; }
public string Content { get; set; }
}
public bool AllowMultiple => throw new NotImplementedException();
public async Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
//Token校验验证
var datas = await continuation();
var value = ((System.Net.Http.ObjectContent)datas.Content).Value;
Message data = new Message()
{
Title = "Success",
Content = JsonConvert.SerializeObject(value)
};
string dataStr = JsonConvert.SerializeObject(data);
var res = new HttpResponseMessage(HttpStatusCode.OK);
res.Content = new StringContent(dataStr, Encoding.UTF8, "application/json");
return res;
}
}
}
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Runtime.Remoting.Contexts;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;
using static Robot2.OpenApi.V2.Filter.AuthorFilter;
namespace Robot2.OpenApi.V2.Filter
{
public class ExceptionFilter : System.Web.Http.Filters.IExceptionFilter
{
public bool AllowMultiple => throw new NotImplementedException();
public Task ExecuteExceptionFilterAsync(HttpActionExecutedContext actionExecutedContext, CancellationToken cancellationToken)
{
Message msg = new Message()
{
Content = "服务器异常",
Title = "Error"
};
return Task.Run(() =>
{
var errormsg = actionExecutedContext.Exception;
if (errormsg is ApiException)
{
var error = errormsg as ApiException;
msg.Content = error.ErrorMessage;
}
else
{
Console.WriteLine(errormsg);
}
HttpResponseMessage httpResponse = new HttpResponseMessage();
HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(msg), Encoding.UTF8, "application/json");
httpResponse.Content = httpContent;
actionExecutedContext.Response = httpResponse;
});
}
}
}
新增的异常类
很简单的异常类,就是继承Exception,来实现一个自定义异常
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Robot2.OpenApi.V2
{
/// <summary>
/// api异常编码
/// </summary>
public class ApiException : Exception
{
/// <summary>
/// 状态编码
/// </summary>
public int StatusCode { get; set; } = 500;
/// <summary>
/// 错误描述
/// </summary>
public string ErrorMessage { get; set; }
/// <summary>
/// 错误编码
/// </summary>
public string ErrorCode { get; set; }
/// <summary>
/// 抛出异常错误,返回结果
/// </summary>
/// <param name="ErrorMsg"></param>
/// <returns></returns>
public static ApiException Oh(string ErrorMsg)
{
return new ApiException()
{
ErrorMessage = ErrorMsg,
ErrorCode = "Error"
};
}
/// <summary>
/// 抛出异常错误,返回结果
/// </summary>
/// <param name="ErrorMsg"></param>
/// <returns></returns>
public static ApiException Oh(string ErrorCode, string ErrorMsg)
{
return new ApiException()
{
ErrorMessage = ErrorMsg,
ErrorCode = ErrorCode
};
}
}
}
新增Controller,编写api代码
Controller代码如下
using Robot2.OpenApi.V2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
namespace ConsoleApp2
{
public class TestController: ApiController
{
[HttpPost]
public string Test1() {
return "ssss";
}
public class sss
{
public string text { get; set; }
}
[HttpPost]
public int Test2(sss t)
{
throw ApiException.Oh($"{t.text}数据error");
}
public Dictionary<string, object> Test3() {
return new Dictionary<string, object>
{
["sdsds"]="wewewe",
["12121"]=3.65
};
}
}
}
Controller 各方法调用截图如下
使用postman调用各个请求方法 ,调用的结果如下
总结
是个很巧妙的构思,希望大家可以一起交流借鉴,也体现了AOP切片思想编程么
如果要在.net core中实现,那就更有趣了
.net core的过滤器种类更多,且分工更细化