Cuyahoga添加模块

Cuyahoga

国外的开源CMS一般都是基于模块设计的 ,好处是可以随意定制自己的页面和模块,这样在以后的应用中就能够灵活的满足变化的功能需求. 一个模块齐全的CMS如DNN , Rainbow就可以快速搭建符合需求的系统.

下面就来介绍如何为Cuyahoga这个著名的开源网站框架加入具有后台管理的公告模块.可以参考这篇如何在Cuyahoga中新增一个简单的功能模块了解基础的步骤.

为Cuyahoga开发自定义模块时,你可以选择任何数据访问策略.然而Cuyahoga本身是使用NHibernate作为数据持久层,可以做到支持多数据库. 采用Castle.Windsor进行依赖注入,降低模块之间的耦合. 我们的数据访问层也将用NHibernate实现.

最终项目的目录结构如下:

主要步骤如下
1 .创建一个Sql文件(Install.sql)用来安装数据表及添加模块的相关信息 , 该sql文件会在安装模块时,由Cuyahoga自动执行.也可以手工执行进行安装.

install.sql
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>IF NOT EXISTS (SELECT * FROM sysobjects WHERE id = OBJECT_ID(N[cm_Announcements]AND OBJECTPROPERTY(id, NIsUserTable= 1)
 
BEGIN
CREATE TABLE [cm_Announcements] (
    
[AnnouncementsID] [int] IDENTITY (1,1)NOT NULL ,
    
[sectionid] [int] NOT NULL ,
    
[createdby] [nvarchar] (100NULL ,//公告作者
    
[Title] [nvarchar] (150NULL ,//公告标题
    inserttimestamp 
datetime DEFAULT current_timestamp NOT NULL,
    updatetimestamp 
datetime DEFAULT current_timestamp NOT NULL,
    
    
CONSTRAINT [PK_cm_Announcements] PRIMARY KEY  NONCLUSTERED 
    (
        
[AnnouncementsID]
    ),
    
CONSTRAINT [FK_cm_Announcements_cm_Modules] FOREIGN KEY 
    (sectionid) 
REFERENCES cuyahoga_section (sectionid)
)
END
GO
/*加入模块信息*/
INSERT INTO cuyahoga_moduletype ([name], assemblyname, classname, path, editpath, inserttimestamp, updatetimestamp) VALUES 
(
AnnouncementsCuyahoga.Modules.AnnouncementsCuyahoga.Modules.Announcements.AnnouncementsModule
Modules/Announcements/Announcements.ascxModules/Announcements/EditAnnouncements.aspxcurrent_timestampcurrent_timestamp)
GO
/*加入模块版本信息*/
INSERT INTO cuyahoga_version (assembly, major, minor, patch) VALUES (Cuyahoga.Modules.Announcements150);
go

2.创建域模型 在本例中是实体类

Announcement.cs
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>using System;
using Cuyahoga.Core.Domain;

namespace Cuyahoga.Modules.Announcements.Domain
{
    public class Announcement
    {
        private 
int _id;
        private string _title;
        private string _content;
        private 
DateTime _expiredate;
        private Section _section;
        private 
User _createdBy;
        private 
DateTime _updateTimestamp;

        /// <summary>
        
/// Property Id (int)
        
/// </summary>
        
public int Id
        {
            get { 
return this._id; }
            
set { this._id = value; }
        }
        
/// <summary>
        
/// Property Title (string)
        
/// </summary>
        
public string Title
        {
            get { 
return this._title; }
            
set { this._title = value; }
        }
        
/// <summary>
        
/// Property Section (Section)
        
/// </summary>
        
public Section Section
        {
            get { 
return this._section; }
            
set { this._section = value; }
        }
        
/// <summary>
        
/// Property CreatedBy (User)
        
/// </summary>
        
public User CreatedBy
        {
            get { 
return this._createdBy; }
            
set { this._createdBy = value; }
        }
        
/// <summary>
        
/// Property UpdateTimestamp (DateTime)
        
/// </summary>
        
public DateTime UpdateTimestamp
        {
            get { 
return this._updateTimestamp; }
            
set { this._updateTimestamp = value; }
        }
        
public Announcement()
        {
            this._id 
= 1;
        }
    }
}

3.创建映射文件

Announcement.hbm.xml
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>xml version=”1.0″ encoding=”utf-8″  >
<hibernate-mapping xmlns=”urn:nhibernate-mapping-2.0″>
  
<class name=”Cuyahoga.Modules.Announcements.Domain.Announcement, Cuyahoga.Modules.Announcements” table=”cm_Announcements”>
    
<id name=”Id” column=”Announcementsid” type=”Int32″ unsaved-value=”-1″>
      
<generator class=”native”>
        
<param name=”sequence”>cm_Announcements_Announcementsid_seq</param>
      
</generator>
    
</id>
    
<timestamp name=”UpdateTimestamp” column=”updatetimestamp” />
    
<property name=”Title” column=”title” type=”String” length=”150″ />
    
<many-to-one name=”Section” class=”Cuyahoga.Core.Domain.Section, Cuyahoga.Core” column=”sectionid” not-null=”true” />
    
<many-to-one name=”CreatedBy” class=”Cuyahoga.Core.Domain.User, Cuyahoga.Core” column=”createdby” not-null=”true” />
  
</class>
</hibernate-mapping>

4.创建公告模块的核心控制类

AnnouncementsModule.cs
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>using System;
using System.Collections;
using System.Xml;
using System.Xml.XPath;
using System.Net;
using System.Web;
using System.Text;
using System.IO;
using System.Threading;

using NHibernate;
using Castle.Services.Transaction;
using Castle.Facilities.NHibernateIntegration;

using log4net;

using Cuyahoga.Core;
using Cuyahoga.Core.Domain;
using Cuyahoga.Core.Service;
using Cuyahoga.Core.Util;
using Cuyahoga.Web.Util;
using Cuyahoga.Web.Components;
using Cuyahoga.Modules.Announcements.Domain;

namespace Cuyahoga.Modules.Announcements
{
    
//采用Facilities管理事务
    [Transactional]
    
public class AnnouncementsModule : ModuleBase, INHibernateModule
    {
        
private static readonly ILog log = LogManager.GetLogger(typeof(AnnouncementsModule));
        
private int _cacheDuration;
        
private ISessionManager _sessionManager;

        //该模块需要用到NHibernate session manager提供的服务 进行依赖注入
        public AnnouncementsModule(ISessionManager sessionManager)
        {
            
this._sessionManager = sessionManager;
        }

        public override void ReadSectionSettings()
        {
            
base.ReadSectionSettings();
            
// Set dynamic module settings
            this._cacheDuration = Convert.ToInt32(base.Section.Settings[CACHE_DURATION]);
        }

        ///不创建子事务
        [Transaction(TransactionMode.RequiresNew)]
        
public virtual IList GetAllAnnouncements()
        {
            ISession session 
= this._sessionManager.OpenSession();
            
string hql = from Announcement f where f.Section.Id = :sectionId;
            IQuery q 
= session.CreateQuery(hql);
            q.SetInt32(
sectionIdbase.Section.Id);
            
return q.List();
        }

        [Transaction(TransactionMode.RequiresNew)]
        public virtual Announcement GetAnnouncementsById(int AnnouncementsID)
        {
            ISession session 
= this._sessionManager.OpenSession();
            
return (Announcement)session.Load(typeof(Announcement), AnnouncementsID);
        }

        [Transaction(TransactionMode.RequiresNew)]
        public virtual void SaveAnnouncement(Announcement announcements)
        {
            ISession session 
= this._sessionManager.OpenSession();
            session.SaveOrUpdate(announcements);
        }

        [Transaction(TransactionMode.RequiresNew)]
        public virtual void DeleteAnnouncements(Announcement announcements)
        {
            ISession session 
= this._sessionManager.OpenSession();
            session.Delete(announcements);
        }
    }
}

5.创建用于前台显示的用户控件 用来显示公告的标题 作者和发布时间.

Announcements.ascx
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><%@ Control Language=C# AutoEventWireup=true Codebehind=Announcements.ascx.cs
    Inherits
=Cuyahoga.Modules.Announcements.Web.Announcements %>
<asp:repeater id=rptAnnouncementItems runat=server enableviewstate=False>
    
<itemtemplate>
            
<div class=genericdetails style=width:100%>
            
<marquee  direction=left >
                
<asp:label id=lblTitle runat=server><%# DataBinder.Eval(Container.DataItem, Title)%></asp:label>
                
<asp:label id=lblAuthor runat=server>作者:<%# DataBinder.Eval(Container.DataItem, CreatedBy.FullName)%></asp:label>
                
<asp:label id=lblTime runat=server>发布时间:<%# DataBinder.Eval(Container.DataItem, UpdateTimestamp)%></asp:label>
            
</marquee>
            
</div>
    
</itemtemplate>
</asp:repeater>

Announcements.ascx.cs
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–>using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

using Cuyahoga.Core.Util;
using Cuyahoga.Web.UI;
using Cuyahoga.Modules.Announcements.Domain;

namespace Cuyahoga.Modules.Announcements.Web
{
    
public partial class Announcements : BaseModuleControl
    {
        
private AnnouncementsModule _module;
        
protected void Page_Load(object sender, EventArgs e)
        {
            
if (!this.IsPostBack && !base.HasCachedOutput)
            {
                
this._module = base.Module as AnnouncementsModule;
                
this.rptAnnouncementItems.DataSource = this._module.GetAllAnnouncements();
                
this.rptAnnouncementItems.DataBind();
            }
        }
    }
}

6.创建公告管理的列表页面

EditAnnouncements.aspx
<!–<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
–><%@ Page Language=C# AutoEventWireup=true Codebehind=EditAnnouncements.aspx.cs
    Inherits
=Cuyahoga.Modules.Announcements.Web.EditAnnouncements %>

<!DOCTYPE html PUBLIC “-//W3C//DTD XHTML 1.0 Transitional//EN” “http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd”>
<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
    
<title>公告管理页面</title>
</head>
<body>
    
<form id=”Form1″ method=”post” runat=”server”>
        
<div id=”moduleadminpane”>
            
<h1>
                公告管理
</h1>
            
<table class=”tbl”>
                
<asp:Repeater ID=”rptAnnouncements” runat=”server” OnItemDataBound=”rptFiles_ItemDataBound”>
                    
<HeaderTemplate>
                        
<tr>
                            
<th>
                                公告标题
</th>
                            
<th>
                                作者
</th>
                            
<th>
                                发布日期
</th>
                            
<th>
                            
</th>
                        
</tr>
                    
</HeaderTemplate>
                    
<ItemTemplate>
                        
<tr>
                            
<td>
                                
<%# DataBinder.Eval(Container.DataItem, Title%>
                            
</td>
                            
<td>
                                
<%# DataBinder.Eval(Container.DataItem, CreatedBy.FullName)%>
                            
</td>
                            
<td>
                                
<asp:Literal ID=”litDateModified” runat=”server”></asp:Literal></td>
                            
<td>
                                
<asp:HyperLink ID=”hplEdit” runat=”server”>修改</asp:HyperLink>
                            
</td>
                        
</tr>
                    
</ItemTemplate>
                
</asp:Repeater>
            
</table>
            
<br />
            
<input id=”btnNew” type=”button” value=”新的公告” runat=”server” name=”btnNew”/>
        
</div>
    
</co

如何实现Asp与Asp.Net共享Session

微软.net中,session的存储机制已经与asp的存储机制不一样,虽然可以在同一个iis下同时运行asp与aspx,但是它们之间不能传递session。
之前大批系统应用到了asp,在升级过程中,如果完全抛弃asp来重写,一来工作量太大,二来以前的成果不能保存下来。

所以微软提出了一个session共享的解决方案,只是此文档光说明原理,并没有说具体的操作步骤,由此,我撰文描述过程。

简单说明原理,asp与asp.net之间的session统一存储在数据库中来实现共享

1、创建数据表
打开sql server查询分析器,运行以下脚本来创建数据表,数据表名为sessionstate
if exists (select * from sysobjects where id = object_id(n'[dbo].[sessionstate]’) and objectproperty(id, n’isusertable’) = 1)
drop table [dbo].[sessionstate]
go

create table [dbo].[sessionstate] (
[id] uniqueidentifier not null ,
[data] [image] not null ,
[last_accessed] [datetime] not null
) on [primary] textimage_on [primary]
go

alter table [dbo].[sessionstate] with nocheck add
constraint [pk_sessionstate] primary key nonclustered
(
[id]
) on [primary]
go

2、下载以下文件 session.rar

将文件解压后,将产生4个文件,分别作如下操作。
复制 global.asa 到系统根目录下,并打开文件,修改application(“sessiondsn”) 为合适的数据库链接字符串,如果系统本身已经有了global.asa,则在此文件中添加如下application:
application(“sessiondsn”) = “initial catalog=sqlservername;persist security info=false;user id=sa;password=****;packet size=4096”
在系统的 web.config 文件中,添加此项
<add key=”sessiondsn” value=”data source=sqlservername;initial catalog=sessiondemodb;persist security info=false;user id=sessiondemodbuser;password=****;packet size=4096″ />
并将其值修改为合适的数据库链接。
将另外两个dll文件复制到系统目录下(或其他合适目录)

3、关闭iis中asp的session选项
打开iis,选择站点,依次选择属性 -> 主目录 -> 配置 -> 应用程序选项,将启用会话状况前的复选勾去除。如下图:
screen.width-350)this.width=screen.width-350″ border=0>

4、安装sessionutility.dll
首先找到 gacutil.exe 文件,一般情况下在 microsoft visual studio .net 2003\sdk\v1.1\bin 目录下
在命令提示符窗口中,执行 gacutil /i sessionutility.dll,(如果执行失败,请将这两个文件的路径都写全了)

5、注册sessionutility.dll为com对象
同样,要找到 regasm.exe 文件,一般情况下在 winnt\microsoft.net\framework\v1.1.4322 目录下
在命令提示符窗口中,执行 regasm.exe sessionutility.dll /tlb:sessionutility.tlb,(如果执行失败,请将这两个文件的路径都写全了)
这样就会产生出一个tlb文件,可当做普通的com组件来调用。

6、注册sessionmanager.dll
这个很简单了,在命令提示符窗口中,执行regsvr32 sessionmanager.dll

7、如果是ntfs格式的系统,请找到 sessionmgr.dll,右键点击,属性,将iusr_<machine_name>权限设置为可读和可执行。

至此,我们已经可以实现了asp与asp.net之间session共享了,那么怎么去用

在asp中,我们要如下使用:
页面开始端
dim session
set session = server.createobject(“sessionmgr.session2”)
session(“userid”) = …



页面结束端
set session = nothing ‘记得一定要释放哦

而在asp.net中,我们要如下使用:
首先,我们要添加对sessionutility的引用
然后,编码时,原来是这样的继承 public class webform1 : system.web.ui.page,修改为public class webform1 : msdn.sessionpage
这样在编码过程中就可以使用session(“userid”)这样的形式了。

注意:虽然session实现了共享,但是session的使用语法,相对于.net中新增的部分,就没有实现,毕竟要照顾asp
譬如session.remove,就不能用了。

 

MS-SQL2005以上的版本解决Syscolumn表中数据不能修改

例如:

在MSSQL2000里面可以获取到相应的数据

获取TrainManage表中的TrainId字段

String.Format(“Select name From Syscolumns Where id = (Select id From sysobjects Where name='{0}’) And autoval Is Not Null”, _TableName)

但是在MSSQL2005以上的版本没有该条记录的数据

解决方案:

String.Format(“Select top 1 name From Syscolumns Where id = (Select id From sysobjects Where name='{0}’) And xtype = 127 “, _TableName)

为什么要这么做呢,而不通过获取某个表的字段名字就行呢。

因为这个是common文件,其他的文件也要调用这个sql语句了

,考虑到这点。所以现在只想到这个了,其他的还没有想到,如果有更好的,希望您能分享一下,如果有错误请批评指出。

如何在ASP.Net中把图片存入数据库

介绍

可能有很多的时候,我们急需把图片存入到数据库当中。在一些应用程序中,我们可能有一些敏感的资料,由于存储在文件系统(file system)中的东西,将很容易被某些用户盗取,所以这些数据不能存放在文件系统中。

在这篇文章中,我们将讨论怎样把图片存入到Sql2000当中。

在这篇文章中我们可以学到以下几个方面的知识:

1.插入图片的必要条件

2.使用流对象

3. 查找准备上传的图片的大小和类型

4.怎么使用InputStream方法?

插入图片的必要条件

在我们开始上传之前,有两件重要的事我们需要做:

#Form 标记的 enctype 属性应该设置成 enctype=”multipart/form-data”

# 需要一个<input type=file>表单来使用户选择他们要上传的文件,同时我们需要导入 System.IO名称空间来处理流对象

把以上三点应用到aspx页面。同时我们需要对SqlServer做以下的准备。

# 需要至少含有一个图片类型的字段的表

# 如果我们还有另外一个变字符类型的字段来存储图片类型,那样会更好一些。

现在,我们准备了一个Sql表(包含了一个image数据类型的字段),还有<input type=file>标记。当然我们还得准备Submit按钮,以便用户在选择了图片以后提交。在这个按钮的Onclick事件里,我们需要读取选取图片的内容,然后把它存入到表里。那我们先来看看这个Onclick事件。

提交按钮的Onclick事件的代码:

Dim intImageSize As Int64
Dim strImageType As String
Dim ImageStream As Stream

‘ Gets the Size of the Image
intImageSize = PersonImage.PostedFile.ContentLength

‘ Gets the Image Type
strImageType = PersonImage.PostedFile.ContentType

‘ Reads the Image
ImageStream = PersonImage.PostedFile.InputStream

Dim ImageContent(intImageSize) As Byte
Dim intStatus As Integer
intStatus = ImageStream.Read(ImageContent, 0, intImageSize)

‘ Create Instance of Connection and Command Object
Dim myConnection As New SqlConnection(ConfigurationSettings.AppSettings(“ConnectionString”))
Dim myCommand As New SqlCommand(“sp_person_isp”, myConnection)

‘ Mark the Command as a SPROC
myCommand.CommandType = CommandType.StoredProcedure

‘ Add Parameters to SPROC
Dim prmPersonImage As New SqlParameter(“@PersonImage”, SqlDbType.Image)
prmPersonImage.Value = ImageContent
myCommand.Parameters.Add(prmPersonImage)

Dim prmPersonImageType As New SqlParameter(“@PersonImageType”, SqlDbType.VarChar, 255)
prmPersonImageType.Value = strImageType
myCommand.Parameters.Add(prmPersonImageType)

Try
myConnection.Open()
myCommand.ExecuteNonQuery()
myConnection.Close()
Response.Write(“New person successfully added!”)
Catch SQLexc As SqlException
Response.Write(“Insert Failed. Error Details are: ” & SQLexc.ToString())
End Try

这是怎么工作的呢?
PersonImage是HTMLInputFile控件的对象。首先需要获得图片的大小,可以使用下面的代码实现:

intImageSize = PersonImage.PostedFile.ContentLength

然后返回图片的类型使用ContenType属性。最后,也是最重要的事就是取得Image Stream,这可以用以下代码实现:

ImageStream = PersonImage.PostedFile.InputStream

我们需要一个字节型数组来存储image 内容。读取整个图片可以使用Stream对象的Read方法来实现。Read(in byte[] buffer,int offset,int count)方法有三个参数。【关于Read方法的详细可以参看.Net FrameWorkSDK】他们是:

buffer

字节数组。此方法返回时,该缓冲区包含指定的字符数组,该数组的 offset 和 (offset + count) 之间的值由从当前源中读取的字节替换。

offset

buffer 中的从零开始的字节偏移量,从此处开始存储从当前流中读取的数据。

count

要从当前流中最多读取的字节数。

这个Read方法用以下代码实现:
intStatus = ImageStream.Read(ImageContent, 0, intImageSize)
.

现在,我们已经读取了整个图片的内容,下一步,我们要把这些内容存入到sql 表。我们将使用存储过程来完成插入图片类型和图片内容到sql 表。如果你浏览了上面的代码,你将会发现我们使用了sqldbtype.image的数据类型(datatype)。Ok了,完成了这些,我们也就成功的把图片存入到SqlServer中了。下面是我们编写的aspx页面。

结论

我们已经讨论了如何把图片存入到Sql Server,那么我们如何从SqlServer中读取图片呢?可以参看我的另一篇文章:在Asp.Net中从SqlServer中检索图片。

ASP.NET中大结果集的分页[翻译]

原文地址:http://www.codeproject.com/aspnet/PagingLarge.asp
作者:Jasmin Muharemovic
译者:Tony Qu(来自BluePrint翻译团队)

下载:
PagingTest Solution (C#) – 55.8 Kb
Paging_Procedures SQL script – 2.48 Kb
Paging_LargeTable SQL script – 0.6 Kb

介绍
在Web应用程序中,对一个大数据库结果集进行分页已经是一个家喻户晓的问题了。简单的说,你不希望所有的查询数据显示在一个单独的页面中,所以带有分页的显示才是更合适的。虽然在传统的asp里这并不是一个简单的任务,但在asp.net中,DataGrid控件把这一过程简化为只有几行代码。因此,在 asp.net中,分页很简单,但是默认的DataGrid分页事件会从数据库中把所有的记录全部读出来放到asp.net web应用程序中。当你的数据在一百万以上的时候,这将引起严重的性能问题(如果你不相信,你可以在你的应用程序中执行一个查询,然后在任务管理器中查看 aspnet_wp.exe的内存消耗情况)这也就是为什么需要自定义分页行为,这样可以保证仅获得当前页需要的数据记录。

在网上有很多关于这个问题的文章和帖子,还有一些成熟的解决方案。我写这篇文章的目的不是向你展示一个可以解决一切问题的存储过程,而是出于优化已有方法,同时为你提供一个可供测试的应用程序,这样你就可以根据自己的需要进行开发。下文是一个很好的开始,它包含了很多不同的方法,并且给出了一些性能测试结果

《如何通过Recordset进行分页?》

但是我对上文的大部分内容不是很满意。第一,半数的方法是用了传统的ADO,很明显它们是为“古老”的asp而写的。剩下的一些方法就是SQL Server存储过程,并且其中的一些由于相应时间过慢而无法使用,正如你在文章最后所看到的性能结果一样,但是还是有一些引起了我的注意。

通用化
我决定对其中的三个方法进行仔细的分析,它们是临时表(TempTable),动态SQL(DynamicSQL)和行计数 (Rowcount)。在下文中,我更愿意把第二个方法称为(升序-降序)Asc-Desc方法。我不认为动态SQL是一个好名字,因为你也可以把动态 SQL逻辑应用于另一个方法中。所有这些存储过程的通病在于,你不得不估计哪些列是你即将要排序的,而不仅仅是估计主键列(PK Columns)而已,这可能导致一系列的问题——对于每个查询来说,你需要通过分页显示,也就是说对于每不同的排序列你必须有许多不同的分页查询,这意味着你要么给每个排序列做不同的存储过程(无论使用哪种分页方法),也么你必须借助动态SQL的帮助把这个功能放在一个存储过程中。这两个方法对于性能有微小的影响,但是它增加了可维护性,特别是当你需要使用这个方法显示不同的查询。因此,在本文中我会尝试使用动态SQL对所有的存储过程进行归纳,但是由于一些原因,我们只能对实现部分的通用性,因此你还是得为复杂查询写独立的存储过程。

允许包括主键列在内的所有排序字段的第二个问题在于,如果那些列没有作适当的索引,那么这些方法一个也帮不上忙。在所有这些方法中,对于一个分页源必须先做排序,对于大数据表来说,使用非索引列排序的成本是可以忽略不计的。在这种情况下,由于相应时间过长,所有的存储过程都是无法在实际情况下使用的。(相应的时间各有不同,从几秒钟到几分钟不等,这要根据表的大小和所要获得的第一个记录而定)。其他列的索引会带来额外的不希望出现的性能问题,例如如果你每天的导入数据很多,它有可能变得很慢。

临时表
首先,我准备先来说一下临时表方法,这是一个广泛被建议使用的解决方案,我在项目中遇到过好几次了,这里有另一篇解释它如何工作的文章,还有一个如何在DataGrid中是用定制化分页(Custom Paging)的例子:

ASP.NET DataGrid分页 第二部分 – 定制化分页

这两篇文章中的方法都是通过把主键数据拷贝到临时表中,然后对主查询做join实现查询优化。下面让我们来看看这个方法的实质:

<!–<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>–>CREATETABLE#Temp(
ID
intIDENTITYPRIMARYKEY,
PK
/*heregoesPKtype*/
)

INSERTINTO#TempSELECTPKFROMTableORDERBYSortColumn

SELECTFROMTableJOIN#TemptempONTable.PK=temp.PKORDERBYtemp.ID
WHEREID>@StartRowANDID<@EndRow

通过把所有的行拷贝到临时表中,我们可以对查询进一步的优化(SELECT TOP EndRow …),但是关键在于最坏情况——一个包含100万记录的表就会产生一个100万条记录的临时表。考虑到这样的情况,再看看上面文章的结果,我决定在我的测试中放弃该方法

升序-降序
这个方法在子查询中使用默认排序,在主查询中使用反向排序,原理是这样的:

<!–<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>–>DECLARE@tempTABLE(
PK
/*PKType*/NOTNULLPRIMARY
)

INSERTINTO@temp
SELECTTOP@PageSizePKFROM(
SELECTTOP(@StartRow+@PageSize)
PK,
SortColumn
/*IfsortingcolumnisdefferentfromthePK,SortColumnmust
befetchedaswell,otherwisejustthePKisnecessary
*/
ORDERBYSortColumn/*defaultorder–typicallyASC*/)
ORDERBYSortColumn/*reverseddefaultorder–typicallyDESC*/

SELECTFROMTableJOIN@TemptempONTable.PK=temp.PK
ORDERBYSortColumn/*defaultorder*/

完整代码:Paging_Asc_Desc

行计数

这个方法的基本逻辑依赖于SQL中的SET ROWCOUNT表达式,这样可以跳过不必要的行并且获得需要的行记录

<!–<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>–>DECLARE@Sort/*thetypeofthesortingcolumn*/
SETROWCOUNT@StartRow
SELECT@Sort=SortColumnFROMTableORDERBYSortColumn
SETROWCOUNT@PageSize
SELECTFROMTableWHERESortColumn>=@SortORDERBYSortColumn

完整代码:Paging_RowCount

子查询
还有两个方法也是我考虑过的,他们的来源不同。第一个是众所周知的三角查询(Triple Query)或者说自查询方法,我找的一个比较透彻的方法在下面的文章中有描述

SQL Server服务器端分页

虽然你需要订阅,但是可以下载一个包含子查询存储过程定义的zip文件。列表4 SELECT_WITH_PAGINGStoredProcedure.txt文件包含一个完整的通用的动态SQL。在本文中,我也用一个类似的包含所有其他存储过程的通用逻辑。这里的原理是连接到整个过程中,我对原始代码做了一些缩减,因为recordcount在我的测试中不需要)

<!–<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>–>SELECTFROMTableWHEREPKIN
(
SELECTTOP@PageSizePKFROMTableWHEREPKNOTIN
(
SELECTTOP@StartRowPKFROMTableORDERBYSortColumn)
ORDERBYSortColumn)
ORDERBYSortColumn

完整代码:Paging_SubQuery

游标
在看google讨论组的时候,我找到了最后一个方法,你可以点这里查看原始帖子。该方法是用了一个服务器端动态游标。许多人试图避免使用游标,因为游标没有关系可言,以及有序性导致其效率不高,但回过头来看,分页其实是一个有序的任务,无论你使用哪种方法,你都必须回到开始行记录。在之前的方法中,先选择所有在开始记录之前的所有行,加上需要的行记录,然后删除所有之前的行。动态游标有一个FETCH RELATIVE选项可以完成魔法般的跳转。基本的逻辑如下:

<!–<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>–>DECLARE@PK/*PKType*/
DECLARE@tblPKTABLE(
PK
/*PKType*/NOTNULLPRIMARYKEY
)

DECLAREPagingCursorCURSORDYNAMICREAD_ONLYFOR
SELECT@PKFROMTableORDERBYSortColumn

OPENPagingCursor
FETCHRELATIVE@StartRowFROMPagingCursorINTO@PK

WHILE@PageSize>0AND@@FETCH_STATUS=0
BEGIN
INSERT@tblPK(PK)VALUES(@PK)
FETCHNEXTFROMPagingCursorINTO@PK
SET@PageSize=@PageSize1
END

CLOSEPagingCursor
DEALLOCATEPagingCursor

SELECTFROMTableJOIN@tblPKtempONTable.PK=temp.PK
ORDERBYSortColumn

完整代码:Paging_Cursor

复杂查询的通用化
我在之前指出,所有的存储过程都是用动态SQL实现通用性的,因此,理论上它们可以用任何种类的复杂查询。下面有一个基于Northwind数据库的复杂查询例子。

<!–<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>–>SELECTCustomers.ContactNameASCustomer,
Customers.Address
+,+Customers.City+,+
Customers.Country
ASAddress,
SUM([OrderDetails].UnitPrice*[OrderDetails].Quantity)AS
[Totalmoneyspent]
FROMCustomers
INNERJOINOrdersONCustomers.CustomerID=Orders.CustomerID
INNERJOIN[OrderDetails]ONOrders.OrderID=[OrderDetails].OrderID
WHERECustomers.Country<>USAANDCustomers.Country<>Mexico
GROUPBYCustomers.ContactName,Customers.Address,Customers.City,
Customers.Country
HAVING(SUM([OrderDetails].UnitPrice*[OrderDetails].Quantity))>1000
ORDERBYCustomerDESC,AddressDESC

返回第二个页面的分页存储调用如下:

<!–<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>–>EXECProcedureName
/*Tables*/
Customers
INNERJOINOrdersONCustomers.CustomerID=Orders.CustomerID
INNERJOIN[OrderDetails]ONOrders.OrderID=[OrderDetails].OrderID
,
/*PK*/
Customers.CustomerID,
/*ORDERBY*/
Customers.ContactNameDESC,Customers.AddressDESC,
/*PageNumber*/
2,
/*PageSize*/
10,
/*Fields*/
Customers.ContactNameASCustomer,
Customers.Address+
,+Customers.City+,+Customers.Country
ASAddress,
SUM([OrderDetails].UnitPrice*[OrderDetails].Quantity)AS[Totalmoneyspent]
,
/*Filter*/
Customers.Country<>USAANDCustomers.Country<>Mexico”’,
/*GroupBy*/
Customers.CustomerID,Customers.ContactName,Customers.Address,
Customers.City,Customers.Country
HAVING(SUM([OrderDetails].UnitPrice*[OrderDetails].Quantity))>1000

值得注意的是,在原始查询中在ORDER BY语句中使用了别名,但你最好不要在分页存储过程中这么做,因为这样的话跳过开始记录之前的行是很消耗时间的。其实有很多种方法可以用于实现,但原则是不要在一开始把所有的字段包括进去,而仅仅是包括主键列(等同于RowCount方法中的排序列),这样可以加快任务完成速度。只有在请求页中,才获得所有需要的字段。并且,在最终查询中不存在字段别名,在跳行查询中,必须提前使用索引列。

行计数(RowCount)存储过程有一个另外的问题,要实现通用化,在ORDER BY语句中只允许有一个列,这也是升序-降序方法和游标方法的问题,虽然他们可以对几个列进行排序,但是必须保证主键中只有一个字段。我猜如果用更多的动态SQL是可以解决这个问题的,但是在我看来这不是很值得。虽然这样的情况很有可能发生,但他们发生的频率不是很高。通常你可以用上面的原理也独立的分页存储过程。

性能测试
在测试中,我使用了四种方法,如果你有更好的方法的话,我很有兴趣知道。不管如何,我需要对这些方法进行比较,并且评估它们的性能。首先我的第一个想法就是写一个asp.net包含分页DataGrid的测试应用程序,然后测试页面结果。当然,这无法反映存储过程的真实响应时间,所以控制台应用程序显得更加适合。我还加入了一个Web应用程序,但不是为了性能测试,而是一个关于DataGrid自定义分页和存储过程一起工作的例子。这两个应用程序都可以在 Paging Test Solution中找到。

在测试中,我使用了一个自动生成得大数据表,大概插入了500000条数据。如果你没有一张这样的表来做实验,你可以点击这里下载一段用于生成数据的表设计和存储过程脚本。我没有使用一个自增的主键列,而是用一个唯一识别码来识别记录的。如果我使用上面提到的脚本,你可能会考虑在生成表之后添加一个自增列,这些自增数据会根据主键进行数字排序,这也意味着你打算用一个带有主键排序的分页存储过程来获得当前页的数据。

为了实现性能测试,我是通过一个循环多次调用一个特定的存储过程,然后计算平均相应时间来实现的。考虑到缓存的原因,为了更准确地建模实际情况——同一页面对于一个存储过程的多次调用获得数据的时间通常是不适合用来做评估的,因此,我们在调用同一个存储过程时,每一次调用所请求的页码应该是随机的。当然,我们必须假设页的数量是固定的,10-20页,不同页码的数据可能被获取很多次,但是是随机获取的。

有一点我们很容易注意到,相应时间是由要获取的页数据相对于结果集开始的位置的距离决定的,越是远离结果集的开始位置,就有越多的记录要跳过,这也是我为什么不把前20也包括进我的随机序列的原因。作为替换,我会使用2的n次方个页面,循环的大小是需要的不同页的数量*1000,所以,每个页面几乎都被获取了1000次(由于随机原因,肯定会有所偏差)

结果
这里有我的测试结果:Paging_Results (Excel文件)





结论
测试是按照从性能最好到最差的顺序进行的——行计数、游标、升序-降序、子查询。有一件事很有趣,通常人们很少会访问前五页之后的页面,因此子查询方法可能在这种情况下满足你的需要,这得看你的结果集的大小和对于远距离(distant)页面的发生频率预测,你也很有可能使用这些方法的组合模式。如果是我,在任何情况下,我都更喜欢用行计数方法,它运行起来十分不错,即使对于第一页也是如此,这里的“任何情况”代表了一些很难实现通用化的情况,在这种情况下,我会使用游标。(对于前两页我可能使用子查询方法,之后再用游标方法)

ASP.NET2.0中用Gridview控件操作数据

在ASP.NET 2.0中,加入了许多新的功能和控件,相比asp.net 1.0/1.1,在各方面都有了很大的提高。其中,在数据控件方面,增加了不少控件,其中的Gridview控件功能十分强大。在本文中,将探讨Gridview控件中的一些功能特性和用法,如果各位读者对Gridview控件不大了解,可以通过《使用ASP.NET 2.0中的Gridview控件》一文,来对Gridview控件有个初步的认识。

  1、使用Gridview插入新记录

  在Gridview控件中,可以实现插入新记录的操作(见《使用ASP.NET 2.0中的Gridview控件》)一文,但如果想实现在Gridview中,实现在Gridview控件的最后一行,提供一个空白行给用户输入要输入的记录,那无疑是很方便的。下面将介绍其实现方法。

  首先,我们打算在让用户进行选择,当用户需要新增一记录时,便点击新增按钮,之后在Gridview的最后一行里,显示一个空白行,让用户按字段进行输入,如下图所示:
  

   
 当用户决定不输入新空白记录时,可以按”cancel”按钮返回,该空白行消失。要实现这样的效果,我们可以充分利用Gridview的footer的模版功能进行自定义,因为有3列,所以,在每一列的footer模版中,定义如下:

<asp:Gridview ID=”Gridview1″ Runat=”server” DataSourceID=”SqlDataSource1″ DataKeyNames=”CustomerID” AutoGenerateColumns=”False” ShowFooter=”True”>
<Columns>
 <asp:TemplateField>
  <ItemTemplate>
   <asp:Label ID=”CustomerIDLabel” Runat=”Server”><%# Eval(“CustomerID”) %></asp:Label>
  </ItemTemplate>
  <FooterTemplate>
   <asp:TextBox ID=”CustomerIDTextBox” Runat=”server”></asp:TextBox>
  </FooterTemplate>
 </asp:TemplateField>

 <asp:TemplateField>
  <ItemTemplate>
   <asp:Label ID=”CompanyNameLabel” Runat=”Server”><%# Eval(“CompanyName”) %></asp:Label>
  </ItemTemplate>
  <FooterTemplate>
   <asp:TextBox ID=”CompanyNameTextBox” Runat=”server”></asp:TextBox>
  </FooterTemplate>
 </asp:TemplateField>

 <asp:TemplateField>
  <FooterTemplate>
   <asp:DropDownList ID=”ContactTitleDropDownList” Runat=”server” DataSourceID=”SqlDataSource2″ DataTextField=”ContactTitle” DataValueField=”ContactTitle”>
   </asp:DropDownList>
   <asp:SqlDataSource ID=”SqlDataSource2″ Runat=”server” SelectCommand=”SELECT DISTINCT [ContactTitle] FROM [Customers]”
ConnectionString=”server=localhost;uid=sa;password=xxx;database=northwind”>
   </asp:SqlDataSource>

   <asp:Button ID=”Button1″ Runat=”server” Text=”Add” OnClick=”Button1_Click” />
   <asp:Button ID=”CancelButton1″ Runat=”server” Text=”Cancel” OnClick=”CancelButton1_Click” />
  </FooterTemplate>

 <ItemTemplate>
  <asp:DropDownList ID=”ContactTitleDropDown” SelectedValue=’<%# Bind(“ContactTitle”) %>’ Runat=”Server” DataSourceID=”SqlDataSource3″ DataTextField=”ContactTitle” DataValueField=”ContactTitle” ></asp:DropDownList>
  <asp:SqlDataSource ID=”SqlDataSource3″ Runat=”server” SelectCommand=”SELECT DISTINCT [ContactTitle] FROM [Customers]”
ConnectionString=”server=localhost;uid=sa;password=xxxx;database=northwind” EnableCaching=”True”>
  </asp:SqlDataSource>
 </ItemTemplate>
 </asp:TemplateField>
</Columns>
</asp:Gridview>

  以上为Gridview的代码,可以看到,在第一,二列的<foottemplate>列中,分别提供了customerid和companyname两个文本框以供用户输入,在第三列的<footertemplate>列中,以dropdownlistbox的形式来显示contracttitle.。其中,请注意第三列的footertemplate中的add和cancel两个按钮的,它们的事件代码如下

<script runat=”server”>
void CancelButton1_Click(object sender, EventArgs e)
{
 Gridview1.ShowFooter = false;
}
void AddButton1_Click(object sender, EventArgs e)
{
 Gridview1.ShowFooter = true;
}

 //点add按钮时,将新增的记录更新到数据库中去
void Button1_Click(object sender, EventArgs e)
{
 TextBox customerID = Gridview1.FooterRow.FindControl(“CustomerIDTextBox”) as TextBox;
 TextBox companyName = Gridview1.FooterRow.FindControl(“CompanyNameTextBox”) as TextBox;
 DropDownList ContactTitle = Gridview1.FooterRow.FindControl(“ContactTitleDropDownList”) as DropDownList;
 SqlDataSource1.InsertParameters[“CustomerID”].DefaultValue = customerID.Text;
 SqlDataSource1.InsertParameters[“CompanyName”].DefaultValue = companyName.Text;  
 SqlDataSource1.InsertParameters[“ContactTitle”].DefaultValue=ContactTitle.SelectedValue;
 SqlDataSource1.Insert();
}
</script>

  其中的cancel按钮的事件,用来取消显示Gridview的footer模版,因此设置showfooter属性为false,而addbutton1按钮,是当用户决定新增记录时点选的,此时将设置showfooter属性为true,以显示各列的foottemplate,从而达到显示新的一个空白行的目的。

  而在更新代码button1_click事件中,将首先使用Gridview1.footerrow.findcontrol的方法,将用户新增的各字段的值提取出来,然后分别赋值给sqldatasource的insertparameters集合(注意要一一对应),最后使用sqldatasource的insert方法,就可以成功向数据库增加一条新记录了。

  另外,为了在窗体加载时,显示数据库northwind中customers表的数据,需要设置sqldatsource1的属性,如下代码:

 <asp:SqlDataSource ID=”SqlDataSource1″ Runat=”server”
InsertCommand=”INSERT INTO [Customers] ([CustomerID], [CompanyName], [ContactTitle]) VALUES (@CustomerID, @CompanyName, @ContactTitle)”
SelectCommand=”SELECT top 5 [CustomerID], [CompanyName], [ContactTitle] FROM [Customers]”
ConnectionString=”server=localhost;uid=sa;password=XXXXX;database=northwind”>
<InsertParameters>
<asp:Parameter Type=”StringName=”CustomerID”></asp:Parameter>
<asp:Parameter Type=”String” Name=”CompanyName”></asp:Parameter>
<asp:Parameter Type=”String” Name=”ContactTitle”></asp:Parameter>
</InsertParameters>
</asp:SqlDataSource>

  其中,必须设置insertcommand和selectcommand属性,设置数据提取和插入的语句,并且要设置好insertparameters集合中,各字段的类型和名称即可。
 2、一次性更新所有的Gridview记录

  我们经常会遇到这样的情况,在Gridview中列出的所有记录中,有时要同时修改多条记录,并且将其保存到数据库中去。那么在Gridview中应该如何实现呢?在Gridview中,有两种实现的方法,下面分别进行介绍:

  先来看下第一种方法,本方法是使用sqldatasource来更新所有记录,但这个方法比较慢,因为每更新一条记录都要建立数据连接并执行updatecommand,会影响性能。其主要代码如下:

<script runat=”server”>
void Button1_Click(object sender, EventArgs e)
{
 for (int i = 0; i < Gridview1.Rows.Count; i++)
 {
  GridviewRow row = Gridview1.Rows[i];
  SqlDataSource1.UpdateParameters[0].DefaultValue = ((TextBox)row.Cells[0].FindControl(“TextBox2”)).Text;
  SqlDataSource1.UpdateParameters[1].DefaultValue = ((TextBox)row.Cells[1].FindControl(“TextBox3”)).Text;
  SqlDataSource1.UpdateParameters[2].DefaultValue = Gridview1.DataKeys[i].Value.ToString();
  SqlDataSource1.Update();
 }
}
</script>
<html xmlns=”http://www.w3.org/1999/xhtml” >
<head id=”Head1″ runat=”server”>
<title>Untitled Page</title>
</head>
<body>
 <form id=”form1″ runat=”server”>
 <div>
 <asp:Gridview ID=”Gridview1″ Runat=”server” DataSourceID=”SqlDataSource1″ DataKeyNames=”CustomerID” AutoGenerateColumns=”False”>
 <Columns>
 <asp:TemplateField SortExpression=”CustomerID” HeaderText=”CustomerID”>
 <ItemTemplate>
  <asp:TextBox Runat=”server” Text=’<%# Bind(“CustomerID”) %>’ ID=”TextBox1″></asp:TextBox>
 </ItemTemplate>

 </asp:TemplateField>
  <asp:TemplateField SortExpression=”CompanyName” HeaderText=”CompanyName”>
  <ItemTemplate>
   <asp:TextBox Runat=”server” Text=’<%# Bind(“CompanyName”) %>’ ID=”TextBox2″></asp:TextBox>
  </ItemTemplate>
 </asp:TemplateField>

 <asp:TemplateField SortExpression=”ContactName” HeaderText=”ContactTitle”>
  <ItemTemplate>
   <asp:TextBox Runat=”server” Text=’<%# Bind(“ContactTitle”) %>’ ID=”TextBox3″></asp:TextBox>
  </ItemTemplate>
 </asp:TemplateField>
 </Columns>

 </asp:Gridview>
<asp:SqlDataSource ID=”SqlDataSource1″ Runat=”server”
SelectCommand=”SELECT [CustomerID], [CompanyName], [ContactName], [ContactTitle] FROM [Customers]”
UpdateCommand=”UPDATE [Customers] SET [CompanyName] = @CompanyName, [ContactTitle] = @ContactTitle WHERE [CustomerID] = @CustomerID”
ConnectionString=”server=localhost;uid=sa;password=xxxx;database=northwind”>
<UpdateParameters>
<asp:Parameter Type=”String” Name=”CompanyName”></asp:Parameter>
<asp:Parameter Type=”String” Name=”ContactTitle”></asp:Parameter>
<asp:Parameter Type=”String” Name=”CustomerID”></asp:Parameter>
</UpdateParameters>
</asp:SqlDataSource>
<asp:Button ID=”Button1″ Runat=”server” Text=”Button” OnClick=”Button1_Click” />
</div>
</form>
</body>
</html>

  在上面的代码中,我们必须首先指定updateparameters参数集合,也就是指出要更新的是哪些字段,它们的类型是什么。之后并指出sqldatasource的updatecommand语句。而在更新按钮button1的CLICK事件中,将以遍历的形式,使用for循环,对Gridview中的每一行进行检查,将每个更新了的文本框的内容放到sqldatasouce的updateparameters参数中去,最后调用sqldatasource的update方法,完成更新。

  方法2使用的是首先遍历Gridview中的每一行,并且使用SQL语句,将要更新的内容连接起来,然后最后才使用command.ExecuteNonQuery()进行更新,效率高了,主要代码如下:

protected void Page_Load(object sender, EventArgs e)
{

if (!Page.IsPostBack)
{
 SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[“AppConnectionString1”].ConnectionString);
 SqlCommand command = new SqlCommand(“SELECT [CustomerID], [CompanyName], [ContactName], [ContactTitle] FROM [Customers]”, con);
 con.Open();
 Gridview1.DataSource = command.ExecuteReader();
 Gridview1.DataBind();
 con.Close();
}
}
protected void Button1_Click(object sender, EventArgs e)
{
 StringBuilder query = new StringBuilder();
 for (int i = 0; i < Gridview1.Rows.Count; i++)
 {
  GridviewRow row = Gridview1.Rows[i];
  string value1 = ((TextBox)row.Cells[0].FindControl(“TextBox2”)).Text.Replace(“’”, “’’”);
  string value2 = ((TextBox)row.Cells[1].FindControl(“TextBox3”)).Text.Replace(“’”, “’’”);
  string value3 = Gridview1.DataKeys[i].Value.ToString();
  query.Append(“UPDATE [Customers] SET [CompanyName] = ’”).Append(value1).Append(“’ , [ContactTitle] = ’”)
.Append(value2).Append(“’ WHERE [CustomerID] = ’”).Append(value3).Append(“’;\n”);
 }

 SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[“AppConnectionString1”].ConnectionString);
 SqlCommand command = new SqlCommand(query.ToString(), con);
 con.Open();
 command.ExecuteNonQuery();
 con.Close();
}
}

  其中要特别注意一点的是,在vs.net 2005 beta 2开始,如果你在web.config中使用了数据库连接字符串的配置,那么应该按如下的方法去写:

<connectionStrings>
<add name=”NorthwindConnectionString” connectionString=”Data Source=LIAO;Initial Catalog=Northwind;User ID=sa;Password=xxxx” providerName=”System.Data.SqlClient”/>
</connectionStrings>

  然后在程序中如下进行读取:

SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings[“AppConnectionString1”].ConnectionString);

推荐几个用得上且免费的.NET控件

<!–
<rdf:RDF xmlns:rdf=”http://www.w3.org/1999/02/22-rdf-syntax-ns#”
xmlns:dc=”http://purl.org/dc/elements/1.1/”
xmlns:trackback=”http://madskills.com/public/xml/rss/module/trackback/”>
<rdf:Description
rdf:about=”http://thcjp.cnblogs.com/archive/2006/06/10/422429.html”
dc:identifier=”http://thcjp.cnblogs.com/archive/2006/06/10/422429.html”
dc:title=”推荐几个用得上且免费的 .NET控件”
trackback:ping=”http://thcjp.cnblogs.com/services/trackbacks/422429.aspx” />
</rdf:RDF>
–>

asp.net图片上传加水印evpic增强版

图片上传组件,可以按时间生成文件名,加水印图片,水印可以设置透明度,位置,e动力编写。

北京联通
上海电信
辽宁联通
河南网通
北方电信

引用页:http://www.mycodes.net/soft/8636.htm

DX TextBox 多功能文章编辑器 v2.0

使用说明:
1.将 bin/DXControls.dll 文件取出,放于你的项目中的 bin 文件夹里.
2.在VS.net中的工具箱中添加部件DXControls.dll,然后就可以直接拖放到页面上.
3.控件包含四个属性:ID,Height,Width,Path. 其中 ID 为编辑器的ID,Height为编辑器高度,Width为编辑器宽度.Path为编辑器的需要的JS等资源文件的目录(默认为dxtb).请手动修改这些参数

北京联通
上海电信
辽宁联通
河南网通
北方电信

引用页 http://www.mycodes.net/soft/7633.htm

Lion.Data.Library.HtmlEditor.Manage v2.0

这是一个针对Lion.Data.Library.HtmlEditor 2.0所使用配置文件的管理程序,只对初学者用
. BTW:如果你会一些xml,可以手动去修改,里面已经写了注释

辽宁联通
上海电信
北京联通

引用页 http://www.mycodes.net/soft/3529.htm

FTB编辑器 For Community Server v2.0增强版

增强功能:
增加插入丰富的发贴表情(可分页)
增强C#,SQL,Javascript,HTML语法高亮着色
增加对FLASH、Microsoft Media,Real Media==多媒体格式的支持

北京联通
上海电信
辽宁联通
河南网通
北方电信

引用页 http://www.mycodes.net/soft/8471.htm

Lion.Data.Library.HtmlEditor v2.0 Src

什么是 HtmlEditor 
HtmlEditor是一个网页的在线文本编辑器,她能够在网页上实现许多桌面编辑软件(如:Word)所具有的强大可视编辑功能;她是一个真正的绿色软件,不需要在计算机上安装任何的客户端软件;并且她是完全开放源代码的,允许无商业目的个人用户免费使用。

辽宁联通
上海电信
北京联通

引用页 http://www.mycodes.net/soft/3528.htm

下载是连接 源码之家 的

asp.net常用的开发技巧

1.Asp.Net中几种相似的标记符号: < %=…%>< %#… %>< % %>< %@ %>解释及用法

答: < %#… %>: 是在绑定控件DataBind()方法执行时被执行,用于数据绑定
如: < %# Container.DataItem(“tit”) %>

< %= %>: 在程序执行时被调用,可以显示后台变量值
如:
*.aspx中: < %= aaa %>
*.cs中: protected string aaa=”姓名”;

< % %>: 内联代码块里面可以在页面文件*.aspx或*.ascx文件里面嵌入后台代码
如:
< %
for(int i=0;i

< %@ %>是在*.aspx页面前台代码导入命名空间,
如:
< %@ Import namespace=”System.Data”%>

2.控件接收哪些类型数据 
答:接收Bind的控件,一般有DropDownList,DataList,DataGrid,ListBox这些集合性质的控件,而被捆绑 的主要是ArrayList(数组),Hashtable(哈稀表),DataView(数据视图),DataReader这四个,以后我们就可以 对号入座,不会出现DataTable被捆绑的错误了:)

DropDownList——ArrayList(数组)
DataList——-Hashtable(哈稀表)
DataGrid——-DataView(数据视图)
ListBox——-DataView(数据视图)

3.DataBind,获得的数据,系统会将其默认为String,怎样转化为其它的类型 
DataBinder.Eval(Container.DataItem,”转换的类型”,”格式”)
最后一个”格式”是可选的,一般不用去管他,Container.DataItem是捆绑的数据项,”转换类型”指的是 Integer,String,Boolean这一类东西.

4.主要命名空间:
< % @ Import Namespace=”System.Data” %> 处理数据时用到
< % @ Import Namespace=”System.Data.ADO” % > 使用ADO.net ; 时用到
< % @ Import Namespace=”System.Data.SQL” %> SQL Server 数据库专用
< % @ Import Namespace=”System.Data.XML” %> 不用看处理XML用到
< % @ Import Namespace=”System.IO” %> 处理文件时用到
< % @ Import Namespace=”System.Web.Util” %> 发邮件时大家会用到
< % @ Import Namespace=”System.Text” %> 文本编码时用到

5.Connections(SQLConection 或者 ADOConnection)的常用属性和方法:
| ConnectionString 取得或设置连结数据库的语句
| ConnectionTimeout 取得或设置连结数据库的最长时间,也是就超时时间
| DataBase 取得或设置在数据库服务器上要打开的数据库名
| DataSource 取得或设置DSN,大家不会陌生吧:)
| Password 取得或设置密码
| UserID 取得或设置登陆名
| State 取得目前联结的状态
| Open() 打开联结
| Close() 关闭联结
| Clone() 克隆一个联结。(呵呵,绵羊可以Connection我也可以)
示例:
SQLConnection myConnection = new SQLConnection();
myConnection.DataSource = “mySQLServer”;
myConnection.Password = “”;
myConnection.UserID = “sa”;
myConnection.ConnectionTimeout = 30;
myConnection.Open();
myConnection.Database = “northwind”;
myConnection.IsolationLevel = IsolationLevel.ReadCommitted
6.Command常用的方法和属性
| ActiveConnection 取得或设置联结Connections
| CommandText 执行的SQL语句或储存过程(StoredProcedure)名
| CommandTimeout 执行的最长时间
| CommandType Command操作的类型(StoredProcedure,Text,TableDirect)三种,默认Text
| Parameters 操作储存过程时使用
| Execute() 执行SQL语句或储存过程
| ExecuteNonQuery() 同上,区别在于不返回记录集
| Clone() 克隆Command
示例:
string mySelectQuery = “SELECT * FROM Categories ORDER BY CategoryID”;
stringmyConnectString=”userid=sa;password=;database=northwind;server=mySQLServer”;
SQLCommand myCommand = new SQLCommand(mySelectQuery);
myCommand.ActiveConnection = new SQLConnection(myConnectString);
myCommand.CommandTimeout = 15;
myCommand.CommandType = CommandType.Text;< /FONT >

7.打开和关闭数据库两种方法:
1.MyConnection.Open(); //打开联结
MyConnection.Close();
2.MyCommand.ActiveConnection.Open();
MyCommand.ActiveConnection.Close()

8.使用DataSet,在数据库中增加、修改、删除一个数据
a.添加数据
DataRow dr=MyDataSet.Tables[“UserList”].NewRow();
dr[“UserName”] = “周讯”;
dr[“ReMark”] = “100”;
dr[“Comment”] = “漂亮MM”;
MyDataSet.Tables.Rows.Add(dr);

b.修改数据
MyDataSet.Tables[“UserList”].Rows[0][“UserName”]=”飞刀大哥”;

c.删除数据
MyDataSet.Tables[“UserList”],Rows[0].Delete();

d.恢复数据
if(MyDataSet.HasErrors)
{
MyDataSet.RejectChanges();
}

e.探测DataSet是否有改动
if(MyDataSet.HasChanges)
{
//保存代码
}else{
//因为没有变化,所以不用保存,以节省时间
}

f.更新数据库
MyComm.Update(MyDataSet); //更新数据库中所有的表
MyComm.Update(MyDataSet,”UserList”); //更新某个表

AJAXToolkit(2)–CascadeDropDown

使用的数据库是SQL Server 2000的自带示例数据库Northwind,首先在一个下拉列表里面显示左右顾客(Customer),选择了相应的Customer后,显示该Customer的所有合同
首先,ASP.NET页面的组织:

xml 代码
  1. <form id=“form1” runat=“server”>
  2. <div>
  3. <asp:ScriptManager ID=“ScriptManager1” runat=“server”>
  4. <!—-></asp:ScriptManager>
  5. <!—->div>
  6. <asp:DropDownList ID=“DropDownList1” runat=“server”>
  7. <!—-></asp:DropDownList> <!—->
  8. <asp:DropDownList ID=“DropDownList2” runat=“server”>
  9. <!—-></asp:DropDownList><!—->
  10. <ajaxToolkit:CascadingDropDown ID=“CascadingDropDown1” runat=“server” TargetControlID=“DropDownList1”
  11. Category=“Customer” PromptText=“Please select a Customers” LoadingText=“[Loading Customers…]”
  12. ServicePath=“WebService.asmx” ServiceMethod=“GetCustomers” />
  13. <!—->
  14. <ajaxToolkit:CascadingDropDown ID=“CascadingDropDown2” runat=“server” TargetControlID=“DropDownList2”
  15. Category=“Order” PromptText=“Please select a order” LoadingText=“[Loading orders…]”
  16. ServiceMethod=“GetOrders” ParentControlID=“DropDownList1” ServicePath=“WebService.asmx” />
  17. <!—->
  18. </form>

这里需要注意的是,需要设置第二个的CascadeDropDown的ParentControlID属性为父类的DropdownList ,如ParentControlID=”DropDownList1″
下面建立一个WebService:
asmx文件

xml 代码
  1. <%@ WebService Language=“C#” CodeBehind=“~/App_Code/WebService.cs” Class=“WebService” %>

WebService.cs文件

c# 代码
  1. using System;
  2. using System.Web;
  3. using System.Collections.Generic;
  4. using System.Web.Services;
  5. using System.Web.Services.Protocols;
  6. using System.Data.SqlClient;
  7. using System.Configuration;
  8. using System.Data;
  9. using System.Collections.Specialized;
  10. /// <summary></summary>
  11. /// WebService 的摘要说明
  12. ///
  13. [WebService(Namespace = “http://tempuri.org/”)]
  14. [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  15. [System.Web.Script.Services.ScriptService]
  16. public class WebService : System.Web.Services.WebService {
  17. public WebService () {
  18. //如果使用设计的组件,请取消注释以下行
  19. //InitializeComponent();
  20. }
  21. [WebMethod]
  22. [System.Web.Script.Services.ScriptMethod]
  23. public AjaxControlToolkit.CascadingDropDownNameValue[] GetCustomers(string knownCategoryValues, string category)
  24. {
  25. SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings[“my”].ConnectionString);
  26. SqlCommand cm = cn.CreateCommand(); //Customer是顶级目录,所以不需要有参数
  27. cm.CommandText = “select customerID,CompanyName from customers”;
  28. cn.Open();
  29. SqlDataReader sdr = cm.ExecuteReader();
  30. List<ajaxcontroltoolkit.cascadingdropdownnamevalue> list = new List<ajaxcontroltoolkit.cascadingdropdownnamevalue>(); </ajaxcontroltoolkit.cascadingdropdownnamevalue></ajaxcontroltoolkit.cascadingdropdownnamevalue>
  31. while (sdr.Read())
  32. {
  33. list.Add(new AjaxControlToolkit.CascadingDropDownNameValue(sdr.GetString(1),sdr.GetString(0)));
  34. }
  35. return list.ToArray();
  36. }
  37. [WebMethod]
  38. [System.Web.Script.Services.ScriptMethod]
  39. public AjaxControlToolkit.CascadingDropDownNameValue[] GetOrders(string knownCategoryValues, string category)
  40. {
  41. //解析上一级的选择,注意是上一级Customer下拉列表中的Category属性
  42. StringDictionary kv = AjaxControlToolkit.CascadingDropDown.ParseKnownCategoryValuesString(knownCategoryValues);
  43. string customer = “”;
  44. if (!kv.ContainsKey(“Customer”))
  45. {
  46. return null;
  47. }
  48. customer = kv[“Customer”];
  49. SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings[“my”].ConnectionString);
  50. SqlCommand cm = cn.CreateCommand();
  51. cm.CommandText = “select OrderID,OrderDate from orders where CustomerID='” + customer + “‘”;
  52. cn.Open();
  53. SqlDataReader sdr = cm.ExecuteReader();
  54. List<ajaxcontroltoolkit.cascadingdropdownnamevalue> list = new List<ajaxcontroltoolkit.cascadingdropdownnamevalue>(); </ajaxcontroltoolkit.cascadingdropdownnamevalue></ajaxcontroltoolkit.cascadingdropdownnamevalue>
  55. while (sdr.Read())
  56. {
  57. list.Add(new AjaxControlToolkit.CascadingDropDownNameValue(sdr.GetInt32(0).ToString() + sdr.GetDateTime(1).ToString(), sdr.GetInt32(0).ToString()));
  58. }
  59. return list.ToArray();
  60. }
  61. }

运行结果:

  • 大小: 26.3 KB

怎么在ASP.NET2.0中使用Membership

摘要:

本文介绍了怎么在ASP.NET 2.0中使用Membership新特性,并且介绍了怎么使用两种不同的MembershipProviderActiveDirectoryMembershipProviderSqlMembershipProvider,前者是基于微软活动目录服务存储用户信息的,或者是基于SQL SERVER存储的。2.0中的这个新机制大大减少了站点用户认证模块的代码量。

目录:

学习目的

使用ActiveDirectoryMembershipProvider

使用SqlMembershipProvider

ActiveDirectoryMembershipProvider的一些设置参数

SqlMembershipProvider的一些设置参数

Membership 的一些API

学习目的:

学会使用Membership进行表单认证

学会设置ActiveDirectoryMembershipProvider

学会使用ActiveDirectoryMembershipProvider建立认证用户

学会设置SqlMembershipProvider

学会建立SQL SERVER Membership数据库

学会使用SqlMembershipProvider建立认证用户

使用ActiveDirectoryMembershipProvider

如果用户信息是存储在活动目录中,而你的内网程序又因为防火墙或者需要适应不同的浏览器等原因不能使用windows集成认证的话,这个时候你可以选择使用ActiveDirectoryMembershipProvider实现表单认证

基本的步骤如下

按照以下步骤来用ActiveDirectoryMembershipProvider实现asp.net程序的用户表单认证

1、配置表单认证

2、配置ActiveDirectoryMembershipProvider

3、建立用户

4、认证用户

1、配置表单认证

要实现表单认证需要设置<authentication>mode属性为“Forms”,然后按照下面的例子配置web.config文件

<authentication mode=”Forms”>

<forms loginUrl=”Login.aspx”

protection=”All”

timeout=”30″

name=”AppNameCookie”

path=”/FormsAuth”

requireSSL=”false”

slidingExpiration=”true”

defaultUrl=”default.aspx”

cookieless=”UseCookies”

enableCrossAppRedirects=”false”/>

</authentication>

· loginUrl 指向登录页面,你需要把它放在支持SSL的目录下

· Protection 设置成“All”表示为认证凭据同时启用数据来源验证和加密

· Timeout 指定了认证的生存时间

· name and path are set to unique values for the current application.

· requireSSL 设置成“false”表示关闭cookieSSL加密

· slidingExpiration 如果设置成“true”的话,每次访问过期时间将会重置

· defaultUrl 就是设置程序的首页

· cookieless 设置成“UseCookies”表示使用cookie来传递认证票据

· enableCrossAppRedirects 设置成“false”表示程序不接受外部的请求

按照下面的例子为<authentication> 增加<authorization>块,表明只有登录过的用户才能进入程序否则会被转到前面loginUrl设置的页面

<authorization>

<deny users=” ” />

<allow users=”*” />

</authorization>

2、配置ActiveDirectoryMembershipProvider

按照下面的例子配置ActiveDirectoryMembershipProvider

<connectionStrings>

<add name=”ADConnectionString”

connectionString=

“LDAP://domain.testing.com/CN=Users,DC=domain,DC=testing,DC=com” />

</connectionStrings>

<system.web>

<membership defaultProvider=”MembershipADProvider”>

<providers>

<add

name=”MembershipADProvider”

type=”System.Web.Security.ActiveDirectoryMembershipProvider, System.Web,

Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”

connectionStringName=”ADConnectionString”

connectionUsername=”<domainName>\administrator”

connectionPassword=”password”/>

</providers>

</membership>

</system.web>

前面的代码为<providers>添加<add>子节点来为membership指定ActiveDirectoryMembershipProvider,活动目录中存储用户信息的连接字符串如下格式LDAP:// server/userdn

· server 是活动目录服务器的IP或者名字

· userdn 是活动目录的DN,格式是/CN=Users然后是逗号加上逗号分割开的域名,比如域名是domain.testing.com,连接字符串就是LDAP://domain.testing.com/CN=Users,DC=domain,DC=testing,DC=com

注意:确保<membership>defaultProvider属性设置成了你的ActiveDirectoryMembershipProvider(在这个例子中是MembershipADProvider),如果需要为机器级别改变这个属性,%windir%\Microsoft.NET\Framework\{Version}\Config\machine.config文件中改写原有的AspNetSqlMembershipProviderAspNetSqlMembershipProvider是使用SQLMembershipProvider\app_data目录中的SQL Server Express数据库来存放用户信息的机制

3、建立用户

可以使用下面的几种方法新建用户

· 打开vs.net2005Website菜单,点击ASP.NET Configuration,然后在安全里面进行设置

· 建立一个ASP.NET页面,放入一个CreateUserWizard控件,这个控件使用配置过的membership provider来实现建立用户的过程

· 手动拖放填写用户名和密码的文本框然后使用Membership APICreateUser方法来实现

注意:其实所有这些方法最终还是使用Membership.CreateUser来建立用户

默认配置的ActiveDirectoryMembershipProvider使用UPNs来进行名字印象,如下

attributeMapUsername=”userPrincipalName”

因为所有用户名都需要按照下面的格式:

UserName@DomainName

如果手动使用Membership.CreateUser方法来创建用户,这么做

Membership.CreateUser(“UserName@DomainName”, “P@ssw0rd”, “userName@emailAddress”);

你也能设置config文件来改变映象方式:

attributeMapUsername=”sAMAccountName”

如果这样设置的话,用户名就如下格式:

UserName

这样建立用户:

Membership.CreateUser(“UserName”, “P@ssw0rd”, “userName@emailAddress”)

注意:你可以设置requiresUniqueEmail“true”来确保所有用户的mail地址不重复

4、认证用户

要认证用户,你必须要建立一个登录页面,而它也就是唯一不需要验证的页面

可以使用以下方法建立登录页面:

l ASP.NET 2.0登录控件,这个控件几乎包含了所有涉及到的操作,它会自动连接配置过的membership provider,不需要写任何代码,登录以后控件可以保存用户信息,比如用加密过的cookie保存。

l 当然你也可以手动来用文本框完成这个过程,可以利用Membership ValidateUser来判断登录情况,登录完成后你还需要用FormsAuthentication类来为用户的浏览器写入cookie,下面是例子:

if (Membership.ValidateUser(userName.Text, password.Text))

{

if (Request.QueryString[“ReturnUrl”] != null)

{

FormsAuthentication.RedirectFromLoginPage(userName.Text, false);

}

else

{

FormsAuthentication.SetAuthCookie(userName.Text, false);

}

}

else

{

Response.Write(“Invalid UserID and Password”);

}

注意:上面两种方式都是使用Membership.CreateUser方法

bool isValidUser = Membership.ValidateUser(“UseName@DomainName”, “P@ssw0rd”);

attributeMapUsername=”sAMAccountName”

bool isValidUser = Membership.ValidateUser(“UserName”, “P@ssw0rd”, “userName@emailAddress”)

使用SQLMemberShipProvider

当在外网做验证或者内网有没有配置活动目录的时候我们可以使用SQLMembershipProvider来作为验证的数据源,其实默认的设置就是使用SQLMembershipProvider

基本步骤

按照如下的步骤来为表单验证启用SqlMembershipProvider

1、配置表单认证

2、按照membership数据库

3、建立用户

4、认证用户

1、省略。。。同ActiveDirectoryMembershipProvider

2、按照membership数据库

在使用SqlMembershipProvider以前需要安装一个membership数据库,使用一个SQL SERVER管理员权限登录到服务器,然后在Visual Studio 2005命令行模式下执行下面的语句

aspnet_regsql.exe -E -S localhost -A m

看下几个参数:

-E 表明此帐号使用windows集成认证

-S 表明需要安装数据库的服务器名

-A m 表明自动为membership建立相应的表和存储过程

注意:Aspnet_regsql 工具同样为其他ASP.NET 2.0特性安装数据库,比如说成员管理,Profile,个性化Web Parts还有Web Events等,当然都会有其他的命令,如果你不使用任何参数的话可以以想到模式运行程序,会允许你在安装的过程中指定数据库服务器和你需要安装的组件

3、配置SqlMembershipProvider

Machine.config其实默认就是使用SQL Server Express作为SqlMembershipProvider的,如果你的数据库不是运行在本机的,可以修改下配置

<connectionStrings>

<add name=”MySqlConnection” connectionString=”Data Source=MySqlServer;Initial Catalog=aspnetdb;Integrated Security=SSPI;” />

</connectionStrings>

<system.web>

<membership defaultProvider=”SqlProvider” userIsOnlineTimeWindow=”15″>

<providers>

<clear />

<add

name=”SqlProvider”

type=”System.Web.Security.SqlMembershipProvider”

connectionStringName=”MySqlConnection”

applicationName=”MyApplication”

enablePasswordRetrieval=”false”

enablePasswordReset=”true”

requiresQuestionAndAnswer=”true”

requiresUniqueEmail=”true”

passwordFormat=”Hashed” />

</providers>

</membership>

更多信息看本文“SqlProviderMembershipProvider属性配置”章节

Step 4. Create Users

4、建立用户:

省略。。。同ActiveDirectoryMembershipProvider

5、认证用户:

省略。。。同ActiveDirectoryMembershipProvider

ActiveDirectoryMembershipProvider的属性配置

1显示了ActiveDirectoryMembershipProvider的属性,默认值和用途

1: ActiveDirectoryMembershipProvider的属性配置

(这部分不翻译)

Attribute

Default Value

Notes

connectionStringName

Points to a connection string contained in the connection strings configuration section. This attribute is required because it points to the primary LDAP bind string that is used for create, update, get, and validate operations.

connectionUserName

Defines the user name used for authentication purposes when connecting to the directory. If this attribute is specified, the companion connectionPassword attribute must also be specified. This attribute is used to configure a set of credentials that can be used to connect to the directory (instead of using the process account or impersonation credentials that are in effect at the time the provider connects to the directory).

connectionPassword

Defines the password used for authentication purposes when connecting to the directory. If this attribute is specified, the companion connectionUserName attribute must also be specified. This attribute is used to configure a set of credentials that can be used to connect to the directory (instead of using the process account or impersonation credentials that are in effect at the time the provider connects to the directory).

connectionProtection

Secure

Defines the transport layer security options that are used when opening connections to the directory. This attribute can have a string value of “Secure” or “None”.

If set to “Secure”, the provider attempts to select the highest level of connection security available, based on the type of directory that the provider connects to. The protection is determined as follows:
SSL is first attempted because SSL is an option that works with both Active Directory and ADAM (ActiveDirectoryConnection
Protection.Ssl)
.
If SSL is not available and the provider is connecting to Active Directory or to a domain-joined ADAM instance, encrypt-sign-and-seal is used (ActiveDirectoryConnection
Protection.SignAndSeal
).
If neither SSL nor encrypt-sign-seal is available, the provider generates a ProviderException, stating that it could not automatically select a secure connection to the configured directory.

enablePasswordReset

False

Controls whether or not a password can be reset. For security reasons, with the ActiveDirectoryMembershipProvider, this attribute can only be set to true if all of the following have been set:
requiresQuestionAndAnswer is set to true.
passwordQuestion, passwordAnswer, attributeMapFailedPasswordAnswer
Count
, attributeMapFailedPassword
AnswerTime
, and attributeMapFailed
PasswordAnswerLockoutTime
have been mapped to attributes in the directory.
Note: Even if this attribute is set to true, password resets are allowed only if the credentials used to perform the reset have Administrator privileges in Active Directory..

enableSearchMethods

False

Allows an administrator to set whether or not search-oriented methods can be called on the provider instance. Because methods such as Find* and GetAllUsers can be very expensive, the default value for this attribute is false.
The following methods throw a NotSupportedException if they are called when this attribute is set to false:
FindUsersByName
FindUsersByEmail
GetAllUsers

requiresQuestionAnd
Answer

False

Determines whether a password question and answer are required for a password reset.

For security reasons, with ActiveDirectoryMembership
Provider
, this attribute can only be set to true if all of the following have been set:
attributeMapPasswordQuestion, attributeMapPasswordAnswer, attributeMapFailedPasswordAnswerCount, attributeMapFailedPasswordAnswerTime, and attributeMapFailedPasswordAnswerLockoutTime

applicationName

/

For this provider, applicationName is included for completeness with other providers. Internally, it does not matter what value is placed here because the application name is not used. The maximum value is 256 characters.

requiresUniqueEmail

False

Specifies whether the e-mail values used in the application must be unique.

maxInvalidPassword
Attempts

5

Indicates the number of failed password attempts or failed password answer attempts allowed before a user’s account is locked. When the number of failed attempts equals the value set in this attribute, the user’s account is locked out.

For the Active Directory provider, this attribute applies only to managing resets that use a password answer. Active Directory manages bad password attempts internally.

passwordAttempt
Window

10

Indicates the time window, in minutes, during which failed password attempts and failed password answer attempts are tracked.

For the Active Directory provider, this attribute applies only to managing resets that use a password answer. Active Directory manages bad password attempts internally.

passwordAnswer
AttemptLockout
Duration

30

Specifies the duration, in minutes, that a lockout due to a bad password answer is considered still in effect. Because Active Directory uses the concept of timing out bad password lockouts, this attribute is necessary to support a similar concept of timing bad password answer attempts.

minRequiredPassword
Length

7

Specifies the minimum number of characters required in a password. The value can be from 1 to 128.

minRequiredNonAlpha
numericCharacters

1

Specifies the minimum number of non-alphanumeric characters required in a password. This configuration attribute cannot be set to a value greater than the value of the minRequiredPasswordLength. This means the configuration setting must be in the range of
0–minRequiredPasswordLength, inclusive of minRequiredPasswordLength.

passwordStrength
RegularExpression

“”

Provides a valid regular expression that the provider will use as part of password strength validation.

attributeMapUsername

userPrincipalName

Defines the mapping from a property on a MembershipUser object to an attribute within the directory.
The only directory attributes for mapping to a username if you are using Active Directory are userPrincipalName or sAMAccountName. The only allowed directory attributes for mapping to username if you are using ADAM is userPrincipalName.

attributeMapEmail

Mail

Defines the mapping from a property on a MembershipUser object to an attribute within the directory.

attributeMapPassword
Question

UNDEFINED

Defines the mapping from a property on a MembershipUser object to an attribute within the directory.

attributeMapPassword
Answer

UNDEFINED

Defines the mapping from a property on a MembershipUser object to an attribute within the directory.

attributeMapFailed
PasswordAnswerCount

UNDEFINED

Defines the mapping from a property on a MembershipUser object to an attribute within the directory.

attributeMapFailed
PasswordAnswerTime

UNDEFINED

Defines the mapping from a property on a MembershipUser object to an attribute within the directory.

attributeMapFailed
PasswordAnswer
LockoutTime

UNDEFINED

Defines the mapping from a property on a MembershipUser object to an attribute within the directory.

如果要启用取回密码你需要在<providers>后增加<add>设置attributeMapPasswordQuestion attributeMapPasswordAnswer 属性来增加ActiveDirectoryMembershipProvider详细见How To: Use Forms Authentication with Active Directory in ASP.NET 2.0.

SqlMembershipProvider Configuration Attributes

SqlMembershipProvider属性配置

2显示了SqlMembershipProvider的属性,默认值和用途

2. SqlMembershipProvider属性配置

属性

默认

用途

connectionStringName

SQL SERVER的连接字符串

enablePasswordReset

False

密码能否重置
安全原因,只有当
requiresQuestionAndAnswer
设置为 true的时候你才可以设置enablePasswordResettrue

requiresQuestionAnd
Answer

False

是否需要启用取回密码

applicationName

/

设置了它可以让多个应用程序在数据库内有所区分,不需要为每个应用建立一个数据库了

requiresUniqueEmail

False

邮件地址是否需要唯一

maxInvalidPassword
Attempts

5

密码输入错误几次就会锁定用户

passwordAttempt
Window

10

每分钟可以失败的次数

passwordFormat

密码方式 Clear, Encrypted, Hashed. 第一种是明文存储,效率比较高,但是SQL SERVER中能直接读取密码,不安全. 第二种是不可逆加密,需要一定的加密换算过程,但是比较安全.第三种是可逆加密,密码不能找回

minRequiredPassword
Length

7

指定至少密码需要几位

minRequiredNonAlpha
numericCharacters

1

指定需要是非数字字母作为密码的位数,不能大于minRequiredPassword
Length

passwordStrength
RegularExpression

“”

指定强度计算的正则表达式

Membership

3列出了一些Membership类重要的一些方法参数和用法

3. Membership 类方法

方法名

参数

备注

CreateUser

string username创建的用户名.
string password
新用户密码
string email
新用户mail地址
string passwordQuestion
string passwordAnswer
bool IsApproved
object providerUserKey

DeleteUser

string username需要删除的用户名
bool removeAllRelatedData

返回true表示删除,false表示没有找到

FindUsersByName

string usernameToMatch
int pageIndex
int pageSize

返回找到的用户的集合,支持通配符*“, “%_“.

FindUsersByEmail

string emailToMatch
int pageIndex
int pageSize

GeneratePassword

int length
Int numberOfNonAlpha
NumericCharacters

GetAllUsers

int pageIndex
int pageSize

返回用户记录集

GetNumberOfUsersOnline

None

返回在线的用户,活动目录不支持

GetUsernameByEmail

string email需要查找的用户的mail地址

UpdateUser

MembershipUser user需要更新的用户名

ValidateUser

string username需要验证的用户名
string password
需要验证的密码

注意 GetAllUsers 方法在 RTM 版本的 .NET Framework 2.0 会取消

特别注意

默认情况下表单认证的票据传输是明文的,为了防止票据被,我们还是建议你为服务器启用SSL。设置requireSSL属性为true来启用SSL,下面的例子显示了怎么启用SSL,还有不管用户使用http还是https形式的url进入网站都能启用,你可以尝试登录到loginUrl指定的页面看看,但是需要保证这个页面是没有任何约束的

<configuration>

<system.web>

<authentication mode=”Forms”>

<forms loginUrl=”https://myserver/mywebapp/secure/Login.aspx”

protection=”All”

timeout=”30″

name=”AppNameCookie”

path=”/FormsAuth”

requireSSL=”true”

slidingExpiration=”true”

defaultUrl=”default.aspx”

cookieless=”UseCookies”

enableCrossAppRedirects=”false”/>

</authentication>

<!—禁止没有权限的用户 –>

<authorization>

<deny users=” ” />

<allow users=”*” />

</authorization>

</system.web>

</configuration>

<!—使得登录页面没有任何限制 –>

<location path=”secure”>

<system.web>

<authorization>

<allow users=”*” />

</authorization>

</system.web>

</location>

翻译原文:http://lovecherry.cnblogs.com/archive/2005/12/05/291092.html

英文原文:http://msdn.microsoft.com/library/en-us/dnpag2/html/PAGHT000022.asp