Categories
Microsoft SharePoint 2010

SharePoint Foundation or Server 2010: Error when you are trying to get an SPListItem value

You get a ‘System.ArgumentException: Value does not fall within the expected range” when you try to get the value of an SPListItem. Here is one solution to your problem!

This article will maybe help out some folks, because I didn’t find the answer elsewhere.

I wanted to retrieve an SPListItem value, and I got the following error:

System.ArgumentException: Value does not fall within the expected range.
at Microsoft.SharePoint.SPFieldMap.GetColumnNumber(String strFieldName, Boolean bThrow)
at Microsoft.SharePoint.SPListItemCollection.GetColumnNumber(String groupName, Boolean bThrowException)
at Microsoft.SharePoint.SPListItemCollection.GetRawValue(String fieldname, Int32 iIndex, Boolean bThrow)
at Microsoft.SharePoint.SPListItem.GetValue(SPField fld, Int32 columnNumber, Boolean bRaw, Boolean bThrowException)
at Microsoft.SharePoint.SPListItem.get_Item(Guid fieldId)

First, I didn’t understand why this error was thrown on a such basic operation in SharePoint development.

Then going step by step trying to find a solution, I noticed that on my current SPList I had several field of type “Lookup” and “Person or Group”, eleven exactly.
 

I finally found the solution in the Web Application settings.

Go to the Central Administration > Manage web applications > General Settings > Resource Throttling.

Then take a look to the option named List View Lookup Threshold.

The description says: Specify the maximum number of Lookup, Person/Group, or workflow status fields that a database query can involve at one time.

This option is the solution to our problem!

By default the value is set to 8. Just modify it depending on your needs. For my part I set it to eleven, and the error didn’t show up again.

Just be carefull with this option, because it is used for performance reason. Don’t raise it too much, just modify it to suit your needs.

 

Please feel free to comment or contact me if you have any question about this article.

Categories
Bing Maps Microsoft

Use Bing Maps REST Services with jQuery to build an autocomplete box and find a location dynamically

In this article we will discover how to build an autocomplete box with Bing Maps REST Services by using only HTML, JSON and jQuery.

Bing Maps REST Services allows us to perform tasks such as creating a map with pushpins, geocoding an address, retrieving imagery metadata, or creating a route.

Here we will learn to use the Locations API of Bing Maps REST Services to build an autocomplete box with jQuery. To be able to reach Bing Maps services, you will need a Bing Maps key. Just go to the Bing Maps Account Center to get one.

 

Creation

First, we will create a simple HTML page with references to jQuery and jQuery UI, an input for the searched location and a div in which the results will be displayed.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Use Bing Maps REST Services with jQuery to build an autocomplete box and find a location dynamically</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.js" type="text/javascript"></script>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/jquery-ui.js" type="text/javascript"></script>
    <link href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/themes/redmond/jquery-ui.css" rel="stylesheet" type="text/css" />
    <style type="text/css">
        #searchBox
        {
            width: 25em;
        }
    </style>
</head>
<body>
    <div>
        <div class="ui-widget">
            <label for="searchBox">
                Search:
            </label>
            <input id="searchBox" />
        </div>
        <div id="searchResult" class="ui-widget" style="margin-top: 1em;">
        </div>
    </div>
</body>
</html>

 

To call the Locations API we use the following url: http://dev.virtualearth.net/REST/v1/Locations

Parameters are required to get a response from the service:

The Bing Maps REST Services also have other optional parameters such as:

  • userLocation (or ul): current position of the user.
  • culture (or c): culture to use for the request.
  • output (or o): output format for the response (JSON or XML). JSON is used by default.
  • jsonp: name of JSON callback function that is called when the response to the request is received. The JSON object provided in the response is passed to the callback function.

 

To create an autocomplete box, we use jQuery UI. The source of the suggestions provided to the user will come from Bing Maps REST Services.

The operation is as follows: when the user type a location, an Ajax request is triggered to call the Locations API of Bing Maps REST Services and a JSON response is received. The response is processed to be displayed as suggestions to the user. Here is the JavaScript to do it:

<script type="text/javascript">
    $(document).ready(function () {
        $("#searchBox").autocomplete({
            source: function (request, response) {
                $.ajax({
                    url: "http://dev.virtualearth.net/REST/v1/Locations",
                    dataType: "jsonp",
                    data: {
                        key: "<yourbingmapskey>",
                        q: request.term
                    },
                    jsonp: "jsonp",
                    success: function (data) {
                        var result = data.resourceSets[0];
                        if (result) {
                            if (result.estimatedTotal > 0) {
                                response($.map(result.resources, function (item) {
                                    return {
                                        data: item,
                                        label: item.name + ' (' + item.address.countryRegion + ')',
                                        value: item.name
                                    }
                                }));
                            }
                        }
                    }
                });
            },
            minLength: 1
        });
    });
</script>

 

We have to pay attention to several things here:

  • We specify to jQuery that the source of the autocomplete is an Ajax request sent to the Locations API of Bing Maps REST Services. Once the request response received, the autocomplete get suggestions thanks to the callback named response.
  • Ajax request has multiple settings:
    • url: is the one for Locations API.
    • dataType: jsonp.
    • jsonp: is jsonp to override the callback function name in the jsonp request, so that jQuery add an extra “?jsonp=?” to the end of the URL to specify the callback. That is required by Bing Maps REST Services.
  • We get the searched term from request.term parameter.
  • We check that the Bing Maps REST Services response contains resource sets and if it has found locations that match searched term (result.estimatedTotal > 0). For more details about Bing Maps REST Services response see: Common Response Description on MSDN.
  • In the response callback, we specify that the suggestion label will be the location name plus the location country, and that the value will be the location name. We also use the property named data to save the full location information in order to use it when the user will the select a location.

 

For example, when a user search “San Francisco”, the following Ajax request url is built and called:

http://dev.virtualearth.net/REST/v1/Locations?jsonp=<callbackname>&key=<yourbingmapskey>&q=San+francisco&_=1298745707161

 

The final working page source looks like below:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Use Bing Maps REST Services with jQuery to build an autocomplete box and find a location dynamically</title>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery/jquery-1.5.1.js" type="text/javascript"></script>
    <script src="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/jquery-ui.js" type="text/javascript"></script>
    <link href="http://ajax.aspnetcdn.com/ajax/jquery.ui/1.8.10/themes/redmond/jquery-ui.css" rel="stylesheet" type="text/css" />
    <style type="text/css">
        .ui-autocomplete-loading
        {
            background: white url('images/ui-anim_basic_16x16.gif') right center no-repeat;
        }
        #searchBox
        {
            width: 25em;
        }
    </style>

    <script type="text/javascript">
        $(document).ready(function () {
            $("#searchBox").autocomplete({
                source: function (request, response) {
                    $.ajax({
                        url: "http://dev.virtualearth.net/REST/v1/Locations",
                        dataType: "jsonp",
                        data: {
                            key: "<yourbingmapskey>",
                            q: request.term
                        },
                        jsonp: "jsonp",
                        success: function (data) {
                            var result = data.resourceSets[0];
                            if (result) {
                                if (result.estimatedTotal > 0) {
                                    response($.map(result.resources, function (item) {
                                        return {
                                            data: item,
                                            label: item.name + ' (' + item.address.countryRegion + ')',
                                            value: item.name
                                        }
                                    }));
                                }
                            }
                        }
                    });
                },
                minLength: 1,
                change: function (event, ui) {
                    if (!ui.item)
                        $("#searchBox").val('');
                },
                select: function (event, ui) {
                    displaySelectedItem(ui.item.data);
                }
            });
        });

        function displaySelectedItem(item) {
            $("#searchResult").empty().append('Result: ' + item.name).append(' (Latitude: ' + item.point.coordinates[0] + ' Longitude: ' + item.point.coordinates[1] + ')');
        }
    </script>
</head>
<body>
    <div>
        <div class="ui-widget">
            <label for="searchBox">
                Search:
            </label>
            <input id="searchBox" />
        </div>
        <div id="searchResult" class="ui-widget" style="margin-top: 1em;">
        </div>
    </div>
</body>
</html>

 

Demo video

Links

Several links that will help you to understand and go further on the subject:

 

Summary

We have seen how to use Bing Maps REST Services with jQuery, jQuery UI to build an autocomplete box and find a location dynamically. As we are using HTML, JSON and jQuery, this can be integrated with whatever technology you prefer.

If you want to go further, take a look at the links above to understand what you can do with Bing Maps REST Services. For example, we could display the selected location on a map with Bing Maps AJAX Control or Bing Maps Silverlight Control. This will certainly be the next subject of one of my future articles in addition to this one.

You can download the full sources here:

Download full sources

 

Please feel free to comment or contact me if you have any question about this article.

Categories
Microsoft Windows Phone 7

First Windows Phone 7 update available

Here are some photos to show you what the update notification looks like on the phone.

I have just received the first update notification on my Samsung Omnia 7. Here are some photos:

I am waiting to update my phone, because of the problem reported by some folks in the update process with the Samsung Omnia 7.

Categories
ASP.NET ASP.NET MVC Microsoft

Create a custom AuthorizeAttribute that accepts parameters of type enum

In this article I will explain how to simply create an AuthorizeAttribute that accepts parameters of type enum in order to avoid roles hard coding.

Have you ever tried to use an [Authorize] attribute and assign roles for example with an Enum value in one of your ASP.NET MVC projects?

If so, you will get the following error message when compiling:

An attribute argument must be a constant expression, typeof expression or array creation expression of an attribute parameter type

 

It is because you need to use static values and it makes impossible to use an Enum to set properties of an Attribute. It means that you can not set the property Roles of an [AuthorizeAttribute] with an Enum value.

That is frustrating, because I personally don’t like having to hard code roles in an application. It makes the application dirty and more complicated to maintain.

 

Hopefully, ASP.NET MVC allows us to customize the [AuthorizeAttribute] easily without having to override the standard security process.

 

 Creation

For our needs we will create the following Enum to declare roles:

namespace MvcApplication.HowTo.Enums
{
    public enum Role
    {
        Administrator = 1,
        UserWithPrivileges = 2,
        User = 3,
    }
}

 

Now we are going to create a custom [AuthorizeAttribute] that accepts Enum as parameters in the constructor. It will inherit from the standard System.Web.Mvc.AuthorizeAttribute:

using System;
using System.Linq;
using System.Web.Mvc;

namespace MvcApplication.HowTo.Attributes
{
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
    public class AuthorizeEnumAttribute : AuthorizeAttribute
    {
        public AuthorizeEnumAttribute(params object[] roles)
        {
            if (roles.Any(r => r.GetType().BaseType != typeof(Enum)))
                throw new ArgumentException("roles");

            this.Roles = string.Join(",", roles.Select(r => Enum.GetName(r.GetType(), r)));
        }
    }
}

As you can see we have to pay attention to several things here:

  • The constructor accepts parameters of type object, that is the little trick. If you use parameters of type Enum, you will get the same error message as above. We can do that because an Enum is an object.
  • To ensure that we are passing parameters of type Enum, we check the type of every roles. If one role is not of type Enum, the constructor will throw an ArgumentException.
  • Then we set the standard Roles property with the name of our roles with the string.Join method.

 

Example of use

Let’s say we want to authorize only users with roles Administrator or UserWithPrivileges on the HomeController action named ThePrivilegeZone. ThePrivilegeZone action will be decorated with our custom authorize attribute like bellow:

using System.Web.Mvc;
using MvcApplication.HowTo.Attributes;
using MvcApplication.HowTo.Enums;

namespace MvcApplication.HowTo.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View();
        }

        public ActionResult About()
        {
            return View();
        }

        [AuthorizeEnum(Role.Administrator, Role.UserWithPrivileges)]
        public ActionResult ThePrivilegeZone()
        {
            return View();
        }
    }
}

Our code is clean like that, isn’t it?

 

To go further

If you take a look with a tool like Reflector, it is interesting to understand how the action ThePrivilegeZone is decorated when compiled. Here is a screenshot:

We understand that once compiled, Role Enum values are used and not names. Here 1 (Administrator) and 2 (UserWithPrivileges).

Note that if you use an Enum for your roles without setting values like we did here, Enum values will be 0, 1, 2, etc. to the number of your roles less 1.

 

Summary

We have seen how to create and use a custom AuthorizeAttribute that accepts parameters of type enum. Here we are only setting roles, but depending on your needs, you can do the same with users. I personally use this custom attribute in my framework so that I am able to reuse it in all my ASP.NET MVC projects.

You can download the example solution here:

Download the Authorize Enum Solution

(Note that the project uses ASP.NET MVC 3)

 

Please feel free to comment or contact me if you have any question about this article.