Maison > Article > développement back-end > Souvenez-vous d'une refactorisation de code .NET (Partie 2)
public override bool TryGetMember(GetMemberBinder binder, out object result) { if (!_dictionary.TryGetValue(binder.Name, out result)) { result = null; return true; } var dictionary = result as IDictionary<string, object>; if (dictionary != null) { result = new DynamicJsonObject(dictionary); return true; } var arrayList = result as ArrayList; if (arrayList != null && arrayList.Count > 0) { if (arrayList[0] is IDictionary<string, object>) result = new List<object>(arrayList.Cast<IDictionary<string, object>>().Select(x => new DynamicJsonObject(x))); else result = new List<object>(arrayList.Cast<object>()); } return true; } } #endregion }
Vient ensuite la méthode GetContent. Le but de cette méthode est très simple. Il s'agit d'assembler le contenu SMS final en fonction des paires clé-valeur de paramètre de variable de modèle et du contenu du modèle SMS transmis précédemment par le client. cette méthode contenait du codage dur, nous devons maintenant la changer en acquisition dynamique.
Exemple de contenu d'un modèle de message texte :
【一应生活】您有一件单号为expressNumbers company,已到communityName收发室,请打开一应生活APP“收发室”获取取件码进行取件。 点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life
J'ai trouvé qu'il y avait un problème avec le contenu d'un tel modèle. Les paramètres variables du modèle sont directement exprimés en mots anglais, et dans le contenu de notre message texte, il peut parfois y avoir des mots anglais, je vais donc ajouter {} à tous les paramètres variables. La modification est la suivante :
【一应生活】您有一件单号为{expressNumbers} {company},已到{communityName}收发室, 请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life
Nous devons remplacer les paramètres variables dans le modèle SMS par les valeurs correspondant aux paramètres variables en fonction de l'objet passé par le client. Ensuite, nous devons d'abord analyser les informations sur la paire clé-valeur dans cet objet.
/// 把object对象的属性反射获取到字典列表中 /// </summary> /// <param name="data">object对象</param> /// <returns>返回Dictionary(属性名,属性值)列表</returns> static Dictionary<string, string> GetProperties(object data) { Dictionary<string, string> dict = new Dictionary<string, string>(); Type type = data.GetType(); string[] propertyNames = type.GetProperties().Select(p => p.Name).ToArray(); foreach (var prop in propertyNames) { object propValue = type.GetProperty(prop).GetValue(data, null); string value = (propValue != null) ? propValue.ToString() : ""; if (!dict.ContainsKey(prop)) { dict.Add(prop, value); } } return dict; }
L'étape suivante consiste à faire correspondre le contenu du modèle de message texte via des expressions régulières.
/// 多个匹配内容 /// </summary> /// <param name="sInput">输入内容</param> /// <param name="sRegex">表达式字符串</param> /// <param name="sGroupName">分组名, ""代表不分组</param> static List<string> GetList(string sInput, string sRegex, string sGroupName) { List<string> list = new List<string>(); Regex re = new Regex(sRegex, RegexOptions.IgnoreCase | RegexOptions.IgnorePatternWhitespace | RegexOptions.Multiline); MatchCollection mcs = re.Matches(sInput); foreach (Match mc in mcs) { if (sGroupName != "") { list.Add(mc.Groups[sGroupName].Value); } else { list.Add(mc.Value); } } return list; } public static string ReplaceTemplate(string template, object data) { var regex = @"\{(?<name>.*?)\}"; List<string> itemList = GetList(template, regex, "name"); //获取模板变量对象 Dictionary<string, string> dict = GetProperties(data); foreach (string item in itemList) { //如果属性存在,则替换模板,并修改模板值 if (dict.ContainsKey(item)) { template = template.Replace("{"+item+"}", dict.First(x => x.Key == item).Value); } } return template; }
De cette façon, l'objet transmis par le client est découplé de notre code d'analyse. L'objet transmis par le client ne dépend plus de l'implémentation de notre code, mais dépend du contenu du modèle dans notre table de données. .configuration.
J'ai écrit ces méthodes et je vais exécuter un test unitaire pour vérifier si cela a l'effet souhaité. Malheureusement, les tests unitaires ne sont pas du tout utilisés dans ce projet. Il n'y a aucun moyen de créer un. testez vous-même les unités
[TestClass] public class MatchHelperTest { [TestMethod] public void ReplaceTemplate() { //模板文本 var template = "【一应生活】您有一件单号为{expressNumbers} {company},已到{communityName}收发室, 请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life"; //数据对象 var data = new { expressNumbers = "2016", company = "长城", communityName = "长怡花园"}; string str = "【一应生活】您有一件单号为2016 长城,已到长怡花园收发室, 请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life"; string str1=MatchHelper.ReplaceTemplate(template, data); Assert.AreEqual(str1,str); //重复标签的测试 template = "【一应生活】您有一件单号为{expressNumbers} {company},已到{communityName}收发室,单号:{expressNumbers}"; str = "【一应生活】您有一件单号为2016 长城,已到长怡花园收发室,单号:2016"; str1=MatchHelper.ReplaceTemplate(template, data); Assert.AreEqual(str1, str); } }
En parlant de tests unitaires, je pense qu'ils ne sont pas utilisés dans de nombreuses entreprises pour de trop nombreuses raisons. Je pense aussi que si le business est simple, il n'est pas nécessaire d'écrire des tests unitaires. Trop d'entreprises entrepreneuriales en Chine sont très rapides sur leurs projets. Si l'on dit que l'écriture de tests unitaires ne prend pas de temps, c'est définitivement un mensonge. Quant à l'écriture de tests unitaires, elle peut améliorer l'efficacité du développement et réduire le taux de retravail. Personnellement, c'est difficile à dire, car même si vous n'écrivez pas de tests unitaires, vous pouvez toujours compenser. par bien d’autres moyens. Opinion personnelle, ne critiquez pas.
Ensuite, modifiez la méthode GetContent comme suit :
public string GetContent(dynamic messageContext) { string strMsg = ""; string TypeCode = string.IsNullOrEmpty(messageContext.serviceCode) ? "001" : messageContext.serviceCode; string channel = messageContext.channel; try{ var Module = unitOfWork.MessageModule.Get(c => c.Type == channel && c.TypeNo == TypeCode).FirstOrDefault(); if (!string.IsNullOrEmpty(Module.Content)) { var content = Module.Content; strMsg = MatchHelper.ReplaceTemplate(content, messageContext); } return strMsg; } catch (Exception ex) { strMsg = ex.Message; } return strMsg; }
(En plus : plaignons-nous du nom des variables précédentes, MessageContext messageContext et string messageContent, elles se ressemblent trop. Je les ai répétées à d'abord. J'ai fait une erreur lors de sa construction. Il est recommandé de ne pas utiliser de noms de variables similaires dans la même méthode pour éviter toute confusion, j'ai encore été trompé et j'étais insupportable, alors je l'ai renommé de manière décisive.) 🎜>
MessageModuleBusiness message ModuleBusiness = new MessageModuleBusiness()Cela dépend de l'implémentation de la classe spécifique, et nous savons que le spécifique est instable, l'abstraction est stable, nous devrions programmer pour les interfaces. Aujourd'hui, vous envoyez des messages texte, demain vous enverrez peut-être des e-mails ou ajouterez des enregistrements de journaux, etc.
public interface IMessageModuleBusiness { /// <summary> /// 组装消息内容 /// </summary> /// <param name="messageContext">动态参数对象</param> /// <returns>组装后的消息内容</returns> string GetContent(dynamic messageContext); }Ensuite, le code appelant est modifié en :
private IMessageModuleBusiness message ModuleBusiness = new MessageModuleBusiness();Le code final externalMerchantSendMessage est :
/// 外部商户发送信息 public ActionResult externalMerchantSendMessage() { try { dynamic param = null; string json = Request.QueryString.ToString(); if (Request.QueryString.Count != 0) //ajax get请求 { //兼容旧的客户调用写法,暂时硬编了 if (json.Contains("param.")) { json = json.Replace("param.", ""); } json = "{" + json.Replace("=", ":'").Replace("&", "',") + "'}"; } else //ajax Post请求 { Request.InputStream.Position = 0;//切记这里必须设置流的起始位置为0,否则无法读取到数据 json = new StreamReader(Request.InputStream).ReadToEnd(); } var serializer = new JavaScriptSerializer(); serializer.RegisterConverters(new[] { new DynamicJsonConverter() }); param = serializer.Deserialize(json, typeof(object)); logger.Info("[externalMerchantSendMessage]param:" + param); bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign); if (!isAuth) { return Json(new Result<string>() { resultCode = ((int)ResultCode.NoPermission).ToString(), resultMsg = "签名或无权限访问" }, JsonRequestBehavior.AllowGet); } var meaage = messageModuleBusiness.GetContent(param); if (string.IsNullOrEmpty(meaage)) { return Json(new Result<string>() { resultCode = ((int)ResultCode.failure).ToString(), resultMsg = "发送失败" }, JsonRequestBehavior.AllowGet); } SMSHelper helper = new SMSHelper(); helper.SendSMS(meaage, param.phone); //发送短信 return Json(new Result<string>() { resultCode = ((int)ResultCode.success).ToString(), resultMsg = "发送成功" }, JsonRequestBehavior.AllowGet); } catch (Exception ex) { return Json(new Result<string>() { resultCode = ((int)ResultCode.failure).ToString(), resultMsg = "发送失败"+ex.Message }, JsonRequestBehavior.AllowGet); } }Dans ce cas, même s'il est appelé par réflexion ou IOC à l'avenir Il est également pratique de découpler à nouveau.