.Net 開發(fā)規(guī)范

  • .Net 開發(fā)規(guī)范

    一七咧、C# 編碼規(guī)范

    1. 代碼組織與風(fēng)格

    1.1. Tab

    • 使一個Tab為4個空格長靶剑。

    1.2. 縮進(jìn)

    • 使一個代碼塊內(nèi)的代碼都統(tǒng)一縮進(jìn)一個Tab長度宙攻。

    1.3. 空行

    • 建議適當(dāng)?shù)脑黾涌招卸辏瑏碓黾哟a的可讀性封孙。

    • 在在類韵吨,接口以及彼此之間有兩行空行:

    • 在下列情況之間有一行空行:

    方法之間匿垄;

    局部變量和它后邊的語句之間;

    方法內(nèi)的功能邏輯部分之間归粉;

    1.4. 函數(shù)長度

    • 每個函數(shù)有效代碼(不包括注釋和空行)長度不要超過50行椿疗。

    1.5. 大括號

    • 開括號“{”放在塊的所有者的下一行,單起一行糠悼;

    • 閉括號“}”單獨放在代碼塊的最后一行届榄,單起一行。

    1.6. 行寬

    • 每行代碼和注釋不要超過70個字符或屏幕的寬度倔喂,如超過則應(yīng)換行铝条,換行后的代碼應(yīng)該縮進(jìn)一個Tab靖苇。

    1.7. 空格

    • 括號和它里面的字符之間不要出現(xiàn)空格。括號應(yīng)該和它前邊的關(guān)鍵詞留有空格班缰,如:while (true) {};

    • 但是方法名和左括號之間不要有空格贤壁。

    • 參數(shù)之間的逗號后加一空格。如:method1(int i1, int i2)

    • for語句里的表達(dá)式之間加一空格鲁捏。如:for (expr1; expr2; expr3)

    • 二元操作符和操作數(shù)之間用空格隔開芯砸。如:i + c;

    • 強(qiáng)制類型轉(zhuǎn)換時,在類型和變量之間加一空格给梅。如:(int) i ;

    2. 注釋

    2.1. 注釋的基本約定

    • 注釋應(yīng)該增加代碼的清晰度;

    • 保持注釋的簡潔双揪,不是任何代碼都需要注釋的动羽,過多的注釋反而會影響代碼的可讀性。

    • 注釋不要包括其他的特殊字符渔期。

    • 建議先寫注釋运吓,后寫代碼,注釋和代碼一起完成

    • 如果語句塊(比如循環(huán)和條件分枝的代碼塊)代碼太長疯趟,嵌套太多拘哨,則在其結(jié)束“}”加上注釋,標(biāo)志對應(yīng)的開始語句信峻。如果分支條件邏輯比較復(fù)雜倦青,也加上注釋。

    • 在VS環(huán)境中通過配置工程編譯時輸出XML文檔文件可以檢查注釋的完整情況盹舞,如果注釋不完整會報告編譯警告产镐;

    2.2. 注釋類型

    2.2.1. 塊注釋
    • 主要用來描述文件,類踢步,方法癣亚,算法等,放在所描述對象的前邊获印。具體格式以IDE編輯器輸入“///”自動生成的格式為準(zhǔn)述雾,另外再附加我們自定義的格式,如下所列:

    /// <Remark作者兼丰,創(chuàng)建日期玻孟,修改日期</ Remark

    對類和接口的注釋必須加上上述標(biāo)記,對方法可以視情況考慮

    2.2.2. 行注釋
    • 主要用在方法內(nèi)部地粪,對代碼取募,變量,流程等進(jìn)行說明蟆技。整個注釋占據(jù)一行玩敏。
    2.2.3. 尾隨注釋
    • 與行注釋功能相似斗忌,放在代碼的同行,但是要與代碼之間有足夠的空間旺聚,便于分清织阳。例:
    int m = 4 ;  // 注釋
    
    • 如果一個程序塊內(nèi)有多個尾隨注釋,每個注釋的縮進(jìn)保持一致砰粹。

    2.3. 注釋哪些部分

    項目 注釋哪些部分
    參數(shù)**** 參數(shù)用來做什么任何約束或前提條件****
    字段/屬性 字段描述
    類的目的已知的問題類的開發(fā)/維護(hù)歷史
    接口 目的它應(yīng)如何被使用以及如何不被使用
    局部變量 用處/目的
    成員函數(shù)注釋 成員函數(shù)做什么以及它為什么做這個哪些參數(shù)必須傳遞給一個成員函數(shù)成員函數(shù)返回什么已知的問題任何由某個成員函數(shù)拋出的異常成員函數(shù)是如何改變對象的包含任何修改代碼的歷史如何在適當(dāng)情況下調(diào)用成員函數(shù)的例子適用的前提條件和后置條件
    成員函數(shù)內(nèi)部注釋 控制結(jié)構(gòu)代碼做了些什么以及為什么這樣做局部變量難或復(fù)雜的代碼處理順序

    2.4. 程序修改注釋

    • 新增代碼行的前后有注釋行說明唧躲,對具體格式不作要求,但必須包含作者碱璃,新增時間弄痹,新增目的。在新增代碼的最后必須加上結(jié)束標(biāo)志嵌器;

    • 刪除代碼行的前后用注釋行說明肛真,刪除代碼用注釋原有代碼的方法。注釋方法和內(nèi)容同新增爽航;刪除的代碼行建議用#region XXX #endregion 代碼段折疊蚓让,保持代碼文件干凈整潔

    • 修改代碼行建議以刪除代碼行后再新增代碼行的方式進(jìn)行(針對別人的代碼進(jìn)行修改時,必須標(biāo)明讥珍,對于自己的代碼進(jìn)行修改時历极,酌情進(jìn)行)。注釋方法和內(nèi)容同新增衷佃;

    3. 命名

    3.1. 命名的基本約定

    • 使用可以準(zhǔn)確說明變量/字段/類的完整的英文描述符趟卸,如firstName。對一些作用顯而易見的變量可以采用簡單的命名纲酗,如在循環(huán)里的遞增(減)變量就可以被命名為 ” i ”匿值。

    • 盡量采用項目所涉及領(lǐng)域的術(shù)語推正。

    • 采用大小寫混合饰及,提高名字的可讀性捉邢。為區(qū)分一個標(biāo)識符中的多個單詞,把標(biāo)識符中的每個單詞的首字母大寫吮螺。不采用下劃線作分隔字符的寫法饶囚。有兩種適合的書寫方法,適應(yīng)于不同類型的標(biāo)識符:

    PasalCasing:標(biāo)識符的第一個單詞的字母大寫鸠补;

    camelCasing:標(biāo)識符的第一個單詞的字母小寫萝风。

    下表描述了不同類型標(biāo)識符的大小寫規(guī)則:

    標(biāo)識符 大小寫 示例
    命名空間 Pascal namespace Com.Techstar.ProductionCenter
    類型 Pascal public class DevsList
    接口 Pascal public interface ITableModel
    方法 Pascal public void UpdateData()
    屬性 Pascal Public int Length{…}
    事件 Pascal public event EventHandler Changed;
    私有字段 Camel private string fieldName;
    非私有字段 Pascal public string FieldName;
    枚舉值 Pascal FileMode{Append}
    參數(shù) Camel public void UpdateData(string fieldName)
    局部變量 Camel string fieldName;
    • 避免使用縮寫紫岩,如果一定要使用规惰,就謹(jǐn)慎使用。同時泉蝌,應(yīng)該保留一個標(biāo)準(zhǔn)縮寫的列表歇万,并且在使用時保持一致揩晴。

    • 對常見縮略詞,兩個字母的縮寫采用統(tǒng)一大小寫的方式(示例:ioStream贪磺,getIOStream)硫兰;多字母縮寫采用首字母大寫,其他字母小寫的方式(示例:getHtmlTag)寒锚;

    • 避免使用長名字(最好不超過 15 個字母)劫映。

    • 避免使用相似或者僅在大小寫上有區(qū)別的名字。

    3.2. 各種標(biāo)示符類型的命名約定

    3.2.1. 程序集命名
    • 公司域名(Techstar)+ 項目名稱 + 模塊名稱(可選)刹前,例如:

    中心系統(tǒng)程序集:Techstar.ProductionCenter泳赋;

    中心系統(tǒng)業(yè)務(wù)邏輯程序集:Techstar. ProductionCenter.Business;

    3.2.2. 命名空間命名
    • 采用和程序集命名相同的方式:公司域名(Techstar)+ 項目名稱 + 模塊名稱腮郊。 另外摹蘑,一般情況下建議命名空間和目錄結(jié)構(gòu)相同。例如:

    中心系統(tǒng):Techstar.ProductionCenter轧飞;

    中心系統(tǒng)下的用戶控件:Techstar.ProductionCenter.UserControl;

    中心系統(tǒng)業(yè)務(wù)邏輯:Techstar. ProductionCenter.Business撒踪;

    中心系統(tǒng)數(shù)據(jù)訪問:Techstar. ProductionCenter.Data过咬;

    3.2.3. 類和接口命名
    • 類的名字用名詞;

    • 避免使用單詞的縮寫制妄,除非它的縮寫已經(jīng)廣為人知掸绞,如HTTP。

    • 接口的名字以字母I開頭耕捞。保證對接口的標(biāo)準(zhǔn)實現(xiàn)名字只相差一個“I”前綴衔掸,例如對IComponent的標(biāo)準(zhǔn)實現(xiàn)為Component;

    • 泛型類型參數(shù)的命名:命名為T或者以T開頭的描述性名字俺抽,例如:

    public class List<T
    
    public class MyClass<TSession
    
    • 對同一項目的不同命名空間中的類敞映,命名避免重復(fù)。避免引用時的沖突和混淆磷斧;
    3.2.4. 方法命名
    • 第一個單詞一般是動詞

    • 如果方法返回一個成員變量的值振愿,方法名一般為Get+成員變量名,如若返回的值 是bool變量弛饭,一般以Is作為前綴冕末。另外,如果必要侣颂,考慮用屬性來替代方法档桃,具 體建議見10.1.2節(jié);

    • 如果方法修改一個成員變量的值,方法名一般為:Set + 成員變量名憔晒。同上藻肄,考慮 用屬性來替代方法蔑舞;

    3.2.5. 變量命名
    • 按照使用范圍來分,我們代碼中的變量的基本上有以下幾種類型仅炊,類的公有變量斗幼;類的私有變量(受保護(hù)同公有);方法的參數(shù)變量抚垄;方法內(nèi)部使用的局部變量蜕窿。這些變量的命名規(guī)則基本相同,見標(biāo)識符大小寫對照表呆馁。區(qū)別如下:

    i. 類的公有變量按通常的方式命名桐经,無特殊要求;

    ii. 類的私有變量采用兩種方式均可:采用加“m”前綴浙滤,例如mWorkerName;

    iii. 方法的參數(shù)變量采用camalString阴挣,例如workerName;

    iv. 方法內(nèi)部的局部變量采用camalString纺腊,例如workerName畔咧;

    • 不要用_或&作為第一個字母;

    • 盡量使用短而且具有意義的單詞揖膜;

    • 單字符的變量名一般只用于生命期非常短暫的變量誓沸。i,j,k,m,n一般用于integer;c,d,e 一般用于characters壹粟;s用于string

    • 如果變量是集合拜隧,則變量名用復(fù)數(shù)。例如表格的行數(shù)趁仙,命名應(yīng)為:RowsCount洪添;

    • 命名組件采用匈牙利命名法,所有前綴均應(yīng)遵循同一個組件名稱縮寫列表

    3.3.組件名稱縮寫列表

    縮寫的基本原則是取組件類名各單詞的第一個字母雀费,如果只有一個單詞干奢,則去掉其中的元音,留下輔音坐儿÷烧停縮寫全部為小寫。

    組件類型 縮寫 例子
    Label Lbl lblNote
    TextBox Txt txtName
    Button Btn btnOK
    ImageButton Ib ibOK
    LinkButton Lb lbJump
    HyperLink Hl hlJump
    DropDownList Ddl ddlList
    CheckBox Cb cbChoice
    CheckBoxList Cbl cblGroup
    RadioButton Rb rbChoice
    RadioButtonList Rbl rblGroup
    Image Img imgBeauty
    Panel Pnl pnlTree
    TreeView Tv tvUnit
    WebComTable Wct wctBasic
    ImageDateTimeInput Dti dtiStart
    ComboBox Cb cbList
    MyImageButton Mib mibOK
    WebComm.TreeView Tv tvUnit
    PageBar Pb pbMaster

    4. 聲明

    • 每行只有一個聲明貌矿,如果是聲明i,j,k之類的簡單變量可以放在一行;

    • 除了for循環(huán)外炭菌,聲明放在塊的最開始部分。for循環(huán)中的變量聲明可以放在for語句中逛漫。如:

    for(int i = 0; I < 10; i++) {
    
    }
    
    • 避免塊內(nèi)部的變量與它外部的變量名相同黑低。****

    5. 表達(dá)式和語句

    • 每行建議只有一條語句。

    • if-else,if-elseif語句,任何情況下克握,都應(yīng)該有“{”蕾管,“}”,格式如下:

    if (*condition*)
    
    {
    
    *statements*;
    
    }
    
    else if (*condition*)
    
    {
    
    *statements*;
    
    }
    
    else
    
    {
    
    *statements*;
    
    }
    
    • for語句格式如下:
    for (*initialization*; *condition*; *update*)
    
    {
    
    *statements*;
    
    }
    
    • while語句格式如下:
    while (*condition*)
    
    {
    
    *statements*;
    
    }
    
    • do-while語句格式如下:
    do
    
    {
    
    *statements*;
    
    }while (*condition*);
    
    • switch語句菩暗,每個switch里都應(yīng)包含default子語句,格式如下:
    switch (*condition*)
    
    {
    
      case ABC:
    
      *statements*;
    
      /* 不含有break  錯誤 */
    
      case DEF:
    
      *statements*;
    
      break;
    
      case XYZ:
    
      *statements*;
    
      break;
    
      default:
    
      *statements*;
    
      break;
    
    }
    
    • try-catch語句格式如下:
    try
    
    {
    
    *statements*;
    
    }
    
    catch (ExceptionClass e)
    
    {
    
    *statements*;
    
    }
    
    finally
    
    {
    
    *statements;*
    
    }
    
    

    6. 類型設(shè)計規(guī)范

    • 確保每個類型由一組定義明確掰曾,相互關(guān)聯(lián)的成員組成,而不僅僅是一些無關(guān)功能的隨 機(jī)集合停团;

    6.1. 類型和命名空間

    • 用命名空間把類型組織成相關(guān)域的層次結(jié)構(gòu)旷坦。例如:

    界面層:Techstar.ProductionCenter;

    業(yè)務(wù)邏輯層:Techstar.ProductionCenter.Business佑稠;

    數(shù)據(jù)訪問層:Techstar.ProductionCenter.Data秒梅;

    • 避免過深的命名空間;

    • 避免太多的命名空間舌胶;

    6.2. 類型和接口的選擇

    • 優(yōu)先采用類而不是接口捆蜀。

    接口的缺點在于語義變化時改變困難。注意接口并不是協(xié)定幔嫂,把協(xié)定和實現(xiàn)分開并非一 定用接口實現(xiàn)辆它,用基類和抽象類同樣可以表達(dá);

    • 建議使用抽象類而不是接口來解除協(xié)定與實現(xiàn)間的偶合履恩;

    • 定義接口娩井,來實現(xiàn)類似多重繼承的效果;

    精心定義接口的標(biāo)志是一個接口只做一件事情似袁。關(guān)鍵是接口的協(xié)定需要保持不變, 如果一個接口包含太多功能咐刨,那么這個胖接口產(chǎn)生變化的機(jī)會就會大得多昙衅。

    6.3. 抽象類設(shè)計:

    • 不要在抽象類中定義公有的或內(nèi)部受保護(hù)的構(gòu)造函數(shù)。因為抽象類無法實例化定鸟,所以這 種設(shè)計會誤導(dǎo)用戶而涉;

    • 為抽象類定義受保護(hù)的構(gòu)造函數(shù)或內(nèi)部構(gòu)造函數(shù);

    6.4. 靜態(tài)類設(shè)計

    靜態(tài)類是一個只包含靜態(tài)成員的類联予,它提供了一種純面向?qū)ο笤O(shè)計和簡單性之間的一個權(quán)衡啼县,廣泛用來提供類似于全局變量或一些通用功能。

    • 少用靜態(tài)類沸久。靜態(tài)類應(yīng)該僅用作輔助類季眷;

    • 避免把靜態(tài)類當(dāng)作雜物箱。每個靜態(tài)類都應(yīng)該有其明確目的卷胯;

    • 不要在靜態(tài)類中聲明或覆蓋實例成員子刮;

    6.5. 枚舉設(shè)計

    • 用枚舉來加強(qiáng)那些表示值的集合的參數(shù),屬性以及返回值的類型性;

    • 優(yōu)先使用枚舉而不是靜態(tài)常量挺峡。例如:

    //不好的寫法
    
    public static class Color
    
    {
    
    public static int Red = 0;
    
    public static int Green = 1;
    
    public static int Blue = 2;
    
    }
    
    //好的寫法
    
    public enum Color
    
    {
    
    Red,
    
    Green,
    
    Blue
    
    }
    
    • 不要把枚舉用于開放的場合葵孤,例如操作系統(tǒng)的版本,朋友的名字等橱赠;

    • 枚舉最后一個值不要加逗號尤仍;

    • 枚舉中不要提供為了今后使用而保留的枚舉值;

    7. 成員設(shè)計規(guī)范

    方法狭姨,屬性宰啦,事件,構(gòu)造函數(shù)以及字段等統(tǒng)稱為成員送挑。

    7.1. 成員設(shè)計的一般規(guī)范

    7.2. 方法的重載規(guī)范绑莺;

    • 避免在重載中隨意的給參數(shù)命名。如果兩個重載中的某個參數(shù)表示相同的輸入惕耕,那么該參數(shù)的名字應(yīng)該相同纺裁。例如:
    public class String
    
    {
    
    //好的寫法
    
    public int IndexOf(string value) { ...}
    
    public int IndexOf(string value, int startIndex) { ...}
    
    //不好的寫法
    
    public int IndexOf(string value) { ...}
    
    public int IndexOf(string str, int startIndex) { ...}
    
    }
    
  • 避免使重載成員的參數(shù)順序不一致。在所有的重載中司澎,同名參數(shù)應(yīng)該出現(xiàn)在相同的位置欺缘。 例如:

public class EventLog

{

public EventLog();

public EventLog(string logName);

public EventLog(string logName, string machineName);

public EventLog(string logName, string machineName, string source);

}
  • 較短的重載應(yīng)該僅僅調(diào)用較長的來實現(xiàn)。另外挤安,重載如果需要擴(kuò)展性谚殊,把最長重載 做成虛函數(shù)。例如:
public class String

{

public int IndexOf(string s)

{

//調(diào)用

return IndexOf(s, 0);

}

public int IndexOf(string s, int startIndex)

{

//調(diào)用

return IndexOf(s, startIndex, s.Length);

}

public virtual int IndexOf(string s, int startIndex, int Count)

{

//實際的代碼

}

}
  • 允許可選參選為null蛤铜。這樣做是為了避免調(diào)用者調(diào)用之前需要檢查參數(shù)是否null嫩絮。例 如:
//允許為null時的調(diào)用

DrawGeometry(brush, pen, geometry);
//不允許為null時的調(diào)用

if (geometry == null) {
  DrawGeometry(brush, pen);
}
else{
  DrawGeometry(brush, pen, geometry);
} 

7.3. 屬性和方法的選擇

  • 基本原則是方法表示操作,屬性表示數(shù)據(jù)围肥。如果其他各方面都一樣剿干,優(yōu)先使用屬性而不 是方法。

  • 使用屬性穆刻,如果該成員表示類型的邏輯attribue

  • 如果屬性的值存儲在內(nèi)存中置尔,而提供屬性的目的僅僅是為了訪問該值,使用屬性而不 要使用方法

  • 如果該操作每次返回的結(jié)果不同氢伟,那么使用方法榜轿。例如來自于.net framework的例子:

//好的寫法

Guid.NewGuid();
//不好的寫法

DateTime.Now;
  • 如果該操作比訪問字段慢一個或多個數(shù)量級,使用方法朵锣。

  • 如果該操作有嚴(yán)重的副作用谬盐,使用方法。

7.4. 屬性的設(shè)計規(guī)范:

  • 如果不應(yīng)該讓調(diào)用方法改變屬性值猪勇,創(chuàng)建只讀屬性设褐;

  • 不要提供只寫屬性;

  • 為所有的屬性提供合理的默認(rèn)值,這樣可以確保默認(rèn)值不會導(dǎo)致漏洞或效率低的代 碼助析;

  • 允許用戶以任何順序來設(shè)置屬性的值犀被;

  • 避免在屬性的獲取方法拋出異常。

屬性的獲取方法應(yīng)該是個簡單的操作外冀,不應(yīng)該有任何的條件寡键。如果一個獲取方法會拋出 異常,按么可能它更應(yīng)該設(shè)計為方法雪隧。

7.5. 構(gòu)造函數(shù)的設(shè)計規(guī)范

  • 建議提供簡單的構(gòu)造函數(shù)西轩,最好是默認(rèn)構(gòu)造函數(shù)。簡單的構(gòu)造函數(shù)增強(qiáng)易用性脑沿;

  • 考慮擴(kuò)展性藕畔,如果構(gòu)造函數(shù)設(shè)計的不自然,建議用靜態(tài)的工廠方法來替代構(gòu)造函數(shù)庄拇;

  • 把構(gòu)造函數(shù)的參數(shù)用作設(shè)置主要屬性的便捷方法注服。如果構(gòu)造函數(shù)參數(shù)僅用來設(shè)置屬 性,應(yīng)和屬性名稱相同措近。僅有大小寫的區(qū)別溶弟;

  • 在構(gòu)造函數(shù)中做最少的工作。任何其他處理應(yīng)該推遲到需要的時候瞭郑;

  • 在類中顯示的聲明公用的默認(rèn)構(gòu)造函數(shù)辜御,如果這樣的構(gòu)造函數(shù)是必須的。

如果沒有顯示默認(rèn)構(gòu)造函數(shù)屈张,填加有參數(shù)構(gòu)造函數(shù)時往往會破壞已有使用默認(rèn)構(gòu)造函數(shù) 的代碼擒权;

  • 避免在對象的構(gòu)造函數(shù)內(nèi)部調(diào)用虛成員。這樣在擴(kuò)展設(shè)計的時候會導(dǎo)致難以理解的現(xiàn) 象阁谆;

7.6. 字段設(shè)計規(guī)范

  • 不要提供公有的或受保護(hù)的字段菜拓。代之以屬性來訪問字段;

  • 只用常量字段來表示永遠(yuǎn)不會改變的量笛厦。否則會導(dǎo)致兼容性問題。下面是正確的例子:

 public struct Int32

 {

 public const int MaxValue = 0x7fffffff;

 public const int MinValue = unchecked((int)0x80000000);

 }
  • 用公有的靜態(tài)只讀字段來定義預(yù)定義的對象實例俺夕。例如:
 public struct Color

 {

 public static readonly Color Red = new Color(0x0000FF);

 }

7.7. 參數(shù)的設(shè)計規(guī)范

  • 用類結(jié)構(gòu)層次中最接近基類類型來作為參數(shù)的類型裳凸,同時要保證該類型能夠提供成員 所需的功能。例如:

要設(shè)計一個集合遍歷的方法劝贸,那么參數(shù)應(yīng)該是IEnbumerable為參數(shù)姨谷,而不應(yīng)該是IList, 這樣方法具有更強(qiáng)的適應(yīng)性映九。

  • 不要使用保留參數(shù)梦湘。如果將來需要更多的參數(shù),那么可以增加重載成員。例如:
 //不好的寫法

 public void Method(string reserved, SomeOption option);

 //好的寫法

 public void Method(SomeOption option);

 //將來填加

 public void Method(SomeOption option, string path);
7.7.1. 參數(shù)設(shè)計中枚舉和布爾參數(shù)的選擇規(guī)范
  • 用枚舉捌议。在代碼閱讀哼拔,書寫中,枚舉都比布爾的可讀性好很多瓣颅。例如:
 //使用布爾型,閱讀的時候不會輕易了解參數(shù)的含義

 FileStream f = File.Open(“1.txt”, true, false);

 //使用枚舉型

 FileStream f = File.Open(“1.txt”,CasingOptions.CaseSenstive, FileMode.Open);
  • 不要使用布爾參數(shù)约炎,除非百分之百肯定絕對不需要兩個以上的值碎节。即使此時,采用枚舉 往往也可以提供更好的可讀性粉怕,如上例健民。

  • 考慮在構(gòu)造函數(shù)中,對確實只有兩種狀態(tài)值的參數(shù)以及用來初始化布爾屬性的參數(shù)使用 布爾類型贫贝;

7.7.2. 參數(shù)驗證的規(guī)范:
  • 驗證傳給公有的秉犹,受保護(hù)的或顯示成員的參數(shù)是否合法。如果驗證失敗平酿,應(yīng)該拋出 System.ArgutmentException或其子類凤优;

  • 拋出System.ArgutmentNullException,如果傳入的null蜈彼,而該成員不支持null筑辨;

7.7.3. 參數(shù)傳遞的規(guī)范:
  • 避免使用輸出參數(shù)或引用參數(shù);

8. 擴(kuò)展性設(shè)計規(guī)范

  • 如果沒有恰當(dāng)理由幸逆,不要把類密封起來棍辕。這些理由包括:

A)類為靜態(tài)類;

B)類的受保護(hù)成員保存了高度機(jī)密信息还绘;

C)類繼承了許多虛成員楚昭,逐個密封的代價太高,不如密封整個類拍顷;

D)不要在密封類中聲明保護(hù)成員或虛成員抚太,因為無法覆蓋其實現(xiàn);

  • 建議用保護(hù)成員用于高級定制昔案。它提供了擴(kuò)展性尿贫,同時也避免了公用接口過于復(fù)雜;

  • 不要使用虛成員踏揣,除非有合適的理由庆亡;

  • 建議只有在絕對必須的時候才用虛成員提供擴(kuò)展性,并使用Template Method模式捞稿;

  • 優(yōu)先使用受保護(hù)的虛成員又谋,而不是公有虛成員拼缝。公有成員通用調(diào)用受保護(hù)的虛成員的方式來提供擴(kuò)展性;

9. 異常處理規(guī)范

  • 異常的思想是只對錯誤采用異常處理:邏輯和編程錯誤彰亥,設(shè)置錯誤咧七,被破壞的數(shù)據(jù),資源耗盡剩愧,等等猪叙。通常的法則是系統(tǒng)在正常狀態(tài)下以及無重載和硬件失效狀態(tài)下,不應(yīng)產(chǎn)生任何異常仁卷。異常處理時可以采用適當(dāng)?shù)娜罩緳C(jī)制來報告異常穴翩,包括異常發(fā)生的時刻;

  • 一般情況下不要使用異常實現(xiàn)來控制程序流程結(jié)構(gòu)锦积;

  • 使用異常而不要用錯誤代碼來報告錯誤芒帕;

  • 通過拋出異常的方式來報告操作失敗。如果成員無法成功地完成它應(yīng)該做的任務(wù)丰介,那么應(yīng)該拋出異常背蟆;

9.1. 異常類型選擇規(guī)范

  • 優(yōu)先考慮使用System命名空間中已有的異常,而不是自己創(chuàng)建新的異常類型哮幢;

  • 使用最合理带膀,最具針對性的異常。例如橙垢,對參數(shù)為空垛叨,應(yīng)拋出 System.ArgutmentNullException,而不是System.ArgutmentException

9.2. 異常處理規(guī)范

  • 不是百分之百確定的情況柜某,不要吞掉異常嗽元;

  • 建議捕獲特定類型的異常,如果理解該異常在具體環(huán)境當(dāng)中產(chǎn)生的原因喂击;

  • 不要捕獲不應(yīng)該捕獲的異常剂癌,通常應(yīng)該允許異常沿著調(diào)用棧傳遞;

  • 進(jìn)行清理工作時用try-finally翰绊,避免使用try-catch佩谷;

  • 在捕獲并重新拋出異常時使用空的throw語句,這是保持調(diào)用棧的最好方法

9.3.標(biāo)準(zhǔn)異常類的使用**

9.3.1. Exception與SystemException
  • 不要拋出這兩種類型的異常监嗜;

  • 避免捕獲這兩種異常琳要,除非是在頂層的異常處理器中;

9.3.2. InvalidOperationException
  • 對象處于不正確狀態(tài)時拋出秤茅;
9.3.3. ArgumentException,ArgumentNullException童叠,ArgumentOutOfRangeException
  • 如果傳入的是無效參數(shù)框喳,拋出參數(shù)異常课幕,盡可能使用位于繼承層次末尾的類型;

  • 在拋出異常時設(shè)置ParaName屬性五垮;

9.3.4. NullRefernceException乍惊,IndexOutOfRangeException,AccessViolationException
  • 不要顯示拋出或捕獲放仗;
9.3.5. StackOverflowException
  • 不要顯示拋出或捕獲润绎;
9.3.6. OutOfMemoryException
  • 不要顯示拋出或捕獲;

9.4. 自定義異常類型設(shè)計規(guī)則

  • 避免太深的繼承層次诞挨;

  • 從已有的異忱蚱玻基類繼承;

  • 異常類以“Exception”做為后綴惶傻;

  • 使異彻骼桑可序列化,使其能跨應(yīng)用程序域和遠(yuǎn)程邊界仍能正常使用银室;

  • 把與安全性有關(guān)的信息保存在私有的異常狀態(tài)中

9.5. 異常與性能

  • 如果在普通場景都會拋出異常涂佃,采用先效驗合法性的方式來避免拋出異常引起的性能 問題;

10. 其他規(guī)定

  • 為避免頻繁改動代碼蜈敢,代碼中只寫比較簡單的和不會經(jīng)常發(fā)生變化的SQL辜荠,如果SQL 經(jīng)常發(fā)生變化或是比較復(fù)雜,存到SysMisc中抓狭,比如統(tǒng)計用到的SQL伯病;

  • 在VS開發(fā)環(huán)境中,采用代碼分析工具來做自動化的代碼分析辐宾,以保證代碼質(zhì)量狱从, 具體的使用建議如下:

A)啟用代碼分析,并設(shè)置當(dāng)風(fēng)格不符合要求時為錯誤而不是警告叠纹;

B)如果不是做代碼審核季研,此開關(guān)應(yīng)關(guān)閉。加上了這個選項的時候編譯很慢誉察;

C)詳設(shè)的時候打開開關(guān)与涡,檢查詳設(shè)是否符合編程規(guī)范;

D)所有的選項都應(yīng)當(dāng)打開持偏。以下內(nèi)容需要單獨設(shè)置:

編碼 名稱 大類 建議 使用等級
CA2209 程序集應(yīng)聲明最小安全性 用法規(guī)則 不建議使用 警告
CA1814 與多維數(shù)組相比驼卖,首選使用交錯的數(shù)組 性能規(guī)則 使用,但降低等級 警告
CA1822 將成員標(biāo)記為 static 性能規(guī)則 較繁鎖鸿秆,且影響代碼質(zhì)量 禁用
CA2210 程序集應(yīng)具有有效的強(qiáng)名稱 設(shè)計規(guī)則 影響Xcopy部署 禁用
CA1302 不要對區(qū)域設(shè)置特定的字符串進(jìn)行硬編碼 全球化規(guī)則 很繁瑣酌畜,并且工具支持的不好。全球化規(guī)則全部禁用 禁用
CA2100 檢查 Sql 查詢中是否有安全漏洞 安全性規(guī)則 都采用參數(shù)化查詢卿叽,有可能會參數(shù)過長桥胞;如果是內(nèi)部參數(shù)恳守,也不會有安全問題 警告

二、項目系統(tǒng)多層結(jié)構(gòu)設(shè)計使用規(guī)范

1. 層的實現(xiàn)基礎(chǔ)

  • 層是通過多組軟件模塊之間經(jīng)過規(guī)劃的調(diào)用來實現(xiàn)的贩虾。

  • 層就是一群負(fù)有特定使命催烘,提供特定服務(wù)的軟件模塊。

2. 多層結(jié)構(gòu)設(shè)計原則

2.1 可重用性

由于業(yè)務(wù)層的獨立存在缎罢,那么業(yè)務(wù)層中的各種服務(wù)可以被不同的應(yīng)用程序使用伊群。
將組件的重用范圍從以前的的單個項目擴(kuò)展到企業(yè)范圍內(nèi)的多個項目。

2.2 配置的靈活性

由于軟件系統(tǒng)被分成了獨立的三層或多層策精,可以按照企業(yè)業(yè)務(wù)的功能需求和
性能需求靈活配置各層次的物理位置舰始,功能劃分,計算機(jī)數(shù)量等蛮寂,為需求迅速增長的分布式
應(yīng)用提供了實現(xiàn)基礎(chǔ)蔽午。例如不同的部門的不同應(yīng)用可以連接到不同的應(yīng)用服務(wù)器上。各個層
次還可單獨選擇最恰當(dāng)?shù)拈_發(fā)工具酬蹋。

2.3 配置的靈活性

開發(fā)并行性:由于層與層之間是采用基于服務(wù)的存燃袄稀(接口調(diào)用),并且是獨立存在的范抓,所
以各層可以在約定好的接口下并行開發(fā)骄恶。

2.4 系統(tǒng)進(jìn)化的容易度

當(dāng)軟件需求變更時或技術(shù)進(jìn)步時,只需要更改相應(yīng)層中的組件匕垫,在保證
接口不變的情況下僧鲁,不會影響系統(tǒng)的其他部分,也不需重新測試系統(tǒng)的其他部分象泵。而且層與
層之間采用基于服務(wù)的調(diào)用方式寞秃,所以,當(dāng)業(yè)務(wù)規(guī)則變化時偶惠,只要更新單一的業(yè)務(wù)層春寿,運行
表示層的各個客戶端便自動地獲得按照新的業(yè)務(wù)規(guī)則處理的能力。在基于業(yè)務(wù)層服務(wù)的基礎(chǔ)
上忽孽,可以采用漸增的方式增加客戶端應(yīng)用種類和接入媒體绑改,因而系統(tǒng)可擴(kuò)展性很好。

3. 分層結(jié)構(gòu)使用原則

上層使用下層提供的服務(wù)兄一,且僅通過調(diào)用層次間的特定接口獲取下層服務(wù)厘线,下層暴露特定接口為上層提供特定服務(wù),且不依賴于上層出革,也不知道上層的存在造壮。下層與相鄰上層之間為一對多的關(guān)系,即同一個下層可能為不同的上層提供服務(wù)骂束。

三耳璧、單元測試編寫原則

1.保持單元測試小巧, 快速

理論上, 任何代碼提交前都應(yīng)該完整跑一遍所有測試套件. 保持測試代碼執(zhí)行迅捷能夠縮短迭代開發(fā)周期.

2.單元測試應(yīng)該是全自動且無交互

測試套件通常是定期執(zhí)行的, 執(zhí)行過程必須完全自動化才有意義. 需要人工檢查輸出結(jié)果的測試不是一個好的單元測試.

3.讓單元測試很容易跑起來

對開發(fā)環(huán)境進(jìn)行配置, 最好是敲條命令或是點個按鈕就能把單個測試用例或測試套件跑起來.

4.對測試進(jìn)行評估

對執(zhí)行的測試進(jìn)行覆蓋率分析, 得到精確的代碼執(zhí)行覆蓋率, 并調(diào)查哪些代碼未被執(zhí)行.

5.立即修正失敗的測試

每個開發(fā)人員在提交前都應(yīng)該保證新的測試用例執(zhí)行成功, 當(dāng)有代碼提交時, 現(xiàn)有測試用例也都能跑通.

如果一個定期執(zhí)行的測試用例執(zhí)行失敗, 整個團(tuán)隊?wèi)?yīng)該放下手上的工作優(yōu)先解決這個問題.

6.把測試維持在單元級別

單元測試即類 (Class) 的測試. 一個 "測試類" 應(yīng)該只對應(yīng)于一個 "被測類", 并且 "被測類" 的行為應(yīng)該被隔離測試. 必須謹(jǐn)慎避免使用單元測試框架來測試整個程序的工作流, 這樣的測試既低效又難維護(hù). 工作流測試 (譯注: 指跨模塊/類的數(shù)據(jù)流測試) 有它自己的地盤, 但它絕不是單元測試, 必須單獨建立和執(zhí)行.

7.由簡入繁

最簡單的測試也遠(yuǎn)遠(yuǎn)勝過完全沒有測試. 一個簡單的 "測試類" 會促使建立 "被測類" 基本的測試骨架, 可以對構(gòu)建環(huán)境, 單元測試環(huán)境, 執(zhí)行環(huán)境以及覆蓋率分析工具等有效性進(jìn)行檢查, 同時也可以證明 "被測類" 能夠被整合和調(diào)用.

下面便是單元測試版的 Hello, world! :

void testDefaultConstruction()
{
Foo foo = new Foo();
assertNotNull(foo);
}

8.保持測試的獨立性

為了保證測試穩(wěn)定可靠且便于維護(hù), 測試用例之間決不能有相互依賴, 也不能依賴執(zhí)行的先后次序.

9.合理的命名測試用例

確保每個方法只測試 "被測類" 的一個明確特性, 并相應(yīng)的命名測試方法. 典型的命名俗定是 test[what], 比如 testSaveAs(), testAddListener(), testDeleteProperty() 等.

10.只測公有接口

單元測試可以被定義為 通過類的公有 API 對類進(jìn)行測試. 一些測試工具允許測試一個類的私有成員, 但這種做法應(yīng)該避免, 它讓測試變得繁瑣而且更難維護(hù). 如果有私有成員確實需要進(jìn)行直接測試, 可以考慮把它重構(gòu)到工具類的公有方法中. 但要注意這么做是為了改善設(shè)計, 而不是幫助測試.

11.看成是黑盒

站在第三方使用者的角度, 測試一個類是否滿足規(guī)定的需求. 并設(shè)法讓它出問題.

12.看成是白盒

畢竟被測試類是程序員自寫自測的, 應(yīng)該在最復(fù)雜的邏輯部分多花些精力測試.

13.芝麻函數(shù)也要測試

通常建議所有重要的函數(shù)都應(yīng)該被測試到, 一些芝麻方法比如簡單的 settergetter 都可以忽略. 但是仍然有充分的理由支持測試芝麻函數(shù):

  • 芝麻 很難定義. 對于不同的人有不同的理解.

  • 從黑盒測試的觀點看, 是無法知道哪些代碼是芝麻級別的.

  • 即便是再芝麻的函數(shù), 也可能包含錯誤, 通常是 "復(fù)制粘貼" 代碼的后果:

    private double weight_;
    private double x_, y_;
    
    public void setWeight(int weight)
    {
      weight = weight_;  // error
    }
    
    public double getX()
    {
      return x_;
    }
    
    public double getY()
    {
      return x_;  // error
    }
    
    

因此建議測試所有方法. 畢竟芝麻用例也容易測試.

14.先關(guān)注執(zhí)行覆蓋率

區(qū)別對待 執(zhí)行覆蓋率實際測試覆蓋率. 測試的最初目標(biāo)應(yīng)該是確保較高的執(zhí)行覆蓋率. 這樣能保證代碼在 少量 參數(shù)值輸入時能執(zhí)行成功. 一旦執(zhí)行覆蓋率就緒, 就應(yīng)該開始改進(jìn)測試覆蓋率了. 注意, 實際的測試覆蓋率很難衡量 (而且往往趨近于 0%).

思考以下公有方法:

void setLength(double length);

調(diào)用 setLength(1.0) 你可能會得到 100% 的執(zhí)行覆蓋率. 但要達(dá)到 100% 的實際測試覆蓋率, 有多少個 double 浮點數(shù)這個方法就必須被調(diào)用多少次, 并且要一一驗證行為的正確性. 這無疑是不可能的任務(wù).

15.覆蓋邊界值

確保參數(shù)邊界值均被覆蓋. 對于數(shù)字, 測試負(fù)數(shù), 0, 正數(shù), 最小值, 最大值, NaN (非數(shù)字), 無窮大等. 對于字符串, 測試空字符串, 單字符, 非 ASCII 字符串, 多字節(jié)字符串等. 對于集合類型, 測試空, 1, 第一個, 最后一個等. 對于日期, 測試 1月1號, 2月29號, 12月31號等. 被測試的類本身也會暗示一些特定情況下的邊界值. 要點是盡可能徹底的測試這些邊界值, 因為它們都是主要 "疑犯".

16.提供一個隨機(jī)值生成器

當(dāng)邊界值都覆蓋了, 另一個能進(jìn)一步改善測試覆蓋率的簡單方法就是生成隨機(jī)參數(shù), 這樣每次執(zhí)行測試都會有不同的輸入.

想要做到這點, 需要提供一個用來生成基本類型 (如: 浮點數(shù), 整型, 字符串, 日期等) 隨機(jī)值的工具類. 生成器應(yīng)該覆蓋各種類型的所有取值范圍.

如果測試時間比較短, 可以考慮再裹上一層循環(huán), 覆蓋盡可能多的輸入組合. 下面的例子是驗證兩次轉(zhuǎn)換 little endian 和 big endian 字節(jié)序后是否返回原值. 由于測試過程很快, 可以讓它跑上個一百萬次.

void testByteSwapper()
{
  for (int i = 0; i < 1000000; i++) {
    double v0 = Random.getDouble();
    double v1 = ByteSwapper.swap(v0);
    double v2 = ByteSwapper.swap(v1);
    assertEquals(v0, v2);
  }
}

17.每個特性只測一次

在測試模式下, 有時會情不自禁的濫用斷言. 這種做法會導(dǎo)致維護(hù)更困難, 需要極力避免. 僅對測試方法名指示的特性進(jìn)行明確測試.

因為對于一般性代碼而言, 保證測試代碼盡可能少是一個重要目標(biāo).

18.使用顯式斷言

應(yīng)該總是優(yōu)先使用 assertEquals(a, b) 而不是 assertTrue(a == b), 因為前者會給出更有意義的測試失敗信息. 在事先不確定輸入值的情況下, 這條規(guī)則尤為重要, 比如之前使用隨機(jī)參數(shù)值組合的例子.

19.提供反向測試

反向測試是指刻意編寫問題代碼, 來驗證魯棒性和能否正確的處理錯誤.

假設(shè)如下方法的參數(shù)如果傳進(jìn)去的是負(fù)數(shù), 會立馬拋出異常:

void setLength(double length) throws IllegalArgumentExcepti

可以用下面的方法來測試這個特例是否被正確處理:

try {
  setLength(-1.0);
  fail();  // If we get here, something went wrong
}
catch (IllegalArgumentException exception) {
  // If we get here, all is fine
}

20.代碼設(shè)計時謹(jǐn)記測試

編寫和維護(hù)單元測試的代價是很高的, 減少代碼中的公有接口和循環(huán)復(fù)雜度是降低成本, 使高覆蓋率測試代碼更易于編寫和維護(hù)的有效方法.

一些建議:

  • 使類成員常量化, 在構(gòu)造函數(shù)中進(jìn)行初始化. 減少 setter 方法的數(shù)量.

  • 限制過度使用繼承和公有虛函數(shù).

  • 通過使用友元類 (C++) 或包作用域 (Java) 來減少公有接口.

  • 避免不必要的邏輯分支.

  • 在邏輯分支中編寫盡可能少的代碼.

  • 在公有和私有接口中盡量多用異常和斷言驗證參數(shù)參數(shù)的有效性.

  • 限制使用快捷函數(shù). 對于黑箱而言, 所有方法都必須一視同仁的進(jìn)行測試. 思考以下簡短的例子:

 public void scale(double x0, double y0, double scaleFactor)
 {
   // scaling logic
 }

 public void scale(double x0, double y0)
 {
   scale(x0, y0, 1.0);
 }

刪除后者可以簡化測試, 但用戶代碼的工作量也將略微增加.

21.不要訪問預(yù)設(shè)的外部資源

單元測試代碼不應(yīng)該假定外部的執(zhí)行環(huán)境, 以便在任何時候/任何地方都能執(zhí)行. 為了向測試提供必需的資源, 這些資源應(yīng)該由測試本身提供.

比如一個解析某類型文件的類, 可以把文件內(nèi)容嵌入到測試代碼里, 在測試的時候?qū)懭氲脚R時文件, 測試結(jié)束再刪除, 而不是從預(yù)定的地址直接讀取.

22.權(quán)衡測試成本

不寫單元測試的代價很高, 但是寫單元測試的代價同樣很高. 要在這兩者之間做適當(dāng)?shù)臋?quán)衡, 如果用執(zhí)行覆蓋率來衡量, 業(yè)界標(biāo)準(zhǔn)通常在 80% 左右.

很典型的, 讀寫外部資源的錯誤處理和異常處理就很難達(dá)到百分百的執(zhí)行覆蓋率. 模擬數(shù)據(jù)庫在事務(wù)處理到一半時發(fā)生故障并不是辦不到, 但相對于進(jìn)行大范圍的代碼審查, 代價可能太大了.

23.安排測試優(yōu)先次序

單元測試是典型的自底向上過程, 如果沒有足夠的資源測試一個系統(tǒng)的所有模塊, 就應(yīng)該先把重點放在較底層的模塊.

24.測試代碼要考慮錯誤處理

考慮下面的這個例子:

Handle handle = manager.getHandle();
assertNotNull(handle);

String handleName = handle.getName();
assertEquals(handleName, "handle-01");

如果第一個斷言失敗, 后續(xù)語句會導(dǎo)致代碼崩潰, 剩下的測試都無法執(zhí)行. 任何時候都要為測試失敗做好準(zhǔn)備, 避免單個失敗的測試項中斷整個測試套件的執(zhí)行. 上面的例子可以重寫成:

Handle handle = manager.getHandle();
assertNotNull(handle);
if (handle == null) return;

String handleName = handle.getName();
assertEquals(handleName, "handle-01");

25.寫測試用例重現(xiàn) bug

每上報一個 bug, 都要寫一個測試用例來重現(xiàn)這個 bug (即無法通過測試), 并用它作為成功修正代碼的檢驗標(biāo)準(zhǔn).

26.了解局限

單元測試永遠(yuǎn)無法證明代碼的正確性!!

一個跑失敗的測試可能表明代碼有錯誤, 但一個跑成功的測試什么也證明不了.

單元測試最有效的使用場合是在一個較低的層級驗證并文檔化需求, 以及 回歸測試: 開發(fā)或重構(gòu)代碼時硝全,不會破壞已有功能的正確性.

四、RESTful API開發(fā)規(guī)范

1. 基本設(shè)計參考準(zhǔn)則

RESTful是API接口一種設(shè)計思想指南, 一種風(fēng)格; 過度糾結(jié)如何遵守規(guī)范只是徒增煩惱楞抡,也違背了使用它的初衷. 但是也應(yīng)該參考幾個基本準(zhǔn)則, e.g:

  • 當(dāng)標(biāo)準(zhǔn)合理的時候遵守標(biāo)準(zhǔn)。
  • API應(yīng)該對程序員友好析藕,并且在瀏覽器地址欄容易輸入召廷。
  • API應(yīng)該簡單,直觀账胧,容易使用的同時優(yōu)雅竞慢。
  • API應(yīng)該具有足夠的靈活性來支持上層UI。
  • API設(shè)計權(quán)衡上述幾個原則治泥。

我們在寫API的時候, 要把API當(dāng)做我們自己的UI來寫, 那么

你的API越容易使用筹煮,那么就會有越多的人去用它

2. HTTP Methods

HTTP 四個常用方法:

  • GET: 獲取某個資源。

  • POST: 創(chuàng)建一個新的資源居夹。

  • PUT: 更新某個已有的資源败潦。

  • DELETE:刪除某個資源。

3. 命名規(guī)則建議

  • 由于我們目前后端用C#, 命名就采用camelCase(駱駝命名) ,這樣存在有些接口語義性不夠強(qiáng), 針對這種可以采用- 符號來連接單詞. (不要用_符號)准脂。

  • URI 片段中盡量使用名詞劫扒、避免使用動詞,動作應(yīng)該通過 get/post/put/delete... 來表述狸膏。

  • URI 片段中始終使用復(fù)數(shù)形式沟饥。

4. URI 設(shè)計指南建議

4.1 簡單的單一對象CRUD:

  • GET /users - 獲取用戶列表

  • GET /users/1 - 獲取 Id 為 1 的用戶

  • POST /users - 創(chuàng)建一個用戶

  • PUT /users/1 - 更新 Id 為 1 的用戶

  • DELETE /users/1 - 刪除 Id 為 1 的用戶

    ?

4.2 關(guān)聯(lián)/級聯(lián)對象的:

  • GET /users/1/products - 獲取 Id 為 1 用戶下的產(chǎn)品列表

  • GET /users/1/products/2 - 獲取 Id 為 1 用戶下 Id 為 2 的產(chǎn)品

  • POST /users/1/products - 在 Id 為 1 用戶下,創(chuàng)建一個產(chǎn)品

  • PUT /users/1/products/2 - 在 Id 為 1 用戶下湾戳,更新 Id 為 2 的產(chǎn)品

  • DELETE /users/1/products/2 - 刪除 Id 為 1 的用戶下 Id 為 2 的產(chǎn)品

    ?

4.3 復(fù)雜參數(shù)查詢的:

針對這種有比較多(一般建議3個以上)參數(shù)的接口, 應(yīng)該考慮使用一個viewModel來接收參數(shù)

    [ResponseType(typeof(PagedResult<ServiceOrderDto))]
    public IHttpActionResult Get([FromUri]OwnerOrderQuery query)
    {
        var result = _ownerOrderSvc.GetOwnerOrderPage(query);
        return Ok(result);
    }

5. 接口返回類型聲明

以.Net Web Api來說, 直接聲明IHttpActionResult , .Net Core的話IActionResult, 由于我們要提api文檔, 接口應(yīng)該還要聲明ResponseType 返回對象類型.

    [Route("{id}/detail")]
    [ResponseType(typeof(ServiceOrderDto))]
    public IHttpActionResult Get(int id)
    {
        var result = _ownerOrderSvc.GetOwnerOrderDetail(id);
        return Ok(result);
    }

有一種不推薦的做法就是對接口返回值類型再包裝一層, 這樣違背了RESTful設(shè)計風(fēng)格, responsebody 就是數(shù)據(jù)數(shù)據(jù). 不推薦做法示例 e.g:

  {
      "code":200,
      "success":true,
      "data":{"id":1,"name":"uoko"},
  }

6.版本號

  • 直接在URI加版本號, 比如https://api.example.com/v1/
  • 將版本號放在HTTP頭信息中,Github采用這種做法贤旷。

7.常用狀態(tài)碼

  • 200 OK - [GET]:服務(wù)器成功返回用戶請求的數(shù)據(jù),該操作是冪等的(Idempotent)砾脑。
  • 201 CREATED - [POST/PUT]:用戶新建或修改數(shù)據(jù)成功幼驶。
  • 202 Accepted - [*]:表示一個請求已經(jīng)進(jìn)入后臺排隊(異步任務(wù))
  • 204 NO CONTENT - [DELETE]:用戶刪除數(shù)據(jù)成功。
  • 400 INVALID REQUEST - [POST/PUT/PATCH]:用戶發(fā)出的請求有錯誤拦止,服務(wù)器沒有進(jìn)行新建或修改數(shù)據(jù)的操作县遣,該操作是冪等的。
  • 401 Unauthorized - [*]:表示用戶沒有權(quán)限(令牌汹族、用戶名萧求、密碼錯誤)。
  • 403 Forbidden - [*] 表示用戶得到授權(quán)(與401錯誤相對)顶瞒,但是訪問是被禁止的夸政。
  • 404 NOT FOUND - [*]:用戶發(fā)出的請求針對的是不存在的記錄,服務(wù)器沒有進(jìn)行操作榴徐,該操作是冪等的守问。
  • 406 Not Acceptable - [GET]:用戶請求的格式不可得(比如用戶請求JSON格式匀归,但是只有XML格式)。
  • 410 Gone -[GET]:用戶請求的資源被永久刪除耗帕,且不會再得到的穆端。
  • 422 Unprocesable entity - [POST/PUT] 當(dāng)創(chuàng)建一個對象時,發(fā)生一個驗證錯誤仿便。
  • 500 INTERNAL SERVER ERROR - [*]:服務(wù)器發(fā)生錯誤体啰,用戶將無法判斷發(fā)出的請求是否成功。

對于我們來說需要知道 200, 400,401,403,404,500這幾種的意思 狀態(tài)碼的完全列表見嗽仪。

8. 文檔&測試

目前我們使用MVChelp doc 已經(jīng)能滿足自動生成文檔, 同時也能做在線的接口測試, 后面可以考慮接入Swagger

更具體的編寫api 接口單元測試, 見單元測試準(zhǔn)則

9. Hypermedia API

Restful API 的設(shè)計最好做到 Hypermedia:在返回結(jié)果中提供相關(guān)資源的鏈接荒勇。這種設(shè)計也被稱為 HATEOAS。這樣做的好處是闻坚,調(diào)用者可以根據(jù)返回結(jié)果就能得到后續(xù)操作需要訪問的地址沽翔。

比如訪問 api.github.com,就可以看到 Github API 支持的資源操作窿凤。

10. 接口安全性

采用 OAuth2協(xié)議 提供身份認(rèn)證

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末仅偎,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子卷玉,更是在濱河造成了極大的恐慌哨颂,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件相种,死亡現(xiàn)場離奇詭異威恼,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)寝并,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進(jìn)店門箫措,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人衬潦,你說我怎么就攤上這事斤蔓。” “怎么了镀岛?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵弦牡,是天一觀的道長。 經(jīng)常有香客問我漂羊,道長驾锰,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任走越,我火速辦了婚禮椭豫,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己赏酥,他們只是感情好喳整,可當(dāng)我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著裸扶,像睡著了一般框都。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上呵晨,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天瞬项,我揣著相機(jī)與錄音,去河邊找鬼。 笑死始锚,一個胖子當(dāng)著我的面吹牛泣特,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播桅锄,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了戒傻?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤蜂筹,失蹤者是張志新(化名)和其女友劉穎需纳,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體艺挪,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡不翩,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了麻裳。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片口蝠。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖津坑,靈堂內(nèi)的尸體忽然破棺而出妙蔗,到底是詐尸還是另有隱情,我是刑警寧澤疆瑰,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布眉反,位于F島的核電站,受9級特大地震影響穆役,放射性物質(zhì)發(fā)生泄漏寸五。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一孵睬、第九天 我趴在偏房一處隱蔽的房頂上張望播歼。 院中可真熱鬧,春花似錦、人聲如沸秘狞。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽烁试。三九已至雇初,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間减响,已是汗流浹背靖诗。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留支示,地道東北人刊橘。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像颂鸿,于是被迫代替她去往敵國和親促绵。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 42,834評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理嘴纺,服務(wù)發(fā)現(xiàn)败晴,斷路器,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,516評論 25 707
  • 前言 人生苦多栽渴,快來 Kotlin 尖坤,快速學(xué)習(xí)Kotlin! 什么是Kotlin闲擦? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,146評論 9 118
  • 春天快過去了墅冷,不太好的情緒贮缕,不太好的心情,卻剛剛好的想起你俺榆。 “畢竟是江南感昼,三月煙花寒”這句話始終念在心頭,而我離...
    墨子毓閱讀 226評論 0 0
  • 3efac30fcc5e閱讀 190評論 0 0