Polly

Polly is a .NET 3.5 / 4.0 / 4.5 / PCL (Profile 259) library that allows developers to express transient exception- and fault-handling policies such as Retry, Retry Forever, Wait and Retry or Circuit Breaker in a fluent manner.

Installing via NuGet

  1. Install-Package Polly

You can install the Strongly Named version via:

  1. Install-Package Polly-Signed

There are now .NET 4.0 Async versions (via Microsoft.Bcl.Async) of the signed and unsigned NuGet packages, which can be installed via:

  1. Install-Package Polly.Net40Async
  2. Install-Package Polly.Net40Async-Signed

Please note: The Polly.Net40Async package is only needed if you are targeting .NET 4.0 and need async capabilities. If you are targeting .NET 4.5 or greater, please use the standard Polly package.

Usage

Step 1 : Specify the type of exceptions you want the policy to handle

  1. // Single exception type
  2. Policy
  3. .Handle<DivideByZeroException>()
  4.  
  5. // Single exception type with condition
  6. Policy
  7. .Handle<SqlException>(ex => ex.Number == 1205)
  8.  
  9. // Multiple exception types
  10. Policy
  11. .Handle<DivideByZeroException>()
  12. .Or<ArgumentException>()
  13.  
  14. // Multiple exception types with condition
  15. Policy
  16. .Handle<SqlException>(ex => ex.Number == 1205)
  17. .Or<ArgumentException>(ex => ex.ParamName == "example")

Step 1b: (optionally) Specify return results you want to handle

From Polly v4.3.0 onwards, policies wrapping calls returning a TResult can also handle TResult return values:

  1. // Handle return value with condition
  2. Policy
  3. .HandleResult<HttpResponse>(r => r.StatusCode == 404)
  4.  
  5. // Handle multiple return values
  6. Policy
  7. .HandleResult<HttpResponse>(r => r.StatusCode == 500)
  8. .OrResult<HttpResponse>(r => r.StatusCode == 502)
  9.  
  10. // Handle primitive return values (implied use of .Equals())
  11. Policy
  12. .HandleResult<HttpStatusCode>(HttpStatusCode.InternalServerError)
  13. .OrResult<HttpStatusCode>(HttpStatusCode.BadGateway)
  14.  
  15. // Handle both exceptions and return values in one policy
  16. int[] httpStatusCodesWorthRetrying = {408, 500, 502, 503, 504};
  17. HttpResponse result = Policy
  18. .Handle<HttpException>()
  19. .OrResult<HttpResponse>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))

For more information, see Handling Return Values at foot of this readme.

Step 2 : Specify how the policy should handle those faults

Retry

  1. // Retry once
  2. Policy
  3. .Handle<DivideByZeroException>()
  4. .Retry()
  5.  
  6. // Retry multiple times
  7. Policy
  8. .Handle<DivideByZeroException>()
  9. .Retry(3)
  10.  
  11. // Retry multiple times, calling an action on each retry
  12. // with the current exception and retry count
  13. Policy
  14. .Handle<DivideByZeroException>()
  15. .Retry(3, (exception, retryCount) =>
  16. {
  17. // do something
  18. });
  19.  
  20. // Retry multiple times, calling an action on each retry
  21. // with the current exception, retry count and context
  22. // provided to Execute()
  23. Policy
  24. .Handle<DivideByZeroException>()
  25. .Retry(3, (exception, retryCount, context) =>
  26. {
  27. // do something
  28. });

Retry forever

  1. // Retry forever
  2. Policy
  3. .Handle<DivideByZeroException>()
  4. .RetryForever()
  5.  
  6. // Retry forever, calling an action on each retry with the
  7. // current exception
  8. Policy
  9. .Handle<DivideByZeroException>()
  10. .RetryForever(exception =>
  11. {
  12. // do something
  13. });
  14.  
  15. // Retry forever, calling an action on each retry with the
  16. // current exception and context provided to Execute()
  17. Policy
  18. .Handle<DivideByZeroException>()
  19. .RetryForever((exception, context) =>
  20. {
  21. // do something
  22. });

Retry and Wait

  1. // Retry, waiting a specified duration between each retry
  2. Policy
  3. .Handle<DivideByZeroException>()
  4. .WaitAndRetry(new[]
  5. {
  6. TimeSpan.FromSeconds(1),
  7. TimeSpan.FromSeconds(2),
  8. TimeSpan.FromSeconds(3)
  9. });
  10.  
  11. // Retry, waiting a specified duration between each retry,
  12. // calling an action on each retry with the current exception
  13. // and duration
  14. Policy
  15. .Handle<DivideByZeroException>()
  16. .WaitAndRetry(new[]
  17. {
  18. TimeSpan.FromSeconds(1),
  19. TimeSpan.FromSeconds(2),
  20. TimeSpan.FromSeconds(3)
  21. }, (exception, timeSpan) => {
  22. // do something
  23. });
  24.  
  25. // Retry, waiting a specified duration between each retry,
  26. // calling an action on each retry with the current exception,
  27. // duration and context provided to Execute()
  28. Policy
  29. .Handle<DivideByZeroException>()
  30. .WaitAndRetry(new[]
  31. {
  32. TimeSpan.FromSeconds(1),
  33. TimeSpan.FromSeconds(2),
  34. TimeSpan.FromSeconds(3)
  35. }, (exception, timeSpan, context) => {
  36. // do something
  37. });
  38.  
  39. // Retry, waiting a specified duration between each retry,
  40. // calling an action on each retry with the current exception,
  41. // duration, retry count, and context provided to Execute()
  42. Policy
  43. .Handle<DivideByZeroException>()
  44. .WaitAndRetry(new[]
  45. {
  46. TimeSpan.FromSeconds(1),
  47. TimeSpan.FromSeconds(2),
  48. TimeSpan.FromSeconds(3)
  49. }, (exception, timeSpan, retryCount, context) => {
  50. // do something
  51. });
  52.  
  53. // Retry a specified number of times, using a function to
  54. // calculate the duration to wait between retries based on
  55. // the current retry attempt (allows for exponential backoff)
  56. // In this case will wait for
  57. // 2 ^ 1 = 2 seconds then
  58. // 2 ^ 2 = 4 seconds then
  59. // 2 ^ 3 = 8 seconds then
  60. // 2 ^ 4 = 16 seconds then
  61. // 2 ^ 5 = 32 seconds
  62. Policy
  63. .Handle<DivideByZeroException>()
  64. .WaitAndRetry(5, retryAttempt =>
  65. TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
  66. );
  67.  
  68. // Retry a specified number of times, using a function to
  69. // calculate the duration to wait between retries based on
  70. // the current retry attempt, calling an action on each retry
  71. // with the current exception, duration and context provided
  72. // to Execute()
  73. Policy
  74. .Handle<DivideByZeroException>()
  75. .WaitAndRetry(
  76. 5,
  77. retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
  78. (exception, timeSpan, context) => {
  79. // do something
  80. }
  81. );
  82.  
  83. // Retry a specified number of times, using a function to
  84. // calculate the duration to wait between retries based on
  85. // the current retry attempt, calling an action on each retry
  86. // with the current exception, duration, retry count, and context
  87. // provided to Execute()
  88. Policy
  89. .Handle<DivideByZeroException>()
  90. .WaitAndRetry(
  91. 5,
  92. retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
  93. (exception, timeSpan, retryCount, context) => {
  94. // do something
  95. }
  96. );

Wait and retry forever

  1. // Wait and retry forever
  2. Policy
  3. .Handle<DivideByZeroException>()
  4. .WaitAndRetryForever(retryAttempt =>
  5. TimeSpan.FromSeconds(Math.Pow(2, retryAttempt))
  6. );
  7.  
  8. // Wait and retry forever, calling an action on each retry with the
  9. // current exception and the time to wait
  10. Policy
  11. .Handle<DivideByZeroException>()
  12. .WaitAndRetryForever(
  13. retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
  14. (exception, timespan) =>
  15. {
  16. // do something
  17. });
  18.  
  19. // Wait and retry forever, calling an action on each retry with the
  20. // current exception, time to wait, and context provided to Execute()
  21. Policy
  22. .Handle<DivideByZeroException>()
  23. .WaitAndRetryForever(
  24. retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)),
  25. (exception, timespan, context) =>
  26. {
  27. // do something
  28. });

For further information on the operation of retry policies, see also the wiki.

Circuit Breaker

  1. // Break the circuit after the specified number of exceptions
  2. // and keep circuit broken for the specified duration.
  3. Policy
  4. .Handle<DivideByZeroException>()
  5. .CircuitBreaker(2, TimeSpan.FromMinutes(1));
  6.  
  7. // Break the circuit after the specified number of exceptions
  8. // and keep circuit broken for the specified duration,
  9. // calling an action on change of circuit state.
  10. Action<Exception, TimeSpan> onBreak = (exception, timespan) => { ... };
  11. Action onReset = () => { ... };
  12. CircuitBreakerPolicy breaker = Policy
  13. .Handle<DivideByZeroException>()
  14. .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);
  15.  
  16. // Break the circuit after the specified number of exceptions
  17. // and keep circuit broken for the specified duration,
  18. // calling an action on change of circuit state,
  19. // passing a context provided to Execute().
  20. Action<Exception, TimeSpan, Context> onBreak = (exception, timespan, context) => { ... };
  21. Action<Context> onReset = context => { ... };
  22. CircuitBreakerPolicy breaker = Policy
  23. .Handle<DivideByZeroException>()
  24. .CircuitBreaker(2, TimeSpan.FromMinutes(1), onBreak, onReset);
  25.  
  26. // Monitor the circuit state, for example for health reporting.
  27. CircuitState state = breaker.CircuitState;
  28.  
  29. /*
  30. CircuitState.Closed - Normal operation. Execution of actions allowed.
  31. CircuitState.Open - The automated controller has opened the circuit. Execution of actions blocked.
  32. CircuitState.HalfOpen - Recovering from open state, after the automated break duration has expired. Execution of actions permitted. Success of subsequent action/s controls onward transition to Open or Closed state.
  33. CircuitState.Isolated - Circuit held manually in an open state. Execution of actions blocked.
  34. */
  35.  
  36. // Manually open (and hold open) a circuit breaker - for example to manually isolate a downstream service.
  37. breaker.Isolate();
  38. // Reset the breaker to closed state, to start accepting actions again.
  39. breaker.Reset();

For further information on the operation of circuit breaker, see also the wiki.

Advanced Circuit Breaker

  1. // Break the circuit if, within any period of duration samplingDuration,
  2. // the proportion of actions resulting in a handled exception exceeds failureThreshold,
  3. // provided also that the number of actions through the circuit in the period
  4. // is at least minimumThroughput.
  5.  
  6. Policy
  7. .Handle<DivideByZeroException>()
  8. .AdvancedCircuitBreaker(
  9. failureThreshold: 0.5, // Break on >=50% actions result in handled exceptions...
  10. samplingDuration: TimeSpan.FromSeconds(10), // ... over any 10 second period
  11. minimumThroughput: 8, // ... provided at least 8 actions in the 10 second period.
  12. durationOfBreak: TimeSpan.FromSeconds(30) // Break for 30 seconds.
  13. );
  14.  
  15. // Configuration overloads taking state-change delegates are
  16. // available as described for CircuitBreaker above.
  17.  
  18. // Circuit state monitoring and manual controls are
  19. // available as described for CircuitBreaker above.

For further information on the operation of Advanced Circuit Breaker, see the Wiki

For more information on the Circuit Breaker pattern in general see:

Step 3 : Execute the policy

  1. // Execute an action
  2. var policy = Policy
  3. .Handle<DivideByZeroException>()
  4. .Retry();
  5.  
  6. policy.Execute(() => DoSomething());
  7.  
  8. // Execute an action passing arbitrary context data
  9. var policy = Policy
  10. .Handle<DivideByZeroException>()
  11. .Retry(3, (exception, retryCount, context) =>
  12. {
  13. var methodThatRaisedException = context["methodName"];
  14. Log(exception, methodThatRaisedException);
  15. });
  16.  
  17. policy.Execute(
  18. () => DoSomething(),
  19. new Dictionary<string, object>() {{ "methodName", "some method" }}
  20. );
  21.  
  22. // Execute a function returning a result
  23. var policy = Policy
  24. .Handle<DivideByZeroException>()
  25. .Retry();
  26.  
  27. var result = policy.Execute(() => DoSomething());
  28.  
  29. // Execute a function returning a result passing arbitrary context data
  30. var policy = Policy
  31. .Handle<DivideByZeroException>()
  32. .Retry(3, (exception, retryCount, context) =>
  33. {
  34. object methodThatRaisedException = context["methodName"];
  35. Log(exception, methodThatRaisedException)
  36. });
  37.  
  38. var result = policy.Execute(
  39. () => DoSomething(),
  40. new Dictionary<string, object>() {{ "methodName", "some method" }}
  41. );
  42.  
  43. // You can of course chain it all together
  44. Policy
  45. .Handle<SqlException>(ex => ex.Number == 1205)
  46. .Or<ArgumentException>(ex => ex.ParamName == "example")
  47. .Retry()
  48. .Execute(() => DoSomething());

Post Execution Steps

Using the ExecuteAndCapture method you can capture the result of executing a policy.

  1. var policyResult = Policy
  2. .Handle<DivideByZeroException>()
  3. .Retry()
  4. .ExecuteAndCapture(() => DoSomething());
  5. /*
  6. policyResult.Outcome - whether the call succeeded or failed
  7. policyResult.FinalException - the final exception captured, will be null if the call succeeded
  8. policyResult.ExceptionType - was the final exception an exception the policy was defined to handle (like DivideByZeroException above) or an unhandled one (say Exception). Will be null if the call succeeded.
  9. policyResult.Result - if executing a func, the result if the call succeeded or the type's default value
  10. */

Asynchronous Support (.NET 4.5, PCL and .NET4.0)

You can use Polly with asynchronous functions by using the asynchronous methods

  • RetryAsync
  • RetryForeverAsync
  • WaitAndRetryAsync
  • WaitAndRetryForeverAsync
  • CircuitBreakerAsync
  • AdvancedCircuitBreakerAsync
  • ExecuteAsync
  • ExecuteAndCaptureAsync

In place of their synchronous counterparts

  • Retry
  • RetryForever
  • WaitAndRetry
  • WaitAndRetryForever
  • CircuitBreaker
  • AdvancedCircuitBreaker
  • Execute
  • ExecuteAndCapture

For example

  1. await Policy
  2. .Handle<SqlException>(ex => ex.Number == 1205)
  3. .Or<ArgumentException>(ex => ex.ParamName == "example")
  4. .RetryAsync()
  5. .ExecuteAsync(() => DoSomethingAsync());

SynchronizationContext

Async continuations and retries by default do not run on a captured synchronization context. To change this, use.ExecuteAsync(...) overloads taking a boolean continueOnCapturedContext parameter.

Cancellation support

Async policy execution supports cancellation via .ExecuteAsync(...) overloads taking a CancellationToken.

Cancellation cancels Policy actions such as further retries and waits between retries. The delegate taken by the relevant.ExecuteAsync(...) overloads also takes a cancellation token input parameter, to support cancellation during delegate execution.

  1. // Try several times to retrieve from a uri, but support cancellation at any time.
  2. CancellationToken cancellationToken = // ...
  3. var policy = Policy
  4. .Handle<WebException>()
  5. .Or<HttpRequestException>()
  6. .WaitAndRetryAsync(new[] {
  7. TimeSpan.FromSeconds(1),
  8. TimeSpan.FromSeconds(2),
  9. TimeSpan.FromSeconds(4)
  10. });
  11. var response = await policy.ExecuteAsync(ct => httpClient.GetAsync(uri, ct), cancellationToken);

.NET4.0 Async support

The .NET4.0 Async support uses Microsoft.Bcl.Async to add async support to a .NET4.0 package. To minimise extra dependencies on the main Polly nuget package, the .NET4.0 async version is available as separate Nuget packagesPolly.Net40Async and Polly.Net40Async-signed.

Handing return values, and Policy<TResult>

As described at step 1b, from Polly v4.3.0 onwards, policies can handle return values and exceptions in combination:

  1. // Handle both exceptions and return values in one policy
  2. int[] httpStatusCodesWorthRetrying = {408, 500, 502, 503, 504};
  3. HttpResponse result = Policy
  4. .Handle<HttpException>()
  5. .OrResult<HttpResponse>(r => httpStatusCodesWorthRetrying.Contains(r.StatusCode))
  6. .Retry(...)
  7. .Execute( /* some Func<HttpResponse> */ )

The exceptions and return results to handle can be expressed fluently in any order.

Strongly-typed Policy<TResult>

Configuring a policy with .HandleResult<TResult>(...) or .OrResult<TResult>(...) generates a strongly-typedPolicy<TResult> of the specific policy type, eg Retry<TResult>AdvancedCircuitBreaker<TResult>.

These policies must be used to execute delegates returning TResult, ie:

  • Execute(Func<TResult>) (and related overloads)
  • ExecuteAsync(Func<CancellationToken, Task<TResult>>) (and related overloads)

ExecuteAndCapture<TResult>()

.ExecuteAndCapture(...) on non-generic policies returns a PolicyResult with properties:

  1. policyResult.Outcome - whether the call succeeded or failed
  2. policyResult.FinalException - the final exception captured; will be null if the call succeeded
  3. policyResult.ExceptionType - was the final exception an exception the policy was defined to handle (like DivideByZeroException above) or an unhandled one (say Exception)? Will be null if the call succeeded.
  4. policyResult.Result - if executing a func, the result if the call succeeded or the type's default value

.ExecuteAndCapture<TResult>(Func<TResult>) on strongly-typed policies adds two properties:

  1. policyResult.FaultType - was the final fault handled an exception or a result handled by the policy? Will be null if the delegate execution succeeded.
  2. policyResult.FinalHandledResult - the final result handled; will be null if the call succeeded or the type's default value

State-change delegates on Policy<TResult> policies

In non-generic policies handling only exceptions, state-change delegates such as onRetry and onBreak take an Exceptionparameter.

In generic-policies handling TResult return values, state-change delegates are identical except they take aDelegateResult<TResult> parameter in place of Exception. DelegateResult<TResult> has two properties:

  • Exception // The exception just thrown if policy is in process of handling an exception (otherwise null)
  • Result // The TResult just raised, if policy is in process of handling a result (otherwise default(TResult))

BrokenCircuitException<TResult>

Non-generic CircuitBreaker policies throw a BrokenCircuitException when the circuit is broken. This BrokenCircuitExceptioncontains the last exception (the one which caused the circuit to break) as the InnerException.

For CircuitBreakerPolicy<TResult> policies:

  • A circuit broken due to an exception throws a BrokenCircuitException with InnerException set to the exception which triggered the break (as previously).
  • A circuit broken due to handling a result throws a BrokenCircuitException<TResult> with the Result property set to the result which caused the circuit to break.

3rd Party Libraries

Acknowledgements

  • lokad-shared-libraries - Helper assemblies for .NET 3.5 and Silverlight 2.0 that are being developed as part of the Open Source effort by Lokad.com (discontinued) | New BSD License
  • @michael-wolfenden - The creator and mastermind of Polly!
  • @ghuntley - Portable Class Library implementation.
  • @mauricedb - Async implementation.
  • @robgibbens - Added existing async files to PCL project
  • Hacko - Added extra NotOnCapturedContext call to prevent potential deadlocks when blocking on asynchronous calls
  • @ThomasMentzel - Added ability to capture the results of executing a policy via ExecuteAndCapture
  • @yevhen - Added full control of whether to continue on captured synchronization context or not
  • @reisenberger - Added full async cancellation support
  • @reisenberger - Added async support for ContextualPolicy
  • @reisenberger - Added ContextualPolicy support for circuit-breaker
  • @reisenberger - Extended circuit-breaker for public monitoring and control
  • @reisenberger - Added ExecuteAndCapture support with arbitrary context data
  • @kristianhald and @reisenberger - Added AdvancedCircuitBreaker
  • @reisenberger - Allowed async onRetry delegates to async retry policies
  • @Lumirris - Add new Polly.Net40Async project/package supporting async for .NET40 via Microsoft.Bcl.Async
  • @SteveCote - Added overloads to WaitAndRetry and WaitAndRetryAsync methods that accept an onRetry delegate which includes the attempt count.
  • @reisenberger - Allowed policies to handle returned results; added strongly-typed policies Policy<TResult>;.
  • @christopherbahr - Added optimisation for circuit-breaker hot path.
  • @Finity - Fixed circuit-breaker threshold bug.

Sample Projects

Polly-Samples contains practical examples for using various implementations of Polly. Please feel free to contribute to the Polly-Samples repository in order to assist others who are either learning Polly for the first time, or are seeking advanced examples and novel approaches provided by our generous community.

Instructions for Contributing

Please check out our Wiki for contributing guidelines. We are following the excellent GitHub Flow process, and would like to make sure you have all of the information needed to be a world-class contributor!

License

Licensed under the terms of the New BSD License

Polly的更多相关文章

  1. 使用Polly让程序有Retry的机制

    有时候我们需要调用其他API的时候出现暂时连接不通超时的情况,那这时候可以通过Polly进行Retry. 1.从nuget引用polly, 2.定义需要处理的异常有哪些,比如 Policy.Handl ...

  2. uva 498 - Polly the Polynomial

    UVa 498: Polly the Polynomial | MathBlog #include <cstdio> #include <cstdlib> using name ...

  3. API网关Ocelot 使用Polly 处理部分失败问题

    在实现API Gateway过程中,另外一个需要考虑的问题就是部分失败.这个问题发生在分布式系统中当一个服务调用另外一个服务超时或者不可用的情况.API Gateway不应该被阻断并处于无限期等待下游 ...

  4. 已被.NET基金会认可的弹性和瞬态故障处理库Polly介绍

    前言 本节我们来介绍一款强大的库Polly,Polly是一种.NET弹性和瞬态故障处理库,允许我们以非常顺畅和线程安全的方式来执诸如行重试,断路,超时,故障恢复等策略. Polly针对对.NET 4. ...

  5. ASP.NET Core 异常重试组件 Polly

    Polly 是一种 .NET 弹性和瞬态故障处理库,允许开发人员以流畅和线程安全的方式表达策略,如重试,断路器,超时,隔离隔离和备用,Polly 适用于 .NET 4.0,.NET 4.5 和 .NE ...

  6. 基于.NET的弹性及瞬间错误处理库Polly

    本文基本是官方说明的翻译和总结(https://github.com/App-vNext/Polly) 什么是Polly? Polly是一款基于.NET的弹性及瞬间错误处理库, 它允许开发人员以顺畅及 ...

  7. LindDotNetCore~Polly组件对微服务场景的价值

    回到目录 Polly是一个开源框架,在github上可以找到,被善友大哥收录,也是.App vNext的一员! App vNext:https://github.com/App-vNext GitHu ...

  8. ASP VNext 开源服务容错处理库Polly使用文档

    在进入SOA之后,我们的代码从本地方法调用变成了跨机器的通信.任何一个新技术的引入都会为我们解决特定的问题,都会带来一些新的问题.比如网络故障.依赖服务崩溃.超时.服务器内存与CPU等其它问题.正是因 ...

  9. 再探Circuit Breaker之使用Polly

    前言 上一篇介绍了使用Steeltoe来处理服务熔断,这篇我们将用Polly来处理服务熔断. 不废话了,直接进正题. 简单的例子 同样先定义一个简单的服务. [Route("api/[con ...

随机推荐

  1. cs

    cs <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.o ...

  2. DNS CNAME的一些细节

    1, 概述 DNS中的CNAME可以减轻运维压力,使得已有的DNS配置具有一定的灵活性和可扩展性.本文对CNAME中的一些细节做阐述, 使DNS服务器的运维人员和开发人员能合理地使用CNAME. 2, ...

  3. CUtilityCode

    (1) 基于boost的生产者/消费者队列 template<typenameData> classconcurrent_queue { private: std::queue<Da ...

  4. WebForm 常用控件

    一.简单控件 1.Label(作用:显示文字) Web中: <asp:Label ID="Label1" runat="server" Text=&quo ...

  5. iptables 设置肯限制流量

    1.查看本机关于IPTABLES的设置情况 [root@tp ~]# iptables -L -n Chain INPUT (policy ACCEPT) target prot opt source ...

  6. 添加sudo权限

    进入超级用户模式.也就是输入"su -",系统会让你输入超级用户密码,输入密码后就进入了超级用户模式.(当然,你也可以直接用root用) 添加文件的写权限.也就是输入命令" ...

  7. 敏捷项目开源管理软件ScrumBasic(2)- 多项目支持

    1.加入Project对象模型 public class Project { [Key] [MaxLength(32)] public string ID { get; set; } public s ...

  8. SSO

  9. 非常好的Oracle教程【转】

    http://www.blogjava.net/kiant/articles/234781.html Oracle 笔记(四).SQL 几个要点 附录: 1.SQL 简介 2.SQL 操作符 3.Or ...

  10. SQL Server 常用高级语法笔记

    自从用了EF后很少写sql和存储过程了,今天需要写个比较复杂的报告,翻出了之前的笔记做参考,感觉这个笔记还是很有用的,因此发出来和园友分享. 1.case...end (具体的值)case后面有值,相 ...