您的位置:首页 > 编程语言 > C#

C#编码规范Version 2.32(四)

2008-09-26 16:07 176 查看

四、Framework特别指导

4.1 数据访问

1.总是使用类型安全的数据集或者数据表。避免使用原始的ADO.NET。
2.访问数据库时总是使用事务。
a)[/b]始终使用WCF,服务组件,System.Transactions等处理事务。
Windows通信基础(Windows Communication Foundation,WCF)是基于Windows平台下开发和部署服务的软件开发包(Software Development Kit,SDK)。WCF为服务提供了运行时环境(Runtime Environment),使得开发者能够将CLR类型公开为服务,又能够以CLR类型的方式使用服务。理论上讲,创建服务并不一定需要WCF,但实际上,使用WCF却可以使得创建服务的任务事半功倍。WCF是微软对一系列产业标准定义的实现,包括服务交互、类型转换、封送(Marshaling)以及各种协议的管理。
使用 System.Transactions 命名空间包含的类可以编写自己的事务应用程序和资源管理器。具体地说,可以创建和参与(与一个或多个参与者)本地或分布式事务。
b)不要使用ADO.NET事务来显示的支持数据库。
3.总是将事务隔离级别设置为序列的。使用其它隔离级别需要管理层决定。
4.不要使用数据源浏览器将数据库连接拖到Windows表单、ASP.NET表单或Web服务中。这样做耦合了界面层和数据层。
5.避免使用SQL Server验证。而是使用Windows验证。
6.将访问SQL Server的组件以调用该组件客户端不同的身份运行。
7.总是在高层用类型安全的类包装存储过程。仅在那个类中调用存储过程。
8.避免在存储过程中放任何逻辑。你应该考虑把这一逻辑放在业务逻辑层上。

4.2 ASP.NET和Web服务

1.避免把代码放到ASP.NET中的ASPX文件中去,所有的代码应该放在不完全类中。
2.尽量把代码放到ASP.NET中的不完全类中。
3.总是在使用session变量之前检查它是否是空。
4.在处理事务的页面或者web服务中,总是把session值放到sqlserver数据库中。
5.避免设置服务器控件的AutoPostback属性为true。
6.打开ASP.NET页面的智能导航。
7.努力为web服务提供接口。
8.总是为web服务提供一个命名控件和服务描述。
9.总是为一个web方法提供描述。
10.当添加一个web服务的参考时,对这个位置应该提供一个有意思的名称。
11.在ASPX.NET页面和web服务中,把访问session变量的权限赋予所有者,仅仅所有者被允许访问这个session变量,其它就不能使用这个session变量。
public class Calculator : WebService
{
int Memory
{
get
{
int memory = 0;
object state = Session["Memory"];
if(state != null)
{
memory = (int)state;
}
return memory;
}
set
{
Session["Memory"] = value;
}
}
[WebMethod(EnableSession=true)]
public void MemoryReset()
{
Memory = 0;
}
}
12.总是修改客户端的web服务包装类去支持cookies,因为你无从得知服务所使用的会话状态。
public class Calculator : SoapHttpClientProtocol
{
public Calculator()
{
C[/b]oo[/b]k[/b]i[/b]e[/b]Con[/b]t[/b]ai[/b]n[/b]e[/b]r = [/b]ne[/b]w [/b]Sy[/b]s[/b]te[/b]m[/b].[/b]N[/b]et.[/b]C[/b]oo[/b]k[/b]ie[/b]C[/b]o[/b]n[/b]tai[/b]n[/b]er[/b]([/b]);[/b]
Url = ...;
}
}

4.3 多线程

1.应用同步机制空间。避免手动同步,这样会造成死锁和紊乱。
2.不要在同步域外面调用你的同步机制空间。
3.用回调方法控制非同步调用,不要等待,调查 或阻碍完成。
4.总是对你的线程进行命名,线程名字能够在线程调试窗体里跟踪,所以做一个调试线程会使程式变得更有效。
Thread currentThread = Thread.CurrentThread;
string threadName = "Main UI Thread";
currentThread.N[/b]a[/b]m[/b]e [/b]= threadName;
5.不要在线程中调用 Suspend() 和 Resume() 。
Suspend()挂起线程,或者如果线程已挂起,则不起作用。
Resume() 继续已挂起的线程。
6.不要调用Thread.Sleep()(将当前线程阻塞指定的毫秒数),除了下面的情况:
a)Thread.Sleep(0)对上下文的转换来说是一个可以接受的最优化的技术。
b)Thread.Sleep()在接受测试或模拟代码
7.不要调用Thread.SpinWait()导致线程等待。
8.不要调用Thread.Abort()去终止一个线程,不是标记线程的结束,而是应用同步对象去完成。
9.避免显示设置线程的优先级来控制执行,你可以基于任务来设置线程的的优先级,使用屏幕存储器的线程应该低于一般水平。 (ThreadPriority.BelowNormal)
10.不要读取threadstate属性的value值,使用Thread.IsActive来确认该线程是否失效。
11.应用程式结束时,不要通过配置线程类型来设定线程。 使用workdog或其他监测实体来终止线程。
12.不要使用线程的本地存储,除非线程的关联性是有保障的。
13.不要调用thread.MemoryBarrier()。
(按如下方式同步内存访问:执行当前线程的处理器在对指令重新排序时,不能采用先执行 MemoryBarrier 调用之后的内存访问,再执行 MemoryBarrier 调用之前的内存访问的方式。)
14.在没有检查你是不是加入了自己的线程,不要调用Thread.Join()
(阻塞调用线程,直到某个线程终止时为止。)
15.始终使用lock()的声明,而不是用明显的monitor manipulation。
16.总是将lock()声明放在他所保护的对象里面。
public class MyClass
{
public void DoSomething()
{
lock(this)
{...}
}
}
17.能够使用同步方法来代替您自己写lock()声明。
18.避免分散锁定。
19.避免用监控器去等待或刺激对象。应该用手工的或自动重起事件。
20.不要使用不稳定变量。锁定对象或域,而不是去确保决定性和线程安全访问。不要使用thread.volatileread(), thread.volatilewrite()或不稳定修改器。
21.在线程池里避免增加大量的线程。
22.永远不要重叠声明lock,因为这样不提供自动锁定。要使用waithandle.waitall()。
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
MyClass obj3 = new MyClass();

//Do not stack lock statements
lock(obj1)
lock(obj2)
lock(obj3)
{
obj1.DoSomething();
obj2.DoSomething();
obj3.DoSomething();
}

4.4序列化

{“序列化”可被定义为将对象的状态存储到存储媒介中的过程。在此过程中,对象的公共字段和私有字段以及类的名称(包括包含该类的程序集)都被转换为字节流,然后写入数据流。在以后“反序列化”该对象时,创建原始对象的精确复本。
一、为什么要选择序列化
一个原因是将对象的状态保持在存储媒体中,以便可以在以后重新创建精确的副本;
另一个原因是通过值将对象从一个应用程序域发送到另一个应用程序域中。
例如,序列化可用于在 ASP.NET 中保存会话状态并将对象复制到 Windows 窗体的剪贴板中。远程处理还可以使用序列化通过值将对象从一个应用程序域传递到另一个应用程序域中。
二、如何实现对象的序列化及反序列化
要实现对象的序列化,首先要保证该对象可以序列化。而且,序列化只是将对象的属性进行有效的保存,对于对象的一些方法则无法实现序列化的。
1、XML序列化
使用 XmLSerializer 类,可将下列项序列化。
公共类的公共读/写属性和字段
实现 ICollection 或 IEnumerable 的类。(注意只有集合会被序列化,而公共属性却不会。)
XmlElement 对象。
XmlNode 对象。
DataSet 对象.
2、二进制序列化
与XML序列化不同的是,二进制序列化可以将类的实例中所有字段(包括私有和公有)都进行序列化操作。这就更方便、更准确的还原了对象的副本。}

1.最好使用二进制格式来序列化。
2.把序列化事件的处理方法标记为私有的。
3.使用IGenericFormatter接口。
4.把非密封的类标记为序列化的。使用sealed 修饰符时,此修饰符会阻止其他类从该类继承。
5.指示在完成整个对象图形的反序列化时通知类。在整个对象图形已经反序列化时运行。
6.当在一个非密封类里使用IDeserializationCallback 的时候,确保子类能调用基类中的OnDeserialization().
7.总是标记未序列化的成员变量为[non-serializable]
8.总是标记序列化类中的委托为[nonserialized]
[Serializable]
public class MyClass
{
[fi[/b]e[/b]ld[/b]:[/b]NonSerialized]
public event EventHandler MyEvent;
}

4.5远程操作Remoting

什么是Remoting,简而言之,我们可以将其看作是一种分布式处理方式。从微软的产品角度来看,可以说Remoting就是DCOM的一种升级,它改善了很多功能,并极好的融合到.Net平台下。Microsoft® .NET Remoting 提供了一种允许对象通过应用程序域与另一对象进行交互的框架。这也正是我们使用Remoting的原因。为什么呢?在Windows操作系统中,是将应用程序分离为单独的进程。这个进程形成了应用程序代码和数据周围的一道边界。如果不采用进程间通信(RPC)机制,则在一个进程中执行的代码就不能访问另一进程。这是一种操作系统对应用程序的保护机制。然而在某些情况下,我们需要跨过应用程序域,与另外的应用程序域进行通信,即穿越边界。
在Remoting中是通过通道(channel)来实现两个应用程序域之间对象的通信的。Remoting的通道主要有两种:Tcp和Http。在.Net中,System.Runtime.Remoting.Channel中定义了IChannel接口。IChannel接口包括了TcpChannel通道类型和Http通道类型。它们分别对应Remoting通道的这两种类型。

1.宁可使用管理配置(配置文档)而不使用程式自动配置。
2.总是在单独调用对象里完成idisposable。(用于释放对象资源的接口)
3.远程操作时总是选用tcp信道和二进制格式 ,除非配置了防火墙。
4.总是为一个对象提供一个null租约。
public class MySingleton : MarshalByRefObject
{
public override object InitializeLifetimeService()
{
return null[/b];
}
}
5.总是为客户端激活的对象提供sponsor。这个sponsor应该返回初始租约时刻。
发起人(Sponsor)
发起人是针对客户端而言的。远程对象就是发起人要租用的对象,发起人可以与服务器端签订租约,约定租用时间。一旦到期后,发起人还可以续租,就像现实生活中租方的契约,房东、租房者之间的关系一样。

6.在客户端应用程式停止时总是不要注册sponsor。
7.总是将远程对象放在类库里。
8.避免使用soapsuds。
XML 架构自动转换为运行库程序集。该工具在生成程序集时始终会生成源代码。
9.避免宿主iis.
宿主iis优点是客户第一次请求的时候,宿主进程自动被启动。就是说“消息驱动服务”。并且可以使用IIS管理宿主进程的生命周期(life cycle)。
缺点是:只能使用HTTP协议绑定(Http Binding)。
10.避免使用单一方向的信道。
11.总是在main()方法里载入远程配置文档,即使该文档为空。并且该应用程式没有使用远程操作。
static void Main()
{
RemotingConfiguration.Configure("MyApp.exe.config");
/* Rest of Main() */
}
12.避免对远程对象激活时使用activator.getobject() and activator.createinstance()。而是使用new。
13.总是在客户端注册port(),目的是允许递归调用。
14.总是将客户端和服务器端的类型过滤配置为full,使其能够递归调用。

4.6 安全

1.总是使用强名称发布代码,该名称对于该应用程式而言是私有的,对于您是公有的。
public class PublicKeys
{
public const string MyCompany = "1234567894800000940000000602000000240000"+ "52534131000400000100010007D1FA57C4AED9F0"+ "A32E84AA0FAEFD0DE9E8FD6AEC8F87FB03766C83"+ "4C99921EB23BE79AD9D5DCC1DD9AD23613210290"+ "0B723CF980957FC4E177108FC607774F29E8320E"+ "92EA05ECE4E821C0A5EFE8F1645C4C0C93C1AB99"+ "285D622CAA652C1DFAD63D745D6F2DE5F17E5EAF"+ "0FC4963D261C8A12436518206DC093344D5AD293";
}
[St[/b]r[/b]on[/b]g[/b]Na[/b]m[/b]e[/b]I[/b]den[/b]t[/b]it[/b]y[/b]Pe[/b]r[/b]m[/b]i[/b]ssi[/b]o[/b]n([/b]S[/b]ec[/b]u[/b]r[/b]i[/b]tyA[/b]c[/b]ti[/b]o[/b]n.[/b]L[/b]i[/b]n[/b]kDe[/b]m[/b]an[/b]d[/b],[/b]
P[/b]ub[/b]l[/b]i[/b]c[/b]Ke[/b]y = PublicKeys.MyCompany)][/b]
public class MyClass
{...}
2.对应用程式配置文档要实施加密和安全保护。
3.当引入一个互操作方法时,要断言不可控代码操作允许,并且声明相应的允许权限。
[DllImport("user32",EntryPoint="MessageBoxA")]
private static extern int Show(IntPtr handle,string text,string caption,
int msgType);
[SecurityPermission(SecurityAction.A[/b]sse[/b]r[/b]t[/b],UnmanagedCode = true)]
[UIPermission(SecurityAction.D[/b]e[/b]ma[/b]n[/b]d[/b],
Window = UIPermissionWindow.SafeTopLevelWindows)]

public static void Show(string text,string caption)
{
Show(IntPtr.Zero,text,caption,0);
}

4.不要通过suppressunmanagedcodesecurity属性来抑制不可控代码的访问。
5.不要使用tlbimp.exe这个不安全转换程式。将ccw包含于可控代码内,使您能够断言和授权。
6.在服务器端发布代码访问策略,授权给microsft, ecma和自身为全信任。
7.在客户端服务器,发布安全策略授权给客户端应用程式,使其有权回调服务器端程式并且能够潜在的显示用户界面。 客户端的应用程式应该予以强名称坚定。
8.在权限集水平总是拒绝权限,因为在附近不能被请求去执行任务。
[assembly:UIPermission(SecurityAction.R[/b]e[/b]qu[/b]e[/b]st[/b]R[/b]e[/b]f[/b]us[/b]e[/b],
Window=UIPermissionWindow.AllWindows)]
9.总是在每一个main()方法里对windows应用principal策略
public class MyClass
{
static void Main()
{
AppDomain currentDomain = Thread.GetDomain();
currentDomain.S[/b]e[/b]t[/b]P[/b]rin[/b]c[/b]ip[/b]a[/b]lP[/b]o[/b]l[/b]i[/b]c[/b]y[/b](PrincipalPolicy.WindowsPrincipal);
}
//other methods
}
10.在没有需要一个不同的权限的情况下,不可断言一个权限。

4.7 System.Transactions

使用 System.Transactions[/b] 命名空间包含的类可以编写自己的事务应用程序和资源管理器。具体地说,可以创建和参与(与一个或多个参与者)本地或分布式事务。[/b]
1.总是处理TransactionScope对象。使代码块成为事务性代码
2.在一个事务的范围之内,在调用complete()之后不要运行任何代码。
3.指示范围中的所有操作都已成功完成。
4.当设置环境中的事务的时候,总是保存旧的环境中的事务并备份它。
5.在发布版本的时候,不要设置事务超时为0(永不超时)。
6.当克隆一个事务的时候,总是使用DependentCloneOption.BlockCommitUntilComplete.
依赖事务阻塞事务的提交过程,直至父事务超时或 Complete 被调用。在此情况下,可以在该事务上完成附加工作,并且可以创建新的登记。
7.为每一个工作线程创建一个新的克隆。不要把相同的克隆作用于多个线程。
8.不要通过事务去克隆TransactionScope的构造器。
9.始终捕捉和抛出TransactionScopeOption.Suppress。

4.8企业服务

1.在事务方法里不要捕获异常。要用autocomplete属性。
2.不要调用setcomplete(), setabort(),连同相关方法。要用autocomplete属性。
[Transaction]
public class MyComponent : ServicedComponent
{
[[/b]Au[/b]t[/b]oC[/b]o[/b]m[/b]p[/b]let[/b]e[/b]][/b]
public void MyMethod(long objectIdentifier)
{...}
}

3.总是覆写canbepooled方法并且返回true(除非您有更好的原因不用返回值)。
public class MyComponent : ServicedComponent
{
protected override bool CanBePooled()
{
r[/b]et[/b]u[/b]r[/b]n true[/b];[/b]
}
}

4.总是在对象池里显示地调用dispose(),除非该组件已被配置为使用JITA。
5.当组件使用JITA时不可调用dispose()。
6.总是为应用程式和组件配置权限水平。
7.将任何应用程式的检证水平配置为私有。
[assembly: ApplicationActivation(ActivationOption.Server)]
[assembly: ApplicationAccessControl(
true, //Authorization AccessChecksLevel=AccessChecksLevelOption.ApplicationComponent, Authentication=AuthenticationOption.Privacy, ImpersonationLevel=ImpersonationLevelOption.Identify)]

8[/b].将客户端程式集的角色水平配置为identity。
9.总是将可服务组件的componentaccesscontrol属性配置为true。
[ComponentAccessControl]
public class MyComponent : ServicedComponent
{...}

10.总是将每一个用户角色配置为marshaler。
[assembly: SecurityRole("Marshaler",SetEveryoneAccess = true)]
11.应用securemethod属性于任何的需要检证的类。
[SecureMethod]
public class MyComponent : ServicedComponent
{...}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐