Home Backend Development C#.Net Tutorial Remember a .NET code refactoring (Part 1)

Remember a .NET code refactoring (Part 1)

Feb 06, 2017 pm 02:37 PM

Requirements: This is the case. To develop a template for sending text messages, different customers may use different templates, and the variable parameters used by different customers are also different.


For emergency purposes, a text message template function for sending text messages has been completed online. The text message template table has also been created, and a new record has been added to the table. I only need to make an interface for adding, deleting, modifying and checking text message templates. It seems that my task is quite simple. An experienced driver should know that he has made a mess.


The picture below shows the originally created table

Remember a .NET code refactoring (Part 1)

The SQL creation script is as follows:

Remember a .NET code refactoring (Part 1)

Before this, an API interface for sending text messages has been developed for customers to call. In other words, the caller (customer) will not modify the code, only me. to modify. Although I am extremely reluctant to take on half-finished tasks, I have no choice but to start all development tasks from scratch.


The entity class code is as follows:

Remember a .NET code refactoring (Part 1)

DOT class:

Remember a .NET code refactoring (Part 1)

##This is the previous code, the business entity class MessageModuleBusiness.cs code is as follows:

public class MessageModuleBusiness : GenericRepository<Model.MessageModule>
    {
        private UnitOfWork.UnitOfWork unitOfWork = new UnitOfWork.UnitOfWork();
        /// 获取模版内容
        public string GetContent(MessageContext messageContext)
        {
            string messageContent = "";
            string TypeCode = string.IsNullOrEmpty(messageContext.serviceCode) ? "001" : messageContext.serviceCode;
            try
            {
                var Module = unitOfWork.MessageModule.Get(c => c.Type == messageContext.channel && c.TypeNo == TypeCode).FirstOrDefault();
                //Content的内容:【一应生活】您有一件单号为expressNumbers company,
                已到communityName收发室,请打开一应生活APP“收发室”获取取件码进行取件。点击下载http://a.app.qq.com/o/simple.jsp?pkgname=com.ening.life
                if (!string.IsNullOrEmpty(Module.Content))
                {
                    var content = Module.Content;
                    content = content.Replace("company", messageContext.company);
                    content = content.Replace("expressNumbers", messageContext.expressNumbers);
                    content = content.Replace("communityName", messageContext.communityName);
                    content = content.Replace("Id", messageContext.Id);
                    content = content.Replace("receiveTime", messageContext.receiveTime);
                    content = content.Replace("fetchCode", messageContext.fetchCode);
                    messageContent = content;
                }
                return messageContent;
            }
            catch (Exception ex) {}
            return "";
        } 
        #endregion
}
Copy after login

MessageContext class, this is an entity object transmitted and called by the client. There are many dynamic tag variables similar to text messages in the object.

public class MessageContext{
        /// 手机号码
        public string phone { get; set; }
        /// 发送信息
        public string message { get; set; }
        /// 签名
        public string sign { get; set; }
        /// 渠道
        public string channel { get; set; }
        /// 内容
        public string content { get; set; }
        /// 取件码
        public string fetchCode { get; set; }
        /// 快递公司
        public string company { get; set; }
        /// 快递单号
        public string expressNumbers { get; set; }
        /// 社区名称
        public string communityName { get; set; }
        /// 到件时间
        public string receiveTime { get; set; }
        /// 序号
        public string Id { get; set; }
        /// 业务代码
        public string serviceCode { get; set; }
    }
Copy after login

Controller method externalMerchantSendMessage, which is for external calls

    /// 外部商户发送信息
        public ActionResult externalMerchantSendMessage(MessageContext param)
        {
            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);
        }
Copy after login

The above are the functions that I have implemented before receiving the development task. It seems that my task is quite simple, but many years of development experience tell me that this needs to be refactored. If I don't care about anything now and just make an interface for adding, deleting, modifying and checking SMS templates, the maintenance people in the future will definitely go crazy. .


Do you see any problem?


This interface method externalMerchantSendMessage is called for all customers, and different customers use different SMS templates, and different templates have different variable parameters. Now all variable parameters are encapsulated in the MessageContext class. The problem is that we cannot determine all variable parameters at once and keep them unchanged.


So, that is to say, once variable parameters need to be added, the code in the MessageContext class must be modified, and the code in the GetContent method is hard-coded and needs to be modified accordingly. . This forms a cycle, constantly adding variable parameters, constantly changing the code, and constantly releasing interface versions...


When I have enough time, I naturally If you are a disciplined programmer, then start refactoring.


Before refactoring, what comes to mind is not various design patterns, but the basic principles of object-oriented design. Various design patterns are like various martial arts routines or moves. Martial arts practitioners should be like Zhang Wuji practicing Tai Chi sword, first learn various routines, and then forget all the routines to master them.


Because moves are dead, people are alive. Every move has its flaws. There is no sure-win move at all. It’s like there is no universal design pattern. Any design All models have shortcomings.


#The core idea of ​​object-oriented design is to encapsulate changes, so first find the change points. From the above analysis, we have discovered the changing point, which is the variable parameters in the SMS template, and these variable parameters are passed by the customer caller, and the parameter variables passed by different customers may be different.


Let’s take a look first, what is passed by the customer? Let's take a look at the customer calling code. There are two calling methods: Get and Post.

function sendMsg() {
            //var appParam ="phone=15914070649&sign=78a7ce797cf757916c2c7675b6865b54&channel=weijiakeji&content=&fetchCode=1
&company=%E9%A1%BA%E4%B8%B0%E5%BF%AB%E9%80%92&expressNumbers=123456&communityName=%E9%95%BF%E5%9F%8E%E4%B8%80%E8%8A%B1%E5%9B%AD&receiveTime=5&Id=1231";
            //Get("/Message/externalMerchantSendMessage?" + appParam, {});

            var data = {
                "phone": "15914070649", "sign": "78a7ce797cf757916c2c7675b6865b54", "channel": "weijiakeji",
                "fetchCode": 1, "company": "%E9%A1%BA%E4%B8%B0%E5%BF%AB%E9%80%92", "Id": "1231"
            };
            Post(&#39;/Message/externalMerchantSendMessage&#39;, data);
        }
        //WebAPI Post方法
        function Post(url, data) {
            $.ajax({
                url: url,
                contentType: "application/json",
                type: "POST",
                dataType: "json",
                async: true,
                cache: false,
                data: JSON.stringify(data),
                success: function (response) {
                    $(&#39;#response&#39;).text(JSON.stringify(response));
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                }
            });
        };
        //// WebApi Get方法
        function Get(url, data) {
            $.ajax({
                url: url,
                contentType: "application/json",
                type: "GET",
                dataType: "json",
                async: true,
                cache: false,
                //data: JSON.stringify(data),
                success: function (response) {
                    $(&#39;#response&#39;).text(JSON.stringify(response));
                },
                error: function (XMLHttpRequest, textStatus, errorThrown) {
                    alert(textStatus);
                }
            });
        };
Copy after login

It can be seen that what the customer passes is a collection of key-value pairs, which is an object in JSON format. According to the previous code bool isAuth = authModelBusiness.isAuth(param.channel, param.phone, param.sign);, it can be analyzed that there are three parameters that all calling customers must pass, that is: channel, phone, sign, The other parameters are the variable parameters and parameter values ​​of the SMS template.


Then the parameter in the method externalMerchantSendMessage(MessageContext param) is a variable object. Isn't there a dynamic in C# 4.0 that is used to describe mutable objects?

Then the first step is to modify the incoming parameter type. It used to be a hard-coded strongly typed MessageContext. Now it does not rely on this type, but dynamic analysis. Modify the externalMerchantSendMessage method code as follows:

##
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("=", ":&#39;").Replace("&", "&#39;,") + "&#39;}";
                }
                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));
Copy after login

DynamicJsonConverter is used to convert JSON strings into Object objects. The code is as follows:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Dynamic;
using System.Linq;
using System.Text;
using System.Web.Script.Serialization;

public sealed class DynamicJsonConverter : JavaScriptConverter
{
    public override object Deserialize(IDictionary<string, object> dictionary, Type type, JavaScriptSerializer serializer)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        return type == typeof(object) ? new DynamicJsonObject(dictionary) : null;
    }

    public override IDictionary<string, object> Serialize(object obj, JavaScriptSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new ReadOnlyCollection<Type>(new List<Type>(new[] { typeof(object) })); }
    }
  #region Nested type: DynamicJsonObject

    private sealed class DynamicJsonObject : DynamicObject
    {
        private readonly IDictionary<string, object> _dictionary;

        public DynamicJsonObject(IDictionary<string, object> dictionary)
        {
            if (dictionary == null)
                throw new ArgumentNullException("dictionary");
            _dictionary = dictionary;
        }

        public override string ToString()
        {
            var sb = new StringBuilder("{");
            ToString(sb);
            return sb.ToString();
        }

        private void ToString(StringBuilder sb)
        {
            var firstInDictionary = true;
            foreach (var pair in _dictionary)
            {
                if (!firstInDictionary)
                    sb.Append(",");
                firstInDictionary = false;
                var value = pair.Value;
                var name = pair.Key;
                if (value is string)
                {
                    sb.AppendFormat("{0}:\"{1}\"", name, value);
                }
                else if (value is IDictionary<string, object>)
                {
                    new DynamicJsonObject((IDictionary<string, object>)value).ToString(sb);
                }
                else if (value is ArrayList)
                {
                    sb.Append(name + ":[");
                    var firstInArray = true;
                    foreach (var arrayValue in (ArrayList)value)
                    {
                        if (!firstInArray)
                            sb.Append(",");
                        firstInArray = false;
                        if (arrayValue is IDictionary<string, object>)
                            new DynamicJsonObject((IDictionary<string, object>)arrayValue).ToString(sb);
                        else if (arrayValue is string)
                            sb.AppendFormat("\"{0}\"", arrayValue);
                        else
                            sb.AppendFormat("{0}", arrayValue);

                    }
                    sb.Append("]");
                }
                else
                {
                    sb.AppendFormat("{0}:{1}", name, value);
                }
            }
            sb.Append("}");
        }
Copy after login

The above is the content of a .NET code reconstruction (Part 1). Please pay attention to more related content. PHP Chinese website (www.php.cn)!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

How to solve code redundancy problems in C++ development How to solve code redundancy problems in C++ development Aug 22, 2023 pm 05:30 PM

How to solve the code redundancy problem in C++ development. Code redundancy means that when writing a program, there are similar or repeated codes in multiple places. This problem not only makes the code difficult to maintain and read, but also increases the size and complexity of the code. For C++ developers, it is particularly important to solve the problem of code redundancy, because C++ is a powerful programming language, but it can also easily lead to code duplication. The root cause of code redundancy problems lies in unreasonable design and coding habits. To solve this problem, you can start from the following aspects: Use functions and classes: C

PHP development: using Rector for code refactoring and optimization PHP development: using Rector for code refactoring and optimization Jun 16, 2023 am 08:38 AM

As time passes and requirements change, a project's code can easily become obsolete and difficult to maintain and extend. In PHP development, refactoring is considered one of the necessary tasks to improve code quality and development efficiency. In this process, using the Rector tool can greatly simplify code reconstruction and optimization work. Rector is an open source PHP code reconstruction tool that can help PHP developers automate code reconstruction and optimization, allowing developers to focus more on business development and function implementation. pass

What are the employment prospects of C#? What are the employment prospects of C#? Oct 19, 2023 am 11:02 AM

Whether you are a beginner or an experienced professional, mastering C# will pave the way for your career.

Share several .NET open source AI and LLM related project frameworks Share several .NET open source AI and LLM related project frameworks May 06, 2024 pm 04:43 PM

The development of artificial intelligence (AI) technologies is in full swing today, and they have shown great potential and influence in various fields. Today Dayao will share with you 4 .NET open source AI model LLM related project frameworks, hoping to provide you with some reference. https://github.com/YSGStudyHards/DotNetGuide/blob/main/docs/DotNet/DotNetProjectPicks.mdSemanticKernelSemanticKernel is an open source software development kit (SDK) designed to integrate large language models (LLM) such as OpenAI, Azure

Getting Started with PHP: Code Refactoring Getting Started with PHP: Code Refactoring May 26, 2023 pm 04:21 PM

Refactoring is a very important process when writing PHP code. As an application grows, the code base becomes larger and harder to read and maintain. Refactoring is to solve this problem and make the code more modular and better organized and extensible. When we refactor the code, we need to consider the following aspects: Code style Code style is a very important point. Keeping your coding style consistent will make your code easier to read and maintain. Please follow PHP coding standards and be consistent. Try using a code style checking tool such as PHP

Java development: How to do code refactoring and quality assessment Java development: How to do code refactoring and quality assessment Sep 21, 2023 am 09:57 AM

Java Development: Code Refactoring and Quality Assessment Introduction: In the process of software development, code refactoring is one of the important means to improve code quality and maintainability. By refactoring the code, the code can be made more elegant, concise, and easy to understand and modify. However, refactoring is not just about simply modifying the code, but a process that requires rational and systematic thinking. This article will introduce how to perform code refactoring and illustrate it with specific code examples. We will also discuss how to evaluate code quality and why evaluation is important. Heavy code

Go language return value type inference and code refactoring Go language return value type inference and code refactoring Apr 30, 2024 am 08:06 AM

Go language return value type inference automatically infers function return value types, simplifying code and improving readability. The return value type can be omitted and the compiler will automatically infer the type based on the actual return value in the function body. Can be used to refactor existing code to eliminate explicit type declarations. For example, the function calculateTotal that calculates the sum of an array of integers can be refactored into: funccalculateTotal(items[]int){}.

How to use Go language for code refactoring practice How to use Go language for code refactoring practice Aug 02, 2023 am 10:05 AM

How to use Go language for code refactoring practice introduction: In the software development process, we often face the challenge of code refactoring. Code refactoring refers to optimizing and restructuring existing code to improve code quality and maintainability. This article will introduce how to use Go language for code refactoring practice, and come with corresponding code examples. 1. Principles of code refactoring Before code refactoring, we need to clarify some principles to ensure the smooth progress of refactoring. The following are some important code refactoring principles: Maintain the consistency of code functionality: After refactoring

See all articles