ImportCatalogPart Web 服务器控件可导入 WebPart 控件的说明文件(或用作 WebPart 控件的其他 ASP.NET 服务器控件)。这样就可以将该控件通过预先指定的设置添加到网页中。该说明文件使用户可以共享 WebPart 控件的设置。
说明文件与控件本身不同。它是以 .WebPart 文件扩展名结尾的 XML 文件,包含有描述控件的状态的名称/值对。除了描述控件的状态以外,说明文件还引用该控件名和包含该控件的程序集(或文件)。
用户导入说明文件之后,该文件中引用的 WebPart 控件将会显示在 ImportCatalogPart 控件中,用户可以将该控件添加到页面中。
将 Web 部件控件与 ImportCatalogPart Web 服务器控件关联
与 ImportCatalogPart 控件关联的 Web 部件控件可以编译为程序集,也可以是一个用户控件(.ascx 文件)。在任一情况下,导入的说明文件中引用的控件都必须存在于包含宿主网页的 Web 服务器上。
用户可使用 ImportCatalogPart 控件将说明文件及其关联的服务器控件导入网页。此控件必须已存在于页面中。如果用户将页面切换到目录显示模式,则显示 ImportCatalogPart 控件。然后,用户就可以浏览到该控件的 .WebPart 说明文件,并导入该控件。控件的外观和属性在导入的说明文件中指定。
在导入 WebPart 控件的说明文件之前,用户必须首先基于现有 WebPart 控件创建(导出)该文件。满足以下条件时,可以为一个控件导出说明文件:
·该控件具有用 Personalizable 属性 (Attribute) 标记的属性 (Property)。
·Web.config 文件已经在 webParts 元素中将 enableExport 属性值设置为 true。
·您已经将控件的 ExportMode 属性值设置为 None 默认值(该值禁止导出)以外的值。
启用 ImportCatalogPart Web 服务器控件
当 Web 部件页处于编辑模式以及用户选择某一关联的 WebPart 控件进行编辑时,在运行时将显示 ImportCatalogPart Web 服务器控件。
一、ImportCatalogPart 类
导入 WebPart 控件(或其他用作 WebPart 控件的 ASP.NET 服务器控件)的说明文件,以便用户可以使用预定义的设置将控件添加到网页中。无法继承此类。
ImportCatalogPart 控件使用户可以导入说明文件,该文件描述了用户希望添加到 WebPartZoneBase 区域的 WebPart 控件或服务器控件的设置。
用户导入说明文件之后,在该文件中引用的 WebPart 控件出现在 ImportCatalogPart 控件中,并且用户可以将该控件添加到页面上。
说明文件与控件本身不同。它是以 .WebPart 扩展名结尾的 XML 文件,并包含名称/值对 -- 通常是属性值 -- 描述控件的状态。
说明文件引用的控件既可以被编译为程序集,也可以是 .ascx 文件中定义的用户控件。在任一情况下,导入的说明文件中引用的控件都必须存在于承载试图导入该控件的网页的 Web 服务器上。说明文件引用该控件名和包含该控件的程序集(或文件),并且说明文件包含影响控件的属性值、外观和行为的设置。
ImportCatalogPart 控件使用户可以共享控件的设置。复杂的控件可以有许多属性和设置。例如,在一个大型公司的典型 Intranet 站点上,一个自定义的 WebPart 控件可能包含许多保存特定于用户环境的值的属性,如数据库连接、部门信息等。该控件还可能包含许多影响其外观的属性。用户可以个性化特定站点上的控件并使其正常工作,导出该控件的说明文件,然后与其他用户共享该说明文件,这些用户可以导入该文件以将该完全配置的控件添加到允许他们个性化的其他 Intranet 站点。只要已编译的程序集或包含控件的用户控件文件存在于承载其站点的 Web 服务器上,用户就可以将控件添加到其他网站中。
用户将说明文件(及其关联的服务器控件)导入网页的机制是 ImportCatalogPart 控件,网页开发人员必须将此控件添加到网页。当用户将网页切换到目录显示模式后,将出现 ImportCatalogPart 控件,用户可以使用此控件浏览到与要导入的服务器控件相对应的 .WebPart 说明文件。按照 ImportCatalogPart 控件提供的 UI 和说明,用户可将所需的服务器控件添加到网页中,并将其外观和属性完全按照导入的说明文件中的说明进行配置。
在 WebPart 控件的说明文件可以导入之前,用户必须首先基于已存在的 WebPart 控件创建(导出)该文件。满足以下条件时,可以为一个控件导出说明文件:
·该控件具有用 Personalizable 属性 (Attribute) 标记的属性 (Property)。
·Web.config 文件将
·开发人员将控件的 ExportMode 属性值设置为默认值 None(该值禁止导出)以外的值。如果 ExportMode 属性 (Property) 值设置为 NonSensitiveData,则当用户导出说明文件时,任何包含具有 Personalizable 属性 (Attribute) 的 IsSensitive 参数的属性 (Property) 都不会被导出。这使得控件开发人员可以防止敏感数据(如连接字符串)在某些情况下被导出。
用户可以导出支持导出的控件,方法是单击出现在控件谓词菜单中的导出谓词,然后按照说明保存该控件的 .WebPart 说明文件。然后其他用户可以导入该文件来配置他们各自的该控件实例。
ImportCatalogPart 类包含若干属性。BrowseHelpText 属性包含当用户浏览到说明文件时提供给用户的说明文本。ImportedPartLabelText 属性包含当导入控件出现在 ImportCatalogPart 控件中时,用作该控件标签的文本。PartImportErrorLabelText 包含当导入控件说明发生错误时显示的文本。如果开发人员没有为 ImportCatalogPart 控件指定标题,则 Title 属性重写基属性来为该控件指定一个默认标题。UploadButtonText 属性包含用户单击以上载说明文件的按钮的文本,UploadHelpText 属性包含上载过程的说明。
ImportCatalogPart 类还包含若干独有的方法。GetAvailableWebPartDescriptions 方法检索目录中每个 WebPart 控件的 WebPartDescription 对象,这使得 ImportCatalogPart 控件无需创建每个服务器控件的实例即可显示其有关信息。GetWebPart 方法根据传递给方法的说明获取某个特定 WebPart 控件的实例。
存在与使用 ImportCatalogPart 控件关联的某些内在风险。一个示例是,有人可能会将恶意数据通过用于导入的说明文件导入到 Web 应用程序中。如果有人将恶意脚本代码作为字符串属性的值放在说明文件中,则当用户导入说明文件并将引用的服务器控件添加到网页时,就有可能执行该脚本。若要将导入带有恶意数据的说明文件的风险降至最低,具有字符串类型属性的服务器控件应该始终对属性数据进行编码。另一风险是通过说明文件导入类型。恶意用户可以通过提交请求将许多程序集加载到 AppDomain 中,导致大量内存被占用。
若要避免与导入相关的风险,可以通过不使用导入功能或 ImportCatalogPart 控件以完全禁用该功能。或者,可以限制哪些用户可以访问该控件。可以使用角色管理以编程方式实现此目的(请参见 使用角色管理授权)。例如,加载网页时,可以通过测试来查看用户是否属于某一特定角色(如管理员角色)。如果用户属于该角色,则可以通过编程方式将 ImportCatalogPart 控件添加到网页中供该用户使用。还可通过声明性方法来限制可以使用 ImportCatalogPart 控件的用户集。在包含目录的网页中,可以放置两个 CatalogZone 控件:一个用于可以导入的用户,另一个用于不可以导入的用户。可以导入的用户的区域将包含 ImportCatalogPart 控件。该区域本身可以置于 LoginView 控件的内部,这样就可以限制该区域内的控件使用,使得只有经过验证身份的用户或指定的角色才能使用该控件。
1.1、示例
下面的代码示例演示如何以声明和编程方式在网页上使用 ImportCatalogPart 控件。此示例包含四部分:
·一个用户控件,可用于更改 Web 部件页上的显示模式。
·一个网页,包含一个 CatalogZone 控件和一个 ImportCatalogPart 控件。
·一个包含两个自定义 WebPart 控件的源代码文件。
·对您在浏览器中加载页面时示例的运行方式的说明。
此代码示例的第一部分是一个用户控件,该控件使用户能够更改网页上的显示模式。应该将下面的源代码放置在一个文件中,并将它命名为 Displaymodemenucs.ascx 或 Displaymodemenuvb.ascx(具体取决于所使用的语言)。
<%@ control language="C#" classname="DisplayModeMenuCS"%>
// Use a field to reference the current WebPartManager.
WebPartManager _manager;
void Page_Init(object sender, EventArgs e)
{
Page.InitComplete += new EventHandler(InitComplete);
}
void InitComplete(object sender, System.EventArgs e)
{
_manager = WebPartManager.GetCurrentWebPartManager(Page);
String browseModeName = WebPartManager.BrowseDisplayMode.Name;
// Fill the dropdown with the names of supported display modes.
foreach (WebPartDisplayMode mode in _manager.SupportedDisplayModes)
{
String modeName = mode.Name;
// Make sure a mode is enabled before adding it.
if (mode.IsEnabled(_manager))
{
ListItem item = new ListItem(modeName, modeName);
DisplayModeDropdown.Items.Add(item);
}
}
// If shared scope is allowed for this user, display the scope-switching
// UI and select the appropriate radio button for the current user scope.
if (_manager.Personalization.CanEnterSharedScope)
{
Panel2.Visible = true;
if (_manager.Personalization.Scope == PersonalizationScope.User)
RadioButton1.Checked = true;
else
RadioButton2.Checked = true;
}
}
// Change the page to the selected display mode.
void DisplayModeDropdown_SelectedIndexChanged(object sender, EventArgs e)
{
String selectedMode = DisplayModeDropdown.SelectedValue;
WebPartDisplayMode mode = _manager.SupportedDisplayModes[selectedMode];
if (mode != null)
_manager.DisplayMode = mode;
}
// Set the selected item equal to the current display mode.
void Page_PreRender(object sender, EventArgs e)
{
ListItemCollection items = DisplayModeDropdown.Items;
int selectedIndex =
items.IndexOf(items.FindByText(_manager.DisplayMode.Name));
DisplayModeDropdown.SelectedIndex = selectedIndex;
}
// Reset all of a user's personalization data for the page.
protected void LinkButton1_Click(object sender, EventArgs e)
{
_manager.Personalization.ResetPersonalizationState();
}
// If not in User personalization scope, toggle into it.
protected void RadioButton1_CheckedChanged(object sender, EventArgs e)
{
if (_manager.Personalization.Scope == PersonalizationScope.Shared)
_manager.Personalization.ToggleScope();
}
// If not in Shared scope, and if user is allowed, toggle the scope.
protected void RadioButton2_CheckedChanged(object sender, EventArgs e)
{
if (_manager.Personalization.CanEnterSharedScope &&
_manager.Personalization.Scope == PersonalizationScope.User)
_manager.Personalization.ToggleScope();
}
Borderwidth="1" Width="230" BackColor="lightgray" Font-Names="Verdana, Arial, Sans Serif" > Text=" Display Mode" Font-Bold="true" Font-Size="8" Width="120" AssociatedControlID="DisplayModeDropdown"/> AutoPostBack="true" Width="120" OnSelectedIndexChanged="DisplayModeDropdown_SelectedIndexChanged" /> Text="Reset User State" ToolTip="Reset the current user's personalization data for the page." Font-Size="8" OnClick="LinkButton1_Click" /> GroupingText="Personalization Scope" Font-Bold="true" Font-Size="8" Visible="false" > Text="User" AutoPostBack="true" GroupName="Scope" OnCheckedChanged="RadioButton1_CheckedChanged" /> Text="Shared" AutoPostBack="true" GroupName="Scope" OnCheckedChanged="RadioButton2_CheckedChanged" />
该代码示例的第二部分为网页。在页顶部有两条 register 指令,一条针对用户控件,一条针对包含两个自定义 WebPart 控件的已编译组件。注意,该页面有一个对 ImportCatalogPart 控件的声明性引用,该控件嵌套在声明性元素的适当的层次结构内。还请注意,
在页的 WebPartZone 控件中,声明了两个自定义 WebPart 控件。
说明: 若要使 Web 部件应用程序的用户能够导出 WebPart 控件的说明文件,还必须启用 Web 应用程序中的导出功能,方法是将 enableExport="true" 属性添加到 Web.config 文件中的
<%@ page language="c#" %>
<%@ register TagPrefix="uc1"
TagName="DisplayModeMenuCS"
Src="DisplayModeMenuCS.ascx" %>
<%@ register tagprefix="aspSample"
Namespace="Samples.AspNet.CS.Controls" %>
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
protected void Button1_Click(object sender, EventArgs e)
{
ImportCatalogPart1.Title = "Import Server Controls";
ImportCatalogPart1.BrowseHelpText = "Enter the path to a "
+ "description file.";
ImportCatalogPart1.UploadButtonText = "Upload Description";
ImportCatalogPart1.UploadHelpText = "Upload a description file.";
ImportCatalogPart1.ImportedPartLabelText = "Imported Controls";
ImportCatalogPart1.PartImportErrorLabelText = "An error occured "
+ "during the import process.";
}
protected void Page_Load(object sender, EventArgs e)
{
Button1.Visible = false;
}
protected void ImportCatalogPart1_PreRender(object sender,
EventArgs e)
{
Button1.Visible = true;
}
>
ImportCatalogPart Control
Font-Names="Verdana, Arial"
Font-Size="110%"
BackColor="LightBlue" />
runat="server"
id="TextDisplayWebPart1"
title = "Text Display WebPart" />
Title="User Information" exportmode="all" />
runat="server" />
runat="server"
Title="My ImportCatalogPart"
OnPreRender="ImportCatalogPart1_PreRender"
BrowseHelpText="Type a path or browse to find a control's
description file."
UploadButtonText="Upload Description File"
UploadHelpText="Click the button to upload the description
file."
ImportedPartLabelText="My User Information WebPart"
PartImportErrorLabelText="An error occurred while trying
to import a description file." />
Text="Update ImportCatalogPart"
OnClick="Button1_Click" />
此代码示例的第三部分是两个 WebPart 控件的源代码。注意,这些控件的一些属性 (Property) 用 WebBrowsable 属性 (Attribute) 标记。这使得 PropertyGridEditorPart 控件能够动态地生成用户界面 (UI),以便用户在这些控件处于编辑模式时编辑这些属性。这些属性 (Property) 也用 WebDisplayName 属性 (Attribute) 标记,指定在编辑用户界面中的每个控件旁显示的标签文本。必须编译此源代码,代码示例才能运行。可以显式编译源代码,并将结果程序集放在网站的 Bin 文件夹或全局程序集缓存中。另外,也可将源代码放入站点的 App_Code 文件夹中,源代码将在运行时在此文件夹中进行动态编译。此代码示例使用动态编译。名为 TextDisplayWebPart 的自定义控件在网页上通过
using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Security.Permissions;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
namespace Samples.AspNet.CS.Controls
{
[AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level = AspNetHostingPermissionLevel.Minimal)]
public class UserInfoWebPart : WebPart
{
HttpServerUtility server = HttpContext.Current.Server;
private String _userNickName = "Add a nickname.";
private String _userPetName = "Add a pet name.";
private DateTime _userSpecialDate = DateTime.Now;
private Boolean _userIsCurrent = true;
private JobTypeName _userJobType = JobTypeName.Unselected;
public enum JobTypeName
{
Unselected = 0,
Support = 1,
Service = 2,
Professional = 3,
Technical = 4,
Manager = 5,
Executive = 6
}
Label NickNameLabel;
Label PetNickNameLabel;
Label SpecialDateLabel;
CheckBox IsCurrentCheckBox;
Label JobTypeLabel;
// Add the Personalizable and WebBrowsable attributes to the
// public properties, so that users can save property values
// and edit them with a PropertyGridEditorPart control.
[Personalizable(), WebBrowsable, WebDisplayName("Nickname")]
public String NickName
{
get
{
object o = ViewState["NickName"];
if (o != null)
return (string)o;
else
return _userNickName;
}
set { _userNickName = server.HtmlEncode(value); }
}
[Personalizable(), WebBrowsable, WebDisplayName("Pet Name")]
public String PetName
{
get
{
object o = ViewState["PetName"];
if (o != null)
return (string)o;
else
return _userPetName;
}
set { _userPetName = server.HtmlEncode(value); }
}
[Personalizable(), WebBrowsable(), WebDisplayName("Special Day")]
public DateTime SpecialDay
{
get
{
object o = ViewState["SpecialDay"];
if (o != null)
return (DateTime)o;
else
return _userSpecialDate;
}
set { _userSpecialDate = value; }
}
[Personalizable(), WebBrowsable(), WebDisplayName("Job Type")]
public JobTypeName UserJobType
{
get
{
object o = ViewState["UserJobType"];
if (o != null)
return (JobTypeName)o;
else
return _userJobType;
}
set { _userJobType = (JobTypeName)value; }
}
[Personalizable(), WebBrowsable(), WebDisplayName("Is Current")]
public Boolean IsCurrent
{
get
{
object o = ViewState["IsCurrent"];
if (o != null)
return (Boolean)o;
else
return _userIsCurrent;
}
set { _userIsCurrent = value; }
}
protected override void CreateChildControls()
{
Controls.Clear();
NickNameLabel = new Label();
NickNameLabel.Text = this.NickName;
SetControlAttributes(NickNameLabel);
PetNickNameLabel = new Label();
PetNickNameLabel.Text = this.PetName;
SetControlAttributes(PetNickNameLabel);
SpecialDateLabel = new Label();
SpecialDateLabel.Text = this.SpecialDay.ToShortDateString();
SetControlAttributes(SpecialDateLabel);
IsCurrentCheckBox = new CheckBox();
IsCurrentCheckBox.Checked = this.IsCurrent;
SetControlAttributes(IsCurrentCheckBox);
JobTypeLabel = new Label();
JobTypeLabel.Text = this.UserJobType.ToString();
SetControlAttributes(JobTypeLabel);
ChildControlsCreated = true;
}
private void SetControlAttributes(WebControl ctl)
{
ctl.BackColor = Color.White;
ctl.BorderWidth = 1;
ctl.Width = 200;
this.Controls.Add(ctl);
}
protected override void RenderContents(HtmlTextWriter writer)
{
writer.Write("Nickname:");
writer.WriteBreak();
NickNameLabel.RenderControl(writer);
writer.WriteBreak();
writer.Write("Pet Name:");
writer.WriteBreak();
PetNickNameLabel.RenderControl(writer);
writer.WriteBreak();
writer.Write("Special Date:");
writer.WriteBreak();
SpecialDateLabel.RenderControl(writer);
writer.WriteBreak();
writer.Write("Job Type:");
writer.WriteBreak();
JobTypeLabel.RenderControl(writer);
writer.WriteBreak();
writer.Write("Current:");
writer.WriteBreak();
IsCurrentCheckBox.RenderControl(writer);
}
}
[AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level = AspNetHostingPermissionLevel.Minimal)]
public class TextDisplayWebPart : WebPart
{
private String _contentText = null;
TextBox input;
Label DisplayContent;
Literal lineBreak;
[Personalizable(), WebBrowsable]
public String ContentText
{
get { return _contentText; }
set { _contentText = value; }
}
protected override void CreateChildControls()
{
Controls.Clear();
DisplayContent = new Label();
DisplayContent.BackColor = Color.LightBlue;
DisplayContent.Text = this.ContentText;
this.Controls.Add(DisplayContent);
lineBreak = new Literal();
lineBreak.Text = @"
";
Controls.Add(lineBreak);
input = new TextBox();
this.Controls.Add(input);
Button update = new Button();
update.Text = "Set Label Content";
update.Click += new EventHandler(this.submit_Click);
this.Controls.Add(update);
}
private void submit_Click(object sender, EventArgs e)
{
// Update the label string.
if (!String.IsNullOrEmpty(input.Text))
{
_contentText = Context.Server.HtmlEncode(input.Text) + @"
";
input.Text = String.Empty;
DisplayContent.Text = this.ContentText;
}
}
}
}
立即运行代码示例。请在浏览器中加载该网页。第一步是编辑 UserInfoWebPart 控件。使用“显示模式”下拉列表控件,并选择“编辑”将页面切换到编辑模式。单击 UserInfoWebPart 控件的谓词菜单(标题栏中的向下箭头),然后单击“编辑”。编辑 UI 出现后,多个编辑控件将会出现在可用于编辑其字段值的 UserInfoWebPart 控件的下面。编辑一些字段,单击“确定”,然后使用“显示模式”下拉菜单将页面返回到浏览模式。
第二步是导出 UserInfoWebPart 控件的 .WebPart 说明文件。单击自定义控件上的谓词菜单(由标题栏中的向下箭头表示),然后单击“导出”。按照说明进行操作,保存控件的 .WebPart 说明文件。现在关闭网页,然后在编辑器中编辑网页源代码。删除
在浏览器中再次加载该网页。UserInfoWebPart 控件将不会出现,因为已经将其移除。使用“显示模式”下拉列表控件,并选择“目录”将页面切换到目录模式。在 ImportCatalogPart 控件中,单击“浏览”按钮,然后浏览到已创建的 .WebPart 文件,再单击“上载”按钮。应出现对该控件的引用并在旁边显示一个复选框。选择该复选框,然后单击“添加”将控件添加到页面中。
当位于页面的此视图中时,单击页面底部附近的“更新 ImportCatalogPart”按钮,可以查看以编程方式更新 ImportCatalogPart 控件的多个属性值的效果。单击该按钮后,观察 UI 中的各种属性有何变化。
最后,单击“关闭”退出目录模式,并将页面返回到浏览模式。UserInfoWebPart 控件现在应显示在页面中,并包含先前导出它时拥有的值。