Pergunta

I have a tool to update all items in SP (link replacement). The tool works most of the time but sometimes it throws me an ArgumentException ("Value does not fall within the expected range.").

Here is the code how I iterate and try to access the value:

   foreach (SPList list in web.Lists)
   {
         foreach (SPListItem item in list.Items)
         {
              foreach (SPField field in list.Fields)
              {
                   if (!field.ReadOnlyField)
                   {
                       if (item.Fields.Contains(field.Id) && item[field.Id] != null)
                       {

The exception is thrown at item[field.Id] and I don't see why. The field is clearly in the item fields collection as the item.Fields.Contains(field.Id) returns true. Also of course the field.Id is a normal Guid.

Am I making some logical error here?

Foi útil?

Solução

I've had success by not using .ID, but using InternalName with .ContainsFieldWithStaticName(). I also check Hidden and CanBeDeleted on the field as these are more system fields and not custom ones, so I'm not worried about them.

Sample below

SPWeb web = SPContext.Current.Web;
foreach (SPList list in web.Lists)
{
    foreach (SPListItem item in list.Items)
    {
        foreach (SPField field in item.Fields)
        {
           if(!field.Hidden && !field.CanBeDeleted && item.Fields.ContainsFieldWithStaticName(field.StaticName) && item.GetFormattedValue(field.InternalName) != null)
            {
                //CODE HERE
            }                        
        }

Outras dicas

I recently had this problem myself; the only difference being that I was using a CAML query. If your code above is abridged and you were too, this may be of use to you.

The problem boiled down to two issues:

a) I hadn't added one of the columns to the ViewFields XML, so the field wasn't in the SPListItem at all.

b) Once I did add it, I had to set my new favourite undocumented attribute Nullable:

<FieldRef Name="Notes" Nullable="True"/>

This ensures there's a null entry for empty fields (as opposed to no entry), so item["Note"] won't return a NullReferenceException immediately; allowing item["Note"] != null.

its difficult to say why you're getting the exception (some casting issue somewhere) , but i've reworked two lines of your code which might help:

  1. Instead of iterating through all fields in the List, Iterate through all fields in the List item

  2. Indexers is a Exception nightmare in c#, try to use a method which should always return something and not throw exceptions (that's the theory anyways).

Here we go:

    SPWeb web = SPContext.Current.Web;
    foreach (SPList list in web.Lists)
    {
        foreach (SPListItem item in list.Items)
        {
            foreach (SPField field in item.Fields)
            {
                if (item.Fields.Contains(field.Id) && item.GetFormattedValue(field.InternalName) != null)
                {
                    //CODE HERE
                }                        
            }

I found a solution to the original problem that was posted here, it took me whole day struggling with xml returned by query. Solution is, In ViewFields, terminate the internal name up to 32 charachters. And then, while getting value, use the internal name terminated up to 32 chars.

This is definately poorly tested code by Microsoft pushed in SP 2010. They must do a better job testing it.

Any fields, which have internal name greater than 32 are a problem if you use viewfields. If you don's use viewfields, you are good, there's no issue.

Try to set the Resource Throttling value up for "List View Lookup Threshold". Go to the Central Admin > Application Management > Manage web applications. Select the web application that needs to be changed, and then go to General Settings > Resource Throttling.

Important note: always evaluate the impact of changing default threshold values in SharePoint and always be aware of the amount of columns in your Lists.

Cheers

I seem to remember running across this one too. Interestingly, GUID isn't the most reliable means of getting the value from an item; using InternalName or title is much more predictable.

If you use a string indexer it'll check that string against Title, InternalName, and the static name for a match.

SPListItem.Item Property (String)

Why doesn't GUID work all the time? Microsoft knows; but they're not telling.

Edit: Looking at my commit notes, it looks like I switched from ID to InternalName to improve 2007 reliability. So this may or may not help with 2010.

First of all:

replace your line of code

foreach (SPListItem item in list.Items) 

with

SPListItemCollection items = l.Items;
foreach(SPListItem item in items)

that's a best practice. Try to replace your line of code that bugs out with:

if (item.Fields.Contains(field.Id) && item.Fields[field.Id] != null)

I'm not sure, but it's possible that in the item[] indexer, only fields exist that contain a value, while the possible fields are in the item.Fields. This explains why item.Fields contains(id) returns a value and item.Fields[id] returns an ArgumentException

Licenciado em: CC-BY-SA com atribuição
Não afiliado a sharepoint.stackexchange
scroll top