请注意,本站并不支持低于IE8的浏览器,为了获得最佳效果,请下载最新的浏览器,推荐下载 Chrome浏览器
欢迎光临。交流群:166852192

orchard2工程指南


Basics

代码审查和签入


为了确保只有最高质量的代码进入项目,请将所有代码更改作为PR提交到GitHub。这包括运行时代码更改,单元测试更新和官方示例的更新。例如,将PR更新发送到单元测试可能看起来像是浪费时间,但是单元测试与产品代码一样重要,因此,查看对它们的更改也同样重要。


优势众多:提高代码质量,更多地了解变化及其潜在影响,避免重复工作,并提高对各个领域取得进展的普遍意识。


源代码管理


:grey_exclamation:我们写的代码的结构和我们用来编写代码的工具。


Repos


要在https://github.com/orchard/ org中创建新的仓库,请联系@ jetski5822。


分支策略


一般来说:


master具有正在处理的代码。
这将随着项目的发展而改变。


解决方案和项目文件夹结构和命名


解决方案文件进入repo根目录。


解决方案名称与repo名称匹配(例如Mvc repo中的Mvc.sln)。


每个项目还需要一个project.json和一个匹配的.xproj文件。这个project.json是项目依赖和配置选项的真实来源。


解决方案需要包含与物理文件夹(src,测试等)匹配的解决方案文件夹。


例如,在使用Banana和Lychee项目的Fruit repo中,您将会检入以下文件:


/Fruit.sln
/ src)
/src/Microsoft.AspNet.Banana
/src/Microsoft.AspNet.Banana/project.json
/src/Mansoft.AspNet.Banana/Banana.kproj
/src/Microsoft.AspNet.Banana/Banana.cs
/src/Microsoft.AspNet.Banana/Util/BananaUtil.cs
/src/Microsoft.AspNet.Lychee
/src/Microsoft.AspNet.Lychee/project.json
/src/Microsoft.AspNet.Lychee/Lychee.kproj
/src/Microsoft.AspNet.Lychee/Lychee.cs
/src/Microsoft.AspNet.Lychee/Util/LycheeUtil.cs
/测试
/test/Microsoft.AspNet.Banana.Tests
/test/Microsoft.AspNet.Banana.Tests/project.json
/test/Microsoft.AspNet.Banana.Tests/BananaTest.kproj
/test/Microsoft.AspNet.Banana.Tests/BananaTest.cs
/test/Microsoft.AspNet.Banana.Tests/Util/BananaUtilTest.cs
注意,运行build命令后,系统将生成以下文件:


/build/*.shade
所有这些文件都设置为在.gitignore文件中被忽略。


Desktop / CoreCLR的条件编译


几乎所有的开发都是为CoreCLR和Desktop .NET做的。由于API更改或行为差异,某些代码将特定于CoreCLR或特定于桌面。构建系统有两个条件编译语句来帮助:


桌面:


#ifdef DNX451
CoreCLR:


#ifdef DNXCORE50
程序集命名模式


一般的命名模式是Orchard。<area>。<subarea>。


构建系统


我们使用一个名为KoreBuild的新系统,该系统是使用构建工具构建的。清单项目在这里:https://github.com/sakeproject/sake


单元测试


我们使用xUnit.net进行所有单元测试。


回购特定样品


一些仓库将有自己的样本项目,用于测试目的和实验。请确保它们在repo中的samples /子文件夹中。


要让示例项目引用src中的项目,您将需要在repo的根目录中有一个global.json文件。默认情况下,项目到项目引用必须是同级文件夹。使用global.json文件允许解决方案指定非标准位置来定位引用。 global.json的格式如下:


{
    “projects”:[“src”]
}}

Coding guidelines

我们写的代码的内容。


编码风格指南 - 一般


最一般的指导原则是,我们使用所有的VS默认设置代码格式化,除了我们把系统名称空间在其他命名空间之前(这曾经是VS的默认,但在更新的VS版本中更改)。


使用四个缩进空格(无制表符)
对私有字段使用_camelCase
避免这个。除非绝对必要
始终指定成员可见性,即使它是默认值(即private string _foo; not string _foo;)
var关键字的用法


var关键字的使用与编译器允许的相同。例如,这些是正确的:


var fruit =“Lychee”;
var fruits = new List <Fruit>();
var flavor = fruit.GetFlavor();
string fruit = null; //不能使用“var”,因为类型不是已知的(虽然你可以做(string)null,不要!)
const string expectedName =“name”; //不能使用“var”与const
以下是不正确的:


string fruit =“Lychee”;
List <Fruit> fruits = new List <Fruit>();
FruitFlavor flavor = fruit.GetFlavor();
使用C#类型关键字偏好.NET类型名称


当使用具有C#关键字的类型时,该关键字用于支持.NET类型名称。例如,这些是正确的:


public string TrimString(string s){
    返回string.IsNullOrEmpty(s)
        ?空值
        :s.Trim();
}}


var intTypeName = nameof(Int32); // can not use C#type keywords with nameof
以下是不正确的:


public String TrimString(String s){
    return String.IsNullOrEmpty(s)
        ?空值
        :s.Trim();
}}
跨平台编码


我们的框架应该支持CoreCLR,它支持多个操作系统。不要假设我们只在Windows上运行(和开发)。代码应该对操作系统之间的差异敏感。这里有一些细节要考虑。


换行符


Windows使用\ r \ n,OS X和Linux使用\ n。当重要时,使用Environment.NewLine而不是硬编码换行符。


注意:这可能不总是可能或必要的。


请注意,当使用带有换行符的@“”文本块时,这些行结尾可能会导致代码中出现问题。


环境变量


OS使用不同的变量名称来表示类似的设置。代码应考虑这些差异。


例如,当查找用户的主目录时,在Windows上变量为USERPROFILE,但在大多数Linux系统上为HOME。


var homeDir = Environment.GetEnvironmentVariable(“USERPROFILE”)
                  ?? Environment.GetEnvironmentVariable(“HOME”);
文件路径分隔符


Windows使用\和OS X和Linux使用/来分隔目录。而不是硬编码任何类型的斜杠,请使用Path.Combine()或Path.DirectorySeparatorChar。


如果这是不可能的(例如在脚本中),请使用正斜杠。在这方面,Windows比Linux更宽容。


什么时候使用内部对比公开和什么时候使用InternalsVisibleTo


作为一组现代的框架,允许使用内部类型和成员,但不鼓励。


InternalsVisibleTo仅用于允许单元测试测试其运行时组装的内部类型和成员。我们不在两个运行时程序集之间使用InternalsVisibleTo。


如果两个运行时程序集需要共享通用帮助程序,那么我们将使用一个“共享源”解决方案,仅使用构建时间包。查看https://github.com/aspnet/Mvc/tree/dev/src/Microsoft.AspNet.Mvc.Common项目以及如何从兄弟项目的project.json文件中引用它。


如果两个运行时程序集需要调用对方的API,则API必须是public的。如果我们需要它,它很可能是我们的客户需要它。


异步方法模式


默认情况下,所有异步方法必须具有异步后缀。在某些特殊情况下,来自以前框架的方法名称将被覆盖。


传递取消令牌是通过一个可选的参数,其值为default(CancellationToken),这相当于CancellationToken.None(我们使用可选参数的几个地方之一)。主要的例外是在已经传递了HttpContext的Web场景中,在这种情况下,上下文有自己的取消令牌,可以在需要时使用。


样本异步方法:


public Task GetDataAsync(
    QueryParams查询,
    int maxData,
    CancellationToken cancellationToken = default(CancellationToken))
{
    ... ...
}}
扩展方法模式


一般规则是:如果常规静态方法就足够了,请避免使用扩展方法。


扩展方法通常用于创建可链接的方法调用,例如,在构建复杂对象或创建查询时。


允许使用内部扩展方法,但要牢记之前的准则:询问自己扩展方法是否是真正最合适的模式。
扩展方法类的命名空间通常应该是表示扩展方法的功能的命名空间,而不是目标类型的命名空间。一个常见的例外是,中间件扩展方法的命名空间通常总是相同的是IAppBuilder的命名空间。


扩展方法容器(也称为“赞助商类型”)的类名通常应遵循<Feature>扩展,<Target> <Feature>扩展或<Feature> <Target>扩展的模式。例如:


namespace食物{
    class Fruit {...}
}}
命名空间Fruit.Eating {
    class FruitExtensions {public static void Eat(this Fruit fruit); }}
  要么
    class FruitEatingExtensions {public static void Eat(this Fruit fruit); }}
  要么
    class EatingFruitExtensions {public static void Eat(this Fruit fruit); }}
}}
当为接口编写扩展方法时,赞助商类型名称不能以I.开头。


文件注释


编写代码的人将写入doc注释。仅公共API。无需对非公开类型的文档评论。


注意:公共意味着客户可以调用,因此它包括受保护的API。然而,一些公共API可能仍然是“仅供内部使用”,但由于技术原因需要公开。我们仍然会有这些API的doc注释,但它们将被适当地记录。


断言


使用Debug.Assert()在代码中声明一个条件。不要使用代码合同(例如Contract.Assert)。


请注意,断言仅用于我们自己的内部调试目的。它们不会在已发布的代码中结束,因此要提醒开发人员条件使用了异常。


单元测试和功能测试


组件命名


Microsoft.Fruit程序集的单元测试在Microsoft.Fruit.Tests程序集中。


Microsoft.Fruit程序集的功能测试位于Microsoft.Fruit.FunctionalTests程序集中。


一般来说,每个产品运行时程序集都应该有一个单元测试程序集。一般来说,每个repo应该有一个功能测试程序集。可以对两者进行异常。


单元测试类命名


测试类名称以Test结束,并且与测试类在同一个命名空间中。例如,Microsoft.Fruit.Banana类的单元测试将在测试程序集中的Microsoft.Fruit.BananaTest类中。


单元测试方法命名


单元测试方法名称必须描述正在测试什么,在什么条件下,什么期望是什么。 Pascal套管和下划线可用于提高可读性。以下测试名称正确:


PublicApiArgumentsShouldHaveNotNullAnnotation
Public_api_arguments_should_have_not_null_annotation
以下测试名称不正确:


测试1
构造函数
FormatString
GetData
单元测试结构


每个单元测试的内容应该分为三个不同的阶段,可选择由这些注释分隔:


//排列
//行动
//断言
这里的关键是,法案阶段只是一个声明。这一个语句只不过是调用你试图测试的一个方法。保持一个语句尽可能简单也是非常重要的。例如,这不是理想的:


int result = myObj.CallSomeMethod(GetComplexParam1(),GetComplexParam2(),GetComplexParam3());
这种风格不推荐,因为太多的事情可能会出错在这一句话。所有的GetComplexParamN()调用可以抛出的各种原因与测试本身无关。因此不清楚有人遇到问题,为什么失败发生。


理想的模式是将复杂的参数构建移动到编配部分:


//排列
P1 p1 = GetComplexParam1();
P2 p2 = GetComplexParam2();
P3 p3 = GetComplexParam3();


//行动
int result = myObj.CallSomeMethod(p1,p2,p3);


//断言
Assert.AreEqual(1234,result);
现在唯一的原因,CallSomeMethod()行可能失败是如果方法本身爆炸。当你使用例如ExceptionHelper这样的帮助器时,这是特别重要的,你传递给它的代理必须失败,只有一个原因。


测试异常消息


通常在单元测试中测试特定异常消息很重要。这确保确切期望的异常是正在被测试的,而不是相同类型的不同异常。为了验证确切的异常,重要的是验证消息。
为了使单元测试更容易,建议将错误消息与RESX资源进行比较。但是,也允许与字符串文字进行比较。


var ex = Assert.Throws <InvalidOperationException>(
    ()=> fruitBasket.GetBananaById(1234));
Assert.Equal(
    Strings.FormatInvalidBananaID(1234),
    ex.Message);
使用xUnit.net的大量内置断言


xUnit.net包括许多种类的断言 - 请使用最适合您的测试。这将使测试更加可读,并且还允许测试运行程序报告最佳可能的错误(无论是本地还是CI机器)。例如,这些都是坏的:


Assert.Equal(true,someBool);


Assert.True(“abc123”== someString);


Assert.True(list1.Length == list2.Length);


for(int i = 0; i <list1.Length; i ++){
    Assert.True(
        String.Equals
            list1 [i],
            list2 [i],
            StringComparison.OrdinalIgnoreCase));
}}
这些都是好:


Assert.True(someBool);


Assert.Equal(“abc123”,someString);


//内置集合断言!
Assert.Equal(list1,list2,StringComparer.OrdinalIgnoreCase);
并行测试


默认情况下,所有单元测试程序集都应以并行模式运行,这是默认值。单元测试不应该依赖于任何共享状态,因此通常应该并行运行。如果测试并行失败,首先要做的是找出为什么;不要只禁用并行测试!


对于功能测试,禁用并行测试是合理的。


在公共API中仅使用完整字词或通用/标准缩写


公共名称空间,类型名称,成员名称和参数名称必须使用完整字词或通用/标准缩写。


这些是正确的:


public void AddReference(AssemblyReference reference);
public EcmaScriptObject SomeObject {get; }}
这些是不正确的:


public void AddRef(AssemblyReference ref);
public EcmaScriptObject SomeObj {get; }}

Product planning and issue tracking

我们如何跟踪什么工作要做。


问题跟踪


错误管理发生在GitHub。每个回购有自己的问题跟踪。无法在repos之间移动错误,因此请确保在正确的repo中打开一个错误。如果一个错误在错误的repo中打开,有人将不得不手动将其复制到正确的repo。


技巧和窍门


:grey_exclamation:我们写的代码的结构和我们用来编写代码的工具。


我打破了我的建设,我不能起床!


构建系统是全新的,所以问题可以抓住我们的惊喜。因此,你有时会最终处于破碎状态,无法构建。以下步骤应该修复大多数损坏的构建:


git clean -xdf(清除所有非源文件控制的文件)
构建(这将运行构建,并将拉入NuGet包等)
GitHub Flavored Markdown


GitHub在整个系统的许多地方支持Markdown(问题,注释等)。但是,这里有一些与常规Markdown的区别:


https://help.github.com/articles/github-flavored-markdown
包括人在一个GitHub讨论


要在GitHub的讨论中包括另一个团队成员,您可以使用@提及将通知发送给该人。这将自动向该人发送通知电子邮件(假设他们没有更改他们的GitHub帐户设置)。例如,在PR的讨论主题或问题跟踪器注释中,您可以键入@username以让他们接收通知。当您希望在PR中的代码评论中“包含”某人时,或者如果您想对问题跟踪器中的问题获得另一种意见,这将非常有用。


交叉回购依赖关系的本地调试


如果你对有交叉回购依赖性的项目进行了大量的更改,你可能会发现每次使用build install创建NuGet包都太费时。另一种方法是使用global.json文件来指定项目引用可以在磁盘上的另一个文件夹中找到。将名为global.json的文件添加到您正在使用的存储库的根目录中,并使用以下语法:


{
    “projects”:[“src”,“../DependencyInjection/src”]
}}
然后你可以更容易地在VS中运行项目,更容易调试,更快速地测试,以及更快地编写代码和重构。
https://github.com/OrchardCMS/Orchard2/wiki/Engineering-Guidelines#product-planning-and-issue-tracking 

作者原创内容不容易,如果觉得内容不错,请点击右侧“打赏”,赏俩给作者花花,也算是对作者付出的肯定,也可以鼓励作者原创更多更好内容。
更多详情欢迎到QQ群 166852192 交流。