Dynamic Data: Prevent inserting and deleting for a specific table

by Heathesh 7. February 2010 04:04

I was using a Dynamic Data Entities Web Application, and my requirement was to have a specific setup table that would only ever have one prepopulated row. This meant that the user should never be allowed to insert a new record, or delete the current record from the table. They should only ever be allowed to edit the record.

To accomplish this, I started off creating a custom attribute that I was going to apply to the specific table's scaffolding. The primary use of scaffolding in Dynamic Data is to hide and display specific fields and tables as required. So to begin with, I personally always create a class to be used for scaffolding for every table within my Dynamic Data site. For example, the table I was currently working with is called SiteSetup, and the scaffolding class I created looked like so:

    using System.ComponentModel.DataAnnotations; //add this using for the MetadataType attribute

    //The namespace used here must be the same as your Entity Model namespace. The best way (if you
    //don't already know the namespace) to find out the correct namespace is to expand your .edmx file
    //and then open the Designer.cs file and you will see the namespace there
    namespace Heathesh.Com.Entity
    {
        /// <summary>
        /// Partial class of my MetaTable, using the MetadataType attribute to indicate the
        /// class I'm using to save my scaffolding info
        /// </summary>
        [MetadataType(typeof(SiteSetupMetaData))]
        public partial class SiteSetup
        {

        }

        public class SiteSetupMetaData
        {
            /// <summary>
            /// I don't want the user to see the Id field, because in this case
            /// the Id field is an int with an Indentity, so the user will never
            /// need to insert or change this
            /// </summary>
            [ScaffoldColumn(false)]
            public object Id { get; set; }
        }
    }


Pay attention to the comments above, especially regarding the namespace. Now I had to create an attribute to indicate that I specifically didn't want to allow insert or delete for this table, so I created my attribute like so:

    using System;

    namespace Heathesh.Com.Entity.Attributes
    {
        /// <summary>
        /// Custom behaviour attribute to be used on MetaTables to prevent inserts and deletes where
        /// required
        /// </summary>
        [AttributeUsage(AttributeTargets.Class)]
        public class CustomBehaviour : System.Attribute
        {
            #region Public Properties
            /// <summary>
            /// Gets or sets a bool indicating whether or not to allow inserts
            /// </summary>
            public bool AllowInsert
            {
                get;
                set;
            }

            /// <summary>
            /// Gets or sets a bool indicating whether or not to allow deletes
            /// </summary>
            public bool AllowDelete
            {
                get;
                set;
            }
            #endregion

            #region Constructor
            /// <summary>
            /// Default constructor forcing the user to indicate whether to allow inserts and deletes
            /// </summary>
            /// <param name="allowInsert"></param>
            public CustomBehaviour(bool allowInsert, bool allowDelete)
            {
                AllowInsert = allowInsert;
                AllowDelete = allowDelete;
            }
            #endregion
        }
    }


The attribute class should be pretty self explanatory. The next thing was I wanted to created a method for my attribute that would allow me to check if the attribute existed on a specific meta table and return the attribute if it did. I also wanted it to be generic, so I created an Attribute Manager class with the relevant code to return any attribute from an attribute collection, like this:

    using System;
    using System.ComponentModel;

    namespace Heathesh.Com.BusinessLogic
    {
        /// <summary>
        /// Attribute manager to read custom attributes on classes, I made this static
        /// so I could use it as an Extension method
        /// </summary>
        public static class AttributeManager
        {
            /// <summary>
            /// Gets the specified attribute from the attribute collection
            /// </summary>
            /// <param name="attributes">Extends an Attribute collection</param>
            /// <param name="attributeType">The type of attribute to check for and return if found</param>
            /// <returns></returns>
            public static Attribute GetAttribute(this AttributeCollection attributes, Type attributeType)
            {
                foreach (Attribute attribute in attributes)
                    if (attribute.GetType().Equals(attributeType))
                        return attribute;

                return null;
            }
        }
    }


I used an Extension method so I could simply extend the Attribute collection, and easily have my method available to me on any Attribute collection. So now that I have my attribute, and a manager class to return it, I needed to add my attribute to my scaffolding code to indicate that I wanted to disable insert and delete for my SiteSetup table. So I changed my SiteSetup scaffolding code to look like this:

    using System.ComponentModel.DataAnnotations; //add this using for the MetadataType attribute
    using Heathesh.Com.Entity.Attributes; //* USING TO ALLOW ME TO ACCESS MY ATTRIBUTE *

    //The namespace used here must be the same as your Entity Model namespace. The best way (if you
    //don't already know the namespace) to find out the correct namespace is to expand your .edmx file
    //and then open the Designer.cs file and you will see the namespace there
    namespace Heathesh.Com.Entity
    {
        /// <summary>
        /// Partial class of my MetaTable, using the MetadataType attribute to indicate the
        /// class I'm using to save my scaffolding info
        /// </summary>
        [MetadataType(typeof(SiteSetupMetaData))]
        [CustomBehaviour(false, false)] //* NEW ATTRIBUTE *
        public partial class SiteSetup
        {

        }

        public class SiteSetupMetaData
        {
            /// <summary>
            /// I don't want the user to see the Id field, because in this case
            /// the Id field is an int with an Indentity, so the user will never
            /// need to insert or change this
            /// </summary>
            [ScaffoldColumn(false)]
            public object Id { get; set; }
        }
    }



Looking at the code, you'll see I added the new using for the attribute, and the attribute above the "public partial class SiteSetup". Okay,  now the last thing left was to remove the insert and delete buttons on the List and Details pages of my Dynamic Data site if  the attribute was present and set appropriately. To begin with, I found my List page (DynamicData\PageTemplates\List.aspx) and opened the code behind. First to hide the insert, I added the following code at the bottom of my Page_Load:

    Attribute customBehaviour = table.Attributes.GetAttribute(typeof(CustomBehaviour));

    if (customBehaviour != null)
        InsertHyperLink.Visible = ((CustomBehaviour)customBehaviour).AllowInsert;


Next, I open my List.aspx file and added an event to the OnDataBound like so: OnDataBound="GridView1_DataBound". I then created the method in my code behind as well as a method to hide the button if required like so:

    /// <summary>
    /// Handles the grid view data bound event
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void GridView1_DataBound(object sender, EventArgs e)
    {
        Attribute customBehaviour = table.Attributes.GetAttribute(typeof(CustomBehaviour));

        if (customBehaviour != null)
            hideDeleteColumn(((CustomBehaviour)customBehaviour).AllowDelete);
    }

    /// <summary>
    /// Hides the delete column
    /// </summary>
    /// <param name="hide"></param>
    private void hideDeleteColumn(bool show)
    {
        if (!show)
            foreach (GridViewRow gridViewRow in GridView1.Rows)
                ((LinkButton)gridViewRow.Cells[0].Controls[3]).Visible = false;
    }

That took care of my List.aspx page, I next opened my Details.aspx page (DynamicData\PageTemplates\Details.aspx) and added an OnLoad event to my DetailsView1 like so: OnLoad="DetailsView1_Load". I then added the relevant code for the OnLoad method in my code behind like so:

    /// <summary>
    /// Handles the details view load
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    protected void DetailsView1_Load(object sender, EventArgs e)
    {
        Attribute customBehaviour = table.Attributes.GetAttribute(typeof(CustomBehaviour));

        if (customBehaviour != null)
            DetailsView1.FindControl("DeleteLinkButton").Visible = ((CustomBehaviour)customBehaviour).AllowDelete;
    }


That was it, I compiled and ran the application, and insert and delete were available for all my tables except the SiteSetup table as I required.

Happy coding!

Comments

10/27/2010 3:18:47 AM #

pingback

Pingback from gloriastoun.wordpress.com

ReadCustomAttributes Method | Камень на душе

gloriastoun.wordpress.com

Comments are closed



Powered by BlogEngine.NET 1.5.0.7 (with enhancements by Heathesh)
Theme by Mads Kristensen (with tweeks by Heathesh)

Certifications

Microsoft Certified Professional

Microsoft Certified Technology Specialist

Answer Questions

 

Tag cloud

Calendar

<<  September 2014  >>
MoTuWeThFrSaSu
25262728293031
1234567
891011121314
15161718192021
22232425262728
293012345

View posts in large calendar

http://heathesh.com