scriptpath属性的拙劣设计

ScriptPath属性的拙劣设计

2007-06-25 20:45 by Jeffrey Zhao, 4256 visits, 网摘, 收藏, 编辑

背景

ExtenderControlBase类是开发AjaxControlTookit服务器端Extender组件的基础。ExtenderControlBase基于ASP.NET AJAX的Exnteder模型提供了许多方便开发人员的强大支持,能够在它的基础上开发Extender确实是一件非常容易的事情,这样我们就可以将更多的精力放在客户端Behavior的逻辑上了,那才是AjaxControlTookit组件的重点。

当基于ExtenderControlBase开发Extender控件时,我们一般总是先为服务器端和客户端的组件同时定义好属性,然后将经历几乎完全集中在客户端Behavior的开发上。在大多数情况下,存放客户端组件代码的JavaScript文件会嵌入到程序集中,然后使用ScriptResource.axd文件发送到页面上。如果我们改变了脚本文件并且想测试修改的效果,那么我们就必须重新编译那个程序集,这样网站引用的程序集将会更新,重新刷新页面时新的脚本文件就会被发送到客户端来。

ScriptPath属性以及它的拙劣设计

很显然,我们如果仅仅为了更新脚本文件而一次又一次地编译程序集会让人觉得异常繁琐,因此出现了ScriptPath属性。ScriptPath属性被定义在ExtenderControlBase类中,它的首要作用就是为开发Extender提供便利。我们可以在开发控件时设置这个属性为某个脚本文件的相对路径,这样页面将会加载这个脚本文件而不是使用程序集中的资源,由此避免了多余的编译。

那么有了ScriptPath属性生活就真的变得美好了呢?那还得看情况。在急于作结论之前还是先看看下面的代码吧。假设我们正在开发AutoCompleteExtender,这是我们正在使用的测试页面。

<asp:TextBox runat="server" ID="myTextBox" Width="300" />

<ajaxToolkit:AutoCompleteExtender runat="server" ID="autoComplete1" 
    TargetControlID="myTextBox" ... />
    
<br />
<asp:Literal ID="Literal1" runat="server"></asp:Literal>

 

大部分的属性被我省略了,因为我们只关心哪些脚本文件会被发送到客户端,所以我们使用下面的代码在页面上写下一系列资源标识。

protected void Page_Load(object sender, EventArgs e)
{
    List<string> identifiers = new List<string>();

    IEnumerable<ScriptReference> scriptReferences = 
        (this.autoComplete1 as IExtenderControl).GetScriptReferences();

    foreach (ScriptReference reference in scriptReferences)
    {
        string value = String.IsNullOrEmpty(reference.Assembly) ? 
            reference.Path + " (External)" : reference.Name + " (Assembly)";

        if (!identifiers.Contains(value))
        {
            identifiers.Add(value);
        }
    }

    StringBuilder sb = new StringBuilder();
    foreach (string refer in identifiers)
    {
        sb.AppendLine(refer + "<br />");
    }

    this.Literal1.Text = sb.ToString();
}

 

在浏览器中打开页面,我们来看一下页面上显示了什么。

  1. AjaxControlToolkit.Compat.Timer.Timer.js (Assembly)
  2. AjaxControlToolkit.Common.Common.js (Assembly)
  3. AjaxControlToolkit.Animation.Animations.js (Assembly)
  4. AjaxControlToolkit.ExtenderBase.BaseScripts.js (Assembly)
  5. AjaxControlToolkit.Animation.AnimationBehavior.js (Assembly)
  6. AjaxControlToolkit.PopupExtender.PopupBehavior.js (Assembly)
  7. AjaxControlToolkit.AutoComplete.AutoCompleteBehavior.js (Assembly)

这是页面使用AutoCompeteExtender所需资源的一个有序列表,请注意现在AutoCompleteExtender的ScriptPath为空。那么如果我们把它按照如下设置又会如何呢?

<ajaxToolkit:AutoCompleteExtender runat="server" ID="autoComplete1" 
    TargetControlID="myTextBox" ScriptPath="AutoCompleteBehavior.js" ... />

 

刷新页面之后您就会发现……

  1. AjaxControlToolkit.ExtenderBase.BaseScripts.js (Assembly)
  2. AutoCompleteBehavior.js (External)

嗨,我知道上一个列表中最后那个资源需要被外部文件所替换,那么其它哪些资源到哪里去了?很显然,现在结果使我们不得不自己手动地添加那些引用。ScriptPath的这个拙劣设计几乎使它成为了ExtenderControlBase中最没有用的属性了。

为什么会这样?

我们现在知道,一旦设置了ScriptPath属性之后有些资源引用就会消失,这是什么原因?以下就是我的简单说明:

AjaxControlTookit中所有的Extender将会和一系列的资源进行绑定。当一个Extender被放置在页面中时,所有的相关资源将会被发送到客户端。这些相关资源分为两种:“功能资源”和“辅助资源”(您不会在任何官方资料中找到这两个概念,因为这是我为了说明问题而自行提出的)。“功能资源”是那些直接用于实现组件功能的资源,将会使用ClientScriptResourceAttribute自定义属性在类上进行标记。“辅助资源”则是指那些可复用的,用于辅助实现组件功能的资源,它们将会使用RequiredScriptAttribute自定义属性标记在类上。RequiredScriptAttribute自定义属性会接受一个类型对象作为参数,这样这个类型上所有的相关资源将会被作为另一个控件的“辅助资源”。

这里还是让我们来看一下AutoCompleteExtender的定义:

[RequiredScript(typeof(CommonToolkitScripts))]
[RequiredScript(typeof(PopupExtender))]
[RequiredScript(typeof(TimerScript))]
[RequiredScript(typeof(AnimationExtender))]
[ClientScriptResource("AjaxControlToolkit.AutoCompleteBehavior",
    "AjaxControlToolkit.AutoComplete.AutoCompleteBehavior.js")]
public class AutoCompleteExtender : AnimationExtenderControlBase
{
    ...
}

 

通过上面的示例我们可以得出这样的结论:“AjaxControlToolkit.AutoComplete.AutoCompleteBehavior.js”是AutoCompleteExtender唯一的“功能资源”,而CommonToolkitScripts, PopupExtener, TimerScript, AnimationExtender这些类的所有相关资源都是AutoCompleteExtender的“辅助资源”。

几乎所有的组件都能被继承,所以我们还必须能够意识到这样一件事情:所有基类的相关资源也将会成为子类的相关资源。例如,从ExtenderControlBase类的定义中可以发现它拥有一个“功能资源”:

[ClientScriptResource(null, Constants.BaseScriptResourceName)]
public abstract class ExtenderControlBase : ExtenderControl, IControlResolver
{
    ...
}

 

由此我们很容易推断出,AjaxControlToolkit中所有的Extender组件都会把“AjaxControlToolkit.ExtenderBase.BaseScripts.js”作为自己的相关资源。

那么,如果我们设定了ScriptPath属性将会发生什么事情呢?最终的结果将会是,所有的与当前组件绑定的资源将会被忽略,也就是说只有ScirptPath指定的外部文件和绑定在基类上的资源会被发送到客户端。正是这点才让ScriptPath属性的境遇不甚理想。

我们该怎么做呢?

AjaxControlToolkit是一个开源的项目,因此我们可以将ScriptPath属性的相关实现修改为合理的状况。但是我更喜欢让它的开发团队来处理这件事情,因为在本地代码和官方发布的最新版本之间作同步总是一件让我感到头疼的事情。所以我在开发Extender时,会使用以下这种简单的做法。我们还是使用AutoCompleteExtender作为示例:

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

    ScriptManager.GetCurrent(this.Page).ResolveScriptReference += 
        new EventHandler<ScriptReferenceEventArgs>(OnResolveScriptReference);
}

private static void OnResolveScriptReference(object sender, ScriptReferenceEventArgs e)
{
    ScriptReference script = e.Script;
    if (script.Name == "AjaxControlToolkit.AutoComplete.AutoCompleteBehavior.js")
    {
        script.Assembly = "";
        script.Name = "";
        script.Path = "AutoCompleteBehavior.js";
    }
}

 

在上面的代码片段中,我们响应了ScriptManager的ResolveScriptReference事件,这样我们就可以修改某个特定的ScriptReference对象使它指向一个外部脚本文件了。这正是我们需要的效果。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: PyCharm脚本路径是指PyCharm中Python脚本文件所在的路径。可以通过在PyCharm中打开脚本文件并查看其路径来获取该路径。在PyCharm中,可以使用Ctrl + Shift + N快捷键打开文件搜索框,然后输入文件名来查找脚本文件并查看其路径。 ### 回答2: Pycharm是一款集成开发环境(IDE)软件,主要用于开发Python语言。在使用Pycharm时,需要设置Python解释器和脚本路径。其中,脚本路径指的是Python文件所在的路径。 设置脚本路径的方法如下: 1. 打开Pycharm软件,进入项目根目录; 2. 点击“File”菜单,选择“Settings”; 3. 在左侧面板中选择“Project”选项,然后选择自己的项目; 4. 在右侧面板中选择“Project Interpreter”选项,然后点击齿轮图标,选择“Show All”; 5. 点击“Interpreter Paths”选项卡,然后添加自己的Python解释器路径; 6. 点击“Python Interpreter”选项卡,选择自己的Python解释器; 7. 点击“Execution”选项卡,在“Script path”中输入Python文件所在的路径。 这样就可以设置好Pycharm的脚本路径。在编写Python代码时,可以直接打开文件并编写代码。然后,通过Pycharm自带的运行按钮或者快捷键执行代码。 总结来说,设置Pycharm的脚本路径可以帮助开发者更加方便地编辑和运行Python代码。通过上述步骤,我们可以轻松找到Python文件所在的路径,并顺利地进行开发工作。 ### 回答3: PyCharm是一个强大的集成开发环境(IDE),通常用于Python编程。在PyCharm中,你可以创建Python项目并编写Python脚本,而对于 script path脚本路径),它是指该脚本文件的存储路径。 在PyCharm中,选择创建Python项目之后,你需要选择项目的存储路径。在该项目中,你可以创建多个Python脚本,每个脚本都需要存储在一个路径下。这个路径就是 script path。 PyCharm的默认脚本路径是项目根目录下的“src”文件夹,但你可以通过修改项目设置中的“Project Structure(项目结构)”来更改脚本存储路径。通过这一设置,你可以添加、删除和重命名脚本路径。 在PyCharm中,你可以轻松地找到每个Python脚本的路径。选择要使用的脚本文件,然后右键单击它,在菜单中选择“Copy Path(复制路径)”选项,这将复制脚本文件的完整路径到你的剪贴板中。你可以在其他应用程序中使用这一路径,例如在命令行界面中运行该脚本。 总之, script path 是指Python脚本文件的存储路径。PyCharm可以让你通过“Project Structure”轻松管理脚本文件的路径,并且可以帮助你快速找到每个脚本文件的完整路径。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值