Hello World
Spiga

方案改进:直接通过User Control生成HTML

2008-07-14 13:24 by 老赵, 41618 visits

对于使用User Control生成HTML的方式,大家应该已经比较熟悉了,老赵也曾经写过一篇文章(《技巧:使用User Control做HTML生成》)来描述这个做法。使用User Control进行HTML生成最大的好处就是将表现(Presentation)逻辑集中在一处,并且能够让前台开发人员使用传统的方式参与到页面开发中来。在其他方面,使用User Control生成HTML的做法直接使用了ASP.NET WebForms引擎,在开发时能够利用到ASP.NET的各种优秀实践。

在“我的衣橱”中大量使用了这种生成HTML的做法。不过当项目达到一定规模之后,这个方法的不足之处也慢慢地体现了出来。就拿《技巧:使用User Control做HTML生成》作为例子来讲,除了显示上必要的Comments.aspx页面和Comments.ascx控件之外,还有一个额外的GetComments.ashx进行客户端与服务器端之间的通信。不过问题就出在这里,当此类做法越来越多时,项目中就会出现大量的此类ashx文件。冗余代码的增加降低了代码的可维护性,试想如果我们需要在某个控件上增加一个额外的属性,就需要去Handler那里编写对应的逻辑。虽不算是繁重的工作,但是如果能解决这个问题,无疑是一个锦上添花的做法。

如果要避免大量Handler的出现,必然需要找到这些Handler的共同之处。这一点并不困难,因为每个Handler的逻辑的确大同小异:

  1. 使用ViewManager加载User Control
  2. 从QueryString或Form中获取参数,并设置对应属性
  3. 使用ViewManager生成HTML代码,并使用Response.Write输出

写一个统一的Handler来将User Control转化为HTML是一件轻而易举的事情。不过因为有第2步,我们就必须应对为不同控件赋不同值的情况。这种“描述性”的内容即是该控件的“元数据(metadata)”,而说到“元数据”各位应该就能很快想到自定义属性(Custom Attribute)这个.NET特有的事物。因此我们的解决方案也使用这种方式来对控件的属性进行“描述”,且看该属性的定义:

public enum UserControlRenderingPropertySource
{
    Form,
    QueryString
}
 
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)]
public class UserControlRenderingPropertyAttribute : Attribute
{
    public string Key { get; set; }
 
    public UserControlRenderingPropertySource Source { get; set; }
}

这个自定义属性只能标记在属性上,而它的作用是定义这个属性值的来源(是Query String还是Form)与集合中的键名。而我们的实现还会根据属性上标记的DefaultValueAttribute为属性设定默认值。定义了Custom Attrubte之后,我们就可以编写这个统一的Handler了。为了在客户端“隐藏”直接请求ascx文件的事实,我们只响应对扩展名为“ucr”的请求:

public class UserControlRenderingHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        string appRelativePath = context.Request.AppRelativeCurrentExecutionFilePath;
        string controlPath = appRelativePath.ToLower().Replace(".ucr", ".ascx");

        var viewManager = new ViewManager<UserControl>();
        var control = viewManager.LoadViewControl(controlPath);
 
        SetPropertyValues(control, context);
       
        context.Response.ContentType = "text/html";
        context.Response.Write(viewManager.RenderView(control));
    }
}

上面代码中的SetPropertyValues方法便是为User Control实例的属性赋值:

private static void SetPropertyValues(UserControl control, HttpContext context)
{
    var metadata = GetMetadata(control.GetType());
    foreach (var property in metadata.Keys)
    {
        object value = GetValue(metadata[property], context) ?? GetDefaultValue(property);
        if (value != null)
        {
            property.SetValue(control, Convert.ChangeType(value, property.PropertyType), null);
        }
    }
}

  SetPropertyValues方法中会调用三个方法:GetMetadata,GetValue和GetDefaultValue。GetMetadata方法会得到关于这个control的元数据,为PropertyInfo - List<UserControlRenderingPropertyAttribute>的键值对(即Dictionary)。然后将metadata传入GetValue方法,以获取由UserControlRenderingPropertyAttribute标记的值。如果GetValue方法返回null,则调用GetDefaultValue方法获取标记在该属性上DefaultValueAttribute。以下就将其余代码附上,没有技术含量,但做一参考:

[展开代码]

至此,UserControlRenderingHandler完成了。不过在真正使用时,还需要进行一些配置。例如,您需要在IIS的ISAPI Mapping中将“.ucr”与aspnet_isapi.dll进行映射,并且在web.config中将*.ucr与UserControlRenderingHandler关联起来。当然,对User Control的属性进行标记是必须的。例如还是《技巧:使用User Control做HTML生成》一文中的例子:

public partial class Comments : System.Web.UI.UserControl
{
    protected override void OnPreRender(EventArgs e)
    {
        // ...
    }
 
    [UserControlRenderingProperty(Key = "page", Source = UserControlRenderingPropertySource.QueryString)]
    public int PageIndex { get; set; }
 
    [DefaultValue(10)]
    public int PageSize { get; set; }
 
    // ...
}

然后,在客户端代码中只要根据路径发起请求即可,UserControlRenderingHandler会在服务器端完成余下的工作。

<script type="text/javascript" language="javascript">
    function getComments(pageIndex)
    {
        new Ajax.Updater(
            "comments",
            "/Controls/Comments.ucr?page=" + pageIndex + "&t=" + new Date(),
            { method: "get" });
       
        return false; // IE only
    }
</script>

不过,这就够了吗?对于一个例子来说,这已经足够了,不过要在产品环境中使用很可能还略显不够。例如,如果只让用户访问到特定的User Control,或者只有特定权限的用户才能访问,又该如何对UserControlRenderingHandler进行改造呢?相信您了解上述做法之后,这点要求对您一定不成问题。

Creative Commons License

本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名赵劼(包含链接),具体操作方式可参考此处。如您有任何疑问或者授权方面的协商,请给我留言

Add your comment

96 条回复

  1. Indigo Dai
    *.*.*.*
    链接

    Indigo Dai 2008-07-13 20:46:00

    沙发
    先顶再看
    老赵好久不发问啦

  2. 老赵
    admin
    链接

    老赵 2008-07-13 20:50:00

    点子不错,实现没啥技术含量——点子是Dflying提出的,老赵负责实现和改进。

  3. 老赵
    admin
    链接

    老赵 2008-07-13 20:50:00

    @Indigo Dai
    忙……
    懒……
    主要是后者……

  4. 李涛
    *.*.*.*
    链接

    李涛 2008-07-13 21:24:00

    抢个地板
    代码我就先不看了,知道老赵喜欢耍内功了,呵呵

  5. 老赵
    admin
    链接

    老赵 2008-07-13 21:40:00

    @李涛
    啥叫耍内功呀?

  6. 李涛
    *.*.*.*
    链接

    李涛 2008-07-13 21:54:00

    @Jeffrey Zhao
    川话中喜欢把玩,用等说成耍,老赵早已经练就北溟神功,故曰:耍内功啊

  7. 醉春风
    *.*.*.*
    链接

    醉春风 2008-07-13 22:03:00

    看了题目,顿觉自己最近想要的一个东西可以实现了。
    这个做法我的好好看看。
    thanks

  8. 王孟军!
    *.*.*.*
    链接

    王孟军! 2008-07-13 22:33:00

    好东西,有时间研究研究

  9. 代码乱了
    *.*.*.*
    链接

    代码乱了 2008-07-13 23:09:00

    关注中,明天再研究

  10. Tony Zhou
    *.*.*.*
    链接

    Tony Zhou 2008-07-13 23:44:00

    网站美女挺多

  11. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2008-07-14 01:16:00

    从HttpHandler去取UserControl的数据并不是一种很好的办法。
    老赵把请求的参数以暴露控件的属性的方式,然后把参数传给控件.
    由于UserControl是必须放在Page里面的,但现在是在HttpHandler中创建一个Page对象,实际中,这个创建出来的Page对象无法获取到请求的参数,这就导致了这个Page只能做为UserControl的一个容器的作用而已,其已经失去了很多功能。如果逻辑有些复杂的话,则需要定义更多的属性,由外界传值进去。
    如果单单是应用于分页还好说。个人认为可以通过User Control产生数据,但不应该在HttpHandler里面为了得到User Control的内容而去创建一个Page对象。HttpHandler更适合于传输json和xaml之类的数据。我的做法是先创建一个page页面,由这个已经创建好的页面来负责加载这个User Control.并不会因为其是Page而在速度上比HttpHandler慢。因为User Control就是基于Page的,有了Page做的事情还是很多的

  12. 老赵
    admin
    链接

    老赵 2008-07-14 02:29:00

    @Clingingboy
    哪些请求参数取不到啊?所有的参数都在HttpContext上,和Page有什么关系,现在是为了生成User Control的HTML,所有的逻辑都是在User Control上的,Page对象在这里本就是个Helper而已。如果有任何需要用到Page中逻辑的地方就是设计上的错误了。就像Page本不应该知道它属于哪个特定的master page,control本不应该知道它属于哪个page一样。
    再者如果是请求一个页面而输出一个HTML片段的话,这就是个设计上的问题了(UpdatePanel这种为了特殊目的自然是个例外)。就像当年AJAX刚出现时很多人不知道有ashx这回事,就用个几乎为空的aspx来Response.Write数据一样,的确能用,但是不能不说是个问题。
    而且HttpHandler本来就是随心所欲地输出各种数据流,何谈适合json/xaml的数据……我还能用它输出图片、输出各种文件呢。

  13. LuChaoShuai
    *.*.*.*
    链接

    LuChaoShuai 2008-07-14 04:53:00

    public void ProcessRequest(HttpContext context)
    {
    HttpApplication app = context.ApplicationInstance;
    string appRelativePath = app.Request.AppRelativeCurrentExecutionFilePath;
    string controlPath = appRelativePath.ToLower().Replace(".ucr", ".ascx");
    var viewManager = new ViewManager<UserControl>();
    var control = viewManager.LoadViewControl(controlPath);
    SetPropertyValues(control, context);
    app.Response.ContentType = "text/plain";
    app.Response.Write(viewManager.RenderView(control));
    app.Response.StatusCode = 200;
    app.CompleteRequest();
    }


    Request.AppRelativeCurrentExecutionFilePath;
    以前不知道还有这么一个属性.谢谢了.

  14. Alvan[未注册用户]
    *.*.*.*
    链接

    Alvan[未注册用户] 2008-07-14 04:59:00

    “control本不应该知道它属于哪个页面”,这句话只说对了一半。它可以不知道它属于哪个页面,但是它一定要知道它不该属于哪个页面——以user control为载体加载异步HTML片段的一个潜在问题就是客户端id冲突,而且在规模稍大的项目中这几乎是一定会出现的问题,除非建立一套完整的server control命名方案或者保证客户端脚本决不使用客户端id。显然这两项要求都是一线程序员最讨厌的东西,所以如果一定要用uc来作为载体,我更倾向于用iframe加载HTML。

  15. 怪怪
    *.*.*.*
    链接

    怪怪 2008-07-14 05:03:00

    其实把这个和UpdatePanel的优点全都占了并统一化的方案也不是没有, 不过在框架上就需要一整套了, 等真能闲下来, 我也拿出来晒晒。 可惜就是我写不出像你这么好的技术文章, 最后估计又是乱七八糟。

    @Alvan
    你说的这些, 花点功夫还是能解决的 :)。 还可以实现过在客户端和服务器端统一的FindControl这样的功能: 只要咱们自己在两边都维护了控件树信息。

  16. micenter
    *.*.*.*
    链接

    micenter 2008-07-14 08:41:00

    顶一个

  17. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2008-07-14 09:03:00

    Page与控件的关系是。Page可以没有控件,但控件不能没有Page.控件可以不知道其放在哪个Page,但应该可以知道Context。
    ashx和aspx最终同为url请求,不同的则是aspx需要在项目中建立一个实体的文件而已,给人的感觉就是模块多了,代码就淤泥了,紧紧为了ajax的数据传输而建页面.当然aspx也能产生数据流,很多人用aspx作为一个页面做验证码,技术上可行,但用HttpHandler更合理.
    我的做法是依赖于一个Page,在其基础上进行封装.犹如ajaxpro这种做法.
    再者如果UserControl职责单一只用于分页,功能确定下来,就可以封装成自定义控件了,建多个UserControl也并不是很好,这个UserControl最后需要封装就是输出HTML的一个模板.

    当然这里只讨论后端生成数据,与前端如何去取后端数据无关,两者可以结合也可以分开.

    关于控件ID的问题,可以通过控件适配器来解决。当然这是要有一定牺牲的.如果控件仅仅(即失去了webform的一些功能)显示而已的话是可以这么做.

    还有如果这个UserControl脱离了这种在HttpHandler下生成HTML的模式.似乎就意义不大了.
    个人见解:)

  18. 坏人
    *.*.*.*
    链接

    坏人 2008-07-14 09:24:00

    文章还没细读,怀疑需求的存在必要性。

  19. willieQ
    *.*.*.*
    链接

    willieQ 2008-07-14 09:29:00

    正需要,收下,回去仔细看~~~~

  20. 老赵
    admin
    链接

    老赵 2008-07-14 09:35:00

    @坏人
    放心,这个做法是经过实际项目考验的,从可用性到必要性都没有问题。

  21. 老赵
    admin
    链接

    老赵 2008-07-14 09:35:00

    @Clingingboy
    在Handler中使用User Control生成HTML意义很大,UserControl在这里就是个独立的模板,而且这种情况下如果要用来生成HTML的User Control,其逻辑一定是内聚的,否则就是设计上的失误。
    说到AJAX Pro,我觉得他一大败笔就是把好好的AJAX Method与页面绑定在一起,但是却没有任何必要,也没有带来任何益处。所以ASP.NET AJAX选择了外部Web Service这样的做法,灵活多了。
    其实你就这样想,平时请求的是aspx,现在请求的是ascx而已,目标就在aspx和ascx上,没有其他的。

  22. 东[未注册用户]
    *.*.*.*
    链接

    东[未注册用户] 2008-07-14 10:47:00

    酷哦....

  23. 子曰2[未注册用户]
    *.*.*.*
    链接

    子曰2[未注册用户] 2008-07-14 10:57:00

    为什么一定要用User Control ,用Page 不行吗。第一次也用异步请求生成Html

  24. Clingingboy
    *.*.*.*
    链接

    Clingingboy 2008-07-14 10:59:00

    关于绑定的Method是分类型的,如数据相关的操作可以不放在页面里面,确实绑定起来没必要,抛开这个来讲,其实在Handler同样是需要与方法绑定起来的,这实际上是一个一样的逻辑.同样也可以通过注册的方式在页面上注册Service分离页面与Service.
    我确实是这么想的,通过aspx请求,原因是Handler无法满足我的需求。

    如果通过传值的话,这个UsrControl功能变的很单调.

  25. opend@live.cn[未注册用户]
    *.*.*.*
    链接

    opend@live.cn[未注册用户] 2008-07-14 11:01:00

    通过User Control生成Html,然后通过IHander得到相关Html,然后通过Ajax调用控制。。。为什么不直接使用IHander输出Json数据?效率应该更高。UserControl可能共用。。。JS也可以。。。
    不过思路很不错

  26. rockshit
    *.*.*.*
    链接

    rockshit 2008-07-14 11:05:00

    功能、设计、以及技术实现方面的问题貌似改分开讨论。

  27. rockshit
    *.*.*.*
    链接

    rockshit 2008-07-14 11:09:00

    ajaxpro的优势的明显的,简单,单纯。ajax.net的使用外部web service的是灵活但是开发有一定的冗余。不可否认的是ajax.net模式在一定程度上也相当简单,但是效率牺牲是一定的。

  28. 老赵
    admin
    链接

    老赵 2008-07-14 11:10:00

    @Clingingboy
    举个Handler不能满足需求的例子吧

  29. 老赵
    admin
    链接

    老赵 2008-07-14 11:11:00

    @rockshit
    ajax.net就是ajaxpro。应该说是asp.net ajax。
    你说效率上牺牲什么了?
    ajaxpro和asp.net ajax实现机制差不多,效率没有差别。

  30. matta[未注册用户]
    *.*.*.*
    链接

    matta[未注册用户] 2008-07-14 11:42:00

    好笑.让我想起一个 通过请求自己的页生成html的方法.

  31. 老赵
    admin
    链接

    老赵 2008-07-14 11:58:00

    @matta
    你似乎没有看懂我的做法?

  32. 子曰2[未注册用户]
    *.*.*.*
    链接

    子曰2[未注册用户] 2008-07-14 12:03:00

    有个问题,如果 UserContorl 被 UserControlRenderingHandler 处理了。那么
    .ascx的还会不会被HttpForbiddenHandler 处理。如果HttpForbiddenHandler 再处理,启不是加载了2次UserContorl

  33. 子曰2[未注册用户]
    *.*.*.*
    链接

    子曰2[未注册用户] 2008-07-14 12:11:00

    .ascx 默认的 处理是由HttpForbiddenHandler来处理的。
    <add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>

  34. 老赵
    admin
    链接

    老赵 2008-07-14 12:13:00

    @子曰2
    你看我的代码,请求的不是.ascx而是.ucr

  35. 子曰2[未注册用户]
    *.*.*.*
    链接

    子曰2[未注册用户] 2008-07-14 12:14:00

    哦。看到了 。其实也没必要。刚查询到MSDN的一句话了。
    在WEBconfig 设置 httphandle 时 。要注意的是相同的后缀名配置多次的话,后面的配置会把前面的覆盖。

  36. 老赵
    admin
    链接

    老赵 2008-07-14 12:14:00

    @子曰2
    一个扩展名不能被两个handler或handlerfactory处理。

  37. 老赵
    admin
    链接

    老赵 2008-07-14 12:15:00

    @子曰2
    其实我文章里也写了……是为了“不要太过暴露”……

  38. 子曰2[未注册用户]
    *.*.*.*
    链接

    子曰2[未注册用户] 2008-07-14 12:15:00

    恩。呵呵。刚刚自己问了个很BC的问题。不好意思!

  39. 子曰2[未注册用户]
    *.*.*.*
    链接

    子曰2[未注册用户] 2008-07-14 12:16:00

    恩,学习!

  40. 老赵
    admin
    链接

    老赵 2008-07-14 12:16:00

    --引用--------------------------------------------------
    子曰2: 恩。呵呵。刚刚自己问了个很BC的问题。不好意思!
    --------------------------------------------------------
    客气

  41. 子曰2[未注册用户]
    *.*.*.*
    链接

    子曰2[未注册用户] 2008-07-14 12:43:00

    UserControlDirectAccessPropertySource 这个类好像没看到定义的。
    是不是写错了。应该是 这个 UserControlRenderingPropertySource枚举类型

  42. 老赵
    admin
    链接

    老赵 2008-07-14 13:21:00

    @子曰2
    没错,谢谢指正。

  43. SZW
    *.*.*.*
    链接

    SZW 2008-07-14 15:15:00

    把Form和QueryString区分开来主要用意是什么呢?

  44. 老赵
    admin
    链接

    老赵 2008-07-14 16:56:00

    @SZW
    没啥用意,就是分开了。
    既然标记了就详细一些,比如Form的key1里获取或者QueryString的Key2里获取属性值。

  45. 果果’er
    *.*.*.*
    链接

    果果’er 2008-07-14 17:27:00

    我也是看了这个以后,自己写了个page来按参数载入UserControl,(?uc=ucABC)
    其它的参数则让UserControl自己去获取。

    感觉这样用UserControl的好处是页面上可以首次有输出,又还可以简单做Ajax。
    我甚至把Ajax都写到UserControl自己里面了,可以自己重新载入自己 :)

  46. 随风流月
    *.*.*.*
    链接

    随风流月 2008-07-14 19:10:00

    @Jeffrey Zhao
    Ajax Pro 的 Method 不一定要和 Web Page 绑定的...

  47. airwolf2026
    *.*.*.*
    链接

    airwolf2026 2008-07-14 19:28:00

    就像当年AJAX刚出现时很多人不知道有ashx这回事,就用个几乎为空的aspx来Response.Write数据一样,的确能用
    -------------------------------------
    -_-!!!俺前几天还这样写....还说page为啥把屁股也给输出出去了...哈哈...

  48. 老赵
    admin
    链接

    老赵 2008-07-14 20:24:00

    @airwolf2026
    屁股?

  49. 老赵
    admin
    链接

    老赵 2008-07-14 20:24:00

    @随风流月
    这还差不多

  50. 老赵
    admin
    链接

    老赵 2008-07-14 20:24:00

    @果果’er
    我这里UserControl不太自己取,因为页面上也会复用这个控件。

  51. hotjava[未注册用户]
    *.*.*.*
    链接

    hotjava[未注册用户] 2008-07-16 21:43:00

    还是用的您上次发的那种老办法,可是我如果使用的是gridview而不是repeater, 就会出现
    Error executing child request for handler 'System.Web.UI.Page'

    请问这是什么原因呢。? 多谢

  52. Cat Chen
    *.*.*.*
    链接

    Cat Chen 2008-07-21 18:17:00

    如果用RoR的思维来做,应该连ucr => ascx的替换也不用,就让用户请求ascx。因为Ajax.Updater会加上一个header声明这是Ajax请求,你拦截请求然后根据header判断怎么处理就够了,更加简洁。

  53. win[未注册用户]
    *.*.*.*
    链接

    win[未注册用户] 2008-07-21 20:36:00

    有个DEMO看过来可能更好
    这样看着那些代码有点烦
    不过老赵还是很利害地
    顶一下

  54. 老赵
    admin
    链接

    老赵 2008-07-21 21:44:00

    @win
    要的就是这个效果,希望读者能够好好阅读代码

  55. 老赵
    admin
    链接

    老赵 2008-07-21 21:46:00

    @Cat Chen
    我就是不希望加特别的header,呵呵。
    而且最终还是要写一个Handler(甚至为了看Header还需要一个Module)……

  56. lixyvip[未注册用户]
    *.*.*.*
    链接

    lixyvip[未注册用户] 2008-07-24 11:45:00

    看了一下 我的衣橱 网站,感觉不错

  57. 凌风
    *.*.*.*
    链接

    凌风 2008-07-28 11:14:00

    我倒觉得老赵的做法很合理呀。
    支持,同时也希望各位在沟通时先把文章看完。

  58. 假正经哥哥
    *.*.*.*
    链接

    假正经哥哥 2008-08-06 09:09:00

    @Jeffrey Zhao
    UserControl 在做通用的Ajax 效果时候还是很有用的。比如把这里的UserControl 变成Webpart ,那么我们可以定义通用的Webpart基类,抛出回调的JS获取Webpart实际的HTML,可以实现通用的带有ajax功能的Webpart,在实际编码人员开发webpart的时候就不需要考虑ajax的效果,只要去实现webpart本身的逻辑就可以了

  59. Evernory
    *.*.*.*
    链接

    Evernory 2008-08-14 19:53:00

    太猛了~学习了~

  60. Indigo Dai
    *.*.*.*
    链接

    Indigo Dai 2008-08-17 17:20:00

    看了文章,第一感觉就是老赵的基本功很强很强,Attribute那段代码博客圆子里能写出的应该为数不多吧。过硬的基本功,再加上其他知识,这才叫程序员啊……

  61. 胡一刀
    *.*.*.*
    链接

    胡一刀 2008-09-01 16:32:00

    如果不用这种 获取Custom Attribute的 方法,反射是不是也可以呢?
    看3.5的语法,似乎有点不习惯

  62. 老赵
    admin
    链接

    老赵 2008-09-01 20:18:00

    @胡一刀
    Custom Attribute不就是反射吗?

  63. vilyliao[未注册用户]
    *.*.*.*
    链接

    vilyliao[未注册用户] 2008-09-25 05:19:00

    一个字:强!
    几个字:老赵太强了!
    -------------------------
    有点疑问:
    1、老赵你不是ajax深入浅出的讲师吗?干么不用asp.net ajax框架做啊?
    把Usercontrol直接放在一个UpdatePanel中不就得了?
    (是不是您只是为了讲解这个技巧才这样做呢?)
    2、个人感觉这样做的性能(包括使用UpdatePanel)这样做都不是最佳的,
    不如在提交Comments时使用ajax方式提交保存到数据库,客户端直接使用js,AppendChild一个回复就可以了,您以为如何?
    (严重佩服您的勤劳与勇敢,我的第2点想法也没有实践,但一定行得通,本人
    太懒了,就不去实践啦!)

  64. SuperSaiyan
    *.*.*.*
    链接

    SuperSaiyan 2008-09-26 21:12:00

  65. 老赵
    admin
    链接

    老赵 2008-09-27 10:13:00

    @vilyliao
    1、我也不是到处用asp.net ajax阿,ajax其实从来就是我的副业……
    2、我的做法有其好处,方便,而且容易维护。

  66. 老赵
    admin
    链接

    老赵 2008-09-27 10:15:00

    @SuperSaiyan
    我现在是能让一个最普通的User Control得到支持,而不是为这个功能进行特殊处理。当然您的做法也可以,我们出发点有点不一样。
    至于所谓反射所带来的性能问题,它远不会是性能瓶颈,而且您要知道,您用的asp.net里的各种功能相当部分是基于反射的——其他框架也是。

  67. SuperSaiyan
    *.*.*.*
    链接

    SuperSaiyan 2008-09-27 11:00:00

    对user control 的 override oninit, 是一个很自然和常见的事情, 把获得参数的逻辑放在其中, 不算特殊处理, 并且符合封装原则. 而你的办法, 用attribute和一段通用的逻辑处理来解决同样的事情, 有点overkill, 感觉不自然. 让user control implment interface, 可能也是有点overkill, 但是, 起码不会用到很多反射, 也符合封装原则.

    动态的user control 的oninit, 会在它被加入parent的children时, 被系统调用.

    反射对于desktop application, 一般来说关系不大. 但是, 对于web server来说, 是要尽量避免的. 我的方案里, 反射的使用降到了最底, 可能在最初获得配置参数部分, .net内部会用到一点反射, 但不是对每个请求都需要使用很多的反射.

  68. www.dache.cn[未注册用户]
    *.*.*.*
    链接

    www.dache.cn[未注册用户] 2008-09-30 11:12:00

    老赵,分页呢,你这么做了,分页如何解决阿!? 如果分页没解决这个方法是不是基本上没什么实际意义呢!

  69. 老赵
    admin
    链接

    老赵 2008-10-01 13:51:00

    @www.dache.cn
    没听懂,我这个做法和分页又没有关系的。

  70. 老赵
    admin
    链接

    老赵 2008-10-01 23:00:00

    @SuperSaiyan
    兄弟不要想当然,优雅的设计往往都会用到反射,合理使用对于性能的影响不会太大,在web应用中也很难成为性能瓶颈。

  71. SuperSaiyan
    *.*.*.*
    链接

    SuperSaiyan 2008-10-02 20:54:00

    我会想当然吗? ;-)

    我写的网页时, 一般要做一点优化, 对性能不利的实现, 或者干脆不用, 或者会被优掉, 一般而言, 弄出个三五倍并不困难, 多的甚至到十倍.
    优雅的设计往往都会用到反射, 但是用到反射的设计未必幽雅, 而幽雅的设计又未必符合性能要求. 在这些相互矛盾的要求中取舍, 往往是个人风格.
    既然到了风格了, 我看, 咱们就没必要争了.

  72. 老赵
    admin
    链接

    老赵 2008-10-02 21:36:00

    @SuperSaiyan
    风格归风格,现在你的观点有点误导群众了。
    反射不是洪水猛兽,只有针对瓶颈的优化才能起到效果,这里反射不会有性能问题的,朋友们可以自己试验一下。
    至于三五倍,十倍,实在不可能和反射扯上关系——当然,我是指在一个正常的应用中的情况。普通的Web应用,性能瓶颈几乎都是在外部IO(例如数据库访问)上。

  73. SuperSaiyan
    *.*.*.*
    链接

    SuperSaiyan 2008-10-02 21:55:00

    我的观点误导群众了吗?

    我并没有说单单把反射去掉能够让性能提升很多. 不过, 我的风格是, 能用简单方法实现, 一般不用复杂方法, 能用性能好的方法实现, 一般不用性能差的方法实现. 性能固然有瓶颈部分, 不过, 积少成多, 也是有用的.

    如果真是误导了, 那恐怕也是因为有些人和我有相近的风格.

    对于你的风格, 我想, 也是有其理由的, 不过世界很大, 各种风格应当能够共存.

  74. mikelij
    *.*.*.*
    链接

    mikelij 2008-11-03 11:16:00

    我在这篇文章中提出了另外一个方法.用RenderControl和Render.
    http://www.cnblogs.com/mikelij/archive/2008/11/03/1325133.html
    欢迎讨论.

  75. 明轩
    *.*.*.*
    链接

    明轩 2008-11-10 17:01:00

    问题在于PageSize上的DefaultValue,VisualStudio 并没有根据DefaltValueAttribute设置PageSize的值,所以我测试时每次请求PageSize初始为0,结果是没有任何数据显示.所以当你不需要指定UserControlRenderingProperty时,但又必须利用该属性的值的时候仅标记DefaltValue是不够的。正如PageSize,在文中:
    [DefaultValue(10)]
    public int PageSize { get; set; }
    而我是这样的:
    [UserControlRenderingProperty()]
    [DefaultValue(1)]
    public int PageSize { get; set; }

    没有UserControlRenderingProperty,UserControlRenderingHandler根本就不去设置它得值

  76. 老赵
    admin
    链接

    老赵 2008-11-10 17:23:00

    @明轩
    修改一下代码?

  77. 陈涵[未注册用户]
    *.*.*.*
    链接

    陈涵[未注册用户] 2008-12-08 13:16:00

    我正在寻求这方面的解决之道呢。。。。。偶是新手,先谢过了。。。

  78. 勇仔
    *.*.*.*
    链接

    勇仔 2008-12-17 13:03:00

    我也问个问题~这代码是什么字体?非常好看。

  79. 勇仔
    *.*.*.*
    链接

    勇仔 2008-12-17 13:33:00

    什么时候我也能做些技术活啊~

  80. 勇仔
    *.*.*.*
    链接

    勇仔 2008-12-17 14:02:00

    看了那个衣橱网站,查看了点源码。 有个建议(我水平有限没什么了不起的建议,可能你们根本不屑一顾。但千万别认为我是来找茬的~我真的是抱着互相帮助的心来提的——经常被人误会所以先声明一下。。。) 你们网站源代码里很多空可以去掉。 源码格式太好了,适合研究HTML的直接看。没必要输出这么好看的HTML,查看了google和百度的源文件都是节省空间到了变态的地步~不需要像google和百度这么小气~少一些空行也不错,如果空行只是一个回车也没关系,但空行有很长一段的空格就没必要了~ 呵呵。

  81. 老赵
    admin
    链接

    老赵 2008-12-17 15:31:00

    @勇仔
    我们的页面都经过gzip,这些空格的尺寸完全被压缩掉的,就算去处这些空格,gzip压缩后也小不了多少。

  82. 勇仔
    *.*.*.*
    链接

    勇仔 2008-12-18 09:03:00

    @Jeffrey Zhao
    gzip是干什么的~呵呵~又多了解了一个东西~
    虽然压缩了,发到客户端还是有这些空白啊。
    我的意思是节约网络资源,减少不必要的流量(我前面说“节省空间”有些词不达意~不好意思,呵呵)。你的网站访问量大的话,每个页面缩小一点效果也是很可观的吧,同时也是为用户着想,减少用户网络流量。
    google天天叫着要标准,他自己的页面就很不标准~~连引号能省的都省了应该也是这个原因吧(像google这个数量级的访问量,减少一个引号都相当于省了成千上万的钱吧。夸张了点~)。
    这只是锦上添花的事,可能你们有更重要的事要做,还没到锦上添花的时候。要怎么对待这个问题也只能你们决定,我只是提个建议。希望没影响到你们的工作。

  83. 老赵
    admin
    链接

    老赵 2008-12-18 10:23:00

    @勇仔
    我说的具体点吧。有两个问题:
    1、压缩页面不是“锦上添花”而是必要的优化(更何况很简单)。
    2、我们页面已经有gzip压缩了,去除空白起不到明显效果。就算去除空白,流量能节省1-2%就了不起了。

    gzip用于压缩html文本很有作用(同样的还有deflate压缩)。
    你应该没有嗅探过我们的页面,你会发现页面都被压缩的很小。
    大量空白字符最适合被压缩,打个比方:
    200k的一张包含空白的页面,gzip后到了大约30K
    去除空白字符后,页面体积缩小到了150K,似乎很有效果,但是gzip后还是有2、28-29K,效果在那里?一个TCP/IP包都有1.4K的大小,建立连接以后多发一点根本没有任何影响。

    兄弟你需要了解更多的东西才能从大方面上做出决策,性能优化更是如此,不是“似乎有效果”就“真的有效果”的。

  84. 勇仔
    *.*.*.*
    链接

    勇仔 2008-12-18 15:31:00

    @Jeffrey Zhao
    gzip我确实没用过。
    gzip能起到减少网络流量的作用?
    你给把压缩后的东西直接发到客户端浏览器还能正常显示?
    除非所有浏览器都有gzip的解压功能,否则哪个浏览器给认识它压缩后的东西是什么?

    查了不少资料发现真的是浏览器都有解压gzip文件的功能。。。所以上面的问题都作废了~

    又长了见识。谢谢。
    事实上我也很想了解更多的东西(可能所有人都想吧)~
    所以我打算以后多来看你的文章,多跟你聊天。不得不佩服我自己~太有才了。

  85. 老赵
    admin
    链接

    老赵 2008-12-18 22:50:00

    @勇仔
    系统是根据请求中是否支持gzip或deflate来选择是否压缩和压缩方式的。

  86. 香港陈冠希[未注册用户]
    *.*.*.*
    链接

    香港陈冠希[未注册用户] 2009-07-24 17:10:00

    为啥再次点击“展开代码”,它不是折叠回去呢??郁闷!!

  87. 海云[未注册用户]
    *.*.*.*
    链接

    海云[未注册用户] 2009-09-17 11:38:00

    如果我的UserControl里有页面事件的话,比如按钮点击事件,还能转化html输入吗

  88. 老赵
    admin
    链接

    老赵 2009-09-17 11:52:00

    @海云
    自然是可以的。
    但是既然是作为模板,就不应该有那么多操作。

  89. 海云[未注册用户]
    *.*.*.*
    链接

    海云[未注册用户] 2009-09-17 12:18:00

    @Jeffrey Zhao
    如何实现?请指教

  90. 老赵
    admin
    链接

    老赵 2009-09-17 12:21:00

    @海云
    你在问什么实现?我的意思是,
    1、包含事件的UserControl和不包含的没有区别。
    2、用于模板的UserControl不应该包含事件。

  91. 海云[未注册用户]
    *.*.*.*
    链接

    海云[未注册用户] 2009-09-17 12:31:00

    @Jeffrey Zhao
    UserControl现在不做为模板,而是为了优化UI体验,所以会包含页面事件,但是实现过程中出现异常
    执行这一句的时候
    HttpContext.Current.Server.Execute(this.pageHolder, writter, true);
    异常信息:执行处理程序“System.Web.UI.Page”的子请求时出错。

  92. 老赵
    admin
    链接

    老赵 2009-09-17 13:01:00

    @海云
    那么是你代码实现和这个做法的冲突,要具体问题具体分析。

  93. 海云[未注册用户]
    *.*.*.*
    链接

    海云[未注册用户] 2009-09-17 14:22:00

    @Jeffrey Zhao
    解决了,new page()的时候使用
    public class FormlessPage : Page
    {
    public override void VerifyRenderingInServerForm(Control control)
    {
    }
    }

  94. 周彬
    *.*.*.*
    链接

    周彬 2009-12-25 11:44:00

    在使用代码测试时,行:
    attributes.Cast<UserControlRenderingPropertyAttribute>()
    错误信息
    Error 1 'System.Array' does not contain a definition for 'Cast'
    and no extension method 'Cast' accepting a first argument of type 'System.Array' could be found (are you missing a using directive or an assembly reference?) E:\MyProject\LinqExtent\UserControlToHtml\Code\UserControlRenderingHandler.cs 88 36 UserControlToHtml
    这个是需要引用什么命名空间吗?

  95. 周彬
    *.*.*.*
    链接

    周彬 2009-12-25 11:54:00

    找到,要引用“using System.Linq;”

  96. Domi.Zhang
    221.10.30.*
    链接

    Domi.Zhang 2012-05-16 14:13:52

    老赵这东西不错,以前也写过类似的东西,但是没有实现属性赋值,毕竟用户控件公开属性的方式很常见,就放弃了。

发表回复

登录 / 登录并记住我 ,登陆后便可删除或修改已发表的评论 (请注意保留评论内容)

昵称:(必填)

邮箱:(必填,仅用于Gavatar

主页:(可选)

评论内容(大于5个字符):

  1. Your Name yyyy-MM-dd HH:mm:ss

使用Live Messenger联系我