双11上云狂欢,0.5折起爆品开抢
Logo

博客

搜索你要找的文章

NET Framework中为我们提供了3种类型的Timer,分别是:
Server Timer(System.Timers.Timer),Thread Timer(System.Threading.Timer )和Windows Timer(System.Windows.Forms.Timer)。

其中Windows Timer和WinAPI中的Timer一样,是基于消息的,而且是单线程的。另外两个Timer则不同于Windows Timer,它们是基于ThreadPool的,这样最大的好处就是,产生的时间间隔准确均匀。Server Timer和Thread Timer的区别在于,Server Timer是基于事件的,而Thread Timer是基于Callback的。

相比之下Thread Timer更轻量级一些,所以下文主要以Thread Timer为例,讲解如何利用Thread Timer在ASP.NET中实现计划任务。

下面给出一个用Timer实现计划任务的类:

 public class ScheduledTask
    {
        private static readonly ScheduledTask _ScheduledTask = null;
        private Timer UpdateTimer = null;
        //间隔时间,这里设置为15分钟
        private int Interval = 15 * 60000;
        private int _IsRunning;
        
        static ScheduledTask()
        {
            _ScheduledTask = new ScheduledTask();
        }
        
        public static ScheduledTask Instance()
        {
            return _ScheduledTask;
        }
        
        public void Start()
        {
            if(UpdateTimer == null)
            {
                UpdateTimer = new Timer(new TimerCallback(UpdateTimerCallback), null, Interval, Interval);
            }
        }

        private void UpdateTimerCallback(object sender)
        {
            if(Interlocked.Exchange(ref _IsRunning, 1) == 0)
            {
                try
                {
                    //此处写你自己想执行的任务
                }
                catch(Exception ex)
                {                    
                }
                finally
                {
                    Interlocked.Exchange(ref _IsRunning, 0);
                }
            }
        }
        
        public void Stop()
        {
            if(UpdateTimer != null)
            {
                UpdateTimer.Dispose();
                UpdateTimer = null;
            }
        }
    } 

首先,注意一下这段:

程序代码 程序代码
private int _IsRunning;


_IsRunning是一个标志,它代表上一个时间间隔触发的任务是否运行完成。

为什么我们需要这个_IsRunning标志呢?
因为,如果我们执行的任务时间很长,就可能造成上一个时间段触发的任务还没有执行完成,下一个任务又开始了,这样就会造成重入的问题。为了解决这个问题,我们用_IsRunning作为一个标志,表示上次的任务是否完成了,如果完成了,我们就执行新的任务,如果没完成就跳过这次的任务继续执行上次的任务。

具体的逻辑在下面这段代码中实现:

程序代码 程序代码
private void UpdateTimerCallback(object sender)
        {
            if(Interlocked.Exchange(ref _IsRunning, 1) == 0)
            {
                try
                {
                    //此处写你自己想执行的任务
                }
                catch(Exception ex)
                {                    
                }
                finally
                {
                    Interlocked.Exchange(ref _IsRunning, 0);
                }
            }
        }



大家看到,上面代码中用到了Interlocked.Exchange这个方法。该方法的作用是保证多线程下给对象赋值的安全性。因为在多线程下,我们直接给_IsRunning赋值是不安全的,所以在这种情况下Interlocked.Exchange就派上了用场。

说完了ScheduledTask类的实现,下面我们看看如何在ASP.NET中调用这个类。
建议在Application_Start中调用这个类,代码如下:

程序代码 程序代码
public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
               ScheduledTask.Instance().Start();
        }

        protected void Application_End(object sender, EventArgs e)
        {
               ScheduledTask.Instance().Stop();
        }
    }


感谢您使用微软产品。

在ASP.NET中,每一个aspx页面在server端都对应一个System.Web.UI.Page实例,所以把一个页面Form中Server Controls的内容(server端对应于page类实例的数据)提交给另一个page类,跟asp中的实现方法有所不同。

在asp.net中,Form提交的工作原理是:

比如说在您的一个aspx文件中,您使用了一个TextBox Server Control. 在您的Page class中, 有这么一个实例:

TextBox TextBox1 = new TextBox();

您可以使用TextBox1在服务器端来引用该对象。当ASP.NET执行完该页面之后,客户端(浏览器)得到的纯HTML/DHTML中,会产生下面的代码,对应于服务器端的逻辑:

<input name="TextBox1" type="text" id="TextBox1" />

注意:上边的“name”属性,和服务器端代码中TextBox1对象的UniqueID Property是一致的。

此时的客户端跟您的程序交互的唯一方式就是HTTP中的POST. POST提交之后,ASP.NET检查“name"是否和其所提交页面对应得Page类中的某一Control的UniqueID一致,如果有,并且该Server Control实现了IPostBackDataHandler借口,则调用LoadPostData函数,您可以重载这个函数。如果实现了IPostBackEventHanlder, ASP.NET调用RaisePostBackEvent().

在ASP.NET中传输Form到另外的页面,Inline Code(代码和html在同一页面)和Code-Behind(代码和html在不同的页面)地实现方式有所不同。下面是Inline Code的一个例子:

在WebForm1.aspx中:
1。为该页面声明类的名称;<%@ Page Language="C#" ClassName="FirstPageClass" %>
2。为每一个要传递到另外页面的元素,定义带Get accessor的Property:
3。使用Server.Transfer("Webform2.aspx")把控制权提交给另外一个WebForm class.

////////////////////////  WebForm1.aspx    ////////////////////////////////////////
<%@ Page Language="C#" ClassName="FirstPageClass" %>

<html>
<head>
<script runat="server">
public string FirstName
{
get
{
return first.Text;
}
}

public string LastName
{
get
{
return last.Text;
}
}

void ButtonClicked(object sender, EventArgs e)
{
Server.Transfer(
"secondpage.aspx");
}

</script>

</head>

<body>

<form runat="server">
First Name:
<asp:TextBox id="first" runat="server"/>
<br>
Last Name:
<asp:TextBox id="last" runat="server"/>
<br>
<asp:Button OnClick="ButtonClicked" Text="Go to second page" runat=server />
</form>
</body>
</html>

//////////////////////////////////////////////////////////////////////

在目的Webform2.aspx中:

1。添加Reference指令;<%@ Reference Page="firstpage.aspx" %>
2。声明一个WebForm1.aspx对应的class的实例:FirstPageClass fp;
3。利用HttpContext class, 获得第一个得到 HTTP Request 的页面的实例(Webform1.aspx):   fp = (FirstPageClass)Context.Handler;

////////////////////  WebForm2.aspx     ////////////////////////////////////////////////////////////////////
<%@ Page Language="C#" %>
<%@ Reference Page="firstpage.aspx" %>
<html>
<head>
<script runat="server">

FirstPageClass fp;

void Page_Load()
{
if (!IsPostBack)
{
fp
= (FirstPageClass)Context.Handler;
}
}
</script>
</head>
<body>

<form runat="server">
Hello
<%=fp.FirstName%> <%=fp.LastName%>
</form>

</body>
</html>
/////////////////////////////////////////////////////////////////////////////////////////////////////////

关于Code-Behinde方式中的详细信息,请您参阅下面的文章:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/cpguide/html/cpconpassingservercontrolvaluesbetweenpages.asp

希望上面的信息对您有所帮助。

-微软全球技术中心

下面的代码示例演示如何使用正则表达式检查字符串是否具有表示货币值的正确格式。注意,如果使用 ^ 和 $ 封闭标记,则指示整个字符串(而不只是子字符串)都必须匹配正则表达式。

using System;
using System.Text.RegularExpressions;

public class Test
{
 public static void Main()
 {
 // Define a regular expression for currency values.
 Regex rx = new Regex(@"^-?\d+(\.\d{2})?$");

 // Define some test strings.
 string[] tests = {"-42", "19.99", "0.001", "100 USD",
 ".34", "0.34", "1,052.21"};

 // Check each test string against the regular expression.
 foreach (string test in tests)
 {
 if (rx.IsMatch(test))
 {
 Console.WriteLine("{0} is a currency value.", test);
 }
 else
 {
 Console.WriteLine("{0} is not a currency value.", test);
 }
 }
 }
}
// The example displays the following output to the console:
// -42 is a currency value.
// 19.99 is a currency value.
// 0.001 is not a currency value.
// 100 USD is not a currency value.
// .34 is not a currency value.
// 0.34 is a currency value.
// 1,052.21 is not a currency value.

下面的代码示例演示如何使用正则表达式检查字符串中重复出现的词。注意如何使用 (?<word>) 构造来命名组,以及稍后如何使用 (\k<word>)在表达式中引用该组。

using System;
using System.Text.RegularExpressions;

public class Test
{

 public static void Main()
 {

 // Define a regular expression for repeated words.
 Regex rx = new Regex(@"\b(?<word>\w+)\s+(\k<word>)\b",
 RegexOptions.Compiled | RegexOptions.IgnoreCase);

 // Define a test string. 
 string text = "The the quick brown fox fox jumped over the lazy dog dog.";

 // Find matches.
 MatchCollection matches = rx.Matches(text);

 // Report the number of matches found.
 Console.WriteLine("{0} matches found in:\n {1}",
 matches.Count,
 text);

 // Report on each match.
 foreach (Match match in matches)
 {
 GroupCollection groups = match.Groups;
 Console.WriteLine("'{0}' repeated at positions {1} and {2}",
 groups["word"].Value,
 groups[0].Index,
 groups[1].Index);
 }
 }
}
// The example produces the following output to the console:
// 3 matches found in:
// The the quick brown fox fox jumped over the lazy dog dog.
// 'The' repeated at positions 0 and 4
// 'fox' repeated at positions 20 and 25
// 'dog' repeated at positions 50 and 54

正则取值

string text = this.textBox1.Text;
MatchCollection mats = Regex.Matches(text, "<a href=\"http://blog.csdn.net/(?<user>[^/]*)/category/(?<catalog>[^\\.]*).aspx\">(?<typetitle>[^<>]*)</a>", RegexOptions.IgnoreCase | RegexOptions.Multiline);
foreach (Match mat in mats)
{
MessageBox.Show(mat.Groups["user"].Value + "--" + mat.Groups["catalog"].Value + mat.Groups["typetitle"].Value + mat.Value);
}
代码
<!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>
  <title>标签示例</title>
  <style type="text/css">
    BODY { font-size: 14px; font-family: "宋体"; }
    OL LI { margin: 8px; }
    #con { font-size: 12px; margin: 0px auto; width: 600px; }
    #tags { padding-right: 0px; padding-left: 0px; padding-bottom: 0px; margin: 0px 0px 0px 10px; width: 400px; padding-top: 0px; height: 23px; }
    #tags LI { background: url(images/tagleft.gif) no-repeat left bottom; float: left; margin-right: 1px; list-style-type: none; height: 23px; }
    #tags LI A { padding-right: 10px; padding-left: 10px; background: url(images/tagright.gif) no-repeat right bottom; float: left; padding-bottom: 0px; color: #999; line-height: 23px; padding-top: 0px; height: 23px; text-decoration: none; }
    #tags LI.emptyTag { background: none transparent scroll repeat 0% 0%; width: 4px; }
    #tags LI.selectTag { background-position: left top; margin-bottom: -2px; position: relative; height: 25px; }
    #tags LI.selectTag A { background-position: right top; color: #000; line-height: 25px; height: 25px; }
    #tagContent { border-right: #aecbd4 1px solid; padding-right: 1px; border-top: #aecbd4 1px solid; padding-left: 1px; padding-bottom: 1px; border-left: #aecbd4 1px solid; padding-top: 1px; border-bottom: #aecbd4 1px solid; background-color: #fff; }
    .tagContent { padding-right: 10px; display: none; padding-left: 10px; background: url(images/bg.gif) repeat-x; padding-bottom: 10px; width: 576px; color: #474747; padding-top: 10px; height: 350px; }
    #tagContent DIV.selectTag { display: block; }
  </style>
</head>
<body>
  <div id="con">
    <ul id="tags">
      <li><a onclick="selectTag('tagContent0',this)" href="javascript:void(0)">标签一</a>
      </li>
      <li class="selectTag"><a onclick="selectTag('tagContent1',this)" href="javascript:void(0)">
        标签二</a> </li>
      <li><a onclick="selectTag('tagContent2',this)" href="javascript:void(0)">自适应宽度的标签</a>
      </li>
    </ul>
    <div id="tagContent">
      <div class="tagContent" id="tagContent0">
        第一个标签的内容</div>
      <div class="tagContent selectTag" id="tagContent1">
        第二个标签的内容</div>
      <div class="tagContent" id="tagContent2">
        第三个标签的内容</div>
    </div>
  </div>
  <script type="text/javascript">
    function selectTag(showContent, selfObj) {
      // 操作标签
      var tag = document.getElementById("tags").getElementsByTagName("li");
      var taglength = tag.length;
      for (i = 0; i < taglength; i++) {
        tag[i].className = "";
      }
      selfObj.parentNode.className = "selectTag";
      // 操作内容
      for (i = 0; j = document.getElementById("tagContent" + i); i++) {
        j.style.display = "none";
      }
      document.getElementById(showContent).style.display = "block";
    }
  </script>
</body>
</html>

许多情况下,asp.net 在 Page_Load 事件中需要动态生成控件,这对于一些新手,包括我在内,会因为回传控件消失,或重复叠加控件等原因搞得头大,经过我翻阅资料和自己的实践,以博客评论页为例,把整个框架写在下面,仅供参考。

<asp:Panel>
<asp:Panel 记录索引 3 >
<asp:Label 昵称 /> <asp:Label 时间 /> <asp:LinkButton 支持按钮_3 /> <asp:LinkButton 删除按钮_3 /> 1楼
</asp:Panel>
<asp:Panel 记录索引 5 >
<asp:Label 昵称 /> <asp:Label 时间 /> <asp:LinkButton 支持按钮_5 /> <asp:LinkButton 删除按钮_5 /> 2楼
</asp:Panel>
</asp:Panel>


记录索引是指数据库中的自动编号。

支持按钮触发事件 LinkButton_support_Click(object sender, EventArgs e)

删除按钮触发事件 LinkButton_del_Click(object sender, EventArgs e)

所有子 Panel 和内部的所有控件都是在 Page_Load 事件中动态创建的,并且不能被嵌套在 if(!IsPostBack)

“点支持累计点击数”和“点删除删除一条记录”都是需要操作数据库的,我以前的做法是操作完数据库后 .Clear() 掉所有控件,再重新生成一次,这样既浪费服务器资源,又容易出现界面上的混乱,譬如显示了两遍该文章的评论。

其实上面代码中 Panel 套 Panel 的好处就是可以根据索引直接删除相应控件,然后直接在页面呈现,而省去上述烦恼。至于累计支持数就更简单了,下面的代码可以轻松解决问题:

string n = ((Label)Panel_commentLists.FindControl("Label_against_" + id)).Text;
n
= (Convert.ToInt32(n) + 1).ToString();
((Label)Panel_commentLists.FindControl(
"Label_against_" + id)).Text = n;

如果有修改和添加评论操作,同样道理,不要重复地全部 .Controls.Add 一次。为了添加时追加一个子 Panel 方便,建议在 Page_Load 的地方传参使用方法来做。

 

补充:在现在的开发中,我更喜欢用动态生成TableRow,TableCell来操作。

41 42 43
Displaying 7 of 637 records