[转载]Asp.net MVC2中你必须知道的扩展点(一):Controller Factory

mikel阅读(1044)

[转载]Asp.net MVC2中你必须知道的扩展点(一):Controller Factory – 海纳百川 – 博客园.

ASP.NET mvc2中提供很多可以扩展的地方,利用这些扩展之后,ASP.NET mvc使用起来更加灵活。Simone Chiaretta曾写过一篇文章:13 ASP.NET MVC extensibility points you have to know。它的文章中概括性的介绍了13个ASP.NET MVC开发人员必须知道的扩展点。我将从这13个扩展点中挑选几个常见的重要的扩展点进行详细的介绍。这篇将文章将首先介绍Controller Factory。

Controller Factory是Asp.MVC框架中一个重要的扩展点。Controller Factory是用来创建控制器。而Controller最常用的场景之一是支持依赖注入。但是如果直接在控制器中使用依赖注入,默认情况下 ASP.NET MVC框架将不会为你创建Controller,而且你还会得到下面这个错误,如下图:

hhh

产生上面错误的原因是DefaultControllerFactory使用Activator.CreateInstance来初始化控制器,而这个方法对你依赖注入的参数一无所知。

这种情况下,我们就要使用自定义的Controller Factory。

一个自定义的Controller Factory需要继承IControllerFactory或者继承过IControllerFactory的类, 如:DefaultControllerFactory。下面代码是一个自定义的Controller factory。

public class MyCustomControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        /* implement controller creation logic */
        return base.GetControllerInstance(requestContext, controllerType);
    }
}

在定义Controller Factory之后,需要在Application_Start()中注册一下:

ControllerBuilder.Current.SetControllerFactory(new MyCustomControllerFactory());

这样MVC框架将会使用你自定的Controller Factory创建Controller。

看下面这个ProductsController,这个控制器在构造函数中接受依赖注入

public class ProductsController : Controller
{
    public ProductsController(IProductRepository repository,IShippingCalculator shippingCalculator,
ITaxService taxService)
    {
        /* ... */
    }
    /* ... */
}

如果自己手动写代码创建这样的Controller是非常乏味的。幸运的是我们不需要自己手写代码去实现。因为存在很多IoC工具供我们使用。在.net 中最好的依赖注入工具之一便是StructureMap,它是一个轻量级开源免费IOC框架。下面我将使用这个工具实现一个简单的MVC中依赖注入的 Demo。

1、到http://structuremap.sourceforge.net/上下载这个工具。在MVC项目中引用StructureMap.dll。

2、在Models中定义一个依赖注入的IMessageProvider接口,以及它的一个实现类StructureMapMessageProvider

namespace MvcApplication1.Models
{
    public interface IMessageProvider
    {
        string GetMessage();
    }

    public class StructureMapMessageProvider : IMessageProvider
    {
        public string GetMessage()
        {
            return "This message was provided by StructureMap";
        }
    }
}

3、利用StructureMap自定义的Controller Factory代码如下:

public class StructureMapControllerFactory : DefaultControllerFactory
{
    protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
    {
        return ObjectFactory.GetInstance(controllerType) as IController;
    }
}

4、定义一个静态类StructureMapBootstrapper,用来初始化StructureMap和设置StructureMapControllerFactory为项目的Controller Factory,代码如下:

public static class StructureMapBootstrapper
{
    public static void Initialize()
    {
        ObjectFactory.Initialize(x => x.AddRegistry(new MyStructureMapApplicationRegistry()));
    }

    public static void SetControllerFactory()
    {
        var controllerFactory = new StructureMapControllerFactory();
        ControllerBuilder.Current.SetControllerFactory(controllerFactory);
    }
}

5、在Global.asax中使用上面的StructureMapBootstrapper类设置Controller Factory和初始化StructureMap。

StructureMapBootstrapper.SetControllerFactory();
StructureMapBootstrapper.Initialize();

6、这样我们就能正常使用了。我们将HomeController设置如下:

[HandleError]
public class HomeController : Controller
{
    private IMessageProvider _messageProvider;

    public HomeController(IMessageProvider messageProvider)
    {
        _messageProvider = messageProvider;
    }

    public ActionResult Index()
    {
        ViewData["Message"] = _messageProvider.GetMessage();

        return View();
    }

}
运行结果如下:
hhhk
总结:本文简单的介绍了一下自定义Controller Factory。下一篇文章将介绍ModelBinder。
参考:asp.net mvc 2 in action

作者:朱祁林
出处:http://zhuqil.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[转载]T-SQL大批量操作数据的时候限制受影响行数的方法

mikel阅读(977)

[转载]T-SQL大批量操作数据的时候限制受影响行数的方法 – 数据库相关 – 博客园.

T-SQL的威力之一就是大批量操作数据。不过某些场景下需要限制t-SQL影响的行数。比如以前艺龙遇到的场景是:对一个发布的表,一次更改太多 的行,可能造成发布的崩溃。这次我遇到的场景是服务器性能不是很好,内存不够大,不限制影响行数的话,内存中可能已经容纳不下执行SQL过程中产生的数据 集,执行起来非常慢。

我们单位的DBA针对这种情况,写过一个存储过程来应对,核心的代码如下:

set rowcount 10000
delete
from temp
WHERE OperateTime > @CurrentDate

while @@rowcount>1
delete
from temp
WHERE OperateTime > @CurrentDate
set rowcount 0

其中用到了两个关键的参数,一个是RowCount,可以设置受影响行数。设为0表示不限。如果上面设了rowcount=10000,下面忘了 设rowcount=0,再执行一个select,最多也就返回10000行。另外一个是@@RowCount,表示上一条sql影响的行数。

在sql server 2008 r2的bookonline中,说下一个版本将废除RowCount,建议改用其他方法,比如使用top参数。

我在最近的这个项目中,对这段代码做了两处改动:一是在删除过程中把被删除的数据插入到一个存档表,另外增加了一条日志:
set rowcount 10000
delete
from temp
OUTPUT deleted.*
INTO temp_deleted
WHERE OperateTime > @CurrentDate
exec PRSDBLOGAffectedRowCount @PackageType,1350,@@RowCount

while @@rowcount>1
delete
from temp
OUTPUT deleted.*
INTO temp_deleted
WHERE OperateTime > @CurrentDate
exec PRSDBLOGAffectedRowCount @PackageType,1350,@@RowCount
set rowcount 0

不 过发现那个while循环语句没有执行,因为@@RowCount返回的是上一句sql“exec PRSDBLOGAffectedRowCount @PackageType,1350,@@RowCount”影响的行数。在PRSDBLOGAffectedRowCount中设了SET NOCOUNT ON,返回的@@RowCount都是0,下面的while循环永远不会执行。

最终修改如下:

declare @TempRowCount int = 0
set rowcount 10000
DELETE
FROM temp
OUTPUT deleted.*
into temp_deleted
WHERE DepartureDate < dateadd(day, 0 – @OldDataExpireDayCount, @CurrentDate)

set @TempRowCount = @@RowCount

exec PRSDBLOGAffectedRowCount @PackageType,100,@TempRowCount

while @TempRowCount>1
begin
DELETE
FROM temp
OUTPUT deleted.*
into temp_deleted
WHERE DepartureDate < dateadd(day, 0 – @OldDataExpireDayCount, @CurrentDate)

set @TempRowCount = @@RowCount

exec PRSDBLOGAffectedRowCount @PackageType,100,@TempRowCount
end
set rowcount 0

[转载][原创]一步一步用C#编写三国杀(一):规则和需求描述

mikel阅读(1281)

[转载][原创]一步一步用C#编写三国杀(一):规则和需求描述 – 忘却之都 – 博客园.

最近做翻译做的头疼,疼过之余,想想之前公司内组织的三国杀开发兴趣小组在三国杀开发问题上几乎又停滞了。于是又翻出来搞了搞,这次却搞的有点像模像样了,特地把思路和方法都共享出来,一起学习。

三国杀在上海是挺风靡的,如果你还不知道玩法和规则,请猛击这里

今天要说的是实现的第一步。为了尽量简化需求,我们最初要实现的东西也挺简单,就是能支持两个玩家自动对战。具体的描述如下:在一个场景中设置两个 玩家,游戏的牌堆中只有三种基本牌:杀、闪、桃。其中,只有杀和桃是属于主动性游戏牌,即可以在自己行动回合将其打出;闪是被动性游戏牌,只有当别人对自 己出杀的时候才可以出闪,否则扣除一点体力,而使用桃则为自己增加一点体力。同样,为了简化实现,只要有能使用的牌,就必须使用;而且,如果你的手牌数量 大于体力值,则需要弃牌直到手牌数与体力值相等。在这种情况下,只要有一方体力为0,游戏结束!

对需求进行整理,不难发现有以下需求待实现:

1、游戏结束的条件:只要有玩家死亡即宣告结束。

2、牌堆的实现,注意牌堆中拿出的牌需要从牌堆中移除,以及洗牌的功能。

3、杀、闪、挑的逻辑实现。

4、从手牌中计算是否还有可用的牌。

5、玩家轮询行动的实现。

在设计中,我的思路是这样的:一局游戏实际都在一个场景中进行,直到游戏结束。因此首先有场景的定义:

/// <summary>
/// 表示游戏场景。
/// </summary>
public class Scene
{
private readonly Player[] players;
}

其中场景中定义了游戏玩家,因为场景中的游戏玩家在场景生成之后就固定了,所以使用了readonly。

同样,游戏实际是个循环,结束的条件就是有玩家死亡。因此,先定义玩家死亡的条件:

private bool IsGameEnds()
{
return players.Where(p => p.IsDead).Count() > 0; // 如果选择到IsDead的Player,游戏结束
}

这样,由于其中引用到了Player类,因此,建立玩家类,来对其按照需求进行设计。代码如下:

Player

/// <summary>
/// 表示游戏中的玩家。
/// </summary>
public class Player
{
private readonly List<GameCard> handCards = new List<GameCard>(20);

public Player(string name, byte maxHp)
{
this.Name = name;
this.Hp = maxHp;
this.MaxHp = maxHp;
}

/// <summary>
/// 表示该玩家的名称。
/// </summary>
public string Name { get; private set; }

/// <summary>
/// 表示该玩家是否已经死亡。
/// </summary>
public bool IsDead
{
get { return Hp == 0; }
}

/// <summary>
/// 表示该玩家所选武将的当前HP.
/// </summary>
public byte Hp { get; private set; }

/// <summary>
/// 表示该玩家所选武将的最大HP.
/// </summary>
public byte MaxHp { get; private set; }
}

其中的handCards表示玩家手中可以拿的手牌数量,这里设定上限为20张。那么同样要开始定义游戏卡牌,代码如下:

GameCard

/// <summary>
/// 表示游戏中用作游戏的卡牌。
/// </summary>
public abstract class GameCard
{
/// <summary>
/// 表示牌的花色。
/// </summary>
public CardMark Mark { get; protected set; }

/// <summary>
/// 表示牌的大小。
/// </summary>
public CardValue Value { get; protected set; }

/// <summary>
/// 表示牌的名称。
/// </summary>
public string Name { get; protected set; }

/// <summary>
/// 对目标玩家使用卡牌。
/// </summary>
/// <param name=”source”>使用卡牌的源对象。</param>
/// <param name=”target”>使用卡牌的目标对象。</param>
public abstract void Use(Player source, Player target);
}

直到现在,所需要的定义已经基本完成。这其中的代码有很多不规范的地方,之所以展现出来,也是为了表现自己的思维过程,在后面会有很多对目前代码的重构。

在这样定义完了之后,下一步将开始仔细分析流程,按照流程先写出最初能运行的版本。(未完待续…)

[转载]在 ASP.NET MVC 中使用 Chart 控件

mikel阅读(1069)

[转载]在 ASP.NET MVC 中使用 Chart 控件 – haogj – 博客园.

在 .NET 3.5 的时候,微软就提供了一个 Chart 控件,网络上有大量的关于在 VS2008 中使用这个控件的文章,在 VS2010 中,这个控件已经被集成到 ASP.NET 4.0 中,可以从工具箱中直接使用了。

这个控件在 ASP.NET 经典的页面中很容易使用,但是在 ASP.NET MVC 中使用,却会出现各种问题。

网上有的说可以这样处理,在 Global.asax 中增加一个方法。

1 protected void Session_Start()
2 {
3 string id = this.Session.SessionID;
4 }

增加之后的结果是这样。

到底应该怎样解决呢?

由于我没有看到 Chart 的源码,从错误的提示信息来说,可以看到是在 Handler 处理中出现问题。

网络上有许多关于配置的文章,例如:

ScottGu 的 Built-in Charting Controls (VS 2010 and .NET 4 Series)

Michael Ceranski 的 Building a Dashboard Using The Microsoft Chart Controls

Delian Tchoparinov 的 Handling chart generated images using Chart Http Handler

但是,很不幸,要么比较过时,大多数的配置在 VS2010 中是不需要的,要么没有解决问题。

ASP.NET MVC 中,处理程序的机制有了很大的变化,不再直接通过处理程序生成结果,而是经过了从处理程序到 Controler 到 Action 的多次传递。与 ASP.NET 经典模式完全不同。

Nic_Roche 在文章 Streaming Chart Images as FileResult from MVC Controllers 中提供了一个思路,在 View 中填入一个图片的引用 ,然后,通过一个 Action 返回这个图片。不过很不幸,下载之后,也没有通过。

方向没有错误,仅仅有一些小的地方需要注意。

下面,我们在 VS2010 中通过 ASP.NET MVC 实现一下。

1. 创建一个 ASP.NET MVC 项目。

2. 在 Index.aspx 这个 View 中插入一个图片的引用 ,引用的地址是一个 Action 。

<img src=/Home/GetChart alt=Chart />

3. 在项目的 Models 中增加一个 Model:StaticModel.cs,提供数据。

1 using System;
2 using System.Data;
3 using System.Configuration;
4 using System.Linq;
5 using System.Web;
6 using System.Web.Security;
7 using System.Web.UI;
8 using System.Web.UI.HtmlControls;
9 using System.Web.UI.WebControls;
10 using System.Web.UI.WebControls.WebParts;
11 using System.Xml.Linq;
12 using System.Collections.Generic;
13
14 namespace mvcChart.Models
15 {
16 public class StaticModel
17 {
18 public static List<int> createStaticData()
19 {
20 List<int> c_data = new List<int>();
21 c_data.Add(1);
22 c_data.Add(6);
23 c_data.Add(4);
24 c_data.Add(3);
25 return c_data;
26 }
27 }
28 }
29

4. 为 Home 的 Controler 增加一个名为 GetChart 的 Action。

注意:

1. 这个 Action 返回的类型是一个 FileResult ,也就是返回一个文件,在这个方法中,使用 FileResult 的派生类 FileStreamResult 通过流返回图片。

2. 在 33 行,将流的当前位置重新设置到起始位置,以便读取生成的图片数据。imageStream.Position = 0;

1 public FileResult GetChart()
2 {
3 List<int> data = Models.StaticModel.createStaticData();
4 System.Web.UI.DataVisualization.Charting.Chart Chart2 = new System.Web.UI.DataVisualization.Charting.Chart();
5 Chart2.Width = 412;
6 Chart2.Height = 296;
7 Chart2.RenderType = System.Web.UI.DataVisualization.Charting.RenderType.ImageTag;
8 Chart2.Palette = ChartColorPalette.BrightPastel;
9 Title t = new Title(IMG source streamed from Controller, Docking.Top, new System.Drawing.Font(Trebuchet MS, 14, System.Drawing.FontStyle.Bold), System.Drawing.Color.FromArgb(26, 59, 105));
10 Chart2.Titles.Add(t);
11 Chart2.ChartAreas.Add(Series 1);
12 // create a couple of series
13 Chart2.Series.Add(Series 1);
14 Chart2.Series.Add(Series 2);
15 // add points to series 1
16 foreach (int value in data)
17 {
18 Chart2.Series[Series 1].Points.AddY(value);
19 }
20 // add points to series 2
21 foreach (int value in data)
22 {
23 Chart2.Series[Series 2].Points.AddY(value + 1);
24 }
25 Chart2.BorderSkin.SkinStyle = BorderSkinStyle.Emboss;
26 Chart2.BorderlineWidth = 2;
27 Chart2.BorderColor = System.Drawing.Color.Black;
28 Chart2.BorderlineDashStyle = ChartDashStyle.Solid;
29 Chart2.BorderWidth = 2;
30 Chart2.Legends.Add(Legend1);
31 MemoryStream imageStream = new MemoryStream();
32 Chart2.SaveImage(imageStream, ChartImageFormat.Png);
33 imageStream.Position = 0;
34 return new FileStreamResult(imageStream, image/png);
35 }

最终的结果如下所示:

源文件下载

[转载]Flex4:利用HttpService与ASP.NET传输JSON数据(登录为例)

mikel阅读(1095)

[转载]Flex4:利用HttpService与ASP.NET传输JSON数据(登录为例) – 虚心使人进步 – 博客园.

开发环境:Flash Builder4,Vs2005

1、首先打开FlashBuilde4,创建一个名为HttpService_Net_Json的flex项目

(图1)

然后下一步,应用程序类型选择web,应用程序服务器类型选择ASP.NET(如图2)

(图2)

下一步,出现配置ASP.NET服务器的设置。我们选择使用IIS,web应用程序根目录选择你IIS下的某个网站所在文件夹,web应用程序 URL设置为你网站的本地地址。注意要确保你当前IIS中已经有此对应的网站。然后我们点击”验证配置”,提示”web 应用程序根目录和URL有效”(如图3)。OK。表示服务器通了。

(图3)

下一步我们选择框架连接为”运行时共享库(RSL)”(如图4),这样可提高Flex发行版的flash加载速度,点击完成。项目就建好了。

(图4)

2、界面设计。这块我不多叙述。跟VS开发环境类似。Flash Builder4内置了丰富的组件。我们将一些Lable、Button、LinkButton、Image、TextInput组件拖到工作区,同时 Fb4支持CSS。我们新建一个Login.css的样式表,对一些组件进行样式控制。最后成型的界面如下图5。

3、提交数据。

我们要实现一个很简单的逻辑-登录。当用户输入用户名和密码,按下”登陆”按钮后,从服务器端返回成功的标志则跳转到default.aspx页面,否则弹出登陆失败的相关消息。

我们采用HtttService与Asp.NET进行交互,服务器端返回JSON格式的数据,Flex客户端进行解析后进行相关操作。

首先我们建立一个HttpService(放在delcarations之间)。设置id,提交到的URL,提交方式为POST,resultFormat为Text,返回结果后的任务分配给LoginHandle(event).

resutl属性简单点就是当返回结果后,通知客户端要做的事情。我们分配给一个loginHandle(event)来处理,成功就跳转,不成功就弹出提示。

mx:resquest是设置需要提交的数据。Flex传递的是成对出现的object.所以我们必须设置键和键值。我们这里只需提交 userName和password。注意这里<userName>和<password>节是区分大小写的,同时要与 aspx.cs文件中的Request中的key对应。比如这边是userName,那么cs文件中就是Request[‘userName’]。

代码

<fx:Declarations>
<!– 将非可视元素(例如服务、值对象)放在此处 –>
<mx:HTTPService id=”loginService” url=”/ajax/login.aspx” method=”POST” resultFormat=”text” result=”loginHandle(event)”>
<mx:request xmlns=””>
<userName>{username.text}</userName>
<password>{password.text}</password>
</mx:request>
</mx:HTTPService>
</fx:Declarations>

好了,一切都准备就绪了。那我们就开始点击Id为LoginButton的按钮来进行提交吧。切换到”设计”视图,在click属性里,点击旁边的+

开发环境会自动给我们生成一个btnLogin_clickHandler(event)方法(如图)。是不是和visual studio很像呢?太方便了

我们再切换到“源代码”视图,看看发生了什么变化。

button按钮多了click属性

<s:Button x=”220″ label=”登陆” height=”60″ y=”90″ alpha=”1.0″ id=”btnLogin” fontFamily=”Arial” styleName=”button” click=”btnLogin_clickHandler(event)”/>

fx:script之间多了一个function  btnLogin_clcikHandler

<fx:Script>
<![CDATA[
protected function btnLogin_clickHandler(event:MouseEvent):void
{
}
]]
>
</fx:Script

ok.完善一下这个方法。加入简单的数据验证,然后HttpService提交。

代码

protected function btnLogin_clickHandler(event:MouseEvent):void
{
// 提交登陆时
if(username.text==“” || password.text==“”){
Alert.show(
用户名或密码不能为空,提示);return;
}
loginService.send();
}

4、处理返回数据。首先我们提交到的ajax/login.aspx.cs代码如下。在此我们简单化没有连接数据库,直接判断userName是否为123,密码是否为456。匹配则登陆成功

返回结果为诸如{“success”:”0″,”msg”:”用户名错误”}这样的严格的JSON格式,即属性和值必须都有双引号。为什么要强调是 严格的JSON格式呢,因为发现FLex的JSON库对非严格的格式的JSON格式解析不成功。比如{“success”:0,”msg”:”用户名错 误”},{success:0,”msg”:”用户名错误”}。但是使用过ExtJS的朋友知道。这样的格式ExtJS是能解析的。我用的JSON库是

http://as3corelib.googlecode.com/files/as3corelib-.93.zip,里的as3corelib.swc(下载后放到fb安装目录下的sdks\4.0.0\frameworks\libs)。不知是版本问题还是什么。还请各位不吝赐教。

代码

protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
string name = Request.Form[userName].ToString();
string pwd = Request.Form[password].ToString();
if (name!=123)
{
Response.Write(
{\success\:\0\,\msg\:\用户名错误\});

}

else
{
if (name==123 && pwd=456)
{
Response.Write(
{\success\:\1\,\msg\:\ok\});
}
else
{
Response.Write(
{\success\:\0\,\msg\:\密码错误\});
}
}
Response.End();
}

好了。服务器端的JSON格式文本组织好了。那么flex客户端该如何处理呢,看下面

先将返回的结果event.result转化为String。然后对其进行JSON编码。最后判断success属性

代码

protected function loginHandle(event:ResultEvent):void{
var rawData:String
=String(event.result);
var obj:Object
=JSON.decode(rawData,false);
if(obj.success==“1){
navigateToURL(
new URLRequest(/default.aspx),_self);
}
else{
Alert.show(obj.msg,
提示);
}
}

OK,一切就绪。最后我们将flex导出发行版本,以便在html或aspx文件中调用生成的swf文件。附上整个工程和aspx文件。

/Files/showker/httpwebservice_net_json包.rar

login.aspx。登陆页面加载swf.

ajax/login.aspx。处理逻辑返回JSON字符串

HttpService_Net_Json。flex发行版本,login.aspx即调用里面的swf文件

HttpService_Net_Json_Project。flex项目。可在flash builder4中导入进行编辑

[转载]ASP.NET身份验证机制membership入门——API篇

mikel阅读(1054)

[转载]ASP.NET身份验证机制membership入门——API篇 – 彬 – 博客园.

不知道什么原因,最近总是头晕脑胀,做什么事情感觉都不在状态,再加上工作忙,觉得好累~不过不管怎么说,写博客一定要坚持,最少一月一篇~这算是给自己的任务吧。

回到正题,前面说过如何去配置Membership,以及如何去使用ASP.NET自带的登陆控件。这次说明一下如何不使用ASP.NET自带的登陆控件,而通过编写代码的方式去完成相应的功能。

要使用Membership我们需要引入System.Web.Security这个命名空间。在这个命名空间中有这么几个常用的类:

  1. Membership
  2. Roles

首先来介绍第一个Membership类,Membership类是一个静态类,提供了所有的对于用户方面的操作,比如注册用户,删除用户,取得用户列表,根据email查找用户等等

方法很多,但是大多数都很简单,我们挑两个比较麻烦点的来详细解释一下:

Membership.CreateUser方法的功能,看名字就知道是创建用户,这个方法有4个重载:

public static MembershipUser CreateUser(string username, string password);

public static MembershipUser CreateUser(string username, string password, string email);

public static MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out MembershipCreateStatus status);

public static MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, object providerUserKey, out MembershipCreateStatus status);

这4个重载的返回值都是MembershipUser类,MembershipUser类其实就是一个实体类,不过里边带了一些方法,比如取得密码,修改密码等方法。至于该使用哪个重载,还记得前面的web.config配置么?比如requiresQuestionAndAnswer设置是否需要密码找回问题和答案,如果该设置为true,那么就得使用第三个,或者第四个重载,提供问题和答案了。isApproved这个参数表示创建的用户是否激活。最后一个MembershipCreateStatus 是一个枚举,用out关键字修饰,用来获得创建用户的状态,比如:MembershipCreateStatus.Success说明创建用户成功,MembershipCreateStatus.InvalidEmail说明电子邮件的格式错误等等。providerUserKey是一个Guid类型的数据,用来指定该用户的UserId。

另一个需要介绍的就是public static bool ValidateUser(string username, string password);这个方法,其实看名字和参数大家都应该猜到这个方法的作用了,两个参数分别是用户名和密码,返回值为是否登录成功。剩下的方法都非常 的简单了。大家应该一看就明白,不过需要提一下的是:ValidateUser方法经常和FormsAuthentication类配合起来使 用,FormsAuthentication类提供了一系列静态方法,用来管理Forms身份验证服务。

FormsAuthentication类中,常用方法有:

public static string HashPasswordForStoringInConfigFile(string password, string passwordFormat);
public static void SetAuthCookie(string userName, bool createPersistentCookie);
public static void RedirectFromLoginPage(string userName, bool createPersistentCookie);

第一个HashPasswordForStoringInConfigFile方法,作用很简单,将传入的password按照 passwordFormat指定的哈希算法生成哈希密码然后返回,passwordFormat的取值可以是”MD5”或是”SHA1″这两个选择。

第二个SetAuthCookie方法,向客户端发送身份验证的票据。userName是登陆的用户名,createPersistentCookie用来告诉Asp.net是否创建一个持久的Cookie,让用户下次访问能够免于登陆。

第三个RedirectFormLoginPage方法,将经过身份验证的用户重定向回最初请求的 URL 或默认 URL。

通常就是这样的用法:

if (Membership.ValidateUser(zhangsan, 123123))
{
FormsAuthentication.RedirectFromLoginPage(
zhangsan, false);
}

Roles类同样是一个静态类,里边封装了所有对于角色相关的方法。比如:创建角色、将用户添加到角色,删除角色等常用操作。使用Roles类 要注意:web.config配置中roleManager节必须正确配置,并且enabled属性必须等于true才可以使用。

Roles类中,需要说一下的是AddUserToRole这个方法,这个方法通常和Membership.CreateUser在一起使用,比如:

if (Membership.CreateUser(zhangsan, 123123))
{
//创建用户成功,给zhangsan分配User角色
Roles.AddUserToRole(zhangsan, User);
}

这样,在创建zhangsan这个用户之后,顺便给zhangsan分配了User这个角色。在后面,就可以再配置文件中做如下配置:

<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<authorization>
<allow roles=”User”/>
<deny users=”?”/>
</authorization>
</system.web>
</configuration>

这样,所有新注册的成员才可以访问本目录下的资源,具体配置可以参考ASP.NET身份验证机制membership入门——配置篇(2)

ok.API的部分就介绍到这里了

[转载]c#实现文件加密、解密及文件拖拽至程序图标直接打开

mikel阅读(964)

[转载]『原创』c#实现文件加密、解密及文件拖拽至程序图标直接打开 – 初学博闻 of .NET CF/.Net – 博客园.

最近,工作特别忙,一直没空子来写Blog,这不,忙里偷闲,顺手写了个文件加解密的小程序,本来公司市场部的同事出去带着合同,怕弄丢了,所以让我们开发个小程序,用于加密合同文件,到客户那里解密打开,然后签订合同,最后加密,带回公司保存。

时间不充裕,也就一上午时间吧,下午就要去签合同了,嘿嘿,于是我亲自试验了一把,下面和大家分享一下吧。

首先,这是个winform的程序,部署在市场部同事的笔记本上面,基于.Net 2.0做的,它的功能大致如下:

  • 加密合同文档(*.doc)
  • 在客户处解密此合同文档,进行编辑,再次加密
  • 回到公司可以通过密码打开它

由于时间关系,只是很粗略的做了个大概。打开vs2008,建立一个winform项目,设计程序界面如下:

很简单的,待会儿在文章最后会有下载地址。我们可以把任意文件,拖入程序界面,即可进行加密,在此暂不作说明,大家可以待会儿下载回去试试,很简单的。

下面分享一下加密代码吧:

代码

using System; using System.Collections.Generic; using System.Text; using System.Security.Cryptography; using System.IO; namespace FileLock { /// <summary> /// 异常处理类 /// </summary> public class CryptoHelpException : ApplicationException { public CryptoHelpException(string msg) : base(msg) { } } public class CryptoHelp { private const ulong FC_TAG = 0xFC010203040506CF; private const int BUFFER_SIZE = 128 * 1024; /// <summary> /// 检验两个Byte数组是否相同 /// </summary> /// <param name="b1">Byte数组</param> /// <param name="b2">Byte数组</param> /// <returns>true-相等</returns> private static bool CheckByteArrays(byte[] b1, byte[] b2) { if (b1.Length == b2.Length) { for (int i = 0; i < b1.Length; ++i) { if (b1[i] != b2[i]) return false; } return true; } return false; } /// <summary> /// 创建Rijndael SymmetricAlgorithm /// </summary> /// <param name="password">密码</param> /// <param name="salt"></param> /// <returns>加密对象</returns> private static SymmetricAlgorithm CreateRijndael(string password, byte[] salt) { PasswordDeriveBytes pdb = new PasswordDeriveBytes(password, salt, "SHA256", 1000); SymmetricAlgorithm sma = Rijndael.Create(); sma.KeySize = 256; sma.Key = pdb.GetBytes(32); sma.Padding = PaddingMode.PKCS7; return sma; } /// <summary> /// 加密文件随机数生成 /// </summary> private static RandomNumberGenerator rand = new RNGCryptoServiceProvider(); /// <summary> /// 生成指定长度的随机Byte数组 /// </summary> /// <param name="count">Byte数组长度</param> /// <returns>随机Byte数组</returns> private static byte[] GenerateRandomBytes(int count) { byte[] bytes = new byte[count]; rand.GetBytes(bytes); return bytes; } /// <summary> /// 加密文件 /// </summary> /// <param name="inFile">待加密文件</param> /// <param name="outFile">加密后输入文件</param> /// <param name="password">加密密码</param> public static void EncryptFile(string inFile, string outFile, string password) { using (FileStream fin = File.OpenRead(inFile), fout = File.OpenWrite(outFile)) { long lSize = fin.Length; // 输入文件长度 int size = (int)lSize; byte[] bytes = new byte[BUFFER_SIZE]; // 缓存 int read = -1; // 输入文件读取数量 int value = 0; // 获取IV和salt byte[] IV = GenerateRandomBytes(16); byte[] salt = GenerateRandomBytes(16); // 创建加密对象 SymmetricAlgorithm sma = CryptoHelp.CreateRijndael(password, salt); sma.IV = IV; // 在输出文件开始部分写入IV和salt fout.Write(IV, 0, IV.Length); fout.Write(salt, 0, salt.Length); // 创建散列加密 HashAlgorithm hasher = SHA256.Create(); using (CryptoStream cout = new CryptoStream(fout, sma.CreateEncryptor(), CryptoStreamMode.Write), chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write)) { BinaryWriter bw = new BinaryWriter(cout); bw.Write(lSize); bw.Write(FC_TAG); // 读写字节块到加密流缓冲区 while ((read = fin.Read(bytes, 0, bytes.Length)) != 0) { cout.Write(bytes, 0, read); chash.Write(bytes, 0, read); value += read; } // 关闭加密流 chash.Flush(); chash.Close(); // 读取散列 byte[] hash = hasher.Hash; // 输入文件写入散列 cout.Write(hash, 0, hash.Length); // 关闭文件流 cout.Flush(); cout.Close(); } } } /// <summary> /// 解密文件 /// </summary> /// <param name="inFile">待解密文件</param> /// <param name="outFile">解密后输出文件</param> /// <param name="password">解密密码</param> public static void DecryptFile(string inFile, string outFile, string password) { // 创建打开文件流 using (FileStream fin = File.OpenRead(inFile), fout = File.OpenWrite(outFile)) { int size = (int)fin.Length; byte[] bytes = new byte[BUFFER_SIZE]; int read = -1; int value = 0; int outValue = 0; byte[] IV = new byte[16]; fin.Read(IV, 0, 16); byte[] salt = new byte[16]; fin.Read(salt, 0, 16); SymmetricAlgorithm sma = CryptoHelp.CreateRijndael(password, salt); sma.IV = IV; value = 32; long lSize = -1; // 创建散列对象, 校验文件 HashAlgorithm hasher = SHA256.Create(); //using (CryptoStream cin = new CryptoStream(fin, sma.CreateDecryptor(), CryptoStreamMode.Read), // chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write)) //{ CryptoStream cin = new CryptoStream(fin, sma.CreateDecryptor(), CryptoStreamMode.Read), chash = new CryptoStream(Stream.Null, hasher, CryptoStreamMode.Write); // 读取文件长度 BinaryReader br = new BinaryReader(cin); lSize = br.ReadInt64(); ulong tag = br.ReadUInt64(); if (FC_TAG != tag) throw new CryptoHelpException("文件被破坏或者密码不正确"); long numReads = lSize / BUFFER_SIZE; long slack = (long)lSize % BUFFER_SIZE; for (int i = 0; i < numReads; ++i) { read = cin.Read(bytes, 0, bytes.Length); fout.Write(bytes, 0, read); chash.Write(bytes, 0, read); value += read; outValue += read; } if (slack > 0) { read = cin.Read(bytes, 0, (int)slack); fout.Write(bytes, 0, read); chash.Write(bytes, 0, read); value += read; outValue += read; } chash.Flush(); chash.Close(); fout.Flush(); fout.Close(); byte[] curHash = hasher.Hash; // 获取比较和旧的散列对象 byte[] oldHash = new byte[hasher.HashSize / 8]; read = cin.Read(oldHash, 0, oldHash.Length); if ((oldHash.Length != read) || (!CheckByteArrays(oldHash, curHash))) throw new CryptoHelpException("文件被破坏"); cin.Flush(); cin.Close(); //} if (outValue != lSize) throw new CryptoHelpException("文件大小不匹配"); } } } }

是不是很明了呢?当然了,网上一搜一大把,我这个也是不小心搜到的,感觉比较不错的代码,后来经过我少许加工,即可使用了。当然,在这里,还要提一 句,这个小程序,为了让它更方便,直接拖拽文件到其图标之上,就默认打开程序,加载该文件,并进行加密操作,听起来是不是很cool!?呵呵,下面再和大 家分享一下如何实现吧:

在窗体的DragDrop和DragEnter事件下,添加如下代码:

代码

private void MainForm_DragEnter(object sender, DragEventArgs e) { if (e.Data.GetDataPresent(DataFormats.FileDrop)) e.Effect = DragDropEffects.Move; else e.Effect = DragDropEffects.None; } private void MainForm_DragDrop(object sender, DragEventArgs e) { string path = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString(); extension = System.IO.Path.GetExtension(path);//扩展名 if (extension == ".encrypted") { btnEncy.Enabled = false; btnDecy.Enabled = true; } else { btnEncy.Enabled = true; btnDecy.Enabled = false; } txtInFile.Text = path; }

Ok,是不是很简单,这样,在程序未启动时,拖拽一个目标文件到程序图标上,程序会自动打开,并进行相应操作。具体的操作,大家可以自己创造更有意义的代码来进行操作!

最后,献上下载地址,源代码:点击下载。

希望对大家有用哦

[转载]设计模式——Facade模式

mikel阅读(1081)

[转载]设计模式——Facade模式 – 探索、挖掘、研究、致用、创新 – 博客园.

本文用Facade模式(外观模式)模拟:管理者向车轮车间下达生产车轮的过程。希望更好的体现出Facade模式的价值

场景描述:

车子零件生产部门接到任务,需要生产一批车轮子给制造车子的部门。

Manager(客户)首先找到车轮子生产车间的负责人(Facade)下达任务:”生产100车轮子去。”

完了,一句话,Manager(客户)的工作完成了。

负责人(Facade)通知轮胎生产线(子系统),车圈生产线(子系统):”你们做100个轮胎出来。”

完事,他的任务也完成了

轮胎生产线(子系统),车圈生产线(子系统)启动机器就开始了

在此之前,有必要回顾一下Facade模式的概述。

Facade模式是一种结构型设计模式(Structural Pattern)。

结构型设计模式,描述如何将类或者对象结合在一起形成更大的结构。

设计模式元老是这样描述Facade模式的:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。

Facade将客户的请求代理给适合的子系统对象。客户发送请求给Facade的方式与子系统通信。

从而客户不需要直接访问子系统对象。Facade隐藏了子系统的内部细节,减少了客户处理的事物,从而实现解耦。

ok,开始


先来构建车间(子系统)角色

01 <span style="font-size: 12pt;"> /// <summary>
02 /// 车圈车间
03 /// </summary>
04 public class RimWorkshop
05 {
06 public void ProduceRim(int count)
07 {
08 //生产中..
09 Console.WriteLine(count+"个车圈,生产完毕");
10 }
11 }
12
13 /// <summary>
14 /// 轮胎车间
15 /// </summary>
16 public class TireWorkshop
17 {
18 /// <summary>
19 /// 生产轮胎
20 /// </summary>
21 public void ProduceTire(int count)
22 {
23 //生产中...
24 Console.WriteLine(count+"个轮胎,生产完毕");
25 }
26 }</span>

再来构建车间负责任人(Facade)角色

01 <span style="font-size: 12pt;"> /// <summary>
02 /// Facaee 模式
03 /// </summary>
04 public class Facade
05 {
06 private int _count;
07 public Facade(int count)
08 {
09 _count = count;
10 }
11
12 /// <summary>
13 /// 生产轮子 (车间管理者)
14 /// </summary>
15 public void ProduceWheel()
16 {
17 //生产轮胎
18 TireWorkshop tws = new TireWorkshop();
19 tws.ProduceTire(_count);
20
21 //生产车圈
22 RimWorkshop rws = new RimWorkshop();
23 rws.ProduceRim(_count);
24 }
25 }
26 </span>


再来构建Manager(客户)角色

01 <span style="font-size: 12pt;"> /// <summary>
02 /// 零件管理者
03 /// </summary>
04 class Manager
05 {
06 /// <summary>
07 /// 下达任务
08 /// </summary>
09 public void RunTask()
10 {
11 //通知造轮子小组任务
12 Facade facade = new Facade(100);
13 //开始生产
14 facade.ProduceWheel();
15
16 Console.ReadLine();
17 }
18 }
19 </span>

杂谈:

Facade模式可应用于下面几种场合中

  1. 希望封装或者隐藏子系统
  2. 只想使用一个复杂系统中的部分功能
  3. 对于一个现有的系统,希望扩展新的功能


[转载]c#美味:使用checked语句防止数据溢出

mikel阅读(921)

[转载]c#美味:使用checked语句防止数据溢出 – Greenerycn’s Blog – 博客园.

C#中有一个关键字checked,它用来判断当前上下文中的数值运算和数值转换是否会溢出。如是是常量溢出,那在编译时就能发现;如果是变量溢出,那在运行时会抛出OverflowException。

数值运算有:++   —   – (unary)   +   –   *   /

有了这个就不用担心数据溢出了。

checked

checked 有两种使用方法:

1.作为操作符来使用

int a = int.MinValue;
int c = checked(a--);

执行的时候会抛出异常:

image

2.检查一大块代码

这样子会对里面所有的代码都做检查

checked
{
    int a = int.MinValue;
    int c = a--;
}

如下图:

image

unchecked

和checked对应,还有一个unchecked关键字,用来取消检查。

也是两种使用;

1.作为运算符

int a = int.MinValue;
int c = unchecked(a--);

这样子就不会抛异常了

image

2.检查一大块代码

unchecked
{
    int a = int.MinValue;
    int c = a--;
}

也不抛异常:

image

/checked 和/checked-

如果代码里总是要写这么多checked语句是不是很烦?如果能有一个编译参数就好,只有设置了就都会检查。微软也想到了这个,它提供了一个/checked 参数来做,也提供了一个/checked-来取消。

  • 溢出检查 /checked,也可以是/checked+
  • 溢出不检查 /checked-

当然,你想取消所有的检查也是可以的,命令行参数是/checked-

csc t2.cs /checked

其中csc是编译器csc.exe , t2.cs 是被编译的代码文件。

我想很多人是用Visual Studio吧。VS里也是可以设置的。

步骤如下,我以VS2010为例,(VS2005,2008差不多)

1。在工程上点右键,选择菜单Properties

image

2。点击“Build”,再点击“Advanced”

image

3。在打开的对话框中,把“Check for arithmetic overflow/underflow”打上勾

image

几个注意

1.checked语句只对当前上下文中的代码有效,即不对调用的函数内部做检查

static void Main(string[] args)
{
    checked
    {
        TestFun();
    }

}

static void TestFun()
{
    int a = int.MinValue;
    int c = a--;
}

这段代码中。不会跑异常,因为checked关键字没有影响到TestFun内部。如果需要这么做的话,要么在TestFun内部加checked关键字,要么打开全局开关(加编译参数/checked或者VS中设置)。

2.checked,unchecked关键字不检查左移和右移是否溢出。

static void Main(string[] args)
{
    checked
    {
        int a = int.MinValue;
        int c = a>>1;
    }

}

执行不会抛异常:

image

3.为了性能考虑,建议Debug时做检查,Release时不做检查。

参考资料

/checked (Check Integer Arithmetic)

http://msdn.microsoft.com/en-us/library/h25wtyxf(v=VS.71).aspx

Arithmetic Overflow Checking using checked/unchecked

http://www.codeproject.com/KB/cs/overflow_checking.aspx

C# 3.0 in a Nutshell, 3rd Edition

Chapter 2.4.5.2. Integral overflow