DynamicData - Generate Columns/Rows (using IAutoFieldGenerator) - Part 5 (original) (raw)
Articles in this Series
- Introduction - A DynamicData Attribute Based Permission Solution using User Roles.
- Part 1 - Permissions Attribute (Metadata) Classes.
- Part 2 - Sample Metadata for project.
- Part 3 - The Helper Extension Methods.
- Part 4 - Limit Tables shown on Default page and List, Edit & Details etc.
- Part 5 - Generate Columns/Rows (using IAutoFieldGenerator)
- Part 6 - Miscellaneous bits
- Part 7 - Updating the ListDetails Page
- DynamicData - Limit the Filter Fields
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;
}
}
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; }
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:
- admin
- fred
- sue
- pam
all passwords are: password