分类目录归档:ASP.NET

缓存的一点测试

做了一下动态生成内容的客户端缓存测试,记录一下用到的代码。

C#的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Services;
using System.Globalization;

namespace WebApplication
{
  [WebService(Namespace = "http://tempuri.org/")]
  [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
  public class demo : IHttpHandler
  {

    public void ProcessRequest(HttpContext context)
    {
      // 设置缓存的秒数。
      TimeSpan timeout_duration = TimeSpan.FromSeconds(10);

      context.Response.ContentType = "application/javascript";
      context.Response.Cache.SetCacheability(HttpCacheability.Public);

      DateTime modifiedSince;
      // 解析请求的头的If-Modified-Since信息。
      DateTime.TryParse(context.Request.Headers["If-Modified-Since"], DateTimeFormatInfo.InvariantInfo, System.Globalization.DateTimeStyles.AdjustToUniversal, out modifiedSince);
      DateTime utcNow = DateTime.UtcNow;
      if (modifiedSince.AddTicks(timeout_duration.Ticks) < utcNow)
      {
        // 内容已过期,重新生成信息,响应200。
        context.Response.Cache.SetMaxAge(timeout_duration);
        context.Application["counter"] = int.Parse(context.Application["counter"].ToString()) + 1;
        context.Response.Cache.SetLastModified(utcNow);
        context.Response.StatusCode = 200;
        context.Response.Write(string.Format("document.write({0})", context.Application["counter"]));
      }
      else
      {
        // 内容未更改,响应304。
        context.Response.Cache.SetMaxAge(modifiedSince + timeout_duration - utcNow);
        context.Response.Cache.SetLastModified(modifiedSince);
        context.Response.StatusCode = 304;
      }
    }

    public bool IsReusable
    {
      get
      {
        return false;
      }
    }
  }
}

php的代码:

<?php
// 设置缓存的秒数。
$timeout_duration = 10;
// 解析请求的头的If-Modified-Since信息。
// 按CTRL+F5强制刷新的时候,这里将被设置为NULL。
$client_time_stamp = $_SERVER['HTTP_IF_MODIFIED_SINCE'];
$client_time_stamp = (isset($client_time_stamp)? strtotime($client_time_stamp): 0);
$now = time();
$server_now_time_str = gmdate('D, d M Y H:i:s'). ' GMT';
header('Content-Type: application/javascript');
if(($client_time_stamp + $timeout_duration) < $now) {
	// 内容已过期,重新生成信息,响应200。
	header("Last-Modified: $server_now_time_str", true, 200);
	header("Cache-Control: max-age={$timeout_duration}");
	$micro = microtime();
	$script = <<<SCRIPT
	document.write('{$micro} <br />');
SCRIPT;
	echo $script;
} else {
	// 内容未更改,响应304。
	header("Last-Modified: {$_SERVER['HTTP_IF_MODIFIED_SINCE']}", true, 304);
	$max_age = $client_time_stamp + $timeout_duration - $now;
	header("Cache-Control: max-age={$max_age}");
}
exit(0);
?>

分部方法(Partial Methods)

什么是分部方法?

在C# 3.0里有一个叫做“分部方法”的新特性,在分部类或结构中可以包含分部方法,一个分部类中包含分部方法的声明,另一个分部类中包含分部方法的实现。分部方法使得对轻量级事件的处理变得可行。

// Definition in file1.cs
partial void onNameChanged();

// Implementation in file2.cs
partial void onNameChanged()
{
  // method body
}

在上面的例子中,onNameChanged方法分别在file1.cs和file2.cs中定义,在file1.cs中这个方法只有声明,而在file2.cs中才给出这个方法的实现。如果在file2.cs中没有实现onNameChanged,那么在编译的时候所有onNameChanged的调用会被删除掉。

下面几点是值得注意的地方:

  • 分部方法必须在分部类(partial class)中定义。
  • 分部方法定义前要有partial限定符。
  • 分部方法不一定要有方法体。
  • 分部方法必须返回void。
  • 分部方法可以为静态方法。
  • 分部方法可以有参数(包括this,ref,params修饰符,但不能用out)。
  • 分部方法必须是private的。

为什么会有分部方法?

那么如何使用分部方法呢?最常见的情况是使用它们做轻量级的事件处理。比如一个工具生成的代码中可能希望在执行的时候能挂上用户自定义的代码。又如,试想一个工具为一个表示客户(customer)的类生成了如下代码:

partial class Customer
{
    string name;
    public string Name
    {
        get { return name; }
        set
        {
            OnBeforeUpdateName();
            OnUpdateName();
            name = value;
            OnAfterUpdateName();
        }
    }
    partial void OnBeforeUpdateName();
    partial void OnUpdateName();
    partial void OnAfterUpdateName();
}

如果用户没有添加任何实现定义,那么上面的代码等同于:

partial class Customer
{
    string name;
    public string Name
    {
        get { return name; }
        set { name = value; }
    }
}

可以看到没有了那些无用的指令。如果用户侦听 OnUpdateName “事件”:

partial class Customer
{
    partial void OnUpdateName()
    {
        DoSomething();
    }
} 

那么最初的定义就会等同于如下代码:

partial class Customer
{
    string name;
    public string Name
    {
        get { return name; }
        set
        {
            OnUpdateName();
            name = value;
        }
    }
    partial void OnUpdateName();
}

尾递归遍历节点树

用尾递归的形式找到节点的所有父节点,并且按照父节点到子节点的顺序排列。记录一下:

节点类:

public class Node
{
    public string Name { get; set; }
    public Node Parent { get; set; }
}

遍历:

private void traverse_node(Node node, Action<Node> con)
{
    if (node == null)
    {
        con(node);
        return;
    }
    traverse_node(node.Parent, (parent) =>
    {
        PlaceHolder1.Controls.Add(
            new Literal() { Text = node.Name + "<br />" });
        con(parent);
    });

}

调用:

protected override void OnPreRender(EventArgs e)
{
    base.OnPreRender(e);

    Node node1 = new Node() { Name = "Node1" };
    Node node2 = new Node() { Name = "Node2" };
    Node node3 = new Node() { Name = "Node3" };
    Node node4 = new Node() { Name = "Node4" };
    Node node5 = new Node() { Name = "Node5" };

    node5.Parent = node4;
    node4.Parent = node3;
    node3.Parent = node2;
    node2.Parent = node1;

    traverse_node(node5, (n) => { });
}

输出的是:

Node1<br />
Node2<br />
Node3<br />
Node4<br />
Node5<br />

动态加载用户控件到Template

1. 创建一个用户控件。

namespace Northwind.WebSite.UserControls
{
    public partial class CategoryDetail : System.Web.UI.UserControl
    {
        private Category category;
        public Category Category
        {
            set { category = value; }
            get { return category; }
        }
        protected void Page_Load(object sender, EventArgs e)
        {

        }
        protected void Page_PreRender(object sender, EventArgs e)
        {
            GridViewProducts.DataSource = category.Products;
            GridViewProducts.DataBind();
            LableCategoryName.Text = category.CategoryName;
            LabelTotalPrice.Text = string.Format("Total price: {0}",
                category.Products.Sum(p =>
                    p.UnitPrice * (p.UnitsInStock + p.UnitsOnOrder)));
        }
        public void ExpandCollapsiblePanel()
        {
            CollapsiblePanelExtender1.Collapsed = false;
        }
    }
}

2. 实现ITemplate。

namespace Northwind.WebSite.TemplateControl
{
    public class CategoryDetailTemplate : ITemplate
    {
        public void InstantiateIn(Control container)
        {
            CategoryDetail detail = (CategoryDetail)BuildManager.
                CreateInstanceFromVirtualPath("~/UserControls/CategoryDetail.ascx", typeof(CategoryDetail));
            container.DataBinding += delegate(object sender, EventArgs e)
            {
                IDataItemContainer container1 = container as IDataItemContainer;

                detail.Category = (Category)container1.DataItem;
                if (container1.DataItemIndex == 0)
                {
                    detail.ExpandCollapsiblePanel();
                }
            };
            container.Controls.Add(detail);
        }
    }
}

3. 动态加载。

namespace Northwind.WebSite
{
    public partial class ProductsByCategory : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Repeater1.ItemTemplate = new CategoryDetailTemplate();
            if (!IsPostBack)
            {
                var ds = Category.GetCategories();
                Repeater1.DataSource = ds;
                Repeater1.DataBind();
            }
        }
    }
}