[C#.NET][User Control] 使用 IExtenderProvider 擴充控制項屬性 並 驗証控制項角色

比如說我要為Textbox增加一個叫Role的屬性,除了繼承Textbox類別增加屬性之外,我們還可以使用IExtenderProvider來為現有的物件擴充屬性,就像下圖那樣,新增了自己定義的屬性

image

 

有了Role屬性之後,我還要驗証登入的帳號是什麼Role,我會利用Thread.CurrentPrincipal屬性來決定角色及規則,若帳號的Role跟控制項的Role相同,該帳號才能使用這個控制項


開始前的準備:

1.我們會需要ProvideProperty Attribute,在類別加入以下定義,其中Role就是我們要擴充的屬性:

[ToolboxItemFilter("System.Windows.Forms"), ProvideProperty("Role", typeof(Control))]

2.類別需要繼承IExtenderProvider介面

3.類別裡需要定義SetRole以及GetRole方法,這樣才能在設計對話框裡看到Role屬性。

4.由GetRole方法回傳的型別決定屬性對話框的樣式,基本上它能依你的屬性來決定樣式,當然你也可以自己定義Attribute,就像下列程式碼是多行字串的樣式:

[DefaultValue(""), Localizable(true), Editor("System.ComponentModel.Design.MultilineStringEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", typeof(UITypeEditor))]

當然囉,特殊的屬性必須要自己定義,比如類別,詳細做法可參考我以前的文章,http://www.dotblogs.com.tw/yc421206/archive/2010/07/04/16351.aspx


接下來就來開始實作:

先建立一個User Control控制項專案Security.Forms

image

 

然後把UserControl1.cs改成RoleContainer.cs,並增加IExtenderProvider繼承,當然你也可以把UserControl的繼承改成Component;UserControl會在UI上顯示控制項,Component不會在UI上顯示控制項,我在VS2010找不到Component的範本,只好手動這樣改,先完成初步的外殼

namespace Security.Forms

{

    [ToolboxItemFilter("System.Windows.Forms"), ProvideProperty("Role", typeof(Control))]

    public partial class RoleContainer : Component, IExtenderProvider

    {

        #region 實作 IExtenderProvider 成员

        public bool CanExtend(object target)

        {

            //排除自己跟Form

            return ((target is Control) && !(target is RoleContainer) && !(target is Form));

        }

        #endregion



        #region construct

        public RoleContainer(IContainer Cont)

            : this()

        {

            if (Cont == null)

            {

                throw new ArgumentNullException("cont");

            }

            Cont.Add(this);

        }



        public RoleContainer()

        {



        }

        #endregion



       //TODO:實作Role屬性



    }

}

TODO裡要做的就是SetRole以及GetRole方法

private List<Role> _RoleControls = new List<Role>();

[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]

public ReadOnlyCollection<Role> RoleControls

{

    get

    {

        return new ReadOnlyCollection<Role>(this._RoleControls);

    }

    private set { }

}



public void SetRole(Control Ctrl, RoleType? ControlRole)

{

    if (Ctrl is RoleContainer)

    {

        return;

    }



    if (ControlRole != null)

    {

        Ctrl.Enabled = Thread.CurrentPrincipal.IsInRole(ControlRole.ToString());

    }



    //判斷控制項是否存在

    Role role = this.findControl(Ctrl, this._RoleControls);

    if (role == null)

    {

        role = new Role() { Control = Ctrl, RoleType = ControlRole };

        this._RoleControls.Add(role);

    }

    else

    {

        role.RoleType = ControlRole;

    }

}



public RoleType? GetRole(Control Ctrl)

{

    Role item = this.findControl(Ctrl, this._RoleControls);

    if (item != null)

    {

        return item.RoleType;

    }

    else

    {

        return null;

    }

}



Role findControl(Control Ctrl, List<Role> Collection)

{

    //判斷控制項是否存在

    var query = from data in Collection

                where data.Control.Name == Ctrl.Name

                let Index = Collection.IndexOf(data)

                select new { Index };

    int count = query.Count();

    Role item = null;

    if (count > 0)

    {

        item = Collection[query.First().Index];

    }

    return item;

}


建立Security.Role Class專案

加入RoleType類別

namespace Security.Role

{

    public enum RoleType

    {

        Admin = 1,

        User = 2,

        PowerUser = 3,

    }

}

加入Identity 類別

namespace Security.Role

{

    public class Identity : IIdentity

    {

        public string AuthenticationType

        {

            get

            {

                return "Custom AuthenticationType";

            }

        }



        public bool IsAuthenticated { get; internal set; }



        public string Name { get; private set; }



        public RoleType RoleType { get; set; }

        public string Password { get; private set; }

        public Identity(string Name)

            : this(Name, "", RoleType.Admin)

        {

        }

        public Identity(string Name, string Password)

            : this(Name, Password, RoleType.Admin)

        {

        }

        public Identity(string Name, RoleType Role)

            : this(Name, "", Role)

        {



        }

        public Identity(string Name, string Password, RoleType Role)

        {

            this.Name = Name;

            this.Password = Password;

            this.RoleType = Role;

        }

    }

}

 

加入Principle 類別,在這裡我用了一些假帳號資料DefaultRoles,verifyIdentity方法會去驗証帳號是否正確

namespace Security.Role

{

    public class Principle : IPrincipal

    {

        #region 實作IPrincipal 成员



        private Identity _Identity;

        public IIdentity Identity

        {

            get

            {

                return _Identity;

            }

        }



        //判斷角色是否在規則內

        public bool IsInRole(string ControlRole)

        {

            RoleType controlRole = (RoleType)Enum.Parse(typeof(RoleType), ControlRole);

            if (this._Identity == null)

            {

                //身份驗證失敗

                return false;

            }

            else

            {

                //身份驗證成功

                if (this._Identity.RoleType == controlRole)

                {

                    //登入角色驗証成功

                    return true;

                }

                else

                {

                    //登入角色驗証失敗

                    return false;

                }

            }

        }



        #endregion



        public Principle(Identity Identity)

        {

            //搜尋帳號是否已建立

            this._Identity = verifyIdentity(Identity);

            if (this._Identity != null)

            {

                this._Identity.IsAuthenticated = true;

            }

        }



        //身份驗証

        Identity verifyIdentity(Identity Identity)

        {

            var query = from data in DefaultRoles

                        where data.Name.ToLower() == Identity.Name.ToLower()

                        let Index = this.DefaultRoles.IndexOf(data)

                        select new { Index };

            int count = query.Count();

            Identity identity = null;

            if (count > 0)

            {

                identity = this.DefaultRoles[query.First().Index];

                return identity;

            }

            else

            {

                return null;

            }

        }



        public override string ToString()

        {

            if (this._Identity == null)

                return "";

            else

                return string.Format("帳號:{0},角色:{1}", this._Identity.Name, this._Identity.RoleType.ToString());

        }



        //定義內建帳號

        private List<Identity> _DefaultRoles;

        public List<Identity> DefaultRoles

        {

            get

            {

                if (this._DefaultRoles == null)

                {

                    this._DefaultRoles = new List<Identity>()

                    {

                        new Identity("admin",RoleType.Admin),

                        new Identity("user",RoleType.User),

                        new Identity("power",RoleType.PowerUser)

                    };

                }

                return _DefaultRoles;

            }

        }

    }

}


完成後在Client裡引用它們建立以下控制項

image

 

定義控制項的Role屬性

image

 

呼叫以下方法決定控制項顯示樣式

void login(string user)

{

    this._Ientity = new Identity(user);

    this._Principle = new Principle(_Identity);

    Thread.CurrentPrincipal = _Principle;



    this.roleContainer1.SwitchRole();

    this.label1.Text = this._Principle.ToString();

}

程式載入,有定義Role屬性的控制項,因身份不明被停用

image

按下admin login
image

按下power login

image

按下user login

image


範例下載

Security.Form.zip

你可能感兴趣的:(Provider)