LA.NET [EN]

Jan 06

ASP.NET AJAX: Building a custom role service provider

Posted in ASP.NET MS AJAX      Comments Off on ASP.NET AJAX: Building a custom role service provider

Yesterday I”ve talked about the new Role service which was introduced by ASP.NET AJAX. Today, I”ll keep talking about it and I”ll show how easy it is to build a custom role service that is responsible for feeding the client role classes. After enabling the role service, the first thing you need to do is create a new web service which must expose two public methods named GetRolesForCurrentUser and IsCurrentUserInRole. These methods should return the roles for the current user and check if a user is associated with a specific role. Unfortunately, the latest version of the platform did not introduced an interface which would define the contract that would have to be implemented by a custom role service. This means that I had to use Reflector to get the correct name/signature for these methods.

In this case, I”m going to use a WCF service that will return roles Role1 and Role2 only when the current user is luis and it will return Role3 for all other users. It”s important to keep in mind that you do need to configure the service so that it uses JSON. The easiest way to accomplish this is by adding a new AJAX-enabled WCF Service (do keep in mind that when you add more than one, you”ll get several unnecessary entries on your web.config. This means that you”ll have to clean it up…). Here”s the code for my service:

[ServiceContract(Namespace = “http://la.net/tests”,,)]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)]
public class CustomRoleService
{
    // Add [WebGet] attribute to use HTTP GET
    [OperationContract]
    public String[] GetRolesForCurrentUser()
    {
        EnsureServiceAvailable();
        String username = GetCurrentUsername();
        if( String.IsNullOrEmpty(username))
        {
            return new String[0];
        }
        //just making something up
        if( String.Compare(“luis”, username) == 0)
        {
            return new String[] {“Role1”, “Role2”};
        }

        //just return role3
        return new String[] {“Role3”};
    }
    [OperationContract]
    public Boolean IsCurrentUserInRole(String role)
    {
        if( role == null )
        {
            throw new ArgumentNullException(“role”);
        }
        EnsureServiceAvailable();

        String username = GetCurrentUsername();
        return IsUserInRole(username, role);
    }

    private static Boolean IsUserInRole(String username, String role)
    {
        if( String.IsNullOrEmpty(username))
        {
            return false;
        }
        if( String.Compare(username, “luis”) == 0)
        {
            return String.Compare(role, “Role1”) == 0 ||
                   String.Compare(role, “Role2”) == 0;
        }
        return String.Compare(role, “Role3”) == 0;
    }

    private static String GetCurrentUsername()
    {
        IPrincipal user = GetCurrentUser();
        return user != null && user.Identity != null ? user.Identity.Name : “”;
    }

    private static IPrincipal GetCurrentUser()
    {
        if(HttpContext.Current == null )
        {
            return Thread.CurrentPrincipal;
        }
        return HttpContext.Current.User;
    }

    private static void EnsureServiceAvailable()
    {
        if( !IsRoleServiceEnabled())
        {
            throw new InvalidOperationException();
        }
    }

    private static Boolean? _roleService;
    private static Boolean IsRoleServiceEnabled()
    {
        if( !_roleService.HasValue )
        {
            ScriptingRoleServiceSection section = (ScriptingRoleServiceSection)
                    WebConfigurationManager.GetWebApplicationSection(“system.web.extensions/scripting/webServices/roleService”);
            _roleService = section.Enabled;
        }
        return _roleService.Value;
    }
}

As you can see, you should always start by checking if the service is enabled. After doing that, you need to get the current logged in user. In this case, we start by checking the current HttpContext: If it”s null, we”ll just use the principal associated with the current thread (this is the same approach which is taken by the default WCF service). The rest of the code is just boilerplate code needed for guaranteeing that the previous conditions are enforced (ie, that user luis is associated with roles Role1 and Role2 and that all the other users are associated with Role3).

The next snippet shows how to use our service on an ASP.NET AJAX page:

<html xmlns=”http://www.w3.org/1999/xhtml”>
<head runat=”server”>
    <title>Untitled Page</title>
    <script type=”text/javascript”>
       function printRoles(){
            Sys.Services.RoleService.load(
                function(){
                    alert( Sys.Services.RoleService.get_roles() )
                }
&nb
sp;           );
        }
    </script>
</head>
<body>
    <form id=”form1″ runat=”server”>
    <div>
       <asp:ScriptManager runat=”server” ID=”manager”>
            <RoleService LoadRoles=”false” Path=”CustomRoleService.svc” />
        </asp:ScriptManager>
        <input type=”button” value=”Get roles” onclick=”printRoles()” />
    </div>
    </form>
</body>
</html>

There is one thing you should keep in mind when using a custom role service: you cannot load the roles automatically (ie, you must set the LoadRoles property to false). Not following this guideline means that you”ll get an exception at runtime. So, on the client side, you”ll always need to call the load method and you”ll have to pass it a callback method so that you”re notified when the client role service gets an answer from our custom service.