[C#]ASP.NET中实现二级或多级域名(修改UrlRewrite)

mikel阅读(1242)

大家应该知道,微软的URLRewrite能够对URL进行重写,但是也只能对域名之后的部分进行重写,而不能对域名进行重写,如:可将 http://www.abc.com/1234/  重写为 http://www.abc.com/show.aspx?id=1234  但不能将
http://1234.abc.com  重写为  http://www.abc.com/show.aspx?id=1234
要实现这个功能,前提条件就是  www.abc.com 是泛解析的,再就是要修改一下URLRewriter了。
总共要修改2个文件
1.BaseModuleRewriter.cs

protected virtual void BaseModuleRewriter_AuthorizeRequest(object sender, EventArgs e)
        
{
            HttpApplication app 
= (HttpApplication) sender;
            Rewrite(app.Request.Path, app);
        }

改为

protected virtual void BaseModuleRewriter_AuthorizeRequest(object sender, EventArgs e)
        
{
            HttpApplication app 
= (HttpApplication) sender;
            Rewrite(app.Request.Url.AbsoluteUri, app);
        }

就是将  app.Request.Path 替换成了  app.Request.Url.AbsoluteUri
2.ModuleRewriter.cs

for(int i = 0; i < rules.Count; i++)
            
{
                
// get the pattern to look for, and Resolve the Url (convert ~ into the appropriate directory)
                string lookFor = "^" + RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].LookFor) + "$";

                
// Create a regex (note that IgnoreCase is set)
                Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);

                
// See if a match is found
                if (re.IsMatch(requestedPath))
                
{
                    
// match found – do any replacement needed
                    string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));

                    
// log rewriting information to the Trace object
                    app.Context.Trace.Write("ModuleRewriter""Rewriting URL to " + sendToUrl);

                    
// Rewrite the URL
                    RewriterUtils.RewriteUrl(app.Context, sendToUrl);
                    
break;        // exit the for loop
                }

            }

改为

for(int i = 0; i < rules.Count; i++)
            
{
                
// get the pattern to look for, and Resolve the Url (convert ~ into the appropriate directory)
                string lookFor = "^" + rules[i].LookFor + "$";

                
// Create a regex (note that IgnoreCase is set)
                Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);

                
// See if a match is found
                if (re.IsMatch(requestedPath))
                
{
                    
// match found – do any replacement needed
                    string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));

                    
// log rewriting information to the Trace object
                    app.Context.Trace.Write("ModuleRewriter""Rewriting URL to " + sendToUrl);

                    
// Rewrite the URL
                    RewriterUtils.RewriteUrl(app.Context, sendToUrl);
                    
break;        // exit the for loop
                }

            }


string lookFor = "^" + RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].LookFor) + "$";
改成了
string lookFor = "^" + rules[i].LookFor + "$";
完成这2处改动之后重新编译项目,将生成的dll复制到bin目录下。
再就是写web.config里的重写正则了

<RewriterRule>
            
<LookFor>http://(\d+)\.abc\.com</LookFor>
            
<SendTo>/show.aspx?id=$1</SendTo>
        
</RewriterRule>

好了大功告成,你在IE地址栏输入http://1234.abc.com,就可以看到http://www.abc.com/show.aspx?id=1234
的结果了
完成这2处改动之后重新编译项目,将生成的dll复制到bin目录下。

修改完了这后,我们再把此 UrlRewriter.dll COPY 到我们项目的Bin目录下。这样就结了么?没有。
首先请确定你的项目之前有按我上篇文章中写到的那样做过UrlRewriter的配置,否则请先回过头来看看那篇文章。

如果你的项目已配置过,那么,我们还要为此做以下几件事情:

1。请确定你的域名是支持泛解析的。然后你的网站为默认网站,否则将不能实现(至少我现在还没有找到好办法)
2。在IIS配置:在IIS\ 你的站点\属性\主目录\配置\映谢 在通配符应用程序配置处插入一个新的映谢。把可执行文件设为和上面ASPX页面同样的配置即可(注意不要勾选 “确定文件是否存在”)。(用处就是使所有请求通过 ASP.NET 的ISAPI来处理,只有这样才能对所有地址进行重写嘛。)
3。查看下你的网站主机头,里面的第一个主机头值必须为空,否则会出现错误的请求。后面就随你加了,看你想绑定多少域名了。(这个办法是江大鱼想出来的。为这个错误我们都想了好多办法。在这里感谢江大鱼。。。)
4。最后改写你的 web.config 文件。
把上节中说到的
  <httpHandlers>
     <add verb="*" path="*.aspx" type="URLRewriter.RewriterFactoryHandler, URLRewriter" />
     <add verb="*" path="*.html" type="URLRewriter.RewriterFactoryHandler, URLRewriter" />
  </httpHandlers>
改为:
  <httpModules>
   <add type="URLRewriter.ModuleRewriter, URLRewriter" name="ModuleRewriter" />
  </httpModules>
(就是改用HTTP 模块来执行重写,而不用HTTP 程序,否则无法重写地址前面。)
然后就来修改我们的重写正则了:
              <RewriterRule>
                   <LookFor>http://(.[0-9]*)\.178b2b\.com/</LookFor>
                   <SendTo>~/Search/Search_Sell.aspx?id=$1</SendTo>
              </RewriterRule>
好了,现在你输入 http://1.178b2b.com/ 就能搜索出相应分类了。但是聪明的你马上就发现。晕死,首页进不去了。呵呵。当然喽。你还得为首页加入重写正则。
              <RewriterRule>
                   <LookFor>http://www\.178b2b\.com/</LookFor>
                   <SendTo>~/index.htm</SendTo>
              </RewriterRule>
大功告成。感觉爽死了吧。呵呵。莫急,如果你二级域名指向的目录下面的页面都用的相对地址连接的图片和其它页面的话,呵呵,你有得忙了,你要全部改成如下方式:
<a href=http://www.178b2b.com/cxlm/league.html target="_blank">诚信联盟</a>
以上就是用UrlRewriter实现二级域名的方法了。


网 上很多朋友看到我这篇文章,按照我的方法做了,但是还是没有得到想要的效果,其实有些问题需要注意一下,我上篇文章也只是提出了解决这一问题的办法的最核 心的内容,有些朋友可能在实际运用中可能会碰到一些问题其实可以根据自己的经验作出相应处理应该可以解决,我在这里帮大家列出几点以帮助大家快速解决问 题。
1.域名解析问题
      输入了域名http://1234.abc.com,浏览器提示找不到网页。首先,你应该确认你的域名是否支持泛域名解析,就是让所有的二级,三级域名都指向你的server。其次,要保证你的站点是服务器上的默认站点,就是80端口主机头为空的站点即可以直接用IP可以访问的http://1234.abc.com,要么要提示你的站点的错误信息,要么会正确的执行你定义的URLRewrite,要么显示你的站点的首页。
2.不能执行重写的问题
      如果你确认你的域名解析是正确的,但是还是不能重写,访问http://1234.abc.com会提示路径"/"找不到…,
如果是这样的话,你先添加  ASPNET_ISAPI的通配符应用程序映射(这一步是必需的,Sorry!没有在上篇文章中提出来)。
操作方法:IIS站点属性 ->主目录 ->  配置

点击插入按键

选择或输入C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\aspnet_isapi.dll
取消"确认文件是否存在"前的钩. 
确定
在来访问http://1234.abc.com  应该是没有问题了。
3. 默认首页失效,因为把请球直接交给ASP.NET处理,IIS定义的默认首页将会失效,出现这种情形:
访问http://www.abc.com 不能访问首页,而通过http://1234.abc.com/default.aspx可以访问。
为解决这个问题,请自己在Web.Config中设置 lookfor /  to /default.aspx 或 index.aspx ..的重写,完全可以解决问题。
OK,我列出了应该会普遍出现的问题的解决方法,如果你出现了我这里没有列出的问题而你自己又不能解决的,请在此回复提问或者给我发邮件或者加我QQ.

[C#]系统二级域名配置说明

mikel阅读(1060)

ASP.NET 用url重写(URLReWriter)实现任意二级域名

好久没有写技术文章,如果大家看不明白,就多看几篇,汗,或者,在文章的后面回复(这是最有效的办法),我会尽力帮助大家解答疑惑.

来找这篇文章的,应该都知道什么叫二级域名吧,废话就不说了.但是讨论前,先要明白一个思想问题.
很多朋友一直考虑不清(我前几天也一直搞不明白)的问题是,我键入一个地址后,怎么这个url就被重写了?
第一步:在浏览器键入了一个地址,比如http://love.kerry.com,点回车后,都发生了什么?
为了把问题简单化,我来这样解释:
第二步:首先,键入的地址被解析,最终来到了一台web服务器.交给IIS处理.在.net的世界中,IIS会把这样的请求再交给一个web处理器 处理,最后,该 web处理器 把处理的结果返回给浏览器,显示给用户看.
请不用忽略这样一个问题,第二步的所有事情都是在服务器端做的.在这些事情进行的时候,用户端的浏览器上面的地址不会改变.即使最后 web处理器 把处理结果返回来的时候,上面的地址也不会改变.
一开始键入的url,只是起一个敲门的作用,门敲完了,作用就算结束了,只有你的眼睛可以看到那个地址,浏览器,服务器等都不知道这个地址.
然后要明白的问题是,所谓url重写,也只是web开发人员知道的内幕情况,用户根本不知道发生了什么,他认为自己键入的地址就是应该出来屏幕上显示的结果.也就是说,我们在幕后控制要显示的内容.
接下来要考虑的是,怎么样控制显示的内容?
从上面说的过程,很明显要在 web处理器 的工作这一步动手脚.

一个最简单的考虑是,用户敲入了一个简单的不带任何参数地址, http://love.kerry.com然后我们把这个地址改成一个符合程序需要的带参数的地址, http://kerry.com?lover=notus,最后处理之.
所谓的url重写,就是在这一步.
用.net的术语来说,我们需要给应用程序注册一个httpmodule,用来处理特定的url
注册httpmodule,在web.config,
处理url,在我们提供的httpmodule程序中

大体相当于这样的一段程序

//用我们的httpmodule程序截获原始url
String originalUrl=” http://love.kerry.com”;
//处理原始url,得到最后需要的url,值为http://kerry.com?lover=notus
String FinalUrl=Rewrite(OriginalUrl);
// context重新将url在内部发送给IIS处理
context.RewritePath(FinalUrl);

接下来,我们来实现url重写.
第一步:确定要对哪些url执行重写,即制定重写规则
第二步:编写httpmodule处理程序
第三步:将编写的httpmodule整合入web程序,开始工作.

上面就是url重写的基本知识,而用url重写实现二级域名,过程一样.因为无论是二级域名还是三级域名,都是一个url地址.只要我们截获这个url地址,就可以在处理的时候动手脚.

这些工作挺麻烦,但是网络上已经有高人给我们写了这样的程序,参看下面的文章:

http://www.microsoft.com/china/msdn/library/webservices/asp.net/URLRewriting.mspx

http://www.cnblogs.com/jzywh/archive/2005/09/29/246650.html

http://www.cnblogs.com/jzywh/archive/2006/02/20/334004.html

文章结束了.

在实施过程中会碰到一些问题,大多是因为看上面的文章不仔细产生的,但是说实话,那么长的文章要看完也不容易.下面我来记录一些重要的问题.其中最后的两个问题,用具体的代码展示了如何处理重写的目标url以达到我们的要求

为什么非要用泛解析?
看了好多朋友的回复,我想现在可能有这样的误解,即,这篇关于url重写的文章只是给大家介绍一些处理方法.至于泛解析不泛解析,并不重要.
如果你不需要实现任意二级域名,那就用不着去实现泛解析,直接把你需要的二级域名定死,然后在url重写里处理好了!
 再退一步,如果连二级域名都不用实现,仅仅是对一个固定域名下的url进行重写,那都不需要修改msdn的那个urlrewriter,直接拿来用就可以实现了简单的url重写. zyw对这个项目进行的修改,只是为了取到全部的url进行更大限度的控制.而如我们所见,一开始msdn的那个urlrewriter并不关心域名的问题
我一开始给文章起这样的题目,是因为最近我项目里用到了,写文档的时候顺便就把这个文章写了

微软的URLRewriter是什么?这个项目在哪里下载的?
这个是在msdn上一篇介绍URLRewriter的文章中提供的示例程序,可以在这里下载到
http://www.microsoft.com/china/msdn/library/webservices/asp.net/URLRewriting.mspx

怎么使用这些代码?麻烦吗?
肯定的说,不麻烦,要做的事情有:
下载代码到你的机器上.
安装后,把URLRewriter这个项目添加到你自己的工程中
按照上面给的地址里的方法,修改代码
配置web.config,开始使用.

什么是httpmodule?

简单理解,就是一块处理http请求的程序
更详细的理解,请查阅sdk文档.

怎么样实现泛解析?

首先,在域名服务商那里添加一个*.kerry.com的二级域名,指向你的服务器ip
然后,在IIS里建立一个站点,这个站点的主机头留空,一般端口是80. 这个站点就是整个服务器端口80的默认网站.
给这个站点添加一个通配符应用程序映射(IIS站点属性 ->主目录 ->  配置),这个映射的目的是要ASP.NET ISAPI接管任何没有在IIS里明确的二级域名站点.

随便输入二级域名的时候,发生了什么?
当IIS检测到传入的url是一个二级域名的时候,它会先检查IIS上有没有注册了这个二级域名的站点,如果有,就转入到这个站点,否则,就会转到默认站点,这个默认站点就是之前配置的主机头为空的那个站点.所以,一个端口只能有一个主机头为空的站点.
我们已经设定由asp.net ISAPI接管这些没有家的孩子.写程序,分析传入的url,执行重写.

为什么我的httpmodule好像没有起作用?

在httpmodule程序里设置断点后,无论怎么样,流程都没有从这里走.原因在于,你没有向web程序注册你的httpmodule程序.这个工作需要在web.config中完成.
<system.web>
<httpModules>
<add type="URLRewriter.ModuleRewriter, URLRewriter"  name="ModuleRewriter" />
</httpModules>
</system.web>

为什么总是提示我”未知的配置节RewriterConfig错误”

这是因为你没有向web程序注册你的RewriterConfig配置节. 这个工作需要在web.config中完成.
<configSections>
<section name="RewriterConfig" type="URLRewriter.Config.RewriterConfigSerializerSectionHandler, URLRewriter" />
</configSections>
然后,你可以在<configuration>里使用RewriterConfig节配置规则了.

url是在httpmodule的哪个部分处理的?

大多的工作是在URLRewriter. ModuleRewriter. Rewrite()方法里.关键阶段是这里:
if (re.IsMatch(requestedPath))
很明显,这个判断传入的url是否是我们要重写的url,大家接着看,
String sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));
这里接受到web.config中配置的要转到的目标url
RewriterUtils.RewriteUrl(app.Context, sendToUrl);
在内部把url重写.

我不想把二级域名写死在web.config中,而且我要重写的目标url也不能写死.比如我们有这样的需要
Love.kerry.com实际的处理页面是kerry.com/action.aspx?id=1
call.kerryl.com实际的处理页面是kerry.com/action.aspx?id=2
walkwith.kerry.com实际的处理页面是kerry.com/walk.aspx
要怎么处理?

这个时候,就需要在上面说的那几个代码里做手脚.
if (re.IsMatch(requestedPath))
{

//找到url里的二级域名
string [] UserHost = app.Request.Url.Host.Split ( new Char [] { '.' } );
string domain2=UserHost [0];

//根据需要设定要重写的目标url
string sendToUrl ;
if(domain2==” Love”)
  sendToUrl =” /action.aspx?id=1”;
else if(domain2==” call”)
  sendToUrl =” /action.aspx?id=2”;
else i f(domain2==” walkwith”)
  sendToUrl =” /walk.aspx”;

RewriterUtils.RewriteUrl(app.Context, sendToUrl);
    
}

在web.config里配置规则的时候,需要这样
<RewriterRule>
<LookFor>http://(\w+)\.kerry\.com</LookFor>
<SendTo>/test.aspx</SendTo>
</RewriterRule>
(\w+)用来匹配任意字符串
这里的test.aspx随便写别的也可以,因为我们根本没有用它.

我有好多不确定二级域名的站点,但是每个站点的页面确定,每个二级域名站点的内容实际上根剧不同的id从数据库调,
情况如这样
http://localhost/kerry/action.aspx?id=1 love.kerry.com/walk.aspx

http://localhost/kerry/action.aspx?id=14 like.kerry.com/walk.aspx

现在传上去,不能显示id参数,都改成二级域名的方式. 这个时候该怎么办?

首先配置规则
<RewriterRule>
<LookFor>http://(\w+)\.kerry \.com\ walk.aspx</LookFor>
<SendTo>/action.aspx</SendTo>
</RewriterRule>
然后在程序里这样处理
//获取二级域名
string [] UserHost = app.Request.Url.Host.Split ( new Char [] { '.' } );
string domain2=UserHost [0];
根据域名获得不同的编号
int id=getIDfromDomain(domain2);
//获得要转向的基本url
 string sendToUrl = RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, re.Replace(requestedPath, rules[i].SendTo));
//加上id参数
if(id>0)
sendToUrl=string.Format ( "{0}?id={1}" , sendToUrl , id );
else
    sendToUrl=”error.aspx”;
//重写
RewriterUtils.RewriteUrl(app.Context, sendToUrl);
如何匹配目录?写了一个lookfor规则 http://love.kerry.com/,但是在浏览器输入这个地址, 总是不能正确的重写,经过trace后发现根本不能匹配,为什么?

首先,我们应该知道,浏览器实际上接受的不是http://love.kerry.com/,而是http://love.kerry.com/default.aspx ,因此,你的</LookFor>规则应该这样写
<LookFor>
http://love.kerry.com/default.aspx
</LookFor>
这个default.aspx应该是你在iis里配置的默认文档,如果你的是index.aspx或其他奇怪的名字,就写成你自己的名字
同样, http://love.kerry.com/fun  这个地址要匹配,需要这样的规则http://love.kerry.com/fun/default.aspx
但是,再罗嗦一句,你的文件根本不需要有fun这个目录,因为…重写了嘛

我搜到网上还有另外一种解决办法…

或许你是指这篇文章

http://blog.csdn.net/mengyao/archive/2007/01/25/1493537.aspx

大家可以看到,其基本的方法都是一样的.之所以没有把这个列在最前面,是因为这个做法有些取巧,可能一开始不是那么好理解.但是我相信看到最后的朋友再看这篇文章,应该都会会心的一笑
Happy programming 
最后ps:本来准备过几天发这个文章,就在刚才,不小心从VSS把这几天写的程序都删除了,还是彻底型的,再次强烈的鄙视微软做的这个垃圾源码管理器 -_-

[JavaScript]BlackBird开源调试框架

mikel阅读(800)

Blackbird 是一个开源的JavaScript库,提供了一种简单的记录日志的方式和一个控制台窗口,有了这个之后,你就可以抛弃alert() 了。支持下面的浏览器:

* Internet Explorer 6+
* Firefox 2+
* Safari 2+
* Opera 9.5

另外,如果你使用的是YUI的话,可以考虑YUI中的Logger组件

[SQL]SQL Server中小心使用@@identity

mikel阅读(953)

@@identity的作用是返回最后插入的标识值,所以有很多朋友使用它来获取插入数据后的标识符。
但有一点是需要注意的,@@identity返回的是最后的标识符,所以,要想正确的返回插入后的标识符,那么就必须保证,你想要的结果是最后的标识符,否则就会隐藏bug。
仔细阅读@@identity的注释:

注释

在一条 Insert、Select INTO 或大容量复制语句完成后,@@IDENTITY 中包含此语句产生的最后的标识值。若此语句没有影响任何有标识列的表,则 @@IDENTITY 返回 NULL。若插入了多个行,则会产生多个标识值,@@IDENTITY 返回最后产生的标识值。如果此语句激发一个或多个执行产生标识值的插入操作的触发器,则语句执行后立即调用 @@IDENTITY 将返回由触发器产生的最后的标识值。若 Insert 或 Select INTO 语句失败或大容量复制失败,或事务被回滚,则 @@IDENTITY 值不会还原为以前的设置。

在返回插入到表的 @@IDENTITY 列的最后一个值方面,@@IDENTITY、SCOPE_IDENTITY 和 IDENT_CURRENT 函数类似。

@@IDENTITY 和 SCOPE_IDENTITY 将返回在当前会话的所有表中生成的最后一个标识值。但是,SCOPE_IDENTITY 只在当前作用域内返回值,而 @@IDENTITY 不限于特定的作用域。

例如:创建表t和t1

drop table t
drop table t1

create table t 
(
id 
int identity(1,1)primary key,
name 
char(10)
)
create table t1 
(
id 
int identity(10,1)primary key,
name 
char(10)
)

创建表t的触发器,作用是当有新的数据插入到表t时,t1也相应的插入一条数据。

触发器
create trigger trigger_insert on t
for insert
as
insert into t1(name) select name from inserted

然后,执行执行如下语句:

insert into t(name) values('me')
select @@identity

这时候,你期望得到的结果是1,但其实返回的结果却是10。
使用时,这就是你要注意的问题啦。
论坛支持:www.help-doc.com
相关知识可以参考:http://www.help-doc.com/17/ShowForum.aspx
SQL Server 2005的帮助中的内容:

SCOPE_IDENTITY、IDENT_CURRENT 和 @@IDENTITY 是相似的函数,因为它们都返回插入到标识列中的值。

IDENT_CURRENT 不受作用域和会话的限制,而受限于指定的表。IDENT_CURRENT 返回为任何会话和作用域中的特定表所生成的值。有关详细信息,请参阅 IDENT_CURRENT (Transact-SQL)

SCOPE_IDENTITY 和 @@IDENTITY 返回在当前会话中的任何表内所生成的最后一个标识值。但是,SCOPE_IDENTITY 只返回插入到当前作用域中的值;@@IDENTITY 不受限于特定的作用域。

例如,有两个表 T1 和 T2,并且在 T1 上定义了 Insert 触发器。当将某行插入 T1 时,触发器被激发,并在 T2 中插入一行。 该方案演示了两个作用域:在 T1 上的插入,以及在 T2 通过触发器的插入。

假设 T1 和 T2 都有标识列,@@IDENTITY 和 SCOPE_IDENTITY 将在 T1 上的 Insert 语句的最后返回不同的值。@@IDENTITY 将返回在当前会话中的任何作用域内插入的最后一个标识列的值。这是在 T2 中插入的值。SCOPE_IDENTITY() 将返回在 T1 中插入的 IDENTITY 值。这是在同一个作用域内发生的最后的插入。如果在任何 Insert 语句作用于作用域中的标识列之前调用 SCOPE_IDENTITY() 函数,则该函数将返回空值。

如果语句和事务失败,它们会更改表的当前标识,从而使标识列中的值出现不连贯现象。即使未提交试图向表中插入值的事务,也永远无法回滚标识值。例如,如果因 IGNORE_DUP_KEY 冲突而导致 Insert 语句失败,表的当前标识值仍然会增加。

[C#]ADO.Net执行存储过程

mikel阅读(730)

存储过程————————————————————————————————


Create PROCEDURE dbo.sptestList

@strOptions varchar(
200= NULL,
@intID 
int = NULL,
@strOut nvarchar(
50= NULL   OUTPUT

AS

SET NOCOUNT ON
不返回影响的行数
SET ANSI_WARNINGS OFF
不返警告

/* 信息列表 */
IF @strOptions
='LIST' BEGIN

Select
   id,
   name,
   subject,
   Source
FROM test 
Where ID 
<=@intID

SET @strOut 
= @strOut + 'out'
RETURN 
50
END
GO


————————————————————————-

//StoredProcedure 调用存储过程
    private void BindData2()
    
{
        SQLConnection MyConn 
= new SQLConnection("Server=.;Database=mine;User=sa;Pwd=123;");
        MyConn.Open();

        SqlCommand MyCmd 
= new SqlCommand();
        MyCmd.Connection 
= MyConn;
        MyCmd.CommandType 
= CommandType.StoredProcedure;
        MyCmd.CommandText 
= "sptestList";
        
string strOut = "in—";
        
int intReturn = 0;

        SqlParameter[] paras 
= 
            
{
                
new SqlParameter("@strOptions","LIST"),
                
new SqlParameter("@intID",100),
                
//长度一定需要
                new SqlParameter("@strOut",SqlDbType.VarChar,200),
                
//用来存返回值,ReturnValue随便写都可以,但类型一定是整型(因为数据库只能返回整型)
                new SqlParameter("ReturnValue",SqlDbType.Int)
            
            }
;
      
        paras[
2].Direction = ParameterDirection.InputOutput;//设置 传入并传出
        paras[2].Value = strOut;
        paras[
3].Direction = ParameterDirection.ReturnValue;//设置 返回值


        
foreach (SqlParameter par in paras)
        
{
            MyCmd.Parameters.Add(par);
        }


        SqlDataAdapter MySda 
= new SqlDataAdapter(MyCmd);
        DataTable MyDtb 
= new DataTable();
        MySda.Fill(MyDtb);

        strOut 
= paras[2].Value.ToString();//接收传出
        intReturn = (int)paras[3].Value;//接收返回值
        Response.Write("Out=" + strOut + "; Return=" + intReturn.ToString() + "<br>");

        
this.Repeater1.DataSource = MyDtb;
        
this.Repeater1.DataBind();

        MyConn.Close();

    }


    
//SqlDataAdapter 执行查询语句
    private void BindData()
    
{
        SqlConnection MyConn 
= new SqlConnection("Server=.;Database=mine;User=sa;Pwd=123;");

        SqlCommand MyCmd 
= new SqlCommand("Select TOP 100 * FROM Test", MyConn);
        SqlDataAdapter MySda 
= new SqlDataAdapter(MyCmd);
        DataTable MyDtb 
= new DataTable();
        MySda.Fill(MyDtb);

        
this.Repeater1.DataSource = MyDtb;
        
this.Repeater1.DataBind();

    }


    
//ExecuteNonQuery 执行插入语句
    protected void FInsert()
    
{
        SqlConnection MyConn 
= new SqlConnection("Server=.;DataBase=mine;Uid=sa;Pwd=123;");

        SqlCommand MyCmd 
= new SqlCommand("Insert INTO StudentInfo(StNo,StName) VALUES(124532,'A111ww')", MyConn);
        MyConn.Open();
        
int i = MyCmd.ExecuteNonQuery();
        Response.Write(i.ToString() 
+ "<br>");
        MyConn.Close();

    }


    
//SqlDataReader
    protected void FReader()
    
{
        SqlConnection MyConn 
= new SqlConnection("Server=.;Database=mine;Uid=sa;Pwd=123");
        MyConn.Open();
        SqlCommand MyCmd 
= new SqlCommand("Select Top 10 StNo,StName from StudentInfo", MyConn);

        SqlDataReader MyRead 
= MyCmd.ExecuteReader();

        
while (MyRead.Read())
        
{
            Response.Write(MyRead[
"StNo"].ToString() + "" + MyRead["StName"].ToString() + "<br>");
        }


        MyConn.Close();

    }


    
//ExecuteScalar
    protected void FScalar()
    
{

        
//<appSettings>
        
//<add key ="SqlConnStr" value="Server=.;DataBase=mine;Uid=sa;Pwd=123"/>
        
//</appSettings>
        
//SqlConnection MyConn = new SqlConnection(ConfigurationManager.AppSettings["SqlConnStr"]);
        SqlConnection MyConn = new SqlConnection("Server=.;Database=mine;Uid=sa;Pwd=123");
        MyConn.Open();
        SqlCommand MyCmd 
= new SqlCommand("Select Total=Count(1) from StudentInfo", MyConn);

        
string MyS = MyCmd.ExecuteScalar().ToString();

        Response.Write(MyS 
+ "<br>");

        MyConn.Close();

    }


//连接Access
    private void BindAccess()
    
{
        
//<add key="AccessConString" value="App_Data/db.mdb" />
        string strAccessPath = ConfigurationManager.AppSettings["AccessConString"].ToString();
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath(strAccessPath));
        con.Open();
        OleDbDataAdapter oda 
= new OleDbDataAdapter("Select * From Result", con);
        DataTable Dtb 
= new DataTable();
        oda.Fill(Dtb);

        
this.Repeater1.DataSource = Dtb;
        
this.Repeater1.DataBind();

        
//———————-二—————————–
        
//string constr = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" + Server.MapPath("App_Data/db.mdb");
        
//OleDbConnection con = new OleDbConnection(constr);
        
//string cmdstr = "Select * FROM Result";
        
//con.Open();
        
//OleDbCommand cmd = new OleDbCommand(cmdstr, con);
        
//OleDbDataReader dr = cmd.ExecuteReader();
    }



//OleDbCommand 执行语句
    protected void Button1_Click(object sender, EventArgs e)
    
{
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;Data Source="
            
+ Server.MapPath(ConfigurationManager.AppSettings["OleDbConnPathStr"]));
        con.Open();

        OleDbCommand cmd 
= new OleDbCommand("Insert Into Products(Product_Id,Title,Spec,Content) Values('ww123','成功添加01','100*1','真的成功了')", con);

        cmd.ExecuteNonQuery();

        con.Close();
        con.Dispose();

        BindData();

    }


    
//OleDbDataAdapter 读取数据
    protected void Button2_Click(object sender, EventArgs e)
    
{
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;Data Source="
            
+ Server.MapPath(ConfigurationManager.AppSettings["OleDbConnPathStr"]));
        con.Open();

        OleDbDataAdapter odad 
= new OleDbDataAdapter("Select * From Products Where ID=123", con);

        DataTable dtb 
= new DataTable();
        odad.Fill(dtb);

        
if (dtb.Rows.Count > 0)
        
{
            DataRow row 
= dtb.Rows[0];

            
this.Label.Text = row["ID"].ToString() + "" + row["Title"].ToString();
        }


        con.Close();
        con.Dispose();
    }


    
//OleDbCommand 执行语句(参数化)
    protected void Button3_Click(object sender, EventArgs e)
    
{
        OleDbConnection con 
= new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0;Data Source="
            
+ Server.MapPath(ConfigurationManager.AppSettings["OleDbConnPathStr"]));
        con.Open();

        OleDbCommand cmd 
= new OleDbCommand();
        cmd.Connection 
= con;
        cmd.CommandType 
= CommandType.Text;
        cmd.CommandText 
= "Insert Into Products(Product_Id,Title,Spec,Content) Values(@Product_Id,@Title,@Spec,@Content)";

        OleDbParameter[] paras 
= {
            
new OleDbParameter("@Product_Id",OleDbType.VarChar),
            
new OleDbParameter("@Title",OleDbType.VarChar),
            
new OleDbParameter("@Spec",OleDbType.VarChar),
            
new OleDbParameter("@Content",OleDbType.VarChar)
        }
;

        paras[
0].Value = "qq123";
        paras[
1].Value = "qq成功添加";
        paras[
2].Value = "10*10";
        paras[
3].Value = "qq真的成功了";

        
foreach (OleDbParameter para in paras)
        
{
            cmd.Parameters.Add(para);
        }


        cmd.ExecuteNonQuery();

        con.Close();
        con.Dispose();

        BindData();
    }

[C#]SqlCommand.ExecuteNonQuery返回值

mikel阅读(912)

当执行Update、Insert 和 Delete时,SQLHelper的ExecuteNonQuery方法能正确的返回受影响的行数,但执行Select时返回值却总是-1,今天上 MSDN查了下SQLCommand.ExecuteNonQuery方法,上边的解释是:

引用内容 引用内容
对于 Update、Insert 和 Delete 语句,返回值为该命令所影响的行数。对于所有其他类型的语句,返回值为 -1。如果发生回滚,返回值也为 -1。

那上述现象的出现就是正常的了,呵呵。
MSDN地址:http://msdn2.microsoft.com/zh-cn/library/system.data.sqlclient.sqlcommand.executenonquery(VS.80).aspx

[JQuery]JQuery事件总结

mikel阅读(762)

  很少写这些,看了1.2.3版本的改进,确实佩服,很方便.
1.绑定事件
(1)

$("p").bind("click", function(e){});

(2)

$("p").click(function() {})

2.删除事件
(1)删除特定事件

$("div").unbind("click");

(2)删除所有事件

$("div").unbind();

3.触发事件
(1)trigger方法 触发特定元素事件

$("div").trigger('click');

(2)triggerHandler方法 与trigger方法相似,但不触发浏览器默认事件,如focus事件,使用此方法,将会阻止焦点到元素上

$("input").triggerHandler("focus");

4.特殊事件
(1)one(string event,function data)
此事件只执行一次则被删除

$("p").one("click", function(){
   alert(
"test");
}
);

(2)hover(over, out)
切换mouSEOver与mouSEOut事件

$("td").hover(
   function ()
{
     $(
this).addClass("hover");
   }
,
   function ()
{
     $(
this).removeClass("hover");
   }

);

可用unbind mouseover与mouseout方法来删除此事件
(3)toggle(oldclick,newclick)
切换执行click事件

     $("li").toggle(
       function ()
{
         $(
this).css("list-style-type", "disc")
                .css(
"color", "blue");
       }
,
       function ()
{
         $(
this).css({"list-style-type":"", "color":""});
       }

     );

可用unbind click方法来删除此事件
5.     1.2.3版本新增功能
(1)事件命名空间(便于管理)
实际使用方面:
1.当不需要全部事件,删除特定2个以上的事件.
示例:

   $("div").bind("click.plugin",function() {} );
   $(
"div").bind("mouseover.plugin", function(){});
   $(
"div").bind("dblclick", function(){});
   $(
"button").click(function() {$("div").unbind(".plugin");   })

在事件名称后面加命名空间,在删除事件时,只需要指定命名空间即可.以上代码执行以后,dbclick仍然存在.
(2)相同事件名称,不同命名的事件执行方法
示例:

$("div").bind("click", function(){ alert("hello"); });
   $(
"div").bind("click.plugin", function(){ alert("goodbye"); });
   $(
"div").trigger("click!"); // alert("hello") only

以上trigger方法则根据事件名称来执行事件.
简单的写几句.以上的几个方法还是非常实用方便的

[原创]重复获得验证码的问题

mikel阅读(887)

验证码的页面可能由于验证码不清楚,单击需要获得新的验证码
服务器端用C#实现如下:

/// <summary>
/// 验证码类,用于生成验证码
/// </summary>
public static class ValidateCode
{
private static string Cr&#101;ateRandomCode(int codeCount)
{
string allChar = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F,G,H,I,J,K,L,M,N,O,P,Q,R,S,T,U,W,X,Y,Z";
string[] allCharArray = allChar.Split(&#39;,&#39;);
string randomCode = "";
int temp = -1;
Random rand = new Random();
for (int i = 0; i < codeCount; i++)
{
if (temp != -1)
{
rand = new Random(i * temp * ((int)DateTime.Now.Ticks));
}
int t = rand.Next(35);
if (temp == t)
{
return Cr&#101;ateRandomCode(codeCount);
}
temp = t;
randomCode += allCharArray&#91;t&#93;;
}
return randomCode;
}
public static MemoryStream Cr&#101;ateImage(out string checkCode)
{
//生成随机数
checkCode = Cr&#101;ateRandomCode(4);
int iwidth = (int)(checkCode.Length * 13.5);
System.Drawing.Bitmap image = new System.Drawing.Bitmap(iwidth, 20);
Graphics g = Graphics.FromImage(image);
Font f = new System.Drawing.Font("Arial", 12, System.Drawing.FontStyle.Bold);
Brush b = new System.Drawing.SolidBrush(Color.Black);
//g.FillRectangle(new System.Drawing.SolidBrush(Color.Blue),0,0,image.Width, image.Height);
g.Clear(Color.White);
g.DrawString(checkCode, f, b, 3, 3);
Pen blackPen = new Pen(Color.Black, 0);
Random rand = new Random();
for (int i = 0; i < 3; i++)
{
int y = rand.Next(image.Height);
g.DrawLine(blackPen, 0, y, image.Width, y);
}
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
g.Dispose();
image.Dispose();
return ms;
}
}
&#91;/code&#93;
使用Asp.net MVC实现的Controller调用验证码的Action如下:
没有生成中间gif,jpg文件
&#91;code&#93;
/// <summary>
/// 获得验证码
/// </summary>
public void GetValidateCode()
{
try
{
//生成验证码
string validateCode;
Session["ValidateCode"] = "";
//生成验证码图片
MemoryStream ms = ValidateCode.Cr&#101;ateImage(out validateCode);
ViewData["Code"] = ms;
//保存到Session
Session["ValidateCode"] = validateCode;
Response.ClearContent();
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());
}
catch (Exception e)
{
Response.Write("验证码生成失败!错误消息:" + e.Message);
}
}

页面代码:

<script language="javascript" type="text/javascript">
//获得验证码
function GetCode()
{
//注意后面一定要加随机数,这样<img>才能更新为新的验证码
$("#validateImg").attr("src","/user/GetValidateCode?sd="+Math.random());
}
</script>
<a id="getCode" href="javascript:GetCode();"><img  id="validateImg"  src="/user/GetValidateCode"  alt="点击获得验证码" /></a>

[C#]C#中的序列化和反序列化

mikel阅读(841)

序列化和反序列化我们可能经常会听到,其实通俗一点的解释,序列化就是把一个对象保存到一个文件或数据库字段中去,反序列化就是在适当的时候把这个文件再转化成原来的对象使用。

  我想最主要的作用有:

  1、在进程下次启动时读取上次保存的对象的信息

  2、在不同的AppDomain或进程之间传递数据

  3、在分布式应用系统中传递数据

  ……

  在C#中常见的序列化的方法主要也有三个:BinaryFormatter、SoapFormatter、XML序列化

  本文就通过一个小例子主要说说这三种方法的具体使用和异同点

  这个例子就是使用三种不同的方式把一个Book对象进行序列化和反序列化,当然这个Book类首先是可以被序列化的。至于怎么使一个类可以序列化可以参见:C#强化系列文章一:ViewState使用兼谈序列化

  Book类

  using System;

  using System.Collections;

  using System.Text;

  namespace SerializableTest

  {

  [Serializable]

  public class Book

  {

  public Book()

  {

  alBookReader = new ArrayList();

  }

  public string strBookName;

  [NonSerialized]

  public string strBookPwd;

  private string _bookID;

  public string BookID

  {

  get { return _bookID; }

  set { _bookID = value; }

  }

  public ArrayList alBookReader;

  private string _bookPrice;

  public void SetBookPrice(string price)

  {

  _bookPrice = price;

  }

  public void Write()

  {

  Console.WriteLine("Book ID:" + BookID);

  Console.WriteLine("Book Name:" + strBookName);

  Console.WriteLine("Book Password:" + strBookPwd);

  Console.WriteLine("Book Price:" + _bookPrice);

  Console.WriteLine("Book Reader:");

  for (int i = 0; i < alBookReader.Count; i++)

  {

  Console.WriteLine(alBookReader[i]); [Page]

  }

  }

  }

  }

  这个类比较简单,就是定义了一些public字段和一个可读写的属性,一个private字段,一个标记为[NonSerialized]的字段,具体会在下面的例子中体现出来

  一、BinaryFormatter序列化方式

  1、序列化,就是给Book类赋值,然后进行序列化到一个文件中

  Book book = new Book();

  book.BookID = "1";

  book.alBookReader.Add("gspring");

  book.alBookReader.Add("永春");

  book.strBookName = "C#强化";

  book.strBookPwd = "*****";

  book.SetBookPrice("50.00");

  BinarySerialize serialize = new BinarySerialize();

  serialize.Serialize(book);2、反序列化

  BinarySerialize serialize = new BinarySerialize();

  Book book = serialize.DeSerialize();

  book.Write();3、测试用的

  BinarySerialize类

  using System;

  using System.Collections.Generic;

  using System.Text;

  using System.IO;

  using System.Runtime.Serialization.Formatters.Binary;

  namespace SerializableTest

  {

  public class BinarySerialize

  {

  string strFile = "c:\book.data";

  public void Serialize(Book book)

  {

  using (FileStream fs = new FileStream(strFile, FileMode.Create))

  {

  BinaryFormatter formatter = new BinaryFormatter();

  formatter.Serialize(fs, book);

  }

  }

  public Book DeSerialize()

  {

  Book book;

  using (FileStream fs = new FileStream(strFile, FileMode.Open))

  {

  BinaryFormatter formatter = new BinaryFormatter(); [Page]

  book = (Book)formatter.Deserialize(fs);

  }

  return book;

  }

  }

  }

  主要就是调用System.Runtime.Serialization.Formatters.Binary空间下的 BinaryFormatter类进行序列化和反序列化,以缩略型二进制格式写到一个文件中去,速度比较快,而且写入后的文件已二进制保存有一定的保密效 果。

  调用反序列化后的截图如下:

  也就是说除了标记为NonSerialized的其他所有成员都能序列化

  二、SoapFormatter序列化方式

  调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看SoapSerialize类

  SoapSerialize类

  using System;

  using System.Collections.Generic;

  using System.Text;

  using System.IO;

  using System.Runtime.Serialization.Formatters.Soap;

  namespace SerializableTest

  {

  public class SoapSerialize

  {

  string strFile = "c:\book.soap";

  public void Serialize(Book book)

  {

  using (FileStream fs = new FileStream(strFile, FileMode.Create))

  {

  SoapFormatter formatter = new SoapFormatter();

  formatter.Serialize(fs, book);

  }

  }

  public Book DeSerialize()

  {

  Book book;

  using (FileStream fs = new FileStream(strFile, FileMode.Open))

  {

  SoapFormatter formatter = new SoapFormatter();

  book = (Book)formatter.Deserialize(fs);

  }

  return book;

  }

  }

  }

  主要就是调用System.Runtime.Serialization.Formatters.Soap空间下的SoapFormatter 类进行序列化和反序列化,使用之前需要应用 System.Runtime.Serialization.Formatters.Soap.dll(.net自带的)

  序列化之后的文件是Soap格式的文件(简单对象访问协议(Simple Object Access Protocol,SOAP),是一种轻量的、简单的、基于XML的协议,它被设计成在WEB上交换结构化的和固化的信息。 SOAP 可以和现存的许多因特网协议和格式结合使用,包括超文本传输协议(HTTP),简单邮件传输协议(SMTP),多用途网际邮件扩充协议(MIME)。它还 支持从消息系统到远程过程调用(RPC)等大量的应用程序。SOAP使用基于XML的数据结构和超文本传输协议(HTTP)的组合定义了一个标准的方法来 使用Internet上各种不同操作环境中的分布式对象。) [Page]

  调用反序列化之后的结果和方法一相同

  三、XML序列化方式

  调用序列化和反序列化的方法和上面比较类似,我就不列出来了,主要就看看XmlSerialize类

  XmlSerialize类

  using System;

  using System.Collections.Generic;

  using System.Text;

  using System.IO;

  using System.Xml.Serialization;

  namespace SerializableTest

  {

  public class XmlSerialize

  {

  string strFile = "c:\book.xml";

  public void Serialize(Book book)

  {

  using (FileStream fs = new FileStream(strFile, FileMode.Create))

  {

  XmlSerializer formatter = new XmlSerializer(typeof(Book));

  formatter.Serialize(fs, book);

  }

  }

  public Book DeSerialize()

  {

  Book book;

  using (FileStream fs = new FileStream(strFile, FileMode.Open))

  {

  XmlSerializer formatter = new XmlSerializer(typeof(Book));

  book = (Book)formatter.Deserialize(fs);

  }

  return book;

  }

  }

  }

  从这三个测试类我们可以看出来其实三种方法的调用方式都差不多,只是具体使用的类不同

  xml序列化之后的文件就是一般的一个xml文件:

  book.xml

  <?xml version="1.0"?>

  <Book xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">

  <strBookName>C#强化</strBookName>

  <strBookPwd>*****</strBookPwd>

  <alBookReader>

  <anyType xsi:type="xsd:string">gspring</anyType>

  <anyType xsi:type="xsd:string">永春</anyType>

  </alBookReader>

  <BookID>1</BookID>

  </Book>输出截图如下:

  也就是说采用xml序列化的方式只能保存public的字段和可读写的属性,对于private等类型的字段不能进行序列化

  关于循环引用:

  比如在上面的例子Book类中加入如下一个属性:

  public Book relationBook;

  在调用序列化时使用如下方法:

  Book book = new Book();

  book.BookID = "1"; [Page]

  book.alBookReader.Add("gspring");

  book.alBookReader.Add("永春");

  book.strBookName = "C#强化";

  book.strBookPwd = "*****";

  book.SetBookPrice("50.00");

  Book book2 = new Book();

  book2.BookID = "2";

  book2.alBookReader.Add("gspring");

  book2.alBookReader.Add("永春");

  book2.strBookName = ".NET强化";

  book2.strBookPwd = "*****";

  book2.SetBookPrice("40.00");

  book.relationBook = book2;

  book2.relationBook = book;

  BinarySerialize serialize = new BinarySerialize();

  serialize.Serialize(book);这样就会出现循环引用的情况,对于BinarySerialize和 SoapSerialize可以正常序列化(.NET内部进行处理了),对于XmlSerialize出现这种情况会报错:"序列化类型 SerializableTest.Book 的对象时检测到循环引用。"