[转载]Asp.Net MVC 权限控制(一):使用 Authorize Roles 简单实现 - Jetlian - 博客园

mikel阅读(693)

来源: [转载]Asp.Net MVC 权限控制(一):使用 Authorize Roles 简单实现 – Jetlian – 博客园

最近由于项目的需要对权限控制做了几个Demo,贴出来供大家拍砖!

 

首先创建一个 BaseController ,让所有的Controller继承自BaseController 。

<div class="container">
<div class="line number1 index0 alt2"><code class="csharp plain">[Authorize]</code></div>
<div class="line number2 index1 alt1"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">BaseController : Controller</code></div>
<div class="line number3 index2 alt2"><code class="csharp plain">{</code></div>
<div class="line number4 index3 alt1"></div>
<div class="line number5 index4 alt2"><code class="csharp plain">}</code></div>
<div class="line number5 index4 alt2">

系统登录需要一个 AccountController ,继承自BaseController ,并添加匿名访问标记 AllowAnonymous。

AccountController 实现系统的登录功能,并将用户信息保存到Cookie中。

<div class="container">
<div class="line number1 index0 alt2"><code class="csharp spaces">    </code><code class="csharp plain">[AllowAnonymous]</code></div>
<div class="line number2 index1 alt1"><code class="csharp spaces">    </code><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">AccountController : BaseController</code></div>
<div class="line number3 index2 alt2"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number4 index3 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">public</code> <code class="csharp plain">ActionResult Index()</code></div>
<div class="line number5 index4 alt2"><code class="csharp spaces">        </code><code class="csharp plain">{</code></div>
<div class="line number6 index5 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">return</code> <code class="csharp plain">View();</code></div>
<div class="line number7 index6 alt2"><code class="csharp spaces">        </code><code class="csharp plain">}</code></div>
<div class="line number8 index7 alt1"></div>
<div class="line number9 index8 alt2"><code class="csharp spaces">        </code><code class="csharp keyword">public</code> <code class="csharp plain">ActionResult Login(</code><code class="csharp keyword">string</code> <code class="csharp plain">returnUrl)</code></div>
<div class="line number10 index9 alt1"><code class="csharp spaces">        </code><code class="csharp plain">{</code></div>
<div class="line number11 index10 alt2"><code class="csharp spaces">            </code><code class="csharp plain">ViewBag.ReturnUrl = returnUrl;</code></div>
<div class="line number12 index11 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">return</code> <code class="csharp plain">View();</code></div>
<div class="line number13 index12 alt2"><code class="csharp spaces">        </code><code class="csharp plain">}</code></div>
<div class="line number14 index13 alt1"></div>
<div class="line number15 index14 alt2"><code class="csharp spaces">        </code><code class="csharp plain">[HttpPost]</code></div>
<div class="line number16 index15 alt1"><code class="csharp spaces">        </code><code class="csharp plain">[AllowAnonymous]</code></div>
<div class="line number17 index16 alt2"><code class="csharp spaces">        </code><code class="csharp plain">[ValidateAntiForgeryToken]</code></div>
<div class="line number18 index17 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">public</code> <code class="csharp plain">ActionResult Login(LoginModel model, </code><code class="csharp keyword">string</code> <code class="csharp plain">returnUrl)</code></div>
<div class="line number19 index18 alt2"><code class="csharp spaces">        </code><code class="csharp plain">{</code></div>
<div class="line number20 index19 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">string</code> <code class="csharp plain">roles = </code><code class="csharp string">""</code><code class="csharp plain">;</code></div>
<div class="line number21 index20 alt2"><code class="csharp spaces">            </code><code class="csharp keyword">var</code> <code class="csharp plain">userName = model.UserName;</code></div>
<div class="line number22 index21 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">if</code> <code class="csharp plain">(userName == </code><code class="csharp string">"admin"</code><code class="csharp plain">)</code></div>
<div class="line number23 index22 alt2"><code class="csharp spaces">            </code><code class="csharp plain">{</code></div>
<div class="line number24 index23 alt1"><code class="csharp spaces">                </code><code class="csharp plain">roles = </code><code class="csharp string">"Admin"</code><code class="csharp plain">;</code></div>
<div class="line number25 index24 alt2"><code class="csharp spaces">            </code><code class="csharp plain">}</code></div>
<div class="line number26 index25 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">else</code> <code class="csharp keyword">if</code> <code class="csharp plain">(userName == </code><code class="csharp string">"ib"</code><code class="csharp plain">)</code></div>
<div class="line number27 index26 alt2"><code class="csharp spaces">            </code><code class="csharp plain">{</code></div>
<div class="line number28 index27 alt1"><code class="csharp spaces">                </code><code class="csharp plain">roles = </code><code class="csharp string">"IBusiness"</code><code class="csharp plain">;</code></div>
<div class="line number29 index28 alt2"><code class="csharp spaces">            </code><code class="csharp plain">}</code></div>
<div class="line number30 index29 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">else</code> <code class="csharp keyword">if</code><code class="csharp plain">(userName == </code><code class="csharp string">"ia"</code><code class="csharp plain">)</code></div>
<div class="line number31 index30 alt2"><code class="csharp spaces">            </code><code class="csharp plain">{</code></div>
<div class="line number32 index31 alt1"><code class="csharp spaces">                </code><code class="csharp plain">roles = </code><code class="csharp string">"IApproval"</code><code class="csharp plain">;</code></div>
<div class="line number33 index32 alt2"><code class="csharp spaces">            </code><code class="csharp plain">}</code></div>
<div class="line number34 index33 alt1"><code class="csharp spaces">            </code></div>
<div class="line number35 index34 alt2"><code class="csharp spaces">            </code><code class="csharp plain">FormsAuthenticationTicket authTicket = </code><code class="csharp keyword">new</code> <code class="csharp plain">FormsAuthenticationTicket(</code></div>
<div class="line number36 index35 alt1"><code class="csharp spaces">            </code><code class="csharp plain">1,</code></div>
<div class="line number37 index36 alt2"><code class="csharp spaces">            </code><code class="csharp plain">userName,</code></div>
<div class="line number38 index37 alt1"><code class="csharp spaces">            </code><code class="csharp plain">DateTime.Now,</code></div>
<div class="line number39 index38 alt2"><code class="csharp spaces">            </code><code class="csharp plain">DateTime.Now.AddMinutes(20),</code></div>
<div class="line number40 index39 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">false</code><code class="csharp plain">,</code></div>
<div class="line number41 index40 alt2"><code class="csharp spaces">            </code><code class="csharp plain">roles</code><code class="csharp comments">//写入用户角色</code></div>
<div class="line number42 index41 alt1"><code class="csharp spaces">            </code><code class="csharp plain">);</code></div>
<div class="line number43 index42 alt2"></div>
<div class="line number44 index43 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">string</code> <code class="csharp plain">encryptedTicket = FormsAuthentication.Encrypt(authTicket);</code></div>
<div class="line number45 index44 alt2"></div>
<div class="line number46 index45 alt1"><code class="csharp spaces">            </code><code class="csharp plain">System.Web.HttpCookie authCookie = </code><code class="csharp keyword">new</code> <code class="csharp plain">System.Web.HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);</code></div>
<div class="line number47 index46 alt2"><code class="csharp spaces">            </code><code class="csharp plain">System.Web.HttpContext.Current.Response.Cookies.Add(authCookie);</code></div>
<div class="line number48 index47 alt1"></div>
<div class="line number49 index48 alt2"><code class="csharp spaces">            </code><code class="csharp keyword">return</code> <code class="csharp keyword">string</code><code class="csharp plain">.IsNullOrEmpty(returnUrl) ?</code></div>
<div class="line number50 index49 alt1"><code class="csharp spaces">                </code><code class="csharp plain">RedirectToAction(</code><code class="csharp string">"Index"</code><code class="csharp plain">, </code><code class="csharp string">"Home"</code><code class="csharp plain">)</code></div>
<div class="line number51 index50 alt2"><code class="csharp spaces">                </code><code class="csharp plain">: RedirectToLocal(returnUrl);</code></div>
<div class="line number52 index51 alt1"><code class="csharp spaces">        </code><code class="csharp plain">}</code></div>
<div class="line number53 index52 alt2"></div>
<div class="line number54 index53 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">private</code> <code class="csharp plain">ActionResult RedirectToLocal(</code><code class="csharp keyword">string</code> <code class="csharp plain">returnUrl)</code></div>
<div class="line number55 index54 alt2"><code class="csharp spaces">        </code><code class="csharp plain">{</code></div>
<div class="line number56 index55 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">if</code> <code class="csharp plain">(Url.IsLocalUrl(returnUrl))</code></div>
<div class="line number57 index56 alt2"><code class="csharp spaces">            </code><code class="csharp plain">{</code></div>
<div class="line number58 index57 alt1"><code class="csharp spaces">                </code><code class="csharp keyword">return</code> <code class="csharp plain">Redirect(returnUrl);</code></div>
<div class="line number59 index58 alt2"><code class="csharp spaces">            </code><code class="csharp plain">}</code></div>
<div class="line number60 index59 alt1"><code class="csharp spaces">            </code><code class="csharp keyword">else</code></div>
<div class="line number61 index60 alt2"><code class="csharp spaces">            </code><code class="csharp plain">{</code></div>
<div class="line number62 index61 alt1"><code class="csharp spaces">                </code><code class="csharp keyword">return</code> <code class="csharp plain">RedirectToAction(</code><code class="csharp string">"Index"</code><code class="csharp plain">, </code><code class="csharp string">"Home"</code><code class="csharp plain">);</code></div>
<div class="line number63 index62 alt2"><code class="csharp spaces">            </code><code class="csharp plain">}</code></div>
<div class="line number64 index63 alt1"><code class="csharp spaces">        </code><code class="csharp plain">}</code></div>
<div class="line number65 index64 alt2"></div>
<div class="line number66 index65 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">public</code> <code class="csharp plain">ActionResult LogOff()</code></div>
<div class="line number67 index66 alt2"><code class="csharp spaces">        </code><code class="csharp plain">{</code></div>
<div class="line number68 index67 alt1"><code class="csharp spaces">            </code><code class="csharp plain">FormsAuthentication.SignOut();</code></div>
<div class="line number69 index68 alt2"><code class="csharp spaces">            </code><code class="csharp keyword">return</code> <code class="csharp plain">RedirectToAction(</code><code class="csharp string">"Index"</code><code class="csharp plain">, </code><code class="csharp string">"Home"</code><code class="csharp plain">);</code></div>
<div class="line number70 index69 alt1"><code class="csharp spaces">        </code><code class="csharp plain">}</code></div>
<div class="line number71 index70 alt2"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number72 index71 alt1"><code class="csharp plain">}</code></div>
<div class="line number72 index71 alt1">
在系统的业务Controller中添加角色验证标记。
</div>
<div class="line number72 index71 alt1">
<div class="container">
<div class="line number1 index0 alt2"><code class="csharp plain">[Authorize(Roles = </code><code class="csharp string">"Admin,IBusiness,IApproval"</code><code class="csharp plain">)]</code></div>
<div class="line number2 index1 alt1"><code class="csharp keyword">public</code> <code class="csharp keyword">class</code> <code class="csharp plain">InfrastructureController : BaseController</code></div>
<div class="line number3 index2 alt2"><code class="csharp plain">{</code></div>
<div class="line number4 index3 alt1"><code class="csharp spaces">    </code><code class="csharp keyword">public</code> <code class="csharp plain">ActionResult Index()</code></div>
<div class="line number5 index4 alt2"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number6 index5 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">return</code> <code class="csharp plain">View();</code></div>
<div class="line number7 index6 alt2"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number8 index7 alt1"></div>
<div class="line number9 index8 alt2"><code class="csharp spaces">    </code><code class="csharp plain">[Authorize(Roles = </code><code class="csharp string">"IBusiness"</code><code class="csharp plain">)]</code></div>
<div class="line number10 index9 alt1"><code class="csharp spaces">    </code><code class="csharp keyword">public</code> <code class="csharp plain">ActionResult Add()</code></div>
<div class="line number11 index10 alt2"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number12 index11 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">return</code> <code class="csharp plain">View();</code></div>
<div class="line number13 index12 alt2"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number14 index13 alt1"></div>
<div class="line number15 index14 alt2"><code class="csharp spaces">    </code><code class="csharp plain">[Authorize(Roles = </code><code class="csharp string">"IApproval"</code><code class="csharp plain">)]</code></div>
<div class="line number16 index15 alt1"><code class="csharp spaces">    </code><code class="csharp keyword">public</code> <code class="csharp plain">ActionResult Approval()</code></div>
<div class="line number17 index16 alt2"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number18 index17 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">return</code> <code class="csharp keyword">this</code><code class="csharp plain">.View();</code></div>
<div class="line number19 index18 alt2"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number20 index19 alt1"></div>
<div class="line number21 index20 alt2"><code class="csharp plain">}</code></div>
<div class="line number21 index20 alt2">
 最后在Global.asax中添加验证。
</div>
<div class="line number21 index20 alt2">
<div class="container">
<div class="line number1 index0 alt2"><code class="csharp color1">/// &lt;summary&gt;</code></div>
<div class="line number2 index1 alt1"><code class="csharp color1">/// 构造方法</code></div>
<div class="line number3 index2 alt2"><code class="csharp color1">/// &lt;/summary&gt;</code></div>
<div class="line number4 index3 alt1"><code class="csharp keyword">public</code> <code class="csharp plain">MvcApplication()</code></div>
<div class="line number5 index4 alt2"><code class="csharp plain">{</code></div>
<div class="line number6 index5 alt1"><code class="csharp spaces">    </code><code class="csharp plain">AuthorizeRequest += </code><code class="csharp keyword">new</code> <code class="csharp plain">EventHandler(Application_AuthenticateRequest);</code></div>
<div class="line number7 index6 alt2"><code class="csharp plain">}</code></div>
<div class="line number8 index7 alt1"></div>
<div class="line number9 index8 alt2"><code class="csharp keyword">protected</code> <code class="csharp keyword">void</code> <code class="csharp plain">Application_AuthenticateRequest(Object sender, EventArgs e)</code></div>
<div class="line number10 index9 alt1"><code class="csharp plain">{</code></div>
<div class="line number11 index10 alt2"><code class="csharp spaces">    </code><code class="csharp plain">HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];</code></div>
<div class="line number12 index11 alt1"><code class="csharp spaces">    </code><code class="csharp keyword">if</code> <code class="csharp plain">(authCookie == </code><code class="csharp keyword">null</code> <code class="csharp plain">|| authCookie.Value == </code><code class="csharp string">""</code><code class="csharp plain">)</code></div>
<div class="line number13 index12 alt2"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number14 index13 alt1"><code class="csharp spaces">        </code><code class="csharp keyword">return</code><code class="csharp plain">;</code></div>
<div class="line number15 index14 alt2"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number16 index15 alt1"><code class="csharp spaces">    </code><code class="csharp plain">FormsAuthenticationTicket authTicket = </code><code class="csharp keyword">null</code><code class="csharp plain">;</code></div>
<div class="line number17 index16 alt2"><code class="csharp spaces">    </code><code class="csharp keyword">try</code></div>
<div class="line number18 index17 alt1"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number19 index18 alt2"><code class="csharp spaces">        </code><code class="csharp plain">authTicket = FormsAuthentication.Decrypt(authCookie.Value);</code></div>
<div class="line number20 index19 alt1"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number21 index20 alt2"><code class="csharp spaces">    </code><code class="csharp keyword">catch</code></div>
<div class="line number22 index21 alt1"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number23 index22 alt2"><code class="csharp spaces">        </code><code class="csharp keyword">return</code><code class="csharp plain">;</code></div>
<div class="line number24 index23 alt1"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number25 index24 alt2"><code class="csharp spaces">    </code><code class="csharp keyword">string</code><code class="csharp plain">[] roles = authTicket.UserData.Split(</code><code class="csharp keyword">new</code> <code class="csharp keyword">char</code><code class="csharp plain">[] { </code><code class="csharp string">','</code> <code class="csharp plain">});</code></div>
<div class="line number26 index25 alt1"><code class="csharp spaces">    </code><code class="csharp keyword">if</code> <code class="csharp plain">(Context.User != </code><code class="csharp keyword">null</code><code class="csharp plain">)</code></div>
<div class="line number27 index26 alt2"><code class="csharp spaces">    </code><code class="csharp plain">{</code></div>
<div class="line number28 index27 alt1"><code class="csharp spaces">        </code><code class="csharp plain">Context.User = </code><code class="csharp keyword">new</code> <code class="csharp plain">System.Security.Principal.GenericPrincipal(Context.User.Identity, roles);</code></div>
<div class="line number29 index28 alt2"><code class="csharp spaces">    </code><code class="csharp plain">}</code></div>
<div class="line number30 index29 alt1"><code class="csharp plain">}</code></div>
<div class="line number30 index29 alt1">

 

 

 代码下载:AuthorizationPro.zip

(注:由于dll太多,文件压缩过大,已将demo中dll包删除)

在现实面前所有的抱怨都是矫情

mikel阅读(1947)

没有面对现实的勇气,就不要抱怨不公平,还要找那么多理由,自己的问题自己解决,抱怨无济于事。

没有什么解决不了的问题,总会有办法过去,勇敢面对吧!

别指望别人能够代替你去承受和面对这些问题,只有自己咬牙坚持面对,相信明天会更好。

在现实面前所有的抱怨都是矫情。

[转载]这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑) - asxinyu - 博客园

mikel阅读(978)

来源: [转载]这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑) – asxinyu – 博客园

    在上个月发表的一篇文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧 ,得到了很多朋友的响应。同时也有很多朋友直接进行使用,反应非常棒,虽然不是每一个都用得上,只要有一个用得上,其实也不错了,其他的就留着收藏,以后 说不定用得上。最近再次整理一些比较实用的.NET开源组件,如果大家有兴趣,下个月再整理2篇,分别是比较大型的和算法方面的。还是发老样子,每次精选 15个我个人认为还比较有用,而且平时曝光度不高的。

  注 意,本文所列出的.NET开源组件都是功能比较实用,但日常中曝光度比较少的,很多大家都知道的项目,我也没必要再发出来了。可能部分已经放弃更新了,但 并不能说就不能用了,对于新手来说,可以是一个学习的过程,同时很多小功能组件,并不需要多长久的更新,稳定就行了。

.NET开源目录:http://www.cnblogs.com/asxinyu/p/4329755.html

本文原文地址:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)

1.FluentValidation验证组件

FluentValidation是一个使用Linq表达式,非常流畅的小型业务对象验证组件。流畅也可以说优雅。类似链式操作。易于理解,功能完善。还可以配合MVC使用直接在页面进行验证,当你看到它的语法时,非常优雅,非常令人心动。看如下官网提供的一段验证代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
using FluentValidation;
public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
    RuleFor(customer => customer.Surname).NotEmpty();
    RuleFor(customer => customer.Forename).NotEmpty()
        .WithMessage("Please specify a first name");
    RuleFor(customer => customer.Discount).NotEqual(0)
        .When(customer => customer.HasDiscount);
    RuleFor(customer => customer.Address).Length(20, 250);
    RuleFor(customer => customer.Postcode).Must(BeAValidPostcode)
        .WithMessage("Please specify a valid postcode");
  }
  private bool BeAValidPostcode(string postcode) {
    //custom postcode validating logic goes here
  }
}
Customer customer = new Customer();
CustomerValidator validator = new CustomerValidator();
ValidationResult results = validator.Validate(customer);
bool validationSucceeded = results.IsValid;
IList<ValidationFailure> failures = results.Errors;

不仅可以使用Linq的操作,还能自带验证返回信息。更重要的是,组件内部已经封装好了10几种验证器。当然可以自定义一个复杂的哦。核心dll文件也不大,130多k。如果好用,可以自己移植到自己的系统哦。直接更好。

官方网站https://github.com/JeremySkinner/FluentValidation

NuGet Packages:Install-Package FluentValidation

ASP.NET MVC集成包:Install-Package FluentValidation.MVC5

2.Expression Evaluator表达式计算

Expression Evaluator是一个轻量级的可以在运行时解析C#表达式的开源免费组件。表达式求值应该在很多地方使用,例如一些工资或者成本核算系统,就需要在后台动态配置计算表达式,从而进行计算求值。本文曾在【原创】.NET开源表达式计算组件介绍与使用一文中介绍过一个.NET平台开源的表达式计算组件NCal。不过经过比较还是这个Expression Evaluator比较强大,虽然部分功能有重叠。也都能计算常规的数学表达式。

Expression Evaluator支持的特性有:

支持算术运算符,支持关系运算符,以及逻辑运算符

支持表达式分组和括号,以及递增递减运算符

支持表达式属性访问以及动态类型,支持字符串的+运算

支持数值类型的后缀d/f/m/l/u/ul、

支持隐式表达式,以及成员访问操作符(.)

支持一些默认的类型,如double, float, char, string, DateTime, Convert, Math

支持foreach循环

。。。等等,更多功能还期待你的使用和发现

简单的数值表达式就不演示了,看一个比较有新意的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class MyClass
{
     public string[] myExternalString;
     public int x;
}
var v = new MyClass();
v.myExternalString = new string[] { "Hello""there""World!" };
v.x = 2;
//关键点,注册符号v
registry.RegisterSymbol("v", v);
//动态计算属性
//返回结果是"there",因为v.x=2,2/2=1,所以返回索引1的值
"v.myExternalString[v.x/2]"

官方网站http://csharpeval.codeplex.com/

3..NET 基础类库

几乎每个搞.NET的人都多多少少会积累自己的常规基础类库,比如XXhelp,XXUntil之类的。都是一些简单功能的封装。同样开源的基础类库也很多,这里就介绍几个,按需选择,不一定都要用,可以提取部分出来给自己用了。

3.1 Craig’s Utility Library

功能性的基类。已经包装得很完善,可以安装单个命名空间的包。例如官方列出了:

1
2
3
4
5
6
7
DataTypes: Install-Package CraigsUtilityLibrary-DataTypes
LDAP: Install-Package CraigsUtilityLibrary-LDAP
SQL: Install-Package CraigsUtilityLibrary-SQL
Encryption: Install-Package CraigsUtilityLibrary-Encryption
Caching: Install-Package CraigsUtilityLibrary-Caching
Math: Install-Package CraigsUtilityLibrary-Math
Validation: Install-Package CraigsUtilityLibrary-Validation

。。。。。。。。。

包括了数据类型转换,加密,Web,ORM,压缩,缓存,数学计算,文件格式,随机数,反射,IOC,验证等基础功能模块。自己去看看了,太多了,一时半会不一定都用得上。

官方网站:https://github.com/JaCraig/Craig-s-Utility-Library

3.2 .NET Extensions

顾名思义就是.NET的扩展类库了。核心功能包括对现有.NET命名空间的大量扩展方法,如:

1
2
3
4
5
6
7
8
9
10
System.Array,
System.Collections.Generic.ICollection<T>,
System.Collections.Generic.IEnumerable<T>,
System.Data.DataRow,
System.Data.DataRowView,
System.Data.IDataReader,
System.DateTime,
System.DateTimeOffset,
System.Dictionary,
System.Exception,

。。。。。。

都是细节性的,就不过多的描述了,自己看吧。

官方网站:http://dnpextensions.codeplex.com/

3.3 C# Developer Utility Library

这个开发人员工具库功能模块也很上面的差别多,有集合,配置,加密,IO,网络,反射,序列化,文本,Web, 验证,日期等的封装。

官方网站:http://scrimpnet.codeplex.com/

4.PDFsharp & MigraDoc

生成PDF文件格式的文档,大家肯定有想过,很多人项目中也肯定用过,方法、组件肯定有很多。由于以前只是了解,并不实际操作,所以也不过多关 注,偶然看到一款开源的操作PDF文件的类库,比较感兴趣,花了点时间看看官方网站的说明,资料都比较齐全,所以推荐一下,以后有时间会写篇文章具体介绍 一下。

PDFSharp组件主要特点有:
1.可以使用任何.NET编程语言动态创建PDF文档
2.很容易使用对象模型来构建文档
3.全部用C#重写设计和编写代码
4.可以生成PDF文件和显示在窗体或者打印,都使用同一源文件
5.可以修改、合并或者分割PDF文件
6.可以控制图片的透明度,嵌入了字体

官方网站:http://www.pdfsharp.net/(X(1)S(dokpp5uzvpyo5mdcr0pwadxu))/MainPage.ashx

5.Chaow Framework

Chaow Framework准确来说,也是一个开发人员基础工具箱,只不过我认为和3中介绍的几个有稍微的区别,这个主要是体现在写法上,扩展方法的使用更加优雅。如果你认为和上面3中介绍的一样,其实也无可厚非,看看它的几个简单例子,管中窥豹吧。

1
2
3
4
5
6
var matchQuery = new {
    BirthDate = 1.January(2000),//创建日期
    Iam = Sex.Man,
    LookingFor = Array.Enum<Sex>(), //创建性别枚举类型
    AgeRange = 18.To(25)            //创建数值范围
}

函数式编程方法:

1
2
3
4
5
Func<intint> fibo = null;
fibo = x => fibo(x - 1) + fibo(x - 2);
fibo = fibo.When(x => x <= 1, x => x); 
fibo = fibo.Memoize();                 
var result = fibo(38);

还有诸如排列组合生成,集合运算相关的扩展方法。

官方网站:http://chaow.codeplex.com/

6.JavaScript.NET

JavaScript.NET是一个将Google V8 Javascript引擎集成和引入到CLI环境的工具,它可以在运行的过程中,使用C#代码来执行JavaScript代码。威力强不强大,还是看代码吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
using (JavascriptContext context = new JavascriptContext())
{
    //设置参数
    context.SetParameter("console"new SystemConsole());
    context.SetParameter("message""Hello World !");
    context.SetParameter("number", 1);
    //JS 脚本
    string script = @"
        var i;
        for (i = 0; i < 5; i++)
            console.Print(message + ' (' + i + ')');
        number += i;
    ";
    //执行脚本
    context.Run(script);
    // 获取参数值
    Console.WriteLine("number: " + context.GetParameter("number"));
}

官方网站:https://github.com/JavascriptNet/Javascript.Net

7.ClearScript

ClearScript的功能和上面的Javascript.NET 是类似的,不仅可以动态的在.NET应用程序中添加JavaScript脚本,还可以添加C#脚本,相当于动态执行C#代码,当然这样的功能组件在前面一 篇文章也介绍过,这个组件支持Google的 V8, 微软的JScript 和 VBScript引擎。功能同样也不含糊,看代码,由于js是本人的硬伤,不多说了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using Microsoft.ClearScript;
using Microsoft.ClearScript.V8;
//创建引擎
using (var engine = new V8ScriptEngine())
{
    engine.AddHostType("Console"typeof(Console));
    engine.Execute("Console.WriteLine('{0} is an interesting number.', Math.PI)");
    engine.AddHostObject("random"new Random());
    engine.Execute("Console.WriteLine(random.NextDouble())");
    engine.AddHostObject("lib"new HostTypeCollection("mscorlib""System.Core"));
    engine.Execute("Console.WriteLine(lib.System.DateTime.Now)");
    engine.Execute("person = { name: 'Fred', age: 5 }");
    Console.WriteLine(engine.Script.person.name);
}

官方网站:http://clearscript.codeplex.com/

8.SharpKit代码转换

这货是一个将C#代码转换为JavaScript代码的开源工具,虽然是和.net平台应用有点相反,但总归是一个奇葩角色,感觉很有意思,没玩过。。。那天实在要写js代码了,用它试试看。

官方网站:http://sharpkit.net/

9.NAudio音频处理

NAudio是一个.NET平台开源的音频和MIDI程序库,包括大量音频 处理相关.NET功能模块,可以加速开发。一直在程序更新中。目前有大量的成熟软件使用了NAudio,例如下面一些软件或者开源项目都有用到,所以应该 很成熟,下面一些组件本身也是开源的,可以进行学习和使用参考:

  • Skype Voice Changer – Modify your voice with audio effects while talking on Skype
  • .NET Voice Recorder – Record your voice, save to MP3, and visualise the waveform using WPF.
  • Pree – Record spoken word without the need for editing.
  • Q2Cue – application for running audio cues in a theatrical or other performance related settings
  • TuneBlade – Stream Windows’ audio to AirPlay receivers
  • Teachey Teach – utility to help English language conversation teachers generate feedback for students
  • Sound Mill – an audio player, list organizer and automation manager
  • SIPSorcery – .NET softphone framework
  • Squiggle – A free open source LAN Messenger
  • Helix 3D toolkit – Multi-format audio player
  • airphone-tv – A revival of axStream to implement control through the iPhone
  • JamNet – a Silverlight drum sample player
  • Jingle Jim – Jingle Software (German language)
  • All My Music
  • iSpy – Open Source Camera Security Software
  • RadioTuna – Online internet radio player
  • Fire Talk New – chat program
  • AVR Audio Guard – utility to fix a HDMI related issue

官方网站:http://github.com/naudio/NAudio

10.Software Protector序列号生成

说简单的,这个东西就是序列号生成器,用来保护应用程序的授权的。可以生成和验证不同类型的序列号(20位),能限制时间(最多999天),还能够锁定特定机器的key。这个组件是GUI界面,内核使用的是SKGL(Serial Key Generating Library)组件。所以使用的时候还是一起吧,地址如下:

官方网站:http://softwareprotector.codeplex.com/

http://skgl.codeplex.com/

11.Toxy文档信息抽取

Toxy是一个获取数据和文档信息的抽取框架, 支持日常很多常见的格式,如docx, xlsx, xls, pdf, txt, epub, html等等。

有意思的是,这个框架的开发者是Tony Qu,也是大名鼎鼎的NPOI的主要开发者。赞一个,NPOI总的来说非常好用。期待越来越强大,因为互联网的数据除了html之外,还有大量的文档格式,如果快速的检索抽取这些元数据信息,是非常有用的。

这里有一篇作者的介绍文档,看起来很牛逼:http://blog.neuzilla.com/2015/03/02/getstartedwithtoxy/

官方网站:http://toxy.codeplex.com/

12..NET Assembly 信息获取

这个比较简单,是获取.net程序集信息的一个小功能组件。如下面这个图显示的程序集的相关信息:

1.jpg

官方网站:http://assemblyinformation.codeplex.com/


如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。

.NET技术爱好者,彩票分析预测

本文原始作者博客http://www.cnblogs.com/asxinyu

E-mail:1287263703@qq.com

如何选择好的联盟?

mikel阅读(902)

最近提现的会员比较多,对会员的任务情况进行了下统计,基本上很多人都喜欢做短平快的任务,注册就拿钱的那种比较受欢迎,理财类的也是大家追捧的对象。

不过会员赚的high不能说明什么,还要看联盟的质量,所以说选择好的联盟会让体验站更加持续的盈利。

如何选择好的联盟?

首先,联盟的任务要全面,很多都是游戏联盟类的,各个联盟之间的游戏有冲突,有的给的奖励多,有的给的少,所以说选择之前最好参考下其他体验站,毕竟都是同行,特别是那些大站,更加容易比较出来联盟的优劣。

其次,联盟的功能接口对接是否容易,稳定性是关键,很多时候联盟的程序问题多,导致很多会员做了任务没有得到奖励,结果还得自己手动调整让站长们手忙脚乱,会员们怨声载道就得不偿失了。

最后,也是最重要的一点儿就是联盟的提现门槛要低,一般都是20提现,结果很多联盟100元甚至时不时的调高提现门槛,总是给人不舍得给钱的感觉,估计也是店大欺客的原因,人家看不起小的体验站吧!不过没办法,人家门槛那么高,资金回款慢,你的站运营的压力就大了,所以这个才是选择联盟的重点。

其他的就不必多说了,联盟是否扣量;是否及时发放奖励;对刷量的处理制度等等都是选择接入联盟前要了解的。

 

[转载][OSGi]OSGi 基本原理 - VictorZhang - 博客园

mikel阅读(781)

来源: [转载][OSGi]OSGi 基本原理 – VictorZhang – 博客园

回到顶部

定义


OSGi(Open Service Gateway Initiative)技术是面向Java的动态模型系统。

这个框架实现了一个优雅、完整和动态地组价模型。应用程序(称为bundle)无序重新引导可以被远程安装、启动、升级和卸载。

OSGi服务平台提供在多种网络设备上无需重启的动态改变构造的功能。

为了最小化耦合度和促使这些耦合度可管理,OSGi技术提供一种面向服务的架构,它能使这些组件动态地发现对方。

OSGi联盟已经开发了例如像HTTP服务器、配置、日志、安全、用户管理、XML等很多公共功能标准组件接口。这些组件的兼容性插件实现可以从进行了不同优化和使用代价的不同计算机服务提供商得到。然而,服务接口能够基于专有权基础上开发。

OSGi的主要职责就是为了让开发者能够创建动态化、模块化的Java系统。

 

回到顶部

OSGi 框架


OSGi框架从概念上可以分为三层:模块层、生命周期层和服务层。

  • Module Layer:模块层主要涉及包及共享的代码;
  • Lifecycle Layer:生命周期层主要涉及Bundle的运行时生命周期管理;
  • Service Layer:服务层主要涉及模块之间的交互和通信。
图 1. OSGi 层次结构

 

回到顶部

模块层


模块层是 OSGi 框架中最基础的部分。

OSGi 的模块化,是通过为 Jar 包添加metadata 来定义哪些类该暴露,哪些类该隐藏,其控制单元叫做 Bundle(jar 包)。

Bundle

首先,必须先了解一个基本概念——什么是Bundle?

什么是 Bundle ?
bundle 是以 jar 包形式存在的一个模块化物理单元,里面包含了代码,资源文件和元数据(metadata),并且jar包的物理边界也同时是运行时逻辑模块的封装边界。
bundle

如何定义 Bundle

Bundle 是 OSGi 中的基本组件,其表现形式仍然为 Java 概念中传统的 Jar 包。
通过 META-INF 目录下的 MANIFEST.MF 文件对其予以进一步的定义。

通常一个 MANIFEST.MF 文件的内容如下:

复制代码
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Util
Bundle-SymbolicName: com.ibm.director.la.util
Bundle-Version: 1.0.0
Bundle-RequiredExecutionEnvironment: J2SE-1.5
Import-Package: org.osgi.framework;version=”1.3.0″
Export-Package: com.ibm.director.la.util;uses:=”org.osgi.framework”
Bundle-ClassPath: lib/junit.jar,
复制代码

MANIFEST.MF 文件存储的实际上是 Bundle 的元数据。

元数据的内容可以精确的定义 Bundle 的各种特征,同时能更好的对 Bundle 进行标识同时帮助用户对Bundle进行理解。

 

回到顶部

生命周期层


生命周期层在OSGi框架中属于模块层上面的一层,它的运作是建立在模块层的功能之上的。
生命周期层的主要功能是控制动态安装、开启、关闭、更新和卸载的bundles。

生命周期层让你能够从外部管理应用或者建立能够自我管理的应用(或者两者的结合),并且给了应用本身很大的动态性。

前面已经了解了 Bundle 的概念和作用。但是要真正使用 Bundle,需要使用生命周期层的API,来和OSGi框架的生命周期层进行交互。

在 标准的Java编程中,可以通过将jar包放到classpath中来使用它。而bundle则不是这样,Bundle只有在被安装(install)到 一个OSGi框架的运行实例中才能用起来。并且OSGi框架支持对这些bundle完整的生命周期管理,并且支持这些管理操作在应用执行完成。

下图为 Bundle 生命周期的状态转移图:

 

http://www.mikel.cn/wp-content/uploads/2015/06/lifecycle2.png

 

重要接口

生命周期层的API主要是由以下三个核心接口来组成的:BundleActivator,BundleContext 和 Bundle。

  • BundleActivator:让你能够捕捉bundle的start和stop事件,并对这两个事件作出自定义的反应。
  • BundleContext:一个bundle在框架中的执行时上下文,这个上下文提供了和框架进行交互的方法。
  • Bundle:在逻辑上表示了一个bundle,OSGi环境中的一个物理bundle对应了一个bundle对象。该对象中包含了bundle的基本信息和bundle生命周期的控制接口。

 

回到顶部

服务层


一个OSGi 服务就是注册到 OSGi 框架中的一个 Java 对象。注册的时候可以设置这个 Service 的属性。而在获取 Service的时候可以根据属性进行过滤。

Bundle 可以通过 Bundle的上下文去注册Service或去查询Service。

一个提供服务的bundle可以发布POJO作为服务的实体;一个使用服务的bundle可以通过这个注册表找到和绑定服务。

http://www.mikel.cn/wp-content/uploads/2015/06/service1.png

 

发布服务

为了让别的bundle能发现这个服务,你必须在发布它之前对其进行特征描述。这些特征包括接口的名字(可以是名字的数组),接口的实现,和一个可选的java.util.Dictionary类型的元数据信息。

复制代码
String[] interfaces =  new String[]{StockListing.class.getName(), StockChart.class.getname()};
Dictionary metadata =  new Properties();
metadata.setProperty(“name”, “LSE”);
metadata.setProperty(“currency”, Currency.getInstance(“GBP”));
metadata.setProperty(“country”, “GB”);
ServiceRegistration registration = bundleContext.registerService(interfaces, new LSE(), metadata);
复制代码
在上面的代码中,我们得到了 ServiceRegistration 对象,我们可以用这个对象来更新服务的元数据:

registration.setProperties(newMetadata);

也可以直接就把这个服务移除:

registration.unregister();

需要注意的是这个对象不能和其他 Bundle 共享,因为它和发布服务的bundle的生命周期相互依存。

也就是说,如果这个 Bundle 已经不在框架执行环境中存在,那么这个对象也不应该存在了,“皮之不存毛将焉附”就是这个道理。

试 想如果这个 ServiceRegistration 共享给了其他的 bundle(具体的说就是其他bundle中存在对这个对象的引用),那么发布服务的那个bundle即使被移除了,由于其他bundle中的引用依然 存在,那么垃圾处理机制不会抹去这个对象,这样不但于理不合,而且实际上这个对象也是不可用的,因为这个对象所依存的bundle已经不在了。
代码中的参数new LSE()是一个POJO,这个对象不需要实现任何OSGi类型或者使用标注,只要满足服务约定(这里就是接口)就可以了。

此外,如果在删除发布的服务之前bundle停止了,框架会帮助你删除这些服务。

 

发现和绑定服务

以下是一个根据实现的接口名称获得的服务的最简单方法:
ServiceReference reference =
bundleContext.getServiceReference(StockListing.class.getName());

注意这里的reference是服务对象的间接引用,可是为什么要用间接引用而不直接返回那个实际的服务对象呢?

实际上是为了将服务的使用和服务的实现进行解耦,将服务注册表作为两者的中间人,达到跟踪和控制服务的目的,同时还可以在服务消失了以后通知使用者。

这个方法的返回类型是ServiceReference,它可以在bundle之间互享,因为它和使用服务的bundle的生命周期无关。

回到顶部

参考资料


OSGi入门篇:模块层

OSGi入门篇:生命周期层

OSGi入门篇:服务层

OSGi原理与最佳实践

以不变应万变

mikel阅读(799)

要想设计好的架构以不变应万变,就要权衡复杂度和需求之间的利弊,避免过渡设计,又要应对业务需求的变化,这是个矛盾的问题。

对于架构来说,很多时候就好比游走在独木桥上,设计不好,就有落河的危险。也不必听了这些觉得架构设计是个神秘并且步步惊心的工作,架构不能一次设计好的,也是随着变化而变化的,不断的重构和迭代升级。

架构设计只能出现最适合的,不会出现万能的。就好比人无完人一样,总追求完美的系统是做不到的,总是会难预料未来的需求怎么样

[转载]解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑 - 汤姆大叔 - 博客园

mikel阅读(1063)

来源: [转载]解读ASP.NET 5 & MVC6系列(16):自定义View视图文件查找逻辑 – 汤姆大叔 – 博客园

之前MVC5和之前的版本中,我们要想对View文件的路径进行控制的话,则必须要对IViewEngine接口的FindPartialViewFindView方法进行重写,所有的视图引擎都继承于该IViewEngine接口,比如默认的RazorViewEngine。但新版本MVC6中,对视图文件的路径方式却不太一样了,目前有两种方式,一种是通过RazorViewEngine,另外一种是通过新特性IViewLocationExpander接口。

通过RazorViewEngine来控制View路径

在新版的RazorViewEngine中,该类提供了两个虚属性(AreaViewLocationFormatsViewLocationFormats),可以用于重写控制,而不必再对FindPartialViewFindView方法进行重写,示例如下:

<pre class="csharp"><code class="hljs cs"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ThemeViewEngine</span> : <span class="hljs-title">RazorViewEngine</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">ThemeViewEngine</span><span class="hljs-params">(IRazorPageFactory pageFactory,
        IRazorViewFactory viewFactory,
        IViewLocationExpanderProvider viewLocationExpanderProvider,
        IViewLocationCache viewLocationCache)</span>
        : <span class="hljs-title">base</span><span class="hljs-params">(pageFactory,
                viewFactory,
                viewLocationExpanderProvider,
                viewLocationCache)</span>
    </span>{
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> IEnumerable&lt;<span class="hljs-keyword">string</span>&gt; AreaViewLocationFormats
    {
        <span class="hljs-keyword">get</span>
        {
            <span class="hljs-keyword">var</span> <span class="hljs-keyword">value</span> = <span class="hljs-keyword">new</span> Random().Next(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>);
            <span class="hljs-keyword">var</span> theme = <span class="hljs-keyword">value</span> == <span class="hljs-number">0</span> ? <span class="hljs-string">"Theme1"</span> : <span class="hljs-string">"Theme2"</span>;  <span class="hljs-comment">// 可通过其它条件,设置皮肤的种类</span>
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">base</span>.AreaViewLocationFormats.Select(f =&gt; f.Replace(<span class="hljs-string">"/Views/"</span>, <span class="hljs-string">"/Views/"</span> + theme + <span class="hljs-string">"/"</span>));
        }
    }

    <span class="hljs-keyword">public</span> <span class="hljs-keyword">override</span> IEnumerable&lt;<span class="hljs-keyword">string</span>&gt; ViewLocationFormats
    {
        <span class="hljs-keyword">get</span>
        {
            <span class="hljs-keyword">var</span> <span class="hljs-keyword">value</span> = <span class="hljs-keyword">new</span> Random().Next(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>);
            <span class="hljs-keyword">var</span> theme = <span class="hljs-keyword">value</span> == <span class="hljs-number">0</span> ? <span class="hljs-string">"Theme1"</span> : <span class="hljs-string">"Theme2"</span>;  <span class="hljs-comment">// 可通过其它条件,设置皮肤的种类</span>
            <span class="hljs-keyword">return</span> <span class="hljs-keyword">base</span>.ViewLocationFormats.Select(f =&gt; f.Replace(<span class="hljs-string">"/Views/"</span>, <span class="hljs-string">"/Views/"</span> + theme + <span class="hljs-string">"/"</span>));
        }
    }
}

然后,通过修改MVcOptions的实例属性ViewEngines即可完成对视图引擎的替换,代码如下:

</code></pre>
<pre class="csharp"><code class="hljs cs">services.AddMvc().Configure&lt;MvcOptions&gt;(options =&gt;
{
    options.ViewEngines.Clear();
    options.ViewEngines.Add(<span class="hljs-keyword">typeof</span>(ThemeViewEngine));
});

这样,系统在查找视图文件的时候,就会按照新注册的ThemeViewEngine的逻辑来执行。

通过IViewLocationExpander来控制View路径

在MVC6中,微软还提供了另外一种新的方式来控制View文件的路径,那就是IViewLocationExpander接口,通过实现该接口即可实现自定义逻辑,并且也可以使用相关的上下文对象。示例如下:

<pre><code class="hljs cs"><span class="hljs-keyword">public</span> <span class="hljs-keyword">class</span> <span class="hljs-title">ThemeViewLocationExpander</span> : <span class="hljs-title">IViewLocationExpander</span>
{
    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">PopulateValues</span><span class="hljs-params">(ViewLocationExpanderContext context)</span>
    </span>{
        <span class="hljs-keyword">var</span> <span class="hljs-keyword">value</span> = <span class="hljs-keyword">new</span> Random().Next(<span class="hljs-number">0</span>, <span class="hljs-number">1</span>);
        <span class="hljs-keyword">var</span> theme = <span class="hljs-keyword">value</span> == <span class="hljs-number">0</span> ? <span class="hljs-string">"Theme1"</span> : <span class="hljs-string">"Theme2"</span>;
        context.Values[<span class="hljs-string">"theme"</span>] = theme;
    }

    <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">virtual</span> IEnumerable&lt;<span class="hljs-keyword">string</span>&gt; <span class="hljs-title">ExpandViewLocations</span><span class="hljs-params">(ViewLocationExpanderContext context,
                                                            IEnumerable&lt;<span class="hljs-keyword">string</span>&gt; viewLocations)</span>
    </span>{
        <span class="hljs-keyword">return</span> viewLocations.Select(f =&gt; f.Replace(<span class="hljs-string">"/Views/"</span>, <span class="hljs-string">"/Views/"</span> + context.Values[<span class="hljs-string">"theme"</span>] + <span class="hljs-string">"/"</span>));
    }
}

在上述自定义的IViewLocationExpander中,实现了2个方法分别是PopulateValuesExpandViewLocationsPopulateValues方法可以让我们想ViewLocationExpanderContext上下文中添加响应的键值对以便后续使用,通过,我们可以利用通过该上下文对象,来查找ActionContextHttpContext对象,以便利用这些对象做响应的判断操作;而ExpandViewLocations方法,只会在没有View缓存或在View缓存里找不到对应key的View文件时才会调用该方法,在该方法内,我们可以动态返回视图的位置。

最后,我们在Startup.cs里通过修改RazorViewEngineOptions实例对象的ViewLocationExpanders属性,来实现注册目的,代码如下:

<pre class="csharp"><code class="hljs cs">services.Configure&lt;RazorViewEngineOptions&gt;(options =&gt;
{
    options.ViewLocationExpanders.Add(<span class="hljs-keyword">typeof</span>(ThemViewLocationExpander));
});

同步与推荐

本文已同步至目录索引:解读ASP.NET 5 & MVC6系列

 
 
 

[转载]ASP.NET MVC随想录——漫谈OWIN - 木宛城主 - 博客园

mikel阅读(785)

来源: [转载]ASP.NET MVC随想录——漫谈OWIN – 木宛城主 – 博客园

回到顶部

什么是OWIN

OWIN是Open Web Server Interface for .NET的首字母缩写,他的定义如下:

OWIN在.NET Web Servers与Web Application之间定义了一套标准接口,OWIN的目标是用于解耦Web Server和Web Application。基于此标准,鼓励开发者开发简单、灵活的模块,从而推进.NET Web Development开源生态系统的发展。

正如你看到的这样,OWIN是接口、契约,而非具体的代码实现,仅仅是规范(specifications),所以要实现自定义基于OWIN的Web Server必须要实现此规范。

历时两年(2010-2012),OWIN的规范终于完成并且当前版本是1.0,在OWIN的官网上可以看到更具体的信息。

回到顶部

为什么我们需要OWIN

过去,IIS作为.NET 开发者来说是最常用的Web Server(没有之一),源于微软产品的紧耦合关系,我们不得不将Website、Web Application、Web API等部署在IIS上,事实上在2010年前并没有什么不妥,但随着近些年来Web的发展,特别是移动互联网飞速发展,IIS作为Web Server已经暴露出他的不足了。主要体现在两个方面,ASP.NET (System.Web)紧耦合IIS,IIS紧耦合OS,这就意味着,我们的Web Framework必须部署在微软的操作系统上,难以跨平台

ASP.NET 和 IIS

我们知道,不管是ASP.NET MVC 还是ASP.NET WEB API 等都是基于ASP.NET Framework的,这种关系从前缀就可以窥倪出来。而ASP.NET的核心正是System.Web这个程序集,而且System.Web紧耦合IIS,他存在于.NET Framework中。所以,这导致了Web Framework严重的局限性:

  • ASP.NET 的核心System.Web,而System.Web紧耦合IIS
  • System.Web 是.NET Framework重要组成,已有15年以上历史,沉重、冗余,性能差,难于测试,约2.5M
  • System.Web要更新和发布新功能必须等待.NET Framework发布
  • .但NET Framework是Windows的基础,往往不会随意更新。

所以要想获取最新的Web Framework是非常麻烦的,幸运的事,微软已经意识到了问题的严重性,最新的Web Framework都是通过Nuget来获取。

当然这是一部分原因,还有一层原因是ASP.NET & IIS实在太过于笨重,如何讲呢?

复杂的生命周期已成为累赘?简单来说,当请求到达服务器时,Windows内核组件HTTP.SYS组件捕获请求,他会分析请求并决定是否交给IIS来处理,当请求到达IIS之后,IIS会根据处理程序映射来匹配请求并交给对应的程序集(实现了ISAPI接口,比如我们熟知的aspnet_isapi.dll是专门用来处理ASP.NET Application)处理,最后加载了CLR运行环境,将请求交给aspnet_wp.exe去处理,这时复杂的ASP.NET生命周期往往令人头大,但事实上有很多时候我们并不需要他。

如下图所示ASP.NET Architecture:

打开IIS,你会发现他提供了非常丰富的功能:缓存、身份验证、压缩、加密等。但随着移动互联网蓬勃的发展,特别是HTML 5越来越成熟的今天,我们看到越来越多的操作发生在客户端,而不是沉重的从服务器产生HTML返回,更多的是通过异步AJAX返回原生的数据。同理,对于 APP来说我们只需要Mobile Service返回数据。显然IIS显得笨重了点,而且IIS作为微软产品系的一环,耦合程度太高。所以我们迫切需要轻量、快速、可扩展的宿主来承载Web Application和Web Service。

IIS 和 OS

IIS必须是安装并运行在Windows操作系统中,这是微软产品的一贯风格,环环相套,但不得不考虑他们的限制和局限性:

  • IIS往往和操作系统(Windows Server)绑定在一起,这意味着对于一些新功能如WebSocket Protocol ,我们不得不等待操作系统Windows Sever 2012、Windows 8的发布(IIS 8.0)。
  • 为了使用WebSocket这类新特性,他仅被IIS 8.0支持,如下所示:

这时你不得不去升级IIS,但升级操作系统可能会引发旧系统的不稳定性,所以要想平稳的升级IIS并不是简单的。

  • IIS作为经典的Web Server必须安装在Windows系统中,Windows Server需要授权使用。

正是由于微软产品系紧耦合的关系,才造成跨平台上的不足,这也是被饱受诟病。所以我们需要OWIN来解耦,在面向对象的世界里,接口往往是解耦的关键,如下图所示:

使用OWIN,Web Framework不再依赖IIS和OS,这意味着你能使用任何你想的来替换IIS(比如:Katana或者Nowin),并且在必要时随时升级,而不是更新操作系统。当然,如果你需要的话,你可以构建自定义的宿主和Pipeline去处理Http 请求。

这一切的改变都是由于OWIN的出现,他提供了明晰的规范以便我们快速灵活的去扩展Pipeline来处理Http请求,甚至可以不写任何一句代码来切换不同的Web Server,前提是这些Web Server 遵循OWIN规范。

回到顶部

OWIN的规范

现在我们已经了解了什么是OWIN已经为什么需要OWIN,现在是时候来分析一下OWIN的规范了。

OWIN Layers

实际上,OWIN的规范非常简单,他定义了一系列的层(Layer),并且他们的顺序是以堆(Stack)的形式定义,如下所示。OWIN中的接口被称之为应用程序委托或者AppFunc,用来在这些层之间通信。

OWIN定义了4层:

Host:主要负责应用程序的配置和启动进程,包括初始化OWIN Pipeline、运行Server。

Server:这是实际的Http Server,绑定套接字并监听的HTTP请求然后将Request和Response的Body、Header封装成符合OWIN规范的字典并发送到OWIN Middleware Pipeline中,最后Application为Response Data填充合适的字段输出。

Middleware:称之为中间件、组件,位于Server与Application之间,用来处理发送到Pipeline中的请求,这类组件可以是简单的Logger或者是复杂的Web Framework比如Web API、SignalR,只要Sever连接成功,Middleware中间件可以是任何实现应用程序委托的组件。

Application:这是具体的应用程序代码,可能在Web Framework之上。对于Web API、SignalR这类Web Framework中间件而言,我们仅仅是改变了他们的托管方式,而不是取代ASP.NET WEB API、SignalR原先的应用程序开发。所以该怎么开发就怎么开发,只不过我们将他们注册到OWIN Pipeline中去处理HTTP 请求,成为OWIN管道的一部分,所以此处的Application即正在意义上的处理程序代码。

Application Delegate

OWIN规范另一个重要的组成部分是接口的定义,用于Server和Middleware的交互。他并不是严格意义上的接口,而是一个委托并且每个OWIN中间件组件必须提供。

从字面上理解,每个OWIN中间件在必须有一个方法接受类型了IDictionary<string,object>的变量(俗称环境字典),然后必须返回Task来异步执行。

Environment Dictionary

环境字典包含了Request、Response所有信息以及Server State。通过Pipeline,每个中间件组件和层都可以添加额外的信息,但环境字典定义了一系列强制必须存在的Key,如下所示:

Request Data:

Required Key Name Value Description
Yes "owin.RequestBody" A Stream with the request body, if any. Stream.Null MAY be used as a placeholder if there is no request body. See Request Body.
Yes "owin.RequestHeaders" An IDictionary<string, string[]> of request headers.  See Headers.
Yes "owin.RequestMethod" string containing the HTTP request method of the request (e.g., "GET""POST").
Yes "owin.RequestPath" string containing the request path. The path MUST be relative to the “root” of the application delegate; see Paths.
Yes "owin.RequestPathBase" string containing the portion of the request path corresponding to the “root” of the application delegate; see Paths.
Yes "owin.RequestProtocol" string containing the protocol name and version (e.g. "HTTP/1.0" or "HTTP/1.1").
Yes "owin.RequestQueryString" string containing the query string component of the HTTP request URI, without the leading “?” (e.g., "foo=bar&baz=quux"). The value may be an empty string.
Yes "owin.RequestScheme" string containing the URI scheme used for the request (e.g., "http""https"); see URI Scheme.

Response Data:

Required Key Name Value Description
Yes "owin.ResponseBody" A Stream used to write out the response body, if any. See Response Body.
Yes "owin.ResponseHeaders" An IDictionary<string, string[]> of response headers.  See Headers.
No "owin.ResponseStatusCode" An optional int containing the HTTP response status code as defined in RFC 2616 section 6.1.1. The default is 200.
No "owin.ResponseReasonPhrase" An optional string containing the reason phrase associated the given status code. If none is provided then the server SHOULD provide a default as described in RFC 2616 section 6.1.1
No "owin.ResponseProtocol" An optional string containing the protocol name and version (e.g. "HTTP/1.0" or "HTTP/1.1"). If none is provided then the“owin.RequestProtocol” key’s value is the default.

Other Data:

Required Key Name Value Description
Yes "owin.CallCancelled" A CancellationToken indicating if the request has been cancelled/aborted. See Request Lifetime.
Yes "owin.Version" The string "1.0" indicating OWIN version. See Versioning.
回到顶部

小结

这些规范看起来可能简单到微不足道,但OWIN的思想就是简单、灵活——通过要求OWIN中间件只依赖AppFun类型,为开发基于OWIN的中间件提供了的最低门槛。同时,通过使用环境字典在各个中间件之间进行信息的传递,而非传统ASP.NET(System.Web)中使用HttpContext贯穿ASP.NET整个生命周期来传递。

既然OWIN是规范,而非真正实现,所以是无法使用在项目中的,若要使用OWIN,必须要实现他,所以这也是接下来我想聊的,OWIN的实现:Katana 。

本博客为木宛城主原创,基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名木宛城主(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。

[转载]ios消息推送--iOS 8.0 后 - Gen_0 - 博客园

mikel阅读(850)

来源: [转载]ios消息推送–iOS 8.0 后 – Gen_0 – 博客园

本文章只提供学习!!

iOS的消息推送(推送通知)有两种,一种是本地推送通知,另一种是远程推送通知。所谓本地推送通知就是使用代码推送消息到用户设备中提醒用户一些信息, 推送形式请查看手机设置。远程推送通知是通过服务器发送消息到用户设备中,iOS的远程推送通知要经过苹果的服务器来推送消息,过程比较麻烦。下面是个人 学习笔记,提供新手学习(当然我也是个新手),不能用于商业用途。

所有的消息推送只在后台或者推出程序才有意义,程序在前台运行的时候是没有意义的,所有发送消息推送的时候请把程序退出或者挂在后台运行才能体现出效果。

一、本地推送通知

以下代码为了更好看到本地推送通知地效果最好写在一个按钮事件中,点击发送通知。


// 1.创建本地推送通知

UILocalNotification *localNotification = [[UILocalNotification alloc] init];

// 2.设置一些属性

// 通知发出的时间(5秒后)

localNotification.fireDate = [NSDate dateWithTimeIntervalSinceNow:5];

// 设置时区(跟随手机的时区)

localNotification.timeZone = [NSTimeZone defaultTimeZone];

// 音乐文件名

localNotification.soundName = @"xxxxx.wav";

// 通知的内容

localNotification.alertBody = @"内容";

// 锁屏界面显示的标题 如下面的写法将显示:滑动来查看内容   格式:"滑动来" + 标题

localNotification.alertAction = @"查看内容"

// 设置app图标数字

localNotification.applicationIconBadgeNumber = 10;

// 设置通知的其他信息

localNotification.userInfo = @{

@"title" : @"好消息"

};//可随意添加

// 设置启动图片

localNotification.alertLaunchImage = @"Default.png";

// 设置重复发出通知的时间间隔

//    localNotification.repeatInterval = NSCalendarUnitMinute;

// 3.发通知

[[UIApplication sharedApplication] scheduleLocalNotification:localNotification];

 

//----------------------------------------------------------

点击发送通知后把程序退出或者挂到后台,等待5秒就会有通知,如果觉得5太长或太短请根据个人需要该上面到代码。

当用户点击通知进入app的时候或者程序运行在前台的时候会在appdelegate中调用下面这个方法

– (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification

如果想当app在前台的时候不做任何事情可以在上面的方法里面最前面加上这句代码:

// 程序正处在前台运行,直接返回

    if (application.applicationState == UIApplicationStateActive) return;

也可以在

– (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中判断是否是点击通知进入app,如下:

</p>
<p class="p1">UILocalNotification *ln = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];

if (ln) {

//点击通知进入app

} else {

//点击app图标进入app

}</p>
<p class="p1">

二、远程推送通知

做远程推送一定要用真机,模拟器不可以。需要到苹果开发者中心配置一些证书,过程比较多,我就不文字描述来了,直接看图片演示过程。

1.首先在钥匙串中配置电脑签名文件

邮件地址一般写公司的就好,选择存储到磁盘,继续。

我就在桌面新建了个叫push到文件夹,点击存储。

2.需要一个AppIDs

(如果在测试阶段已经有了就不需要了,到时候直接用那个就可以,注意:AppIDs一定要是完整的,不能是 xxx.xxx.*  做消息推送一定要是完整的ID),没有就弄一个,过程跟弄测试这书一样。反正做远程消息推送一定要真机测试,在做真机测试的时候已经有AppIDs了, 这个过程就不贴出来了,不会的同学可以先去查看怎么配置真机测试证书。

3.配置一个开发证书

点击加号

选择APNs 然后continue

选择自己应用的AppID   之后continue 继续continue

选择第一步的时候保存证桌面push文件夹中的电脑签名文件

最好我开发证书也保存到push文件夹中,方便管理。

4.接下来配置生产证书

点击production  点击加号

选择production中的APNs  接下来所有的步骤跟配置开发证书一模一样,就不一一贴过程来。

5.这步骤才是最重要的。

点击加号

点击continue

选择你应用的APP ID

选择配置测试的时候生成的这书(本文没说明怎么配置测试证书,不知道请先查看如何配置测试证书)

选择测试设备,全部选择都没关系

按意起个名字就好了点击generate  下载到push文件夹中。

6.安装所有到证书,可以直接拖到我到证书中

导出开发证书

起个名developmentPush,文件格式选择.p12

我这里输入abcd1234,你们随意,记住就行。

接下来也把生产证书导出来,我把名字起为productionPush,密码设置和开发证书一样(只是为了不混淆,不一样也可以),过程一样,就不贴图片了。

到这里就要所有到准备工作做好了,接下来是测试。

测试远程推送时候我是使用极光推送,你们有什么好的开源都可以使用。地址:www.jpush.cn ,注册个用户、登录。

登录上去点击创建应用

只要填写我选中都部分就可以了,开发证书就是developmentPush.p12文件,密码就是自己设置的密码。生产证书就是productionPush.p12文件。

创建好之后会得到一个appkey   要记下来,没记住也没事,在选择应用中点击你添加的应用也可以看到。

然后下载iOS  SDK 地址:www.jpush.cn/common/products#product-sdk

下载好之后把里面的lib文件夹添加到工程中

接着在工程中创建plist文件

名字一定要是PushConfig.plist

点击plist文件

添加三个键值对,内容一定要一样,最后一个就是在极光推送创建应用的Appkey

必要的框架

  • CFNetwork.framework
  • CoreFoundation.framework
  • CoreTelephony.framework
  • SystemConfiguration.framework
  • CoreGraphics.framework
  • Foundation.framework
  • UIKit.framework
  • Security.framework
  • libz.dylib

其中有3个是在创建工程的时候就用了,不需要重复添加

然后在工程中的appdelegate中添加以下代码:

#import “APService.h”

在- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions方法中添加以下代码:

</p>
<p class="p1">// Required

#if __IPHONE_OS_VERSION_MAX_ALLOWED &gt; __IPHONE_7_1

if ([[UIDevice currentDevice].systemVersion floatValue] &gt;= 8.0) {

//可以添加自定义categories

[APService registerForRemoteNotificationTypes:(UIUserNotificationTypeBadge |

UIUserNotificationTypeSound |

UIUserNotificationTypeAlert)

categories:nil];

} else {

//categories 必须为nil

[APService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |

UIRemoteNotificationTypeSound |

UIRemoteNotificationTypeAlert)

categories:nil];

}

#else

//categories 必须为nil

[APService registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge |

UIRemoteNotificationTypeSound |

UIRemoteNotificationTypeAlert)

categories:nil];

#endif

// Required

[APService setupWithOption:launchOptions];</p>
<p class="p1">

//----------------------------------------------------

最后添加以下方法:

</p>
<p class="p5">#pragma mark - 获取DeviceToken

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken {



// Required

[APService registerDeviceToken:deviceToken];

}



- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {



// Required

[APService handleRemoteNotification:userInfo];

}



- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {



// IOS 7 Support Required

[APService handleRemoteNotification:userInfo];

completionHandler(UIBackgroundFetchResultNewData);

}</p>
<p class="p5">

这样就大功告成了,用真机运行你的程序,然后退出程序,或者挂到后台。

这么发送通知呢?在极光推送平台点击你创建的应用,点击推送,发送通知

好了,完成。如果从下载iOS SDK开始就不懂的同学可以查看教程,地址:http://docs.jpush.io/guideline/ios_guide/

 上面整个教程在极光推送平台也有教程。

以上的文章只是我个人学习笔记,有什么错误的地方请不要喷,请您提出来让我改正,写博文不易,请不要乱复制拷贝别人的心得为自己的东西,感谢大家。

[转载]使用Redis实现高并发分布式序列号生成服务 - 浮云-Mignet - 博客园

mikel阅读(1168)

来源: [转载]使用Redis实现高并发分布式序列号生成服务 – 浮云-Mignet – 博客园

序列号的构成

为建立良好的数据治理方案,作数据掌握、分析、统计、商业智能等用途,业务数据的编码制定通常都会遵循一定的规则,一般来讲,都会有自己的编码规则和自增序列构成。比如我们常见的身份证号、银行卡号、社保电脑号等等。

以某公司产品标识码(代表该产品的唯一编码)的构成为例:

规则定义:商品款号(8位)+颜色号(3位)+号型码(3位) (共14位)

其标识码为:62X19001 001 46A

业务含义为: 2009年男装秋冬季仿毛套西黑色170A版

简单来讲,业务编码是由规则和序列构成,规则是允许定义和编辑的,序列通常要求并发安全。整个序列号生成规则要求读写并发安全。

序列号生成方案

由于Redis的高性能,高并发和数据一致性的保证,以及断电数据不丢失,分布式扩展能力等优势。我们采用Redis存储并持久化序列和业务规则来配置和管理整个序列号的产生。

规则定义举例:前缀+时间(YYYYMMDD)+所使用的序列(指定长度),那么产生的序列号类似于SO20150520000124

具体规则可根据实际业务需求来设计。

实现要求:整个生成过程使用Jedis完成,保证原子事务。并通过压力测试。

序列号实现方案

1.         规则配置管理

在Redis的设计中,要想实现比如

select * from users where user.location=”shanghai”

这样的查询,是没办法通过value进行比较得出结果的。但是可以通过不同的数据结构类型来做到这一点。比如如下的数据定义

users:1 {name:Jack,age:28,location:shanghai}

users:2 {name:Frank,age:30,location:beijing}

users:location:shanghai [1]

其中users:1 users:2 分别定义了两个用户信息,通过Redis中的hash数据结构,而users:location:shanghai 记录了所有上海的用户id,通过集合数据结构实现。

这样通过两次简单的Redis命令调用就可以实现我们上面的查询。

Jedis jedis = jedisPool.getResource();

Set<String> shanghaiIDs = jedis.smembers(“users:location:shanghai”); //遍历该set

 //… //通过hgetall获取对应的user信息

jedis.hgetAll(“users:” + shanghaiIDs[0]);

通过诸如以上的设计,可以实现简单的条件查询。但是这样的问题也很多,首先需要多维护一个ID索引的集合,其次对于一些 复杂查询无能为力(当然也不能期望Redis实现像关系数据库那样的查询,Redis不是干这的)。针对本序列号生成方案,这种方式完全是够用的,可以直 接参考本节的代码示例。

如果想更进一步,Redis2.6集成了Lua(Redis是用ANSI C写的,可以想象支持Lua是一件很自然的事),可以通过eval命令,直接在RedisServer环境中执行Lua脚本,就是说可以让你用Lua脚 本,对Redis中存储的key value进行操作,这个意义就大了,甚至可以将系统所需的各种业务写成一个个lua脚本,提前加载进入Redis,然后对于请求的响应,只需要调用一个 个lua脚本就行。(当然这些操作也完全可以使用Jedis来完成,但显然lua效率更高)

比如,现在我们要实现一个‘所有年龄(age)大于28岁的用户(user)’这样一个查询,那么通过以下的Lua脚本就可以实现

public static final String SCRIPT = “local resultKeys={};”

 + “for k,v in ipairs(KEYS) do “

 + ”  local tmp = redis.call(‘hget’, v, ‘age’);”

+ ”  if tmp > ARGV[1] then “

+ ”   table.insert(resultKeys,v);”

 + ”  end;”

 + ” end;”

 + “return resultKeys;”;

执行脚本代码

Jedis jedis = jedisPool.getResource();

jedis.auth(auth);

List<String> keys = Arrays.asList(allUserKeys);

List<String> args = new ArrayList<>();

args.add(“28”);

List<String> resultKeys = (List<String>)jedis.evalsha(funcKey, keys, args);

return resultKeys;

注意,以上的代码中使用的是evalsha命令,该命令参数的不是直接用Lua脚本字符串,而是提前已经加载到 Redis中的函数的一个SHA索引,通过以下的代码将系统中所有需要执行的函数提前加载到Redis中,通常在自己的系统中维护一个函数哈希表 funcTable,后续需要实现什么功能,就从函数表中获取对应功能的SHA索引,通过evalsha调用就行。

String shaFuncKey = jedis.scriptLoad(SCRIPT);//加载脚本到Redis中,获取sha索引 funcTable.put(funcName_age, shaFuncKey);//添加到系统维护的函数表中

通过以上的方法,便可以使较为复杂的查询放到Redis中去执行,提高效率。

可见,想要将全部业务代码都使用lua脚本来实现的业务系统是可能的,lua脚本等同于关系型数据库中的存储过程或者函数。当然,全部使用lua的开发成本未必不大,毕竟不是关系型数据库,存储思维不同。

代码示例:

//配置生成规则(CRUD):

//假设销售单号生成规则:prefix+time+seq

//生成之后的结果类似于:SO20150520023014

//——模拟常规数据库操作——

//添加数据

shardedJedis.hset(“rules”, “somaster”,

 “name:销售单号,prefix:SO,time:YYYYMMDD,seq:seq_so,seq_len:6”);

shardedJedis.hset(“rules”, “pomaster”,

 “name:采购单号,prefix:PO,time:YYYYMMDD,seq:seq_po,seq_len:6”);

shardedJedis.hset(“rules”, “test”, “name:test,prefix:PO,time:YYYYMMDD,seq:seq_po,seq_len:6”);

//判断某个值是否存在

System.out.println(shardedJedis.hexists(“rules”, “test”));

// 删除指定的值

System.out.println(shardedJedis.hdel(“rules”, “test”));

// 获取指定的值

System.out.println(shardedJedis.hget(“rules”, “somaster”));

// 获取所有的keys

System.out.println(shardedJedis.hkeys(“rules”));

// 获取所有的values

System.out.println(shardedJedis.hvals(“rules”));

//更新 = 插入同名的key

System.out.println(“update before:”+shardedJedis.hvals(“rules”));

System.out.println(shardedJedis.hset(“rules”, “somaster”, “new test somaster”));

System.out.println(“update after:”+shardedJedis.hvals(“rules”));

我示例代码中使用的是hash而不是直接使用key-value来存储,是更优的方案。至此CRUD都能直接满足了,最后,你获取到所有values,需要自己处理分页。

也可以使用list和set组合的方式存储。这种方式是将list index和set key对应起来,根据序号进行分页是容易的,但在每次新增和删除时,都需要修改序号和key的对应关系。

两者相比,使用hash的成本显然更低,也不易出错。

2.         序列号的使用

Redis中对序列的生成早已考虑周到,使用单线程操作序列的方式以保证并发安全,同时,使用也极其简单。更多操作详见官网API

代码示例

//sequence

System.out.println(“seq:”+shardedJedis.incr(“seq”));

System.out.println(“seq:”+shardedJedis.incr(“seq”));

System.out.println(“another_seq:”+shardedJedis.incr(“another_seq”));

最后,生成序列服务只需要通过对应的规则名,获取规则表达式,解析之后结合序列号,最终生成即可。

并发测试

这里我们使用CyclicBarrier做并发测试,CyclicBarrier会开启指定数量的线程,等待这些线程就绪之后,同时执行测试内容,以达到真实并发的测试目的。

Loadrunner等压力测试工具也能完成测试任务。

<div class="container">
<div class="line number1 index0 alt2"><code class="java keyword">public</code> <code class="java keyword">class</code> <code class="java plain">CyclicBarrierTest {</code></div>
<div class="line number2 index1 alt1"><code class="java spaces">    </code><code class="java comments">//初始化</code></div>
<div class="line number3 index2 alt2"><code class="java spaces">    </code><code class="java plain">JedisPoolTest test = </code><code class="java keyword">new</code> <code class="java plain">JedisPoolTest();</code></div>
<div class="line number4 index3 alt1"><code class="java spaces">    </code><code class="java keyword">public</code> <code class="java keyword">static</code> <code class="java keyword">void</code> <code class="java plain">main(String[] args) {</code></div>
<div class="line number5 index4 alt2"><code class="java spaces">         </code><code class="java keyword">int</code> <code class="java plain">count = </code><code class="java value">1000</code><code class="java plain">;</code></div>
<div class="line number6 index5 alt1"><code class="java spaces">         </code><code class="java plain">CyclicBarrier cyclicBarrier = </code><code class="java keyword">new</code> <code class="java plain">CyclicBarrier(count);</code></div>
<div class="line number7 index6 alt2"><code class="java spaces">         </code><code class="java plain">ExecutorService executorService = Executors.newFixedThreadPool(count);</code></div>
<div class="line number8 index7 alt1"><code class="java spaces">         </code><code class="java keyword">for</code> <code class="java plain">(</code><code class="java keyword">int</code> <code class="java plain">i = </code><code class="java value">0</code><code class="java plain">; i &lt; count; i++)</code></div>
<div class="line number9 index8 alt2"><code class="java spaces">              </code><code class="java plain">executorService.execute(</code><code class="java keyword">new</code> <code class="java plain">CyclicBarrierTest().</code><code class="java keyword">new</code> <code class="java plain">Task(cyclicBarrier));</code></div>
<div class="line number10 index9 alt1"></div>
<div class="line number11 index10 alt2"><code class="java spaces">         </code><code class="java plain">executorService.shutdown();</code></div>
<div class="line number12 index11 alt1"><code class="java spaces">         </code><code class="java keyword">while</code> <code class="java plain">(!executorService.isTerminated()) {</code></div>
<div class="line number13 index12 alt2"><code class="java spaces">              </code><code class="java keyword">try</code> <code class="java plain">{</code></div>
<div class="line number14 index13 alt1"><code class="java spaces">                   </code><code class="java plain">Thread.sleep(</code><code class="java value">10</code><code class="java plain">);</code></div>
<div class="line number15 index14 alt2"><code class="java spaces">              </code><code class="java plain">} </code><code class="java keyword">catch</code> <code class="java plain">(InterruptedException e) {</code></div>
<div class="line number16 index15 alt1"><code class="java spaces">                   </code><code class="java plain">e.printStackTrace();</code></div>
<div class="line number17 index16 alt2"><code class="java spaces">              </code><code class="java plain">}</code></div>
<div class="line number18 index17 alt1"><code class="java spaces">         </code><code class="java plain">}</code></div>
<div class="line number19 index18 alt2"><code class="java spaces">    </code><code class="java plain">}</code></div>
<div class="line number20 index19 alt1"></div>
<div class="line number21 index20 alt2"><code class="java spaces">    </code><code class="java keyword">public</code> <code class="java keyword">class</code> <code class="java plain">Task </code><code class="java keyword">implements</code> <code class="java plain">Runnable {</code></div>
<div class="line number22 index21 alt1"><code class="java spaces">         </code><code class="java keyword">private</code> <code class="java plain">CyclicBarrier cyclicBarrier;</code></div>
<div class="line number23 index22 alt2"></div>
<div class="line number24 index23 alt1"><code class="java spaces">         </code><code class="java keyword">public</code> <code class="java plain">Task(CyclicBarrier cyclicBarrier) {</code></div>
<div class="line number25 index24 alt2"><code class="java spaces">              </code><code class="java keyword">this</code><code class="java plain">.cyclicBarrier = cyclicBarrier;</code></div>
<div class="line number26 index25 alt1"><code class="java spaces">         </code><code class="java plain">}</code></div>
<div class="line number27 index26 alt2"></div>
<div class="line number28 index27 alt1"><code class="java spaces">         </code><code class="java color1">@Override</code></div>
<div class="line number29 index28 alt2"><code class="java spaces">         </code><code class="java keyword">public</code> <code class="java keyword">void</code> <code class="java plain">run() {</code></div>
<div class="line number30 index29 alt1"><code class="java spaces">              </code><code class="java keyword">try</code> <code class="java plain">{</code></div>
<div class="line number31 index30 alt2"><code class="java spaces">                   </code><code class="java comments">// 等待所有任务准备就绪</code></div>
<div class="line number32 index31 alt1"><code class="java spaces">                   </code><code class="java plain">cyclicBarrier.await();</code></div>
<div class="line number33 index32 alt2"><code class="java spaces">                   </code><code class="java comments">// 测试内容</code></div>
<div class="line number34 index33 alt1"><code class="java spaces">                </code><code class="java comments">// 待测试的url</code></div>
<div class="line number35 index34 alt2"><code class="java spaces">                    </code><code class="java plain">String host = </code><code class="java string">"<a href="http://172.25.2.14/seqno?">http://172.25.2.14/seqno?</a>"</code><code class="java plain">;</code></div>
<div class="line number36 index35 alt1"><code class="java spaces">                    </code><code class="java plain">String para = </code><code class="java string">"sysTemNo=ERP&amp;seqName=WH-ZONE-ID&amp;iVar=00"</code><code class="java plain">;</code></div>
<div class="line number37 index36 alt2"><code class="java spaces">                    </code><code class="java plain">System.out.println(host + para);</code></div>
<div class="line number38 index37 alt1"><code class="java spaces">                    </code><code class="java plain">URL url = </code><code class="java keyword">new</code> <code class="java plain">URL(host);</code></div>
<div class="line number39 index38 alt2"><code class="java spaces">                    </code><code class="java plain">HttpURLConnection connection = (HttpURLConnection) url.openConnection();</code></div>
<div class="line number40 index39 alt1"><code class="java spaces">                    </code><code class="java comments">// connection.setRequestMethod("POST");</code></div>
<div class="line number41 index40 alt2"><code class="java spaces">                    </code><code class="java comments">// connection.setRequestProperty("Proxy-Connection", "Keep-Alive");</code></div>
<div class="line number42 index41 alt1"><code class="java spaces">                    </code><code class="java plain">connection.setDoOutput(</code><code class="java keyword">true</code><code class="java plain">);</code></div>
<div class="line number43 index42 alt2"><code class="java spaces">                    </code><code class="java plain">connection.setDoInput(</code><code class="java keyword">true</code><code class="java plain">);</code></div>
<div class="line number44 index43 alt1"><code class="java spaces">                    </code><code class="java plain">PrintWriter out = </code><code class="java keyword">new</code> <code class="java plain">PrintWriter(connection.getOutputStream());</code></div>
<div class="line number45 index44 alt2"><code class="java spaces">                    </code><code class="java plain">out.print(para);</code></div>
<div class="line number46 index45 alt1"><code class="java spaces">                    </code><code class="java plain">out.flush();</code></div>
<div class="line number47 index46 alt2"><code class="java spaces">                    </code><code class="java plain">out.close();</code></div>
<div class="line number48 index47 alt1"><code class="java spaces">                    </code><code class="java plain">BufferedReader in = </code><code class="java keyword">new</code> <code class="java plain">BufferedReader(</code><code class="java keyword">new</code> <code class="java plain">InputStreamReader(connection.getInputStream()));</code></div>
<div class="line number49 index48 alt2"><code class="java spaces">                    </code><code class="java plain">String line = </code><code class="java string">""</code><code class="java plain">;</code></div>
<div class="line number50 index49 alt1"><code class="java spaces">                    </code><code class="java plain">String result = </code><code class="java string">""</code><code class="java plain">;</code></div>
<div class="line number51 index50 alt2"><code class="java spaces">                    </code><code class="java keyword">while</code> <code class="java plain">((line = in.readLine()) != </code><code class="java keyword">null</code><code class="java plain">) {</code></div>
<div class="line number52 index51 alt1"><code class="java spaces">                        </code><code class="java plain">result += line;</code></div>
<div class="line number53 index52 alt2"><code class="java spaces">                    </code><code class="java plain">}</code></div>
<div class="line number54 index53 alt1"><code class="java spaces">                    </code><code class="java plain">System.out.println(result);</code></div>
<div class="line number55 index54 alt2"><code class="java comments">//                   System.out.println(test.getJedis().incr("seq"));</code></div>
<div class="line number56 index55 alt1"><code class="java comments">//                System.out.println(test.getShardedJedis().incr("seq"));</code></div>
<div class="line number57 index56 alt2"><code class="java spaces">              </code><code class="java plain">} </code><code class="java keyword">catch</code> <code class="java plain">(Exception e) {</code></div>
<div class="line number58 index57 alt1"><code class="java spaces">                   </code><code class="java plain">e.printStackTrace();</code></div>
<div class="line number59 index58 alt2"><code class="java spaces">              </code><code class="java plain">}</code></div>
<div class="line number60 index59 alt1"><code class="java spaces">         </code><code class="java plain">}</code></div>
<div class="line number61 index60 alt2"><code class="java spaces">    </code><code class="java plain">}</code></div>
<div class="line number62 index61 alt1"><code class="java plain">}</code></div>
<div class="line number62 index61 alt1">

测试结果:

单台Redis未经任何设置,500并发100% pass,到1000并发时只有67%pass率,此时存在连接超时和被拒的情形。但不存在任何重复号码或丢失号码。500并发数其实已经完全满足我当前 系统的要求。考虑到Redis本身可以集群扩展,完全能够应对将来更高的并发需求。