使用 UIAPB 在 Web 应用程序中实现多任务(子窗口)功能






4.42/5 (10投票s)
本文描述了一种使用用户界面流程应用程序块 2.0 实现共享会话、多任务功能的解决方案。
引言
我看到许多人在论坛上抱怨使用用户界面流程应用程序块 (UIPAB) 时,单用户运行多任务功能的问题。尤其是在Web应用程序中(事实上,每个问题都提到了Web应用程序)。UIPAB 的官方文档建议实现 `ITask` 接口,并明确处理单用户同时运行多个任务的情况(尽管没有提供代码示例)。本文通过对 UIPAB 代码进行一些小的更改来解决这个问题。请注意,UIPAB 可从 Microsoft 的模式与实践网站下载。
隐藏的问题
使用 UIPAB 实现多个窗口(包含多个任务)场景存在一个基本问题。
UIPAB 将 `ActiveTaskID` 存储在会话变量中,该变量由同一台计算机上的所有浏览器实例共享。因此,UIPAB 本身一次只能激活一个任务(它保存所有任务的状态,但一次只保持一个任务处于活动状态)。`ActiveTaskID` 用于 `WebFormView` 类的 `Load` 事件处理程序中,以检索任务的状态。
解决方案
这种行为导致 UIPAB 只能激活一个任务。我们需要一种方法来在一个实例中激活多个任务。这使我们得出一个明显的结论:我们不能将 `ActiveTaskID` 存储在会话中。我们需要将其与页面一起存储。我考虑将其存储在页面的 ViewState 中。但是,由于所有导航都通过 `Response.Redirect` 进行,因此无法将 `TaskID` 存储在 ViewState 中。然后,我决定将 taskID 放入页面请求的查询字符串中。我必须对 Microsoft 提供的代码进行两处更改才能实现这一点。
- 对 `WebFormView` 类的更改:用以下内容替换默认的 `GetSessionMoniker` 方法
private SessionMoniker GetSessionMoniker()
{
SessionMoniker sessionMoniker = null;
try
{
sessionMoniker = SessionMoniker.GetFromSession(new Guid(Request.QueryString["taskId"]));
}
catch(Exception ex)
{
throw new UIPException(Resource.Exceptions.RES_ExceptionTaskNotFound);
}
return sessionMoniker;
}
public void ActivateView( string previousView, Guid taskId, string navGraph, string view )
{
// create a session moniker
SessionMoniker sessionMoniker = new SessionMoniker( navGraph, view, taskId);
// store the moniker into the session, so the next view can get the task information
sessionMoniker.StoreInSession();
ViewSettings viewSettings = UIPConfiguration.Config.GetViewSettingsFromName( view );
if( viewSettings == null )
throw new UIPException(
Resource.ResourceManager.FormatMessage(
Resource.Exceptions.RES_ExceptionViewConfigNotFound, view ) );
HttpContext.Current.Session[WebFormView.CurrentTaskKey] = taskId.ToString();
RedirectToNextView(previousView, viewSettings, taskId);
}
private void RedirectToNextView(string previousView, ViewSettings viewSettings, Guid taskId)
{
try
{
if (previousView == null)
HttpContext.Current.Response.Redirect(
HttpContext.Current.Request.ApplicationPath +
"/" + viewSettings.Type +
"?taskID=" +
taskId.ToString(),
true);
else
HttpContext.Current.Response.Redirect(
HttpContext.Current.Request.ApplicationPath +
"/" + viewSettings.Type
+ "?taskID=" +
taskId.ToString(),
false);
}
catch (System.Threading.ThreadAbortException) { }
}
使用代码
按原样使用代码。您可以通过下载修改后的 UIP 代码直接开始使用它。或者,您可以自己对从 Microsoft 网站下载的 UIPAB 代码进行更改。
注意
对 UIPAB 的修改完全由我本人完成,Microsoft 与此无关。如果由于使用此代码(特别是修改的功能)而遇到任何问题,Microsoft 对此概不负责。商业用途的代码应在彻底测试后才能使用。对于因使用所包含的代码而产生的任何错误行为,我不承担任何责任。
本文使用 UIPAB 2.0。相同的更改也可以应用于 UIPAB 1.x,但我个人没有这样做。