“Cuckoo”通过精心收集,向本站投稿了4篇使用SQL Server数据服务开发功能强大且可扩展的应用程序,下面就是小编整理后的使用SQL Server数据服务开发功能强大且可扩展的应用程序,希望大家喜欢。

篇1:使用SQL Server数据服务开发功能强大且可扩展的应用程序
本文使用了以下技术:
SQL Server
本文将介绍以下内容:
SSDS 数据模型
管理实体、容器和颁发机构
创建示例 Web 应用程序
类序列化和反序列化
本专栏基于 SQL Server 数据服务的预发布版本撰写而成,文中包含的所有信息均有可能发生变更。
目录
SSDS 数据模型
构建分类广告系统
添加城市
添加类别
更新和删除实体
添加和删除列表架构
分类 Web 应用程序
类反序列化
使用自定义列表架构
展望未来
Microsoft 数据平台由一组丰富的产品和技术组成,它包括所有数据类型并涵盖了整个领域范围,从一端的非结构化二进制数据到另一端的高度结构化在线分析处理 (OLAP) 多维数据集。虽然这些技术可以解决您将面临的任何应用场合,但通常必须要在时间和硬件资源方面进行一些前期投资,然后才能开始对解决方案进行编码。
对于应用程序开发人员而言,通常很难估计某个应用程序在其整个生命周期过程中所需的存储和处理要求。如果您面对的是新兴的创业公司,其资金比较紧张而且用来制定硬件投资决策的数据不足,则此问题可能尤为明显。为解决有关这些前期投资的问题,Microsoft 最近在其已经很强大的数据平台中又增添了一项新技术:SQL Server® 数据服务 (SSDS)。
SSDS 并非传统意义上的盒装软件产品术语,而是一个强大的、无尺度的数据服务,它在内部使用可靠的 SQL Server 技术并依据行业标准 Web 服务接口来公开其功能。SSDS 可提供易用而灵活的数据模型,可通过开放的行业标准协议对其进行访问。
不论是使用 Microsoft® .NET Framework、Java 还是其他技术进行开发,都可以使用 SSDS 进行数据存储。此外,SSDS 的设计使开发人员能够迅速置备帐户并立即开始对其进行开发。
SSDS 为开发人员提供了一种数据后端,它不受可用驱动器托架或支架空间的限制。通过使用 SSDS 作为数据平台,您的应用程序可以随意使用所需数量的数据。无论是 1GB 字节的存储还是 1PB 字节的存储,您只需支付这些资源的费用即可使用。
许多网站和应用程序都具有循环访问模式,在这种模式下,您需要具有足够的容量来容纳峰值负载(即使这些负载是瞬态的)。通过使用 SSDS 作为数据后端,您可以将精力集中在应用程序上,而不是集中在数据平台容量规划上。
在本文中,我将为您介绍有关围绕 SSDS 开发数据解决方案的基础知识。首先,我将制订 SSDS 使用的数据模型。然后,通过向您展示如何使用 SSDS 构建简单的在线分类广告系统来深入介绍开发细节,具体如图 1 所示。
图 1 SSDS 托管的分类应用程序示例
SSDS 数据模型
SSDS 提供了一种灵活的基于实体的数据模型。此模型包含三个主要元素,即颁发机构、容器和实体,这些统称为 ACE 概念(请参见图 2)。SSDS 颁发机构可与关系型领域的数据库相关。置备了颁发机构后,SSDS 将会为您创建访问该颁发机构的 DNS 名称。例如,如果您置备了一个名为 ssdsdemo 的颁发机构,则可以通过以下 URI 访问它:
复制代码
ssdsdemo.data.beta.mssds.com
图 2基本 SSDS 组件
颁发机构还可以是地理位置单元,这意味着创建的 DNS 名称将会映射到您托管数据的指定 Microsoft 数据中心。如果您创建了两个颁发机构 americasdemo.data.beta.mssds.com 和 europedemo.data.beta.mssds.com,则每一个都将分别与距离用户最近的不同数据中心建立关联。
颁发机构包含容器的集合,而容器则类似于关系型数据库中的表。主要差别在于您需要将架构附加到数据库表中以使表中的所有行都属于同类。SSDS 中的容器不需要架构,因此您可以将异类实体存储在一个方便的位置。它只是一个实体集合。在当前发布的 SSDS 中,所有查询都被控制在单一容器内。
还需重点指出的是,每个容器都位于 SSDS 群集的不同节点中。在 SQL Server 中,要获得额外的性能,应将不同的表放在不同的心轴上以最大程度地发挥读/写功能。这与 SSDS 非常相似,只不过每个容器都将位于单独的计算机中。通过将数据分割到多个容器中并将请求分为多个线程,您可以获得额外的性能提升,因为读和写将不再受到单一计算机的限制。
关于容器最后要注意的一点是,虽然每个容器都被放置在 SSDS 群集中的单独节点上,但出于灾难恢复目的,还应将数据复制到多个其他节点上。如果容器所在的计算机发生故障,系统会自动提升一个备份副本以确保您的应用程序不会损失任何数据或性能。
实体可以看作是关系型数据库中表的一行。实体只是名称/值对的属性包。这些名称/值对可被分组为两个类别:可分辨系统属性和灵活属性。
可分辨系统属性是所有实体共有的,包括 ID、Kind 和 Version 等。ID 用于唯一标识实体。ID 在其所在的容器中必须是唯一的,但不同容器中的实体可以具有相同的 ID。Kind 用于将类似的实体分类在一起。实体上没有附加任何架构,因此具有相同 Kind 的实体并不能保证其结构也相同,Version 用于标识当前的实体版本。此值在每次操作后都会进行更新。
灵活属性是开发人员在其中存储应用程序数据的位置。灵活属性支持简单的类型:String、decimal、bool、datetime 和 binary。每种灵活属性的前 256 个字节都被编制了索引。
构建分类广告系统
为了说明 SSDS 的功能并概要介绍开发体验,我将带您实现一个在线分类系统 Contoso Classifieds 示例。此示例包含两个独立的应用程序:一个是 Windows® Forms 应用程序(用于管理系统),一个是用户将要使用的 ASP.NET 应用程序(Contoso Classifieds 主站点)。此应用程序通过 SOAP 接口(在 Windows Forms 应用程序中)和具像状态传输 (REST) 接口(在 ASP.NET 应用程序中)来访问 SSDS。
注册了 SSDS 帐户后,您将会收到一个用户名和密码。在这里,您可以决定是否开始构建颁发机构、容器和实体。对于 Contoso Classifieds,我将建立颁发机构 contosoclassifieds,在测试版 SSDS 中服务 URI 端点是 data.data.beta.mssds.com。
contosoclassifieds 颁发机构包括两个容器:Categories 和 Cities。Categories 包含与 Listing 类别相关的实体。Cities 包含与系统中定义的每个城市相对应的实体。这些实体只是指向特定城市的颁发机构的指针。各城市特定的颁发机构在每个列表类别中都对应一个容器(请参见图 3)。
图 3 Contoso Classifieds 元素
我之所以采用这种设计是因为考虑到几个原因。我选择按城市来实现颁发机构,以便可以确保颁发机构被置备在从地理位置而言最接近其服务人口的数据中心。我选择每个 listing 类别对应一个容器,这样做不但可以简化查询模式,而且还可以将负载分布到群集中的多个计算机中(请记住,容器会扩展到后端群集中的指定节点上)。图 4 显示了 Contoso Classifieds Administration 客户端的用户界面。
图 4 分类应用程序管理客户端
如前所述,开发人员需要自行决定是否创建应用程序要使用的任何颁发机构、容器和实体。在此示例应用程序中,所有工作都是通过 Perform. Initial Setup(执行初始设置)按钮的单击事件实现的。(包括错误处理在内的全部代码都包括在本文的代码下载中。)
置备 SSDS 颁发机构非常简单。在本示例代码中,我使用的是 SitkaSoapServiceClient,先前我曾为它向 SSDS SOAP 接口添加了一个服务引用:
using (SSDSClient.SitkaSoapServiceClient ssdsProxy =new SSDSClient.SitkaSoapServiceClient)您已看到了一个 Authority 对象,但 SSDS 的作用域是什么?作用域对象在 SSDS 中被用来提供对象在 SOAP 服务中的寻址方式,类似于 URI 在 REST 服务中的使用方式。
您首先应该做的是设置服务的用户名和密码:
ssdsProxy.ClientCredentials.UserName.UserName =txtUserName.Text;ssdsProxy.ClientCredentials.UserName.Password =txtPassword.Text;您需要创建一个颁发机构,它应该处于 ACE 模型的最高级别,以便先创建一个空作用域:
SSDSClient.Scope serviceScope = new SSDSClient.Scope();现在创建 Contoso Classifieds 颁发机构。它将容纳系统中的常规配置信息
SSDSClient.Authority contosoAuth =new SSDSClient.Authority();contosoAuth.Id = “contosoclassifieds”;并将创建任务提交到 SSDS
ssdsProxy.Create(serviceScope, contosoAuth);现在已创建了主 Contoso Classifieds 颁发机构并将您的作用域指向了它,接下来要创建容器以容纳要为其提供分类广告的城市并将容器的创建任务提交到 SSDS:
serviceScope.AuthorityId = contosoAuth.Id;SSDSClient.Container citiesContainer = new SSDSClient.Container();citiesContainer.Id = “Cities”;ssdsProxy.Create(serviceScope, citiesContainer);创建容器的过程与创建颁发机构的过程类似。唯一的区别在于您创建的是 Container 对象而非 Authority 对象,而且您更新的是指向颁发机构(要在其中创建容器)的作用域,而非空作用域。
在应用程序中创建容器以容纳您要支持的所有 Header 和 Listing 类别:
SSDSClient.Container categoriesContainer =new SSDSClient.Container();categoriesContainer.Id = “Categories”;ssdsProxy.Create(serviceScope, categoriesContainer);颁发机构创建完毕后,您可以使用 HTTP 或 HTTPS 将 Web 浏览器指向它,而且可以使用 REST 接口查看容器的内容。设置颁发机构时只需使用 SSDS 创建的新 DNS 名称即可。在本例中,URL 为:
contosoclassifieds.data.data.beta.mssds.com/v1将此 URL 输入到浏览器之后,系统将提示您进行身份验证。身份验证一经通过,您即可在浏览器中看到如下内容:
xmlns:xsi=“www.w3.org//XMLSchema-instance”
xmlns:x=“www.w3.org/2001/XMLSchema”>
颁发机构名称采用的是小写字母,因为在 SSDS 为颁发机构创建 DNS 条目后,您必须遵守 DNS 命名约定。
容器创建完毕后,如果您刷新浏览器并以 ?q=“” 形式在 URL 中添加一个空查询,将会看到 EntitySet 中会返回单一的 Container 对象。EntitySet 只是作为查询响应返回的实体的集合。初始设置完成后,示例应用程序将创建一个颁发机构 (contosoclassifieds) 和两个容器(Categories 和 Cities):
xmlns:xsi=“www.w3.org/2001/XMLSchema-instance”
xmlns:x=“www.w3.org/2001/XMLSchema”>
现在初始设置已经完成,让我们继续添加用于城市的功能。
添加城市
如前所述,Contoso Classifieds 将每个城市的列表都放在其本身的颁发机构中,以便您可以选择它所在的数据中心。(试用版 SSDS 当前并不支持此功能,但在产品最终发布时会提供支持。)
用来添加城市的代码与用来进行初始设置的代码相似。使用 SOAP 代理来设置凭据、创建空作用域、设置颁发机构 ID 并发出创建命令:
SSDSClient.Authority cityAuth =new SSDSClient.Authority();cityAuth.Id = cityAuthorityName;ssdsProxy.Create(serviceScope, cityAuth);至此已创建了新的城市颁发机构,接下来向主 contosoclassifieds 颁发机构中的 Cities 容器添加一个指针实体:
serviceScope.AuthorityId = “contosoclassifieds”;serviceScope.ContainerId = “Cities”;//Create the City Entity, and set its properties appropriatelySSDSClient.Entity cityEntity = new SSDSClient.Entity();cityEntity.Id = cityAuthorityName;cityEntity.Kind = “CityServed”;cityEntity.Properties = new DictionarycityEntity.Properties[“AuthorityUri”] =
string.Format(“{0}.data.data.beta.mssds.com/v1/”, cityAuthorityName);
cityEntity.Properties[“Name”] = txtCity.Text;
//Issue the create to SSDS
ssdsProxy.Create(serviceScope, cityEntity);
让我们简单梳理一下。我已经创建了一个主 contosoclassifieds 颁发机构,用于存储系统范围的所有数据。在该颁发机构中有一个 Cities 容器,应用程序针对的各个城市所对应的实体都包含在其中。该实体包含城市的显示名称以及指向包含所有列表的颁发机构的指针。
添加类别
至此您已添加了颁发机构、容器和实体。下一步是实现列表类别功能。为此需要使用 SSDS 的查询、更新和删除功能。
Contoso Classifieds 将支持类别标题,并使用其下方的子类别来存储用户实际发布的内容。如果打算对此数据使用关系型模型,通常应使用数据的标题/行模式。但是,SSDS 使用的灵活实体数据模型允许您对数据采用您喜欢的任何形式。在 Contoso Classifieds 应用程序中,我选择使用单个实体来表示每个类别标题以及属于它的所有子类别(请参见图 5)。
图 5 应用程序使用的实体数据模型
请注意,我使用此模式只是为了显示实体所具有的灵活本质,并说明尽管多个实体可以具有相同的 Kind,但这并不能使实体属于同类。实体可以采用您希望的任何形式。
对于此方案而言,更合理的方法应该是使用两个不同的 Kind 实体(Category 和 Listing Category),并使 CategoryID 在所有实体中都具有 flex 属性。这将允许您发出如下查询:
from e in entities where e[“CategoryID”] == “For Sale” select e请注意我说的是 flex 属性。如前所述,容器中的实体必须具有唯一的 ID,这可以限制您使用可分辨系统属性 ID。还要注意我发出的查询语法。SSDS 使用类似 LINQ 的查询语法,大多数 .NET Framework 开发人员对它都应该很熟悉。
如果您回过头来看一下图 4 中所示的管理应用程序,会注意到一个表示列表类别的树视图以及两个用于添加类别标题和列表类别的文本框。让我们深入了解一下添加类别标题背后的实现过程。
与上面的代码一样,您使用 SitkaSOAPServiceClient、设置凭据并将作用域设置为 contosoclassifieds 颁发机构和 Categories 容器。现在您只需创建实体即可:
SSDSClient.Scope serviceScope = new SSDSClient.Scope();serviceScope.AuthorityId = “contosoclassifieds”;serviceScope.ContainerId = “Categories”;SSDSClient.Entity categoryHeaderEntity = new SSDSClient.Entity();categoryHeaderEntity.Id = CategoryID;categoryHeaderEntity.Kind = “Category”;您还可以添加单个 flex 属性,其中将包含类别名称。请注意,这只会向 flex 属性集合中添加单个属性:
categoryHeaderEntity.Properties =new DictionarycategoryHeaderEntity.Properties[“CategoryName”] = CategoryName;
下一步是添加列表类别。由于 Contoso Classifieds 在类别标题中使用单个实体来表示整个列表类别集合,因此您需要检索类别实体、添加附加列表类别(作为附加 flex 属性添加)并将更新提交到 SSDS。
要检索类别实体,请将作用域设置为直接指向它然后再调用 Get 方法,这将直接检索实体而不会发出查询:
SSDSClient.Scope serviceScope = new SSDSClient.Scope();serviceScope.AuthorityId = “contosoclassifieds”;serviceScope.ContainerId = “Categories”;serviceScope.EntityId = CategoryID;//Retrieve the Category EntitySSDSClient.Entity categoryEntity = ssdsProxy.Get(serviceScope);现在只需确定新属性的索引、添加它作为附加 flex 属性并发出更新命令即可(请参见图 6)。
图 6:添加 Flex 属性
//Determine whether this is the first listing//category being added to this headerif (categoryEntity.Properties.Count >2) {propCount = ((categoryEntity.Properties.Count - 1) / 2);propCount++;}else {propCount = 1;}//Create the FlexProperties for the new listing categorystring listingIdPropName = string.Format (“ListingCategoryID{0}”, propCount);string listingNamePropName = string.Format (“ListingCategoryName{0}”, propCount);categoryEntity.Properties[listingIdPropName] = ListingCategoryID;categoryEntity.Properties[listingNamePropName] = ListingCategoryName;//Issue the update to SSDSssdsProxy.Update(serviceScope, categoryEntity);更新和删除实体
更新列表类别与添加附加 flex 属性一样简单。对于每个更新,您都需要检索实体、进行本地更新并提交,以便将更新的实体及作用域传递给 Update 方法。
首先将服务作用域设置为主 contosoclassifieds 颁发机构。同时,将其指向 Categories 容器以及要更新的类别所对应的实体:
SSDSClient.Scope serviceScope = new SSDSClient.Scope();serviceScope.AuthorityId = “contosoclassifieds”;serviceScope.ContainerId = “Categories”;serviceScope.EntityId = currentHdrNode.Name;获取要进行更新的实体:
SSDSClient.Entity categoryEntity = ssdsProxy.Get(serviceScope);现在,您可以重新初始化 flex 属性集合并重新添加列表类别的所有 flex 属性。此外,您本来应该可以对每个 flex 属性进行循环并加以更新,但由于此实体的结构过于简单,因此如图 7 所示重新创建实体会更为容易一些。
图 7 更新属性
categoryEntity.Properties = new DictionarycategoryEntity.Properties[“CategoryName”] = currentHdrNode.Text;
int propCount = 1;
if (e.Node.Parent != null) {
//Loop through each node and add its category ID and
//category name flex property.
foreach (TreeNode node in e.Node.Parent.Nodes) {
string listingIdPropName = string.Format (“ListingCategoryID{0}”, propCount);
string listingNamePropName = string.Format (“ListingCategoryName{0}”, propCount);
categoryEntity.Properties[listingIdPropName] = node.Name;
categoryEntity.Properties[listingNamePropName] = node.Text;
//if we are re-adding the updated category, the tree view
//will still have its old value, so set the flex property
//to the updated value
if (node.Name == e.Node.Name) {
categoryEntity.Properties[listingIdPropName] = m_OldSelectNode.Name;
categoryEntity.Properties[listingNamePropName] = e.Label;
}
propCount++;
}
}
//Submit the update to SSDS
ssdsProxy.Update(serviceScope, categoryEntity);
要删除某个实体或容器,请将 ServiceScope 指向该项目并调用 SitkaSoapServiceClient 的 Delete 方法。如果是 Header,则删除整个实体:
if (m_OldSelectNode.Parent == null) {ssdsProxy.Delete(serviceScope);}对于其他实体,与处理更新时一样,您可以重新创建 flex 属性集合并加以重新构建,然后对已删除节点以外的所有节点执行添加操作。
SSDSClient.Entity categoryEntity = ssdsProxy.Get(serviceScope);categoryEntity.Properties = new DictionarycategoryEntity.Properties[“CategoryName”] = CategoryName;
int propCount = 1;
foreach (TreeNode node in entityNode.Nodes) {
string listingIdPropName = string.Format (“ListingCategoryID{0}”, propCount);
string listingNamePropName = string.Format (“ListingCategoryName{0}”, propCount);
if (node.Text != m_OldSelectNode.Text) {
categoryEntity.Properties[listingIdPropName] = node.Name;
categoryEntity.Properties[listingNamePropName] = node.Text;
propCount++;
}
}
最后,将更新命令发给 SSDS 并从树视图中删除相应节点:
ssdsProxy.Update(serviceScope, categoryEntity);tvCategories.Nodes.Remove(m_OldSelectNode);添加和删除列表架构
试用版 SSDS 当前不支持架构,
虽然计划在未来加入对架构的支持,但其实在 SSDS 中自行添加架构是一项很简单的任务。唯一需要注意的是您必须从应用程序中管理架构,因为此时 SSDS 不会强制执行架构。
对于 Contoso Classifieds,由管理员针对某些列表类别定义自定义的架构是一种不错的方法。您可以在管理客户端内定义架构,随后在实现网站时使用它。
截至现在,同一容器内没有任何异类实体。由于每个实体都具有 Kind 属性,因此您可以利用这一点将不同的实体类型存储在同一容器中,并可以查询特定类型(在本例中为 Kind)的实体。虽然没有与 Kind 关联的架构约定,但利用此机制很容易将相似的数据进行分组。现在,我将新实体 Kind ListingSchema 添加到 Categories 容器中。
添加列表架构的对话框非常简单,如图 8 所示。管理员可以使用它来定义与某个列表关联的附加字段,也可以将某些字段标识为必填字段。稍后我将对此进行详细介绍,同时为您演示如何实现实际的网站。
图 8 自定义列表架构
用于添加 ListingSchema 实体的过程与您刚刚看到的过程相同,但这一次将使用不同的实体 (Kind)。图 9 显示了如何添加 ListingSchema 的代码。针对 For Sale Cars 类别添加了列表架构之后,可注意到 Categories 容器的内容包括两个不同的实体类型,而且同一容器中的数据完全不同。
图 9 添加架构
listingSchemaEntity.Kind = “ListingSchema”;listingSchemaEntity.Properties = new DictionarylistingSchemaEntity.Properties[“ListingID”] = m_ListingID;
listingSchemaEntity.Properties[“ListingName”] = m_ListingName;
int propCount = 0;
bool required = false;
foreach (DataGridViewRow row in dataGridView1.Rows) {
if (row.IsNewRow) continue;
propCount++;
listingSchemaEntity.Properties[string.Format (“Property{0}Name”,propCount)] =
row.Cells[“colFieldName”].Value.ToString();
listingSchemaEntity.Properties[string.Format (“Property{0}DataType”, propCount)] =
row.Cells[“colDataType”].Value.ToString();
if (row.Cells[“colRequired”].Value == null) {
required = false;
}
else {
required = Convert.ToBoolean(row.Cells [“colRequired”].Value.ToString());
}
listingSchemaEntity.Properties[string.Format (“Property{0}Required”, propCount)] = required;
}
if (propCount >0) {
using (SSDSClient.SitkaSoapServiceClient ssdsProxy = new SSDSClient.SitkaSoapServiceClient()) {
//Set username and password for the service
...
//Set service scope to the main contoso classifieds
//authority. Point it to the categories container
...
//If this entity doesn't exist, create it
if (listingSchemaID == “” || listingSchemaID == null) {
ssdsProxy.Create(serviceScope, listingSchemaEntity);
}
//Otherwise update it
else {
serviceScope.EntityId = listingSchemaID;
ssdsProxy.Update(serviceScope, listingSchemaEntity);
}
}
MessageBox.Show(“Custom Schema Saved”, “Custom Schema Saved”,
MessageBoxButtons.OK, MessageBoxIcon.Information);
this.Hide();
}
管理客户端的最后一项工作是在列表类别被删除时删除自定义列表架构。我之前讨论过删除实体和容器,但那时我知道要删除的实体或容器的 ID。删除架构意味着首先要发出 LINQ 查询以检索附加到列表类别的所有列表架构,然后再将其删除。查询内容如下所示:
string.Format(@“from e in entitieswhere e.Id == ”“{0}”“ select e”, CategoryID);此查询将返回 ListingSchema 实体的列表,此时您需要做的就是将其删除。图 10 显示了完整的 DeleteListingSchema 方法。
图 10 DeleteListingSchema
//Retrieve the custom schema entity for this listingstring linqQuery = string.Format(@“from e in entities where e.Id == ”“{0}”“ select e”, CategoryID);ListssdsProxy.Query(serviceScope, linqQuery);
foreach (SSDSClient.Entity entity in entities) {
//If more than 1 flex property on the entity, the
//header has listing categories attached to it.
if (entity.Properties.Count >1) {
//Calculate the number of Listing Categories
int propCount = ((entity.Properties.Count - 1) / 2);
for (int x = 1; x < propCount + 1; x++) {
//Delete the listing schema for each listing
//in this category
DeleteListingSchema(entity.Properties[“ListingCategoryID” +
x.ToString()].ToString());
}
}
}
此时,Contoso Classifieds Administration 客户端已完成,我可以继续使用 SSDS 的 REST 接口来实现网站。
分类 Web 应用程序
如前所述,您可以通过 SSDS 的 REST 接口和 SOAP 接口对其进行访问(就像我对 Contoso Classifieds Administration 客户端所做的那样)。无论选择哪个接口,概念和功能都是相同的,但使用 REST 会直接调用 HTTP(或 HTTPS)。
在开始之前,先回顾一下图 1 中所示的 Web 应用程序主界面。有一个代表列表类别的树视图、一个主内容区域以及一个由当前受应用程序支持的所有城市组成的 Datalist。仔细看一下各个部分,我将向您展示基于 SSDS 来开发 ASP.NET 应用程序是多么容易。
如果您看一下树视图的 ASPX 代码,就会发现它其实非常简单:
Groups
nselectednodechanged=“TreeView1_SelectedNodeChanged”>
奇妙的事情发生在隐藏的代码中,如图 11 所示。您面对的第一件事情就是构建 URI,即指向 Categories 容器的指针。由于此数据并不是特定于城市的,因此我选择将其存储在主 contosoclassifieds 颁发机构中的 Categories 容器内。
图 11 构建树视图
TreeView1.Nodes.Clear();appDataUri = string.Format(@“{0}.{1}{2}”,conSSDSAuthName, conSSDSUri, “Categories”);query = @“from e in entities where e.Kind == ”“Category”“ select e”;UriBuilder newUri = new UriBuilder(appDataUri);newUri.Query = String.Format(“q='{0}'”, Uri.EscapeDataString(query));string xmlResults =HTTPHelper.GetHTTPWebRequest(newUri.Uri.ToString(),new System.Net.NetworkCredential(conSSDSUsername, conSSDSPassword));XmlDocument categoriesDoc = new XmlDocument();categoriesDoc.LoadXml(xmlResults);XmlNodeList nodeList = categoriesDoc.SelectNodes(“//Category”);int nodeIndex = 0;foreach (XmlNode node in nodeList) {if (node.ChildNodes.Count >3) {int propCount = ((node.ChildNodes.Count - 1) / 2);TreeNode tn = new TreeNode(node.ChildNodes[2].InnerText,node.ChildNodes[0].InnerText);TreeView1.Nodes.Add(tn);for(int x=1;xtn = new TreeNode(node.ChildNodes[(x*2)+2].InnerText,
node.ChildNodes[(x*2)+1].InnerText);
TreeView1.Nodes[nodeIndex].ChildNodes.Add(tn);
}
}
else {
TreeNode tn = new TreeNode(node.ChildNodes[2].InnerText, node.ChildNodes[0].InnerText);
TreeView1.Nodes.Add(tn);
}
nodeIndex++;
}
之后,我继续使用 LINQ 查询来检索具有 Kind 类别的所有实体,然后再使用 UriBuilder 对象将其放在一起并添加必要的 HTTP 转义。接下来,我调用 GetHTTPWebRequest 方法,并使用 SSDS 用户名和密码传入转义的 URI 和 NetworkCredential 对象。GetHTTPWebRequest 返回字符串形式的 EntitySet 以及满足查询谓词的所有实体。
GetHTTPWebRequest 是一种静态辅助方法,可隐藏某些 HTTP 细节:
WebRequest request =HttpWebRequest.Create(Uri.EscapeUriString(serviceUri));request.Credentials = requestCredential;request.Method = “GET”;request.ContentType = XmlContentType;// Get the response and read it in to a string.using (HttpWebResponse response =(HttpWebResponse)request.GetResponse()) {return ReadResponse(response);}现在需要做的就是创建一个新 WebRequest 对象、设置传递给该对象的凭据、设置相应的 HTTP 动词、将 ContentType 设置为 XML 以及调用 GetResponse 方法。接下来调用 ReadResponse,这是另一个静态辅助方法,它使用流读取器读取 HTTPResponse 并将其返回给调用方。隐藏的代码随后将获取返回的 XML、将其加载到 XmlDocument 中并加载其中的树视图。
类反序列化
在此之前,代码一直只是手动操作 XML,但也可以很容易地获取实体并将其反序列化为一个类。在本例中,应用程序将使用 CityServed 类。
基本 Entity 类是一个相当初级的类。该类同时包含 ID 和 Version 的属性,而这些属性为所有实体所共有。此外,它还包含序列化类时所必需的一些属性。
CityServed(如图 12 所示)继承自基本 Entity 类。泛型 Query 方法将返回 CityServed 类型实体的列表:
foreach (CityServed i in HTTPHelper.QueryappDataUri, query, new System.Net.NetworkCredential(
conSSDSUsername, conSSDSPassword)))
图 12 CityServed
[XmlRoot(ElementName = “CityServed”, Namespace = “”)]public class CityServed : Entity {[XmlElement(ElementName = “AuthorityUri”)]public object AuthorityUriField;[XmlElement(ElementName = “Name”)]public object NameField;public override string ToString() {return Name;}[XmlIgnore]public string AuthorityUri {get { return (string)AuthorityUriField; }set { AuthorityUriField = value; }}[XmlIgnore]public string Name {get { return (string)NameField; }set { NameField = value; }}}Query 方法包括在本文的代码下载中,它只是一种泛型静态辅助方法,用于调用我们之前使用过的 GetHTTPWebRequest 方法。图 13 中显示了 Serialize 和 Deserialize 方法。Query 方法与 Serialize 和 Deserialize 方法相结合,允许您使用强类型化 .NET 对象并将其保存在 SSDS 中。
图 13 序列化和反序列化实体
private static T DeserializeXmlSerializer ser = new XmlSerializer(typeof(T));
T flex = (T)ser.Deserialize(stm);
XmlDocument xDom = new XmlDocument();
xDom.LoadXml(xmlPayload);
return flex;
}
public static T Deserialize
using (MemoryStream stm = new MemoryStream()) {
Encoding encoding = new UTF8Encoding(false);
stm.Write(encoding.GetBytes(xmlPayload), 0, encoding.GetByteCount(xmlPayload));
stm.Position = 0;
return Deserialize
}
}
public static string Serialize
using (MemoryStream stm = new MemoryStream()) {
Serialize(stm, flex);
stm.Position = 0;
using (StreamReader reader = new StreamReader(stm)) {
return reader.ReadToEnd();
}
}
}
private static void Serialize
XmlSerializer ser = new XmlSerializer(typeof(T));
Encoding encoding = new UTF8Encoding(false);
XmlWriterSettings settings = new XmlWriterSettings();
settings.CloseOutput = false;
settings.ConformanceLevel = ConformanceLevel.Document;
settings.Encoding = encoding;
settings.Indent = true;
settings.OmitXmlDeclaration = true;
using (XmlWriter writer = XmlWriter.Create(stm, settings)) {
ser.Serialize(writer, flex);
}
}
使用自定义列表架构。
如前所述,SSDS 实体非常灵活,因为每个实体都可以具有您需要的任何形式。例如,Contoso Classifieds Administration 客户端为您提供了向列表类别添加架构的能力。您还可以从 SSDS 中抽出自定义架构并动态创建可用来向系统中添加列表的输入窗体。
第一步创建包含以下四列的 DataTable:Field、Value、DataType 和 Required。此表将存储管理员为列表定义的字段。接着我将执行查询以了解是否已为列表定义了自定义架构:
string appDataUri = string.Format(@“{0}.{1}{2}”,conSSDSAuthName, conSSDSUri, “Categories”);string query = string.Format(@“from e in entities where e[”“ListingID”“] == ”“{0}”“ select e”,listingCategoryID);UriBuilder newUri = new UriBuilder(appDataUri);newUri.Query = String.Format(“q='{0}'”, Uri.EscapeDataString(query));string xmlResults = HTTPHelper.GetHTTPWebRequest(newUri.Uri.ToString(),new System.Net.NetworkCredential(conSSDSUsername, conSSDSPassword));XmlDocument categoriesDoc = new XmlDocument();categoriesDoc.LoadXml(xmlResults);XmlNodeList nodeList = categoriesDoc.SelectNodes(“//ListingSchema”);然后我可以将返回的 XML 加载到 DataTable 中并将其绑定到 DataList。
在 REST 接口中,您需要构建实体的 XML 表示并向要将实体插入其中的容器发出 HTTP POST。构建实体非常容易,您只需使用样板实体并对每个字段执行循环,然后将其作为节点添加到 XML 文档中即可:
foreach (DataListItem fieldItem in dlAddFields.Items) {Label lblField = (Label)fieldItem.FindControl(“lblAddField”);TextBox tbItem = (TextBox)fieldItem.FindControl(“txtAddValue”);Label lblFieldType = (Label)fieldItem.FindControl(“lblAddFieldType”);entity = entity + String.Format(@“ <{0} xsi:type='x:{1}'>{2}”, lblField.Text.Replace(“ ”, “”),lblFieldType.Text, tbItem.Text);}最后,构建 URI 以指向要执行 POST 操作的容器并发出 POST:
string serviceUri = string.Format(@“{0}.{1}{2}”,postingAuthority, conSSDSUri, postingContainer);HTTPHelper.PostHTTPWebRequest(serviceUri, entity,new System.Net.NetworkCredential(conSSDSUsername, conSSDSPassword));展望
SSDS 很容易进行开发。我想重申的一点是:SSDS 是构建在可靠的 SQL Server 和 Windows Server® 技术之上的。团队决定仅在 SSDS 的初始试用版中公开有限的功能集,实际上其功能远不止这些。现在可供使用的功能子集将帮助解决客户需要处理的许多问题。
David Robinson 是 Microsoft SQL Server 数据服务团队的高级项目经理。他的任务是向产品中加入一些引人注目的新功能。他还喜欢参加社区活动,并且非常希望收到有关 SSDS 的客户反馈。
篇2:使用MEF构建可扩展的Silverlight应用
“托管扩展性框架(Managed Extensibility Framework,简称MEF),是微软 .NET框架下为提高应用和组件复用程度而推出的,用于使组件能够最大化的重用 ,使用MEF能够使静态编译的.NET应用程序转换为动态组合,这将是创建可扩展应 用、可扩展框架和应用扩展的好途径。它将做为.NET Framework 4.0的组成部分 之一发布。现在,MEF也将被包含在Silverlight 4.0中。
那么MEF是怎样工作的呢?简单分为三个步骤:
Export (输出)
Import (输入)
Compose (组合)
简短说一下MEF的工作原理,MEF的核心包括一个catalog和一个 CompositionContainer。category用于发现扩展,而container用于协调创建和梳 理依赖性。每个可组合的Part提供了一个或多个Export,并且通常依赖于一个或 多个外部提供的服务或 Import。每个Part管理一个实例为应用程序运行。
下面我们做一个小型可扩展计算器示例来解释这三个过程
1.首先下载MEF框架包,Silverlight 4.0会自带,不过微软已经将其开源了。
www.codeplex.com/MEF
2.创建一个Silverlight Navigate Application ,并添加程序集引用 (MEF_Beta_2\bin\SL目录下 System.ComponentModel.Composition.dll)
在项目下添加两个类文件Package.cs和PackageCatalog.cs,这两个文件在最 新的MEF版本中没有提供,主要用于加载silverlight的Xap包。
这两个文件在MEF框架的Sample中提供了(MEF_Beta_2 \Samples\PictureViewer\pic.ruiwen.common),将这两个类的访问修饰符改 为public, 添加后注意修改命名空间。
3.修改Home.cs 类
代码
using System;using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using System.ComponentModel;
namespace MefDemo
{
//用于更新界面的委托
public delegate void OperateHandler(IOperate Op);
///
/// 运算器接口
///
public interface IOperate
{
double Op(double left, double right);
string Symbol { set; get; }
string Label { get; set; }
}
///
/// 加法运算器
///
[Export(typeof(IOperate))]
public class AddButton : Button, IOperate
{
[Import (“AddButtonContract”,AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“AddSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left + right;
}
#endregion
public AddButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 减法运算器
///
[Export(typeof(IOperate))]
public class SubButton : Button, IOperate
{
[Import (“SubButtonContract”,AllowRecomposition=true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“SubSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left - right;
}
#endregion
public SubButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 为每个运算器的属性提供值
///
public class ComponentAttributeProvider
{
[Export(“AddButtonContract”)]
public string AddLabel { get { return “Add”; } }
[Export(“AddSybomContract”)]
public string AddSymbol { get { return “+”; } }
[Export(“SubButtonContract”)]
public string SubLabel { get { return “Sub”; } }
[Export(“SubSybomContract”)]
public string SubSymbol { get { return “-”; } }
}
}4.修改 Home.xaml
代码
xmlns=“schemas.microsoft.com/winfx//xaml/presentation”
xmlns:x=“schemas.microsoft.com/winfx/2006/xaml”
xmlns:d=“schemas.microsoft.com/expression/blend/” xmlns:mc=“schemas.openxmlformats.org/markup- compatibility/2006”
xmlns:navigation=“clr- namespace:System.Windows.Controls;assembly=System.Windows.Controls.Navi gation”
mc:Ignorable=“d” d:DesignWidth=“640” d:DesignHeight=“480”
Title=“Home”
Style=“{StaticResource PageStyle}”>
5.新建类 OperatorComponent.cs
代码
using System;using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using System.ComponentModel;
namespace MefDemo
{
//用于更新界面的委托
public delegate void OperateHandler(IOperate Op);
///
/// 运算器接口
///
public interface IOperate
{
double Op(double left, double right);
string Symbol { set; get; }
string Label { get; set; }
}
///
/// 加法运算器
///
[Export(typeof(IOperate))]
public class AddButton : Button, IOperate
{
[Import (“AddButtonContract”,AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“AddSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left + right;
}
#endregion
public AddButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 减法运算器
///
[Export(typeof(IOperate))]
public class SubButton : Button, IOperate
{
[Import (“SubButtonContract”,AllowRecomposition=true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“SubSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left - right;
}
#endregion
public SubButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
///
/// 为每个运算器的属性提供值
///
public class ComponentAttributeProvider
{
[Export(“AddButtonContract”)]
public string AddLabel { get { return “Add”; } }
[Export(“AddSybomContract”)]
public string AddSymbol { get { return “+”; } }
[Export(“SubButtonContract”)]
public string SubLabel { get { return “Sub”; } }
[Export(“SubSybomContract”)]
public string SubSymbol { get { return “-”; } }
}
}6.运行,
这样就构建了一个简单的运算器,其中的Export、Import就像一个 个管道一样相互连接。
# 按照这样的设计,我们想要对其进行扩展,就必须把接口分离。新建一个 Silverlight ClassLibrary Project(Named ContractLibrary),这个Library用来 封装所有的扩展接口,定义Import/Export契约。
现在把原项目中的OperatorComponent.cs 类中的接口迁移到Library项目中, 新建类文件OperateContract.cs 。
代码
using System;using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
namespace ContractLibrary
{
public delegate void OperateHandler(IOperate Op);
///
/// 运算器接口
///
public interface IOperate
{
double Op(double left, double right);
string Symbol { set; get; }
string Label { get; set; }
}
}编译通过后在Silverlight主工程(MefDemo)中添加对ContractLibrary项目的 引用
# 再新建一个Silverlight ClassLibrary Project (Named StaticExtension),,这个工程就是我们用来静态扩展的DLL。
a).在工程下新建我们的运算器类,AddButton.cs , SubButton.cs.(代码不变 ).
b).但注意要添加对ContractLibrary项目的引用和MEF的框架集引用) 。
c).添加全局属性配置类(ComponentConfiguration.cs)
d).删除主工程中的ComponetOperater.cs.
e).添加对StaticExtension的引用.
OK,这样我们就可以任意扩展运算器,添加更多的扩展运算了。
那么下面是添加一个新的乘法运算所要做的工作。
在StaticExtension中添加新类 Multiply.cs
代码
using System;using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using ContractLibrary;
namespace StaticExtension
{
///
/// 乘法运算器
///
[Export(typeof(IOperate))]
public class MultiplyButton : Button, IOperate
{
[Import(“MultiplyButtonContract”, AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“MultiplySybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left * right;
}
#endregion
public MultiplyButton()
{
this.Click += (s, e) =>ClickAction (this);
}
}
}# 上面的是静态加载,那么现在我们使用MEF实现动态扩展运算器。桌面程序 的动态扩展是动态加载DLL,而对于Silverlight的Web程序则是动态加载Xap包了 。
新建普通Silverlight Application(Named DynamicExtension).
11.去掉勾选Add a test page that references the application.
1).删掉App和Main等不必要的文件,只留一个空的Silverlight项目,以减少 Xap包的大小。
2).添加ContractLibrary和MEF框架集的引用(可以将引用程序集属性 CopyLocal设置为false,因为我们在主工程中已经添加了,可以重用)
3).添加类Division.cs.
代码
using System;using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
using ContractLibrary;
namespace DynamicExtension
{
///
/// 乘法运算器
///
[Export(typeof(IOperate))]
public class DivisionButton : Button, IOperate
{
[Import(“DivisionButtonContract”, AllowRecomposition = true)]
public string Label { get { return this.Content.ToString(); } set { this.Content = value; } }
[Import(“DivisionSybomContract”, AllowRecomposition = true)]
public string Symbol { set; get; }
[Import(“ClickHandler”)]
public OperateHandler ClickAction { get; set; }
#region IOperate 成员
public double Op(double left, double right)
{
return left * right;
}
#endregion
public DivisionButton()
{
this.Click += (s, e) => ClickAction(this);
}
}
}4).添加配置类ComponentConfiguration.cs
代码
using System;using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel.Composition;
namespace DynamicExtension
{
///
/// 为每个运算器的属性配置值
///
public class ComponentConfiguration
{
[Export(“DivisionButtonContract”)]
public string AddLabel { get { return “Div”; } }
[Export(“DivisionSybomContract”)]
public string AddSymbol { get { return “/”; } }
}
}5).修改Home.cs ,为其注册下载包的相关事件和回调
1.代码
using System;using System.Windows;using System.Windows.Controls;using System.Windows.Navigation;using System.Collections.ObjectModel;using System.ComponentModel.Composition.Hosting;using System.Reflection;using System.ComponentModel.Composition;using ContractLibrary;namespace MefDemo{public partial class Home : Page{[ImportMany(typeof (IOperate),AllowRecomposition = true)]public ObservableCollection[Export(“ClickHandler”)]
public OperateHandler ClickHandler { get { return OperateButton_Click; } }
private PackageCatalog Catalog;
///
/// 用于界面控件响应运算后的一些更新工 作
///
///
Ok,最终界面。
点击DynamicLoadOperate按钮后
程序中还有很多细节没有展开说明,理论性的介绍可以参考MSDN和CodePlex上 的文档。
源码下载:download.csdn.net/source/2062158
篇3:基于可扩展计算机网络设计软件系统的开发设计的论文
基于可扩展计算机网络设计软件系统的开发设计的论文
根据人们对现代智能通信的需求,研究可扩展计算机网络软件系统的开发和设计,从而为计算机网络技术今后的发展提供建议。
1计算机网络设计软件的可扩展性
实现软件的可扩展性是所有软件开发人员的目的,其能够使软件的使用寿命有效延长,此种可扩展性不仅表现在软件规模方面,还表现在软件功能方面。基于可扩展性的计算机网络软件使用具有独特的功能,此种计算机网络技术的使用的扩展主要从三方面出发:
(1)软件功能。可视化软件功能的可扩展性主要表现为以下方面:通过网络技术功能的创新,在展现全新网络产品功能的基础上将软件网络化协议功能相互结合,实现网络技术发展的有效追踪。
(2)性能分析。在性能分析方面,以网络技术规模化的发展为基础,实现网络优化设计及使用。根据全新的性能模型,全面评价项目的设计质量。以软件使用能力的便捷化使用能够有效创建全新的性能模型结构。
(3)软件外部接口。在实现计算机软件外部接口的基础上,全面分析网络设计项目并且将其保存,重视网络设计管理的规范化,实现软件的优化设计,对软件外部接口进行全面优化,实现接口的可扩展性。
2系统的分析和实现
(1)系统的结构分析。以计算机网络设计的内容为基础,能够将软件分为四个基础功能:分别为系统调度模块,其主要目的就是实现系统功能的调度;网络拓扑设计模块,其主要目的就是设计可视化网络拓扑结构,并且划分子网、网络路由及网络设计参数;网络性能分析,其主要目的就是以软件系统的设计的性能需求为基础创建性能分析模型,全面分析网络的运行效果、安全性及开销;网络性能仿真,其主要目的就是实现网络的仿真运算。
为了有效实现系统软件外部功能的扩展,在设计过程中还要添加数据库接口模块,实现系统和数据库的接口连接,使用标准化数据库系统及软件系统完成接口设计,软件使用分层模型进行设置,将所有的功能模块相互结合,图1为系统的结构图。通过下图可以看出来,将软件分为两层结构,系统第一层主要包括调度模块,通过网络设计参数、对象实现和第二层接口实现此层的功能,并且将第二层和操作系统接口实现软件系统的调度功能。软件的第二层主要包括网路仿真模块、网络拓扑设计及性能分析,其主要目的就是實现软件的具体使用功能及软件的全新功能。根据基于数据库的多层软件体系结构,数据库结构的`主要目的及时连接数据库和其他软件系统,其虽然在软件系统中的,但是并没有被存放到分层结构中,其是一个独立的设备参数,将系统中的功能模块进行相互连接,其通过面向对象实现创建。软件其他部分的功能实现都是相互独立的,但是和网络设备参数和对象共享接口。在调用第二层功能的时候,软件第一层能够对数据访问接口进行更改。因为所有的数据都是根据共享数据进行,假如共享数据的结构不发生变化,网络功能扩展的主要目的就是创建完善的网络设备数据库。
(2)系统设计过程中的问题。在设计网络软件过程中,首先要进行网络拓扑图编辑及处理,在网络设计过程中,创建设备并且删除,从而实现划分设备,实现子网创建及管理。在网络配置过程中,根据网络的应用及配置优化进行项目化合理设计,并且进行数据库设计的优化及使用。在展示设备过程中,要实现设备工作的配置和仿真处理。
(3)标示对象及类。在进行对象及类标示的过程中,尤为重要的就是实现对象的使用及分析,在进行软件结构的实现过程中,以此能够有效表现出软件系统特殊的扩展能力。在进行系统调度的时候,要实现网络拓扑的优化设计,将网络仿真的使用为基础,重视性能优化设计和分析,从而全面分析仿真性能及运算,展现出系统的功能性。根据软件的功能进行扩展,并且使用网络设备对象,创建有效的网络设备及类。
篇4:如何将使用PB5开发的应用程序平滑迁移到PB6
如何将使用PB5开发的应用程序平滑迁移到PB6
PowerBuilder作为客户/服务器(Client/Server)方式下开发数据库应用程序的主要开发工具,在中国拥有大量的用户,很多程序员至今仍在使用这个4GL开发工具。PowerBuilder可以支持各种主流关系型数据库,包括ORACLE、SYBASE、INFORMIX、DB2等,以及各种单机版本的个人数据库,包括ACCESS、SQL ANYWHERE、FOXPRO、DBASE等,它具有强大的数据库开发功能,很多在其他开发工具中需要多行代码才能完成的工作,在PowerBuilder中只需一行代码,就可顺利完成。正因为如此,它几乎成为开发数据库应用的事实标准,尤其是它独创的数据窗口(DATA WINDOW)技术,为广大程序员津津乐道。虽然在某些情况下它的可视化编程能力不如VB、DELPHI等其他4GL开发工具,尤其是设置对象属性的方法落后于前者,编写脚本语言时对一个对象不支持多窗口修改(PB5、PB6版本),比较繁琐,但它强大的开发能力,仍得到广大程序员的认可,国内应用该工具(尤其是PowerBuilder5版本)开发的C/S应用程序比比皆是。但Sybase公司宣布PowerBuilder5版本不再提供对2000年的支持,并相继推出了PowerBuilder6、PowerBuilder7,作为PowerBuilder5的升级换代产品,广大程序员使用PowerBuilder5开发的应用程序必须平滑过渡到PowerBuilder6及其后续版本上,才能保证能安全应对2000年可能带来的各种问题。
PowerBuilder6虽然在功能上比PowerBuilder5版本有明显增强,尤其是在分布式计算、WEB开发方法和跨平台技术方面有显著提高,但两者在开发界面上变化不大,广大程序员在开发方式上几乎不需要太多地考虑两者之间的变化;在程序代码的设计上,PowerBuilder6淘汰了原来部分通过专用函数和事件,增加了一些新的对象事件和函数。SYBASE公司在PowerBuilder6软件包中提供了
PB迁移助手(PowerBuilder Migration Assistant),帮助程序员顺利完成迁移。为此,必须将原有使用PowerBuilder5开发的部分代码,修改为使用PowerBuilder6方式开发的代码,因为这些淘汰代码在以后的PowerBuilder版本中将不再提供支持。
当程序中存在淘汰代码时,在迁移过程中可能会发生迁移错误,造成无法正常生成PowerBuilder6版本的PBL文件,甚至连PowerBuilder5版本的PBL文件也可能无法使用。因此,在使用PowerBuilder迁移之前,必须修改相应代码,以保证迁移能顺利进行。
下面介绍如何使用PowerBuilder迁移助手,将原有使用PowerBuilder5开发的应用程序,安全地迁移(Migrate)到PowerBuilder6版本。首先,选择开始菜单→程序→Powersoft→PowerBuilder6→Migration Assistant,进入PowerBuilder迁移助手,见图1.
图1 打开迁移助手(Migration Assitant)
使用PowerBuilder迁移助手完成迁移,主要有三个步骤:
使用迁移助手,指定要迁移的PowerBuilder5版本的源程序库文件(PBL)。
选择PowerBuilder迁移助手的Select Libraries活页,在左侧的文件管理器窗口中,指定要迁移的PBL文件,双击相应的PBL文件;或者右击鼠标,在弹出菜单中选择Select library,则相关的PBL文件被依次显示在右侧的.窗口中,见图2.要清除检查的
PBL文件,双击选定的PBL文件即可,若清除全部文件,右击鼠标,选择Clear All菜单。
图2 指定要扫描的PBL文件
指定要检查PBL内容的方式。
对于在PowerBuilder6中无效的函数和事件,Sybase建议使用新版本中的语法和事件,因为部分PowerBuilder5的函数和事件以后不会继续支持。
选择Options活页,指定要检查的语法类型。这里可以检查的语法类型有PFC语法、PowerScript脚本语法、FUNCky语法和自定义的语法函数、过程等。见图3.
图3 指定扫描的类型
其中,PFC语法检查会明确给出在PowerBuilder作废的PFC事件和函数;而FUNCky功能在PowerBuilder6中将不再支持;PowerScript脚本检查会显示新版本中不支持PowerScript的事件和函数;你也可以指定一个TXT文本文件,里面包含你自定义的无效函数和事件,定制(CUSTOM)检查会扫描在PBL中自定义的无效函数和事件。
完成扫描,并根据扫描结果修改代码。
在指定全部PBL文件后,选择迁移助手右下角的Search按钮,迁移助手开始对全部选择的PBL文件,按指定的检查范围进行详细的检查,见图4.
扫描检查完毕后,迁移助手在
Search Results窗口中显示建议修改的代码对象、事件、函数名称,以及修改的方法等,见图5,你只需按照扫描结果的提示,打开PowerBuilder5,修改原来的代码并改为PowerBuilder6支持的方式,然后存盘,(注意:在修改前请一定要正确备份原始文件,以便在发生意外时可以安全恢复),然后,你就可以在PowerBuilder中使用前面介绍的方法顺利完成迁移了。
图4 开始扫描过程
图5 显示扫描结果
只要按照上面的步骤,正确完成了PowerBuilder6迁移升级前的准备,一定可以顺利的完成应用程序升级。最后再提醒一次,在迁移之前,千万不要忘记事先备份源代码,以免发生意外呦。
我的联系电话是:010-66747858
010-62046688呼7653
北京市朝阳区华严北里5号 100029












