DynamicData - Generate Columns/Rows (using IAutoFieldGenerator) - Part 5 (original) (raw)

Articles in this Series

This is the heart of controlling which fields are shown in the List, Details, Edit views etc. Listing 1 is a skeleton of the Column/Row Generator, as you can see it is a class that is passed a table and has a loop which returns a ICollection of DynamicFields. The foreach loop is where the columns are processed similarly to the if (!column.Scaffold) which tests to see if the column to scaffolded.

using System.Collections.Generic; using System.Web.DynamicData;

public class FilteredFieldsManager : IAutoFieldGenerator { protected MetaTable _table;

public FilteredFieldsManager(MetaTable table)
{
    _table = table;
}

public ICollection GenerateFields(Control control)
{
    List<DynamicField> oFields = new List<DynamicField>();

    // where do I put this test I think in the page?
    foreach (MetaColumn column in _table.Columns)
    {
        // carry on the loop at the next column 
        // if scaffold column is set to false
        if (!column.Scaffold)
            continue;

        // create new DynamicField
        DynamicField newField = new DynamicField();

        // assign column name and add it to the collection
        newField.DataField = column.Name;
        oFields.Add(newField);
    }
    return oFields;
}

}

Listing 1

The class is used like:

// code to add column level security table = GridDataSource.GetTable(); GridView1.ColumnsGenerator = new FilteredFieldsManager(table);

Listing 2

The code in Listing 2 is added to the Page_Init event, this is all that is needed in the pages code behind to add column level security.

Customising the FieldGenerator class

The first change is to add a new member variable _roles and change the Constructor to take an array of Strings.

protected MetaTable _table; protected String[] _usersRoles;

public FilteredFieldsManager(MetaTable table, params String[] roles) { _table = table; _usersRoles = roles; }

Listing 3

Then in the GenerateFields method the permission for the current column will be assigned a local variable and then add a test to the if (!column.Scaffold) so that if the column is DenyRead then the column will also be skipped see Listing 4.

// get permissions for current column for current user roles. var fieldPermissions = column.GetFieldPermissions(Roles.GetRolesForUser());

// carry on the loop at the next column // if scaffold table is set to false or DenyRead if (!column.Scaffold fieldPermissions.Contains(FieldPermissionsAttribute.Permissions.DenyRead)) continue;

Listing 4

The next step is to add a DynamicReadonlyField class so that id a field is marked DenyEdit then a read only field can be returned instead of the regular DynamicField see Listing 5.

public class DynamicReadonlyField : DynamicField { public override void InitializeCell( DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex) { if (cellType == DataControlCellType.DataCell) { var control = new DynamicControl() { DataField = DataField };

        // Copy various properties into the control
        control.UIHint = UIHint;
        control.HtmlEncode = HtmlEncode;
        control.NullDisplayText = NullDisplayText;

        // this the default for DynamicControl and has to be
        // manually changed you do not need this line of code
        // its there just to remind us what we are doing.
        control.Mode = DataBoundControlMode.ReadOnly;

        cell.Controls.Add(control);
    }
    else
    {
        base.InitializeCell(cell, cellType, rowState, rowIndex);
    }
}

}

Listing 5 - Thanks to David Ebbo for this class and the explanation here on the DynamicData forum.

Now if we add a test for the column has a DenyEdit security attribute assigned then the field can now be set to an DynanicReadOnlyField. In Listing 6 the fieldPermissions variable can be tested to see if it contains a DenyEdit permission.

DynamicField f; if (fieldPermissions.Contains(FieldPermissionsAttribute.Permissions.DenyEdit)) { f = new DynamicReadonlyField(); } else { f = new DynamicField(); }

f.DataField = column.Name; oFields.Add(f);

Listing 6

Listing 7 shows the code to test for foreign Key tables parent and child table permissions and if DenyRead do not show the field for the column.

//if foreign key table is hidden then hide the column that references it in this table if (column.GetType() == typeof(MetaChildrenColumn)) { // Get permissions for current columns child table var childTablePermissions = column.GetChildrenTablePermissions(Roles.GetRolesForUser());

// carry on the loop at next column
if (childTablePermissions.Contains(TablePermissionsAttribute.Permissions.DenyRead))
    continue;

}

//if foreign key table is hidden then hide the column that references it in this table if (column.GetType() == typeof(MetaForeignKeyColumn)) { // Get permissions for current columns parent table var parentTablePermissions = column.GetFkTablePermissions(Roles.GetRolesForUser());

// carry on the loop at next column
if (parentTablePermissions.Contains(TablePermissionsAttribute.Permissions.DenyRead))
    continue;

}

Listing 7

Put it all together in Listing 8.

public class FilteredFieldsManager : IAutoFieldGenerator { protected MetaTable _table; protected String[] _usersRoles;

public FilteredFieldsManager(MetaTable table, params String[] roles)
{
    _table = table;
    _usersRoles = roles;
}

public ICollection GenerateFields(Control control)
{
    List<DynamicField> oFields = new List<DynamicField>();

    // Get table permissions
    var tablePermissions = _table.GetTablePermissions(this._usersRoles);

    // if table is DenyRead then do not output any fields
    if (!tablePermissions.Contains(TablePermissionsAttribute.Permissions.DenyRead))
    {
        foreach (MetaColumn column in _table.Columns)
        {
            // get permissions for current column for current user roles.
            var fieldPermissions
                = column.GetFieldPermissions(Roles.GetRolesForUser());

            // carry on the loop at the next column 
            // if scaffold table is set to false or DenyRead
            if (!column.Scaffold  fieldPermissions
                .Contains(FieldPermissionsAttribute.Permissions.DenyRead))
                continue;

            // if foreign key table is hidden then hide
            // the column that references it in this table
            if (column.GetType() == typeof(MetaChildrenColumn))
            {
                // Get permissions for current columns child table
                var childTablePermissions
                    = column.GetChildrenTablePermissions(Roles.GetRolesForUser());

                // carry on the loop at next column
                if (childTablePermissions
                    .Contains(TablePermissionsAttribute.Permissions.DenyRead))
                    continue;
            }

            // if foreign key table is hidden then hide
            // the column that references it in this table
            if (column.GetType() == typeof(MetaForeignKeyColumn))
            {
                // Get permissions for current columns parent table
                var parentTablePermissions
                    = column.GetFkTablePermissions(Roles.GetRolesForUser());

                // carry on the loop at next column
                if (parentTablePermissions
                    .Contains(TablePermissionsAttribute.Permissions.DenyRead))
                    continue;
            }

            DynamicField f;
            if (fieldPermissions
                .Contains(FieldPermissionsAttribute.Permissions.DenyEdit))
            {
                f = new DynamicReadonlyField();
            }
            else
            {
                f = new DynamicField();
            }

            f.DataField = column.Name;
            oFields.Add(f);
        }
    }
    return oFields;
}

}

Listing 8

having done all this remember all you have to add to the page is:

// code to add column level security table = GridDataSource.GetTable(); GridView1.ColumnsGenerator = new FilteredFieldsManager(table, Roles.GetRolesForUser());

SQL Server 2005

SQL Server 2008

the sample already has Login and Roles setup (Account details below).

Website users:

all passwords are: password