苔藓 / InfoPath 表单服务器 (InfoPath 2007) 下拉列表中的性能

其他类别: InfoPath

摘要: InfoPath 2007 窗体部署到 MOSS 服务器提供供应商绑在 MOSS 的自定义列表的下拉列表. 在选择供应商, 规则将字段值分配给少量的文本字段 (例如销售代表名称, 地址, 城市, 状态, 邮编和电话. 性能很可怕. 我们注意到性能变得更糟 (非线性方式) 对于每个额外的字段,我们更新了这种方式. 即, 如果我们只是,更新销售代表姓名, 花 [x] 时间. 如果我们更新销售代表, 地址 1, 地址 2, 城市, 状态, 邮编, 花 10 时间更长.

解决方案: 编写的 web 服务 (可以找到示例代码 在这里) 这通过一个供应商的名称和它回返回供应商详细信息. 然后, 这种方式分配字段. 虽然这似乎太慢, 我们分配时没有明显的性能差异 1 与字段 8 字段. 作为额外的奖励, 用户可以得到"与服务器联系酷" 赛昂 虽然他们等待窗体调用和消费服务结果的影响.

苔藓: 出现异常. (HRESULT 的异常: 0x 80020009 (DISP_E_EXCEPTION))

更新: 我们永远不会确定此问题和它从来没有表面的根本原因.

我们注意到在发展地盘实施过程中突然, 两个用户都无法访问网站集合. 这些帐户可以验证到主站点, 但当试图访问特定网站集, 他们只是得到一个空白屏幕. 不显示错误, 只是一个白色的空白页.

我们以站点集合管理员的身份登录,并尝试添加这些用户之一,站点管理员以及此时间, 后按下"确定", 我们得到此消息:

出现异常. (HRESULT 的异常: 0x 80020009 (DISP_E_EXCEPTION))

我们花了一些时间研究这个,不幸的是, 想出来任何有用的东西. 诊断日志中有一些消息, 但很难完全将它们关联起来这个问题.

在结束, 我们的网站集删除和重新创建它,解决它.

如果我找出是什么导致这在将来, 我将更新这个帖子.

苔藓: 迭代通过自定义列表和返回到 InfoPath 的筛选的数据

业务方案:

提供一种方法,使用户可以快速输入准确的采购申请.

业务问题:

客户端与几个几百个供应商做生意.

供应商"类型" 具体. 这意味着供应商销售计算机设备 (例如:. 戴尔) 或办公用品 (例如:. 钉书钉).

我们如何使最终用户创建一个有效的供应商的采购请购单选择?

业务解决方案:

在"类型"通过系统中区分供应商.

使用户能够选择"类型" 产品,然后提供适当的供应商筛选的集.

技术解决方案:

InfoPath 表单而设计使用户能够输入在线购买请购单.

两个 InfoPath 选择列表控制选择供应商. 第一次, 用户选择"采购类型". 这就限制了第二次的选择列表包含只有卖那采购类型的供应商. 这是一个经典的级联下拉.

供应商存储在 MOSS 与供应商的属性,如名称的自定义列的自定义列表, 地址和特别是"类型".

要消耗的 InfoPath 客户端的 web 服务实现循环访问自定义供应商列表, 返回只有供应商匹配提供的"类型".

调用 web 服务通过 InfoPath 表单.

吸取的教训:

  • 第一次, 看来有必要走这条路. 我宁愿做完全属于 InfoPath 的筛选并不创建任何的 web 服务功能. 不过, 表单服务器不提供所需的筛选功能. 我们可以把放到规则"类型" 选择列表中的重新打开供应商查询窗体, 但我们不能让它正常工作. 因此, 这是有必要实现的 web 服务.
  • 这是一个经典"级联选择列表" 在 InfoPath 中的问题形成服务器世界并且有很好的例子很多外面解释如何解决这一问题.
  • 供应商列表中的列的为空值不会返回一个空字符串时这样引用: initItem["供应商名称"]. 相反, 它将返回 null.

一些其他笔记:

  • 返回一个[] 供应商的因为一些难以返回数组. InfoPath 抱怨它和我没有时间或倾向去争. 这, 答案是肯定的, 人工限制放的供应商总数. 它也迫使我执行修剪() 方法在阵列上的因为我痛恨的返回回 100 的空供应商. InfoPath 不关心, 但它唠唠叨叨我. (再次, 这是比 InfoPath 争夺数组列表更容易).
  • 我实施 GetSpecificVendorByName() 功能以及为, 这可能是有教育意义.

代码:

使用 系统;
使用 System.Web;
使用 System.Web.Services;
使用 System.Web.Services.Protocols;
使用 Microsoft.SharePoint;
使用 System.Configuration;

/// <摘要>
///
供应商服务: 提供了相关的供应商服务,今天由 infopath 客户端窗体.
///
/// 历史:
/// ——–
/// 07/24/07: 初始编码, Paul J. 加文的 Conchango.
///
/// </摘要>
[Web 服务(Namespace = "http://www.conchango.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
公众 VendorService : System.Web.Services.Web 服务
{

/// <摘要>
/// 表示由 MSUSA 维护的自定义 sharepoint 列表中的供应商.
/// </摘要>
公众 供应商
{
公众 供应商() { }

公众 供应商(SPItem initItem)
{
如果 (! (initItem["供应商名称"] == 则为 null)) VendorName = initItem["供应商名称"].ToString();
如果 (! (initItem["地址 1"] == 则为 null)) VendorAddress1 = initItem["地址 1"].ToString();
如果 (! (initItem["地址 2"] == 则为 null)) VendorAddress2 = initItem["地址 2"].ToString();
如果 (! (initItem["城市"] == 则为 null)) VendorCity = initItem["城市"].ToString();
如果 (! (initItem["VendorPhone"] == 则为 null)) VendorPhone = initItem["VendorPhone"].ToString();
如果 (! (initItem["PurchaseType"] == 则为 null)) VendorType = initItem["PurchaseType"].ToString();
如果 (! (initItem["状态"] == 则为 null)) VendorState = initItem["状态"].ToString();
如果 (! (initItem["邮编"] == 则为 null)) VendorZip = initItem["邮编"].ToString();
如果 (!(initItem["传真"] == 则为 null)) VendorFax = initItem["传真"].ToString();
如果 (!(initItem["SalesRepName"] == 则为 null)) VendorSalesRepName = initItem["SalesRepName"].ToString();

VendorItemId = initItem.ID; // 保持通过 MOSS 的唯一 ID.
}

公众 int VendorItemId;
公众 字符串 VendorName;
公众 字符串 VendorAddress1;
公众 字符串 VendorAddress2;
公众 字符串 VendorCity;
公众 字符串 VendorState;
公众 字符串 VendorZip;
公众 字符串 VendorPhone;
公众 字符串 VendorType;
公众 字符串 VendorSalesRepName;
公众 字符串 VendorFax;
}

公众 VendorService () {

//取消注释以下行如果使用设计的部件
//InitializeComponent();
}

私人 供应商[] GenerateTestVendors()
{
供应商[] resultList;
resultList = 新增功能 供应商[100];

供应商 v;
v = 新增功能 供应商();
v.VendorAddress1 = "v1_address1";
v.VendorAddress2 = "v1_address2";
v.VendorCity = "v1_city";
v.VendorName = "v1_vendorname";
v.VendorPhone = "v1_vendorphone";
v.VendorState = "v1_st";
v.VendorType = "v1_type";
v.VendorZip = "v1_zip";

resultList[0] v =;

v = 新增功能 供应商();

v.VendorAddress1 = "v2_address1";
v.VendorAddress2 = "v2_address2";
v.VendorCity = "v2_city";
v.VendorName = "v2_vendorname";
v.VendorPhone = "v2_vendorphone";
v.VendorState = "v2_st";
v.VendorType = "v2_type";
v.VendorZip = "v2_zip";

resultList[1] v =;

v = 新增功能 供应商();
v.VendorAddress1 = "v3_address1";
v.VendorAddress2 = "v3_address2";
v.VendorCity = "v3_city";
v.VendorName = "v3_vendorname";
v.VendorPhone = "v3_vendorphone";
v.VendorState = "v3_st";
v.VendorType = "v3_type";
v.VendorZip = "v3_zip";

resultList[2] v =;

返回 resultList;

}

[WebMethod]
公众 供应商 GetSpecificVendorById(int vendorId)
{
字符串 SpVendorSiteName; // 主机供应商自定义列表的实际的 MOSS 站点名称.
字符串 SpVendorListName; // 实际的苔藓列表包含供应商的名称.

SpVendorSiteName = ConfigurationSettings.AppSettings["VendorListHostingSite"].ToString();
SpVendorListName = ConfigurationSettings.AppSettings["VendorList"].ToString();

使用 (SPSite 网站 = 新增功能 SPSite(SpVendorSiteName))
{

使用 (SPWeb web = 网站。OpenWeb())
{

写入 currentList = web。列表[SpVendorListName];

SPItem specificItem = currentList.Items[vendorId];

返回 新增功能 供应商(specificItem);

} // 使用 spweb web = site.openweb()
} // 使用 spsite 网站 = 新 spsite("http://本地主机/瑞穗")

}

[WebMethod]
// 假设供应商名称是唯一, 从业务的角度
公众 供应商 GetSpecificVendorByVendorName(字符串 将)
{
字符串 SpVendorSiteName; // 主机供应商自定义列表的实际的 MOSS 站点名称.
字符串 SpVendorListName; // 实际的苔藓列表包含供应商的名称.

SpVendorSiteName = ConfigurationSettings.AppSettings["VendorListHostingSite"].ToString();
SpVendorListName = ConfigurationSettings.AppSettings["VendorList"].ToString();

使用 (SPSite 网站 = 新增功能 SPSite(SpVendorSiteName))
{
使用 (SPWeb web = 网站。OpenWeb())
{

写入 currentList = web。列表[SpVendorListName];

foreach (SPItem vendorItem 在中 currentList.Items)
{
如果 (vendorItem["供应商名称"] == 则为 null) «««;

如果 (vendorItem["供应商名称"].ToString().等于(将))
返回 新增功能 供应商(vendorItem);
}

供应商 v = 新增功能 供应商();
v.VendorPhone = "找不到: " + 将;

返回 v;

返回 则为 null;

} // 使用 spweb web = site.openweb()
} // 使用 spsite 网站 = 新 spsite("http://本地主机/瑞穗")

} // 方法

[WebMethod]
公众 供应商[] GetVendorsOfType (字符串 过滤式)
{

字符串 SpVendorSiteName; // 承载 t 的实际的 MOSS 站点名称
他供应商自定义列表.
字符串 SpVendorListName; // 实际的苔藓列表包含供应商的名称.

SpVendorSiteName = ConfigurationSettings.AppSettings["VendorListHostingSite"].ToString();
SpVendorListName = ConfigurationSettings.AppSettings["VendorList"].ToString();

供应商[] resultList;
int vendorIndex = 0;
resultList = 新增功能 供应商[1000];

// 初始化默认友好消息列表.
供应商 v = 新增功能 供应商();
v.VendorName = 选择供应商类型来填充该列表。";
resultList[0] v =;

// 转换为小写为以后更容易的字符串比较的筛选器.
过滤式 = filterType.ToLower();

// 如果筛选器类型传递的是"测试", 生成一些简单的数据.
#区域 过滤器类型 ="测试"
如果 (等于 filterType。("测试"))
返回 GenerateTestVendors();
#endregion

如果 (true)
{
使用 (SPSite 网站 = 新增功能 SPSite(SpVendorSiteName))
{
使用 (SPWeb web = 网站。OpenWeb())
{

v = 则为 null;

写入 currentList = web。列表[SpVendorListName];

// 循环访问供应商列表中的所有项.
foreach (SPItem vendorItem 在中 currentList.Items)
{

字符串 lowerVendorType;

lowerVendorType = vendorItem["PurchaseType"].ToString().ToLower();
lowerVendorType = lowerVendorType.Substring(3);

如果 (等于 lowerVendorType。(过滤式))
{
resultList[vendorIndex ] = 新增功能 供应商(vendorItem);
}
} // 通过在列表中的所有供应商进行迭代


返回 TrimVendorArray(vendorIndex, resultList);
// 返回 resultList;

} // 使用 spweb web = site.openweb()
} // 使用 spsite 网站 = 新 spsite("http://本地主机/瑞穗")

} // 如果为 true,

返回 则为 null;
}

私人 供应商[] TrimVendorArray(int newsize, 供应商[] originalVendorArray)
{
供应商[] trimmedArray;

如果 (newsize = = 0) newsize = 1;
trimmedArray = 新增功能 供应商[newsize];

int currentCounter = 0;

(currentCounter = 0; currentCounter < newsize; currentCounter )
{
trimmedArray[currentCounter] originalVendorArray =[currentCounter];
}

返回 trimmedArray;

}
}

苔藓: InfoPath 调试观察

InfoPath 表单服务器错误消息是误导.

在 InfoPath 窗体的开发过程, 我会将它发布到 MOSS 服务器和访问的窗体. 该窗体将开始加载,然后生成一个误导性的错误消息,我指向 windows 事件日志以了解详细信息. 事实上, 没有消息被写入 windows 事件日志. 而是, 消息被发送到 MOSS ascii 诊断日志. 你可以跟踪,通过中央服务管理.

你需要在你的脚上快速. MOSS 喜欢写到日志文件, 频繁地和过程. 这可以被修剪,但默认的日志写的行为是"一切都尽可能快地".

苔藓: 更新自定义列表

有许多好例子的更新通过 SDK 的自定义列表. 这里是另一个.

业务问题: 设计了 InfoPath 表单,使用户能够输入在线采购申请. 大埔请购单编号应该是传统序列基于整数值和自动计算.

业务解决方案: 创建一个包含两列的自定义 MOSS 列表: "ControlField" 和"ControlValue". 值列包含下一个采购请购单编号. 请注意该泛型"控制" 对未来控制字段可根据需要使用提供的命名约定.

技术解决方案: 创建的 InfoPath 客户端访问的 web 服务. 在 web 服务返回返回下一个采购请购单编号和更新列表中的值.

吸取的教训:

  • 当 InfoPath 窗体中添加此 web 服务作为数据源, 认为有必要将它转换为 udc 并将它存储到数据连接库.
  • 此外发现它有必要启用跨域脚本通过中央服务管理 // 应用程序管理 // 表单服务器配置.
  • 第一次试图访问 web 服务的形式, 它需要一段时间,有时, 它将超时时间. 我摆弄表单服务器配置中的设置,以扩大的超时设置和那似乎帮助.

代码:

使用 系统;
使用 System.Web;
使用 System.Web.Services;
使用 System.Web.Services.Protocols;
使用 Microsoft.SharePoint;
使用 System.Configuration;

[Web 服务(Namespace = "http://www.conchango.com/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
公众 PoService : System.Web.Services.Web 服务
{
公众 PoService () {

//取消注释以下行如果使用设计的部件
//InitializeComponent();
}

/// <摘要>
/// 从 sharepoint po 号码控制列表获得下一个 PO 编号.
/// 该列表中的增量 PO 编号.
/// </摘要>
/// <返回></返回>
[WebMethod]
公众 字符串 GetNextPoNumber()
{
字符串 SpPoControlSiteName; // 实际的 MOSS 站点承载的大埔控制列表名称.
字符串 SpPoControlListName; // 包含宝控件的实际苔藓列表的名称.

SpPoControlSiteName = ConfigurationSettings.AppSettings["PoControlListHostingSite"].ToString();
SpPoControlListName = ConfigurationSettings.AppSettings["PoControlList"].ToString();

字符串 nextPoReqNumber = "xyzzy";

使用 (SPSite 网站 = 新增功能 SPSite(SpPoControlSiteName))
{
使用 (SPWeb web = 网站。OpenWeb())
{

写入 currentList = web。列表[SpPoControlListName];

foreach (SPItem controlItem 在中 currentList.Items)
{

如果 (((字符串)controlItem["ControlField"]).等于("NextPoNumber"))
{
nextPoReqNumber = (字符串)controlItem["ControlValue"];

int int_nextPoReqNumber;
int_nextPoReqNumber = 转换.ToInt32(nextPoReqNumber);

int_nextPoReqNumber ;

controlItem["ControlValue"] int_nextPoReqNumber =;
controlItem.Update();
}

} // 定位, 读取和更新采购订单编号列表中.


} // 使用 spweb web = site.openweb()
} // 使用 spsite 网站 = 新 spsite("http://本地主机/瑞穗")

返回 nextPoReqNumber;

}
}