aspx工作流中ExtendedProperties数据无法读取

简单来说是因为拓展的属性名出现了重复,在出现重复的情况下,会以字段的Guid的形势展现。

解决办法:

  1. 不要使用和字段中相同名称的哈希表字段。
  2. 在无法使用ExtendedProperties[“Name”]得到数据的时候,使用ExtendedProperties["FieldGuid"]来得到数据。

Just like to say a big thanks to Andrew Carter for pointing me in the right direction on this one.

Andrew Carter's post
http://suguk.org/forums/thread/9820.aspx
Scott Wickham's post
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1131769&SiteID=1

It seems you have to create your own hash variable along side the other variable:

taskHash["UserInputField"] = UserInputField.Text;
taskHash["UserInputField_ForHash"] = UserInputField.Text;
taskHash["Status"] = "Completed";
taskHash["Status_ForHash"] = "Completed";


=============================================================================
Here is a copy of the answer from Scott in the above link:
Since we're using WSS 3.0 and not MOSS 2007, we have to create and use ASP forms for any custom Workflow Task Edit pages instead of being able to use InfoPath forms (which would be nice...maybe some day we'll step up to MOSS). The custom Workflow Edit Pages are used for custom Task Content Types that we create so that our Workflow Tasks can have additional fields beyond the standard Workflow Task fields. Once you've collected the values for the Task fields from the user on the ASP Workflow Task Edit form, the typical procedure is to create a hashtable and fill the hashtable with key/value pairs that represent the names of your Task fields and their associated values, as such:

// This function is called when the user clicks the Save/Submit button
// on the Custom Task Edit ASP form
public void btnSubmit_Click(object sender, EventArgs e)
{
// Create a hashtable that will be used to update the values of task fields
Hashtable taskHash = new Hashtable();
// For each field, create two values in the hashtable. If the field name
// matches a field in the Task content type, the field name will not be
// searchable as a key within the ExtendedProperties hashtable. So
// create a second field that is a duplicate of the first but having a
// name that doesn't exactly match an existing field in the Task
// content type. That way it will be a searchable key within the
// ExtendedProperties hashtable.
taskHash["UserInputField"] = UserInputField.Text;
taskHash["UserInputField_ForHash"] = UserInputField.Text;
taskHash["Status"] = "Completed";
taskHash["Status_ForHash"] = "Completed";
// Alter the task using the vaues in the hashtable
SPWorkflowTask.AlterTask(taskListItem, taskHash, true);
// Redirect to the appropriate web page
SPUtility.Redirect(taskList.DefaultViewUrl, SPRedirectFlags.UseSource, HttpContext.Current);
}


When you make the SPWorkflowTask.AlterTask() call, the values in the hashtable are stored in the Task in the ExtendedProperties collection for the Task. That having been done, the onTaskChanged() event of your Workflow (if you have defined one for this task) will fire. If you want to access the just-changed values for this task, you will find them in the ExtendedProperties collection of the AfterProperties for the task:

private void onTaskChanged_Invoked(object sender, ExternalDataEventArgs e)
{
// The taskIsComplete boolean variable is used as the
// test for the while loop in our workflow that controls
// when we break out of the loop and move to the
// CompleteTask() step. When the value is set to
// "Complete" on the ASP form, the ASP form saves it
// in the Task and then we retrieve it here in the
// onTaskChanged() event
if (taskAfterProperties.ExtendedProperties["Status_ForHash"] == "Completed")
taskIsComplete = true;
else
taskIsComplete = false;
}


The thing to note (and the thing that caused us a lot of grief trying to figure out) is that you cannot access the field in the ExtendedProperties hashtable using the actual name of the field. This is because, for some reason, even though you store the field in the hashtable using the Name of the field as the key (e.g., "Status"), the ExtendedProperties collection actually uses the GUID of the field as the key and not the field name.

To show it visually, here are the actual contents of the hashtable from the code above (using Visual Studio debugger). The first column shows the key values for the hashtable, and the second column shows the corresponding values for each key:

ExtendedProperties Count = 10 System.Collections.Hashtable

[{53101f38-dd2e-458c-b245-0c236cc13d1a}] "DOMAIN\\swickham"
[{c15b34c3-ce7d-490a-b133-3f4de8801b76}] "Completed"
["Status_ForHash"] "Completed"
[{1c5518e2-1e99-49fe-bfc6-1a8de3ba16e2}] "ows_UserInputField_ForHash='yes' ows_Status_ForHash='Completed' "
[{f1e020bc-ba26-443f-bf2f-b68715017bbc}] "512"
[{8cbb9252-1035-4156-9c35-f54e9056c65a}] " \n \n \nTABLE.mail\n{\n..."
[{1d22ea11-1e32-424e-89ab-9fedbadb6ce1}] 155
[{4c12d635-7607-4911-a54a-7c239acdfcc3}] "yes"
["UserInputField_ForHash"] "yes"
[{4d2444c2-0e97-476c-a2a3-e9e4a9c73009}] "2007-01-19T17:10:55Z"

Notice that both values got saved for each field, but in the case of the field name for "Status", the GUID for the Status field is saved as the key and not the string "Status" that we asked it to save. Therefore, you can't retrieve the value of the Status field using "Status" as the key to the hashtable. The only time the ExtendedProperties will actually use the values you store as Field Names for the key is when the Field Names you use do not match any actual field names in the Task Content Type. That's why we use the scheme in the first block of code where we save the value of the field twice...first using the actual Field Name and the second time using a modified version of the field name that is similar enough to recognize. Then whenever we want to access the Task Field values in situations where we can get at them directly through the Field Collection (vs. through the ExtendedProperties Collection), we can use code such as:

string taskStatus = taskListItem["Status"];

And whenever we want to access the Task Field values in situations where we can't get at them directly through the Field Collection and must use the ExtendedProperties Collection, we can use code such as:

string taskStatus = taskAfterProperties.ExtendedProperties["Status_ForHash"];

and both values will be the same.

Please let us know if we're missing a much better way of doing this!

Scott

Here are a couple of functions that I wrote that make it so that you don't have to use the clever approach used by Scott above if you don't like it.  Basically these functions do the dirty work of first looking for the value by name in the hashtable, then if that fails, resolving the key to the field ID and trying that.  If that fails, it will return null value.

These functions aren't quite reusable as written. They use the workflowProperties member of your workflow class to get a reference to the SharePoint TaskList associated with your workflow.  That reference is then used to lookup the ID of the field matching the key you provide as necessary.

In the end, this is a little more code, but if made reusable I think it provides a cleaner implementation so that you're not being forced to introduce conventions that reduce the maintainability of the code.

Code Snippet

        private object GetExtendedProperty(SPWorkflowTaskProperties properties, string key)

        {

            // First try to get the value by hashtable key

            if (properties.ExtendedProperties.ContainsKey(key))

            {

                // Key was found, so just return the value

                return properties.ExtendedProperties[key];

            }

            else

            {

                // Key was not found in hashtable, so it may have been translated to the field's Guid

                Guid fieldId;

 

                // Try to get the Guid for the field, using "key" as the display name

                if (TryGetTaskListFieldId(key, out fieldId))

                {

                    // We got the field's id, now use that to retrieve the value (or null) from the hashtable

                    return properties.ExtendedProperties[fieldId];

                }

                else

                {

                    // Field wasn't found either

                    return null;

                }

            }

        }

 

        private bool TryGetTaskListFieldId(string displayName, out Guid fieldId)

        {

            if (workflowProperties.TaskList.Fields.ContainsField(displayName))

            {

                fieldId = workflowProperties.TaskList.Fields[displayName].Id;

                return true;

            }

            else

            {

                fieldId = default(Guid);

                return false;

            }

        }

SharePoint's programmers: BAD MONKEYS,

I have encounted very very very very much bugs in sharepoint.

 

NOTICE: your method below only use for Display Name, it can not apply for 'InternalName' which very important in globalization apps:

 

private bool TryGetTaskListFieldId(string displayName, out Guid fieldId)

        {

            if (workflowProperties.TaskList.Fields.ContainsField(displayName))

            {

                fieldId = workflowProperties.TaskList.Fields[displayName].Id;

                return true;

            }

            else

            {

                fieldId = default(Guid);

                return false;

            }

        }

The reason is below code of monkeys in Microsoft.SharePoint.SPFieldCollection class:

 

workflowProperties.TaskList.Fields.ContainsField(displayName) Is check field name in both DisplayNameDict and InternalNameDict collections:

public bool ContainsField(string fieldName)
            {
            if (!this.DisplayNameDict.ContainsKey(fieldName) && !this.InternalNameDict.ContainsKey(fieldName))
            {
            return this.InternalNameWithPrefixDict.ContainsKey(fieldName);
            }
            return true;
            }
            
(OK for DisplayName and InternalName)

But:  fieldId = workflowProperties.TaskList.Fields[displayName].Id; Is only check field name in DisplayNameDict:

 

internal SPField GetFieldByDisplayName(string strDisplayName, bool bThrowException)
            {
            object obj2 = this.DisplayNameDict[strDisplayName];
            if (obj2 != null)
            {
            return this[(int) obj2];
            }
            if (bThrowException)
            {
            throw new ArgumentException();
            }
            return null;
            }
            
Because I worked in globalization application -> spent my 2 days to debug and survey sharepoint code by reflect tool

原文地址:https://www.cnblogs.com/ceci/p/1390808.html