using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Net; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; using Vinno.FIS.Sonopost.Helpers; using Vinno.FIS.Sonopost.WebApi.Models; using Vinno.IUS.Common.Log; namespace Vinno.FIS.Sonopost.WebApi { internal class WebApiEngine { private static readonly int CONTROLLER_STR_LEN = "Controller".Length; private readonly ConcurrentDictionary _controllerReference; public const string ROUTE_PREFIX = "/api/"; internal WebApiEngine() { _controllerReference = new ConcurrentDictionary(); Register(); } private void Register() { Assembly assembly = GetType().Assembly; Type baseControllerType = typeof(BaseController); Type[] types = assembly.GetTypes() .Where(x => baseControllerType.IsAssignableFrom(x) && x != baseControllerType) .ToArray(); foreach (Type type in types) { object[] attrs = type.GetCustomAttributes(typeof(WebApiControllerAttribute), false); if (attrs.Length == 0) continue; WebApiControllerAttribute attr = (WebApiControllerAttribute)attrs[0]; string controllerName = attr.Name; if (string.IsNullOrWhiteSpace(controllerName)) { controllerName = type.Name.Substring(0, type.Name.Length - CONTROLLER_STR_LEN); } string key = controllerName.ToLower(); if (!_controllerReference.ContainsKey(key)) { _controllerReference.TryAdd(key, type); } } } /// /// Handle Api Request /// /// /// /// Response Json String public string Handle(string route, string requestJson, HttpListenerContext context) { string[] routeSplits = route.Split('/'); string controllerName = routeSplits[0]; string actionName = routeSplits[1]; if (!_controllerReference.ContainsKey(controllerName)) { return null; } Assembly assembly = GetType().Assembly; Type classType = _controllerReference[controllerName]; BaseController instance = (BaseController)assembly.CreateInstance(classType.FullName); IEnumerable baseFieldInfos = classType.BaseType.GetRuntimeFields(); foreach (FieldInfo fieldInfo in baseFieldInfos) { if (fieldInfo.FieldType.Equals(context.GetType())) { fieldInfo.SetValue(instance, context); } } MethodInfo[] methodInfos = classType.GetMethods(); foreach (MethodInfo methodInfo in methodInfos) { if (!methodInfo.IsPublic) continue; if (methodInfo.IsConstructor || methodInfo.IsStatic || methodInfo.IsVirtual || methodInfo.IsAbstract) continue; object[] attrs = methodInfo.GetCustomAttributes(typeof(WebApiActionAttribute), false); if (attrs.Length == 0) continue; WebApiActionAttribute attr = (WebApiActionAttribute)attrs[0]; string attrActionName = string.IsNullOrWhiteSpace(attr.Name) ? methodInfo.Name : attr.Name; if (!actionName.Equals(attrActionName.ToLowerInvariant())) continue; object[] parameters = null; try { ParameterInfo[] parameterInfos = methodInfo.GetParameters(); if (parameterInfos.Length > 0) { var parameter = JsonHelper.JsonToObj(requestJson, parameterInfos[0].ParameterType, new JsonSerializerOptions { NumberHandling = JsonNumberHandling.AllowReadingFromString }); parameters = new object[] { parameter }; } object result = methodInfo.Invoke(instance, parameters); return JsonHelper.ToJson(result, new JsonSerializerOptions { NumberHandling = JsonNumberHandling.WriteAsString, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull }); } catch (Exception ex) { Logger.WriteLineError($"[{nameof(WebApiEngine)}]{nameof(Handle)} error: {ex}"); return Result.Fail("RequestError").ToJson(); } } return null; } } }