亲手搭建一个基于Asp.Net WebApi的项目基础框架2
本篇目的:封装一些抽象类
1::封装日志相关类
2:封装一个Service操作类
3:封装缓存操作类
4:封装其他一些常用Helper
1.1在Framework项目里面建立好相关操作类文件夹,以便于区分
在项目中我们抽象出来的东西一般不直接对应具体的实现,而是要有一种面向接口的编程思维,这里我们封装的操作对象在具体应用时还是通过配置文件的形式配置具体应用哪一个。
本项目中我使用的是log4net记录程序日志信息。log4net是一个功能著名的开源日志记录组件.但是我们要抽象出一个日志接口ILogHelper
namespace zjl.Framework.Log { interface ILogHelper { void WriteLog(Type t, string info, LogType type, string fromIP); } public enum LogType { Info = 0, Error = 1 } public enum LogTypeEnum { /// <summary> /// 文本日志 /// </summary> Log4Net = 1, /// <summary> /// MongoDB数据库日志 /// </summary> MongoDB = 2 } }
这里我们定义的接口只有一个写日志的方法,参数包含日志类型LogType和LogType的枚举如果有其他日志类型还可以继续扩展。
继续我们添加一个日志实现类LogHelper并实现ILogerHelper接口
这里我们要安装一下Log4net,使用Nuget命令安装
安装好了之后实现相关代码,这是一个log4的实现代码
using log4net; using log4net.Appender; using log4net.Config; using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace zjl.Framework.Log { public class LogHelper : ILogHelper { public LogHelper() { string baseDir = AppDomain.CurrentDomain.BaseDirectory; var logCfg = new FileInfo(baseDir + @"Configs\Log4net.config"); XmlConfigurator.ConfigureAndWatch(logCfg); } /// <summary> /// 配置文件路径 /// </summary> /// <param name="path"></param> private void ConfigFilePath(string path) { var repository = LogManager.GetRepository(); var appenders = repository.GetAppenders(); foreach (RollingFileAppender roolingfileappender in appenders) { roolingfileappender.File = path; roolingfileappender.ActivateOptions(); } } /// <summary> /// 写日志 /// </summary> /// <param name="t"></param> /// <param name="ex"></param> public void WriteLog(Type t, string info, LogType type, string fromIP) { var mLog = LogManager.GetLogger(t); info = string.Format("FromIP:{0}\r\n{1}", fromIP, info); switch (type) { case LogType.Info: mLog.Info(info); break; case LogType.Error: mLog.Error(info); break; default: mLog.Info(info); break; } } } }
接下来再提供一个日志的单例LogProvider来具体的提供写日志服务
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using zjl.Framework.Helper; namespace zjl.Framework.Log { public class LogProvider { //存放SQL数据库的接口实例 private Dictionary<Type, ILogHelper> Log = new Dictionary<Type, ILogHelper>(); // 依然是静态自动hold实例 private static volatile LogProvider instance = null; // Lock对象,线程安全所用 private static object syncRoot = new Object(); private LogProvider() { //将来业务扩展可以在此为所有服务做配置化接口注册 Log.Add(typeof(LogHelper), new LogHelper()); } public static LogProvider Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new LogProvider(); } } return instance; } } /// <summary> /// 获取Service实例 /// </summary> /// <typeparam name="T">需要获取的接口类型</typeparam> /// <returns>DA实例,如果不存在则返回null</returns> public ILogHelper GetLogHelper() { switch ((LogTypeEnum)Convert.ToInt32(ConfigHelper.Instance.getSystemConfig().LogSet)) { case LogTypeEnum.Log4Net: return Log[typeof(LogHelper)]; } return null; } /// <summary> /// 异步调用日志记录 /// </summary> /// <param name="logInfo"></param> public void WriteLogAsyn(LogRequest logInfo) { Thread t = new Thread(new ParameterizedThreadStart(WriteLog)); t.Start(logInfo); } private void WriteLog(object o) { LogRequest log = o as LogRequest; this.GetLogHelper().WriteLog(log.declaringType, log.logInfo, log.logType, log.ipAddress); } } public class LogRequest { public Type declaringType { get; set; } public string logInfo { get; set; } public LogType logType { get; set; } public string ipAddress { get; set; } } }
上述Helper类中有用到 ConfigHelper,因为我们指定使用的数据库类型或者日之类型的时候只希望是以自定义配置的方式完成.所以封装了一个配置文件操作类
using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using zjl.Framework.Cache; namespace zjl.Framework.Helper { public class ConfigHelper { private static volatile ConfigHelper instance = null; // Lock对象,线程安全所用 private static object syncRoot = new Object(); private ConfigHelper() { } public static ConfigHelper Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) { instance = new ConfigHelper(); string serverPath = ConfigurationManager.AppSettings["ConfigPath"].ToString(); //判断是否是绝对路径 if (!Path.IsPathRooted(serverPath)) { serverPath = System.Web.HttpRuntime.AppDomainAppPath + serverPath; } ConfigWatcher.SetupWacher(serverPath); } } } return instance; } } public SystemConfig getSystemConfig() { SystemConfig config = CacheManager.Get<SystemConfig>("App.SystemConfig"); if (config != null) { return config; } string serverPath = ConfigurationManager.AppSettings["SystemConfig"].ToString(); //判断是否是绝对路径 if (!Path.IsPathRooted(serverPath)) { serverPath = System.Web.HttpRuntime.AppDomainAppPath + serverPath; } CacheManager.Insert("App.SystemConfig", XmlHelper.DeSerialize<SystemConfig>(serverPath)); return CacheManager.Get<SystemConfig>("App.SystemConfig"); } } #region 自定义系统配置类 [XmlType(TypeName = "config")] public class SystemConfig { /// <summary> /// 日志设置(0:关闭日志,1:文本日志,2:nosql数据库日志,3:sql数据库日志) /// </summary> [XmlElement("LogSet")] public int LogSet { get; set; } /// <summary> /// 数据库设置(0:两个数据库都访问,优先访问nosql数据库,1:sql数据库,2:nosql数据库) /// </summary> [XmlElement("DBSet")] public int DBSet { get; set; } /// <summary> /// Redis缓存设置(0:不设Redis缓存,优先访问数据库,1:设置Redis缓存,优先访问redis缓存,不存在则访问数据库) author:liwx(2016/11/09) /// </summary> [XmlElement("RedisSet")] public int RedisSet { get; set; } } #endregion }
还有一个自定义的缓存配置类
接下来 再封装一个services操作类,其实这个类就是封装服务列表和http请求的过程 ,应为我们后面会分布式部署各个独立的模块,而各个独立的模块又相当于一个子服务,所以需要在配置文件中配置服务路径
所有的服务请求,我们在程序中都会使用代理的类去向各个服务发送请求。所以直接上封装好的Server代码吧
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; namespace zjl.Framework.Server { [XmlType(TypeName = "Config")] public class Services { [XmlArray("Services")] public List<Service> List { get; set; } } [XmlType(TypeName = "Service")] public class Service { [XmlAttribute] public string Name { get; set; } [XmlAttribute] public string Url { get; set; } [XmlAttribute] public string Server { get; set; } [XmlAttribute] public string Method { get; set; } [XmlAttribute] public bool IsRelative { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; namespace zjl.Framework.Server { [XmlType(TypeName = "Config")] public class Servers { [XmlArray("Servers")] public List<Server> List { get; set; } } [XmlType(TypeName = "Server")] public class Server { [XmlAttribute] public string Name { get; set; } [XmlAttribute] public string Url { get; set; } } }
using System; using System.Collections.Generic; using System.Configuration; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; using zjl.Framework.Helper; namespace zjl.Framework.Server { public class ServiceCommon { public static Dictionary<string, Service> InitServiceList() { Dictionary<string, Server> servers = new Dictionary<string, Server>(); Dictionary<string, Service> services = new Dictionary<string, Service>(); string serverPath = ConfigurationManager.AppSettings["ServerConfig"].ToString(); string servicePath = ConfigurationManager.AppSettings["ServiceConfig"].ToString(); //判断是否是绝对路径 if (!Path.IsPathRooted(serverPath)) { serverPath = System.Web.HttpRuntime.AppDomainAppPath + serverPath; } //获取服务器列表 Servers serverList = XmlHelper.DeSerialize<Servers>(serverPath); foreach (var server in serverList.List) { servers.Add(server.Name, server); } //判断是否是绝对路径 if (!Path.IsPathRooted(servicePath)) { servicePath = System.Web.HttpRuntime.AppDomainAppPath + servicePath; } //获取服务列表 Services serviceList = XmlHelper.DeSerialize<Services>(servicePath); foreach (var service in serviceList.List) { if (service.IsRelative && servers.Keys.Contains(service.Server)) { service.Url = servers[service.Server].Url + service.Url; } services.Add(service.Name, service); } return services; } /// <summary> /// 获取服务器列表 /// </summary> /// <returns></returns> public static Dictionary<string, Server> InitServerList() { Dictionary<string, Server> servers = new Dictionary<string, Server>(); Servers serverList = XmlHelper.DeSerialize<Servers>(ConfigurationManager.AppSettings["ServerConfig"].ToString()); foreach (var server in serverList.List) { servers.Add(server.Name, server); } return servers; } } }
最后还是使用一个单例来提供实例化
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using Newtonsoft.Json; namespace zjl.Framework.Server { public class ServiceHandler { // 依然是静态自动hold实例 private static volatile ServiceHandler instance = null; private static volatile Dictionary<string, Service> serviceList = null; // Lock对象,线程安全所用 private static object syncRoot = new Object(); private ServiceHandler() { serviceList = ServiceCommon.InitServiceList(); } public static ServiceHandler Instance { get { if (instance == null) { lock (syncRoot) { if (instance == null) instance = new ServiceHandler(); } } return instance; } } /// <summary> /// 返回字符串对象 /// </summary> /// <param name="serviceName">服务名称</param> /// <param name="param">请求的参数,GET请求传字符串,Post请求直接传对象</param> /// <returns></returns> public string Request2Str(string serviceName, object param) { Service service = null; string resultStr = ""; //判断是否存在该服务的配置 if (!serviceList.Keys.Contains(serviceName)) { throw new Exception("调用服务未找到!"); return null; } service = serviceList[serviceName]; switch (service.Method.ToUpper()) { case "GET": resultStr = Get(service.Url, param as string); break; case "POST": resultStr = Post(service.Url, param); break; default: break; } return resultStr; } /// <summary> /// 向服务器发起请求 /// </summary> /// <typeparam name="T">返回的对象类型</typeparam> /// <param name="serviceName">服务名称</param> /// <param name="param">请求的参数,GET请求传字符串,Post请求直接传对象</param> /// <returns></returns> public T Request<T>(string serviceName, object param) where T : class,new() { return JsonConvert.DeserializeObject<T>(Request2Str(serviceName, param)); } //public void reflashServiceList() //{ // serviceList = ServiceCommon.InitServiceList(); //} public Dictionary<string, Service> getServiceList() { return ServiceCommon.InitServiceList(); } private string Get(string url, string param) { string result = WebRequestHelper.GetData(param, url); return result; } private string Post(string url, object param) { string paramString = JsonConvert.SerializeObject(param); string result = WebRequestHelper.PostData(paramString, url); return result; } } }
http请求类
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Text; using System.Threading.Tasks; namespace zjl.Framework.Helper { public class WebRequestHelper { /// <summary> /// 以POST 形式请求数据 /// </summary> /// <param name="RequestPara"></param> /// <param name="Url"></param> /// <returns></returns> public static string PostData(string RequestPara, string Url) { return PostData(RequestPara, Url, "application/json"); } /// <summary> /// 以POST 形式请求数据 /// </summary> /// <param name="RequestPara"></param> /// <param name="Url"></param> /// <returns></returns> public static string PostData(string RequestPara, string Url, string ContentType) { WebRequest hr = HttpWebRequest.Create(Url); string ReturnVal = null; byte[] buf = Encoding.GetEncoding("utf-8").GetBytes(RequestPara); hr.ContentType = ContentType; hr.ContentLength = buf.Length; hr.Method = "POST"; using (Stream RequestStream = hr.GetRequestStream()) { RequestStream.Write(buf, 0, buf.Length); RequestStream.Close(); } using (WebResponse response = hr.GetResponse()) { using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8"))) { ReturnVal = reader.ReadToEnd(); } } return ReturnVal; } /// <summary> /// 以GET 形式获取数据 /// </summary> /// <param name="RequestPara"></param> /// <param name="Url"></param> /// <returns></returns> public static string GetData(string RequestPara, string Url) { string ReturnVal = null; RequestPara = RequestPara.IndexOf('?') > -1 ? (RequestPara) : ("?" + RequestPara); WebRequest hr = HttpWebRequest.Create(Url + RequestPara); byte[] buf = Encoding.GetEncoding("utf-8").GetBytes(RequestPara); hr.Method = "GET"; using (WebResponse response = hr.GetResponse()) { using(StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("utf-8"))) { ReturnVal = reader.ReadToEnd(); } } return ReturnVal; } } }
好了 这样几个通用的抽象工具类就封装的差不多了 没有看懂的小伙伴们不要着急 ,我会附上源码,可能要等到我全部介绍完了才会有人看懂我想表达什么。博主在全部介绍完会上一个完整的案例。