I want to implement access control for usercontrols depending on user role(s), I want to do it on the control base class, in such way that on every user control I only need to set a string with allowed roles to see the user control
This is how an user control class may look like:
public partial class SimpleMenu : MyUsrControlBase
{
protected void Page_Load(object sender, EventArgs e)
{
AlloweRoles = "RoleA, RoleB"
//specific user control functionality
}
}
The base class:
public abstract class MyUsrControlBase : UserControl
{
private string _allowedRoles;
protected internal string AllowedRoles
{
set
{
_allowedRoles = value;
ValidateRoles();
}
}
private ValidateRoles()
{
//Role validation logic
if (RoleHasAccess)
{
// Set user control visibility to true
}
else
{
// Set user control visibility to false
}
}
}
How to set up user control visibility from the base class depending on the validation result?
Also which event in the user control is the best to set the roles?
AlloweRoles = "RoleA, RoleB"
You can set the inherited Visible property from the base class:
private void ValidateRoles()
{
// Role validation logic.
Visible = RoleHasAccess;
}
EDIT: Concerning your second question, you can initialize the AllowedRoles property in the derived class' constructor, so it will be set for the whole lifespan of the user control:
public partial class SimpleMenu : MyUserControlBase
{
public SimpleMenu()
{
AllowedRoles = "RoleA, RoleB";
}
}
Related
I have a main window in WPF and it contains:
A Tab Control having different tabs. Each tab has a different control in it and contains a data grid.
A frame control - it also has different controls respectively for data entry.
A Refresh Button (Yet to implement)
I have implemented the tab controls and frame for data entry successfully but problem is I cannot refresh the tab control until I switch across the tabs. I want to have a central Refresh button on main-window (one I aforementioned).
Can anyone guide me how can I do it?
And since tab's current object type will only be decided at the Run-time, so is it Polymorphism?
You can use an interface for all the usercontrols:
public interface IRefreshAble
{
void Refresh();
}
public interface ICanDeleteItem
{
void Delete(/*parameters omitted*/);
bool CanDelete { get; }
}
public interface IHoldATypedItem ///sorry for bad name
{
Type TheType { get; }
}
Then you implement this interface by the usercontrols:
public class TheUserControl : UserControl, IRefreshAble, ICanDeleteItem, IHoldATypedItem
{
public void Refresh()
{
//Your refreshcode
}
public bool CanDelete {get { /*code that indicates if an item can be deleted*/ } }
public void Delete(/*parameters ommited*/)
{
if(CanDelete)
{
//Delete Item
}
}
public Type TheType { get { return typeOf(Employee); } }
// otherstuff
}
Now you can put all of your UserControls(for example) in a List<IRefreshAble> and do stuff like:
foreach(IRefreshAble item in theList)
{
item.Refresh();
}
If you have more than this Refresh() method common for all Usercontrols you can just expand the interface for this members and get the polymorphism you need.
I've created some custom textboxes which are inherited from textbox.
For the next step I want to register javascript with a wrapper.
Decorator pattern allow me to do if only I can inherit it from textbox and pass custom textbox as a constructor parameter.
Problem is that how can I use constructor when I add a control to aspx page or basically how can I use decorator pattern for asp.net controls.
EDIT:
Simply this is my validation base class (IField is an validation interface. This can be ignored):
public abstract class ValidationBase : TextBox, IField
{
private readonly IField _field;
protected ValidationBase(IField field)
{
_field = field;
}
public int MinLength
{
get { return _field.MinLength; }
set { _field.MinLength = value; }
}
public bool Required
{
get { return _field.Required; }
set { _field.Required = value; }
}
// other porperties etc...
protected override void OnPreRender(EventArgs e)
{
// DO SOME STUFF...
base.OnPreRender(e);
}
}
And this is my concrete class (EmailField is a concrete impl. of IField ignore...):
public class ValidationEmail : ValidationBase
{
public ValidationEmail()
: base(new EmailField(string.Empty))
{
}
}
And finally I want to implement this (I've made up my mind on wordpad this can't be the exact impl.):
public class JsRegisterDecorator : ValidationBase
{
private readonly ValidationBase _validationObj;
//I am not quite sure about the constructor but i can handle
public JsRegisterDecorator(ValidationBase concreteValidationObj)
: base(concreteValidationObj)
{
_validationObj = concreteValidationObj;
}
//Wrap the properties
protected override void OnPreRender(EventArgs e)
{
//Register JS Files...
_validationObj.OnPreRender(e);
}
}
The problem is that How can I use this decorator? Because asp.net construct controls automatically:
<vc:ValidationEmail ID="ValidationEmail1" runat="server"/>
I don't know can I use this (where can I put the constructor parameter?):
<vc:JsRegisterDecorator ID="ValidationEmailWithJs1" runat="server"/>
I don't think Decorator pattern fits well here. In general I saw more applications of Builder and Factory Method for ASP.NET controls.
To partially solve your task you can use ControlBuilder. It will give you ability to change the type of the control from ValidationBase to JsRegisterDecorator or ValidationEmail. You need to decorate ValidationBase class with ControlBuilderAttribute, inherit builder class from ControlBuilder and override Init method.
[ControlBuilder(typeof(ValidationBaseBuilder))]
public abstract class ValidationBase : TextBox, IField { }
public class ValidationBaseBuilder: ControlBuilder
{
public override void Init(TemplateParser parser, ControlBuilder parentBuilder, Type type, string tagName, string id, System.Collections.IDictionary attribs)
{
var newType = typeof(/*here you can put a JsRegisterDecorator type*/);
base.Init(parser, parentBuilder, t, tagName, id, attribs);
}
}
But I'm not sure about such approach. ControlBuilder cannot give you easy control over constructor. Surely you can override ProcessGeneratedCode in ControlBuilder and David Ebbo has a blog post worth reading but it would not be an easy task to rewrite constructor for control and make solution simple.
As alternative that will work I can suggest to add an abstract (or virtual) method like RegisterScripts inside ValidationBase and call it in OnPreRender. Every control will know what scripts it needs and the process of new validator control creation will be clean and simple. If you want to separate knowledge of JS scripts from concrete implementations then approach as seen in ASP.NET DynamicData (read MetaTable) could be used.
Another thing that I can see is that your idea is close enough to DynamicControl and maybe it would be possible to get more ideas from ASP.NET DynamicData like Field Templates and IFielTemplateFactory.
I solve my problem AlexanderManekovskiy's help and also some other questions:
ASP.NET RenderControl or RenderChildren fail
How to add child nodes to custom asp.net user control derived from System.Web.UI.Control
ASP.NET Custom/User Control With Children
And here is the solution:
I've made JsRegistererForValidationBase as a WebControl and implemented INamingContaier.
For the children elements I've created Children property which accepts olny list of Validation Base.
And finally OnInit method, I've registered the js.
Here is the code:
[ParseChildren(true)]
[PersistChildren(true)]
[ToolboxData(#"<{0}:JsRegistererForVB runat=""server""></{0}:JsRegistererForVB>")]
public class JsRegistererForValidationBase : WebControl, INamingContainer
{
private ValidationFieldCollection _children;
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public ValidationFieldCollection Children
{
get
{
if (_children == null)
_children = new ValidationFieldCollection();
return _children;
}
}
protected override void CreateChildControls()
{
Controls.Clear();
foreach (var c in _children)
Controls.Add(c);
}
protected override void OnInit(EventArgs e)
{
//DO THE REGISTER STUFF
base.OnInit(e);
}
protected override void Render(HtmlTextWriter writer)
{
RenderChildren(writer);
}
}
public class ValidationFieldCollection : List<ValidationBase> { }
}
And at the aspx side it becomes like this:
<vc:JsRegisterer ID="JsRegisterer1" runat="server">
<Children>
<vc:ValidationEmail ID="ValidationEmail1" runat="server"/>
<vc:ValidationEmail ID="ValidationEmail2" runat="server"/>,
<!--etc-->
</Children>
</vc:JsRegisterer>
For the detailed imlementation I added the code to codeplex
i have 1 aspx page and 1 user control. I want to access hidden field of aspx page in the code behind of user control page.
Please help me on this.
Use Page.FindControl
var hiddenField = this.Page.FindControl("hiddenField") as HiddenField;
Here's one way to do it:
Expose the hidden field control as a public property of the containing page.
In the user control, cast Page to the specific type of the containing page.
Access the property.
I don't really like this approach as it tightly couples the user control with the containing page type, but this seems to happen frequently in web forms.
Example
public class MyPage : Page
{
public HtmlInputHidden MyHiddenField
{
get{ return this.hdnField1; }
}
}
public class MyUserControl : UserControl
{
protected override OnLoad( EventArgs e )
{
MyPage p = (MyPage)Page;
HtmlInputHidden h = p.MyHiddenField;
}
}
Example 2 - Parent Initializes Child
This example is cleaner in that the child is agnostic of its parent. However, it requires the parent to initialize the child at the right time (which can be tricky with the web form page lifecycle) and requires that the parent have knowledge of the inner workings of the child.
public class MyPage : Page
{
protected override OnLoad( EventArgs e )
{
this.MyUserControl.Initialize( this.MyHiddenField );
}
}
public class MyUserControl : UserControl
{
public void Initialize( HtmlInputHidden input )
{
// now child user control has access to the data without needing to know
// about its parent
}
}
I'm designing a simple expander control.
I've derived from UserControl, drawn inner controls, built, run; all ok.
Since an inner Control is a Panel, I'd like to use it as container at design time. Indeed I've used the attributes:
[Designer(typeof(ExpanderControlDesigner))]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
Great I say. But it isn't...
The result is that I can use it as container at design time but:
The added controls go back the inner controls already embedded in the user control
Even if I push to top a control added at design time, at runtime it is back again on controls embedded to the user control
I cannot restrict the container area at design time into a Panel area
What am I missing? Here is the code for completeness... why this snippet of code is not working?
[Designer(typeof(ExpanderControlDesigner))]
[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
public partial class ExpanderControl : UserControl
{
public ExpanderControl()
{
InitializeComponent();
....
[System.Security.Permissions.PermissionSet(System.Security.Permissions.SecurityAction.Demand, Name = "FullTrust")]
internal class ExpanderControlDesigner : ControlDesigner
{
private ExpanderControl MyControl;
public override void Initialize(IComponent component)
{
base.Initialize(component);
MyControl = (ExpanderControl)component;
// Hook up events
ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService));
IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService));
s.SelectionChanged += new EventHandler(OnSelectionChanged);
c.ComponentRemoving += new ComponentEventHandler(OnComponentRemoving);
}
private void OnSelectionChanged(object sender, System.EventArgs e)
{
}
private void OnComponentRemoving(object sender, ComponentEventArgs e)
{
}
protected override void Dispose(bool disposing)
{
ISelectionService s = (ISelectionService)GetService(typeof(ISelectionService));
IComponentChangeService c = (IComponentChangeService)GetService(typeof(IComponentChangeService));
// Unhook events
s.SelectionChanged -= new EventHandler(OnSelectionChanged);
c.ComponentRemoving -= new ComponentEventHandler(OnComponentRemoving);
base.Dispose(disposing);
}
public override System.ComponentModel.Design.DesignerVerbCollection Verbs
{
get
{
DesignerVerbCollection v = new DesignerVerbCollection();
v.Add(new DesignerVerb("&asd", new EventHandler(null)));
return v;
}
}
}
I've found many resources (Interaction, designed, limited area), but nothing was usefull for being operative...
Actually there is a trick, since System.Windows.Forms classes can be designed (as usual) and have a correct behavior at runtime (TabControl, for example).
ParentControlDesigner doesn't know what you want do. It only knows you want your UserControl to be a container.
What you need to do is implement your own designer which enables design mode on the panel:
using System.ComponentModel;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace MyCtrlLib
{
// specify my custom designer
[Designer(typeof(MyCtrlLib.UserControlDesigner))]
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
}
// define a property called "DropZone"
[Category("Appearance")]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public Panel DropZone
{
get { return panel1; }
}
}
// my designer
public class UserControlDesigner : ParentControlDesigner
{
public override void Initialize(System.ComponentModel.IComponent component)
{
base.Initialize(component);
if (this.Control is UserControl1)
{
this.EnableDesignMode(
(UserControl1)this.Control).DropZone, "DropZone");
}
}
}
}
I learned this from Henry Minute on CodeProject. See the link for some improvements on the technique.
In addition to the answer above. It is mentioned in the comments, that the user is able to drag the WorkingArea. My fix for that is to include the WorkingArea panel in another panel, setting it to Dock.Fill. To disallow the user to change it back, I have created a class ContentPanel that overrides and hides the Dock property:
class ContentPanel : Panel
{
[Browsable(false)]
public override DockStyle Dock
{
get { return base.Dock; }
set { base.Dock = DockStyle.Fill; }
}
}
For me, this makes it sufficiently safe. We are only using the control internally, so we mainly want to prevent developers from accidently dragging things around. There are certainly ways to mess it up anyway.
To prevent the working area from being moved/resized in the designer you have to create a class for that working area that hides the Location, Height, Width, Size properties from the designer:
public class WorkingArea : Panel
{
[Browsable(false)]
[EditorBrowsable(EditorBrowsableState.Never)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public new Point Location
{
get
{
return base.Location;
}
set
{
base.Location = value;
}
}
...
}
Here is the design problem in pseudo example:
It is ASP.NET User control (UC) which uses the "Food" object as data source and this object has property FoodType - "Veg" || "Nonveg".
The user control changes UI display depending upon FoodType property. In code-behind class of User Control, some methods have same if/then/else condition: if(Food.FoodType == "Veg")... else ...
Here, I would like use State-like pattern such that code-behind class of User Control will contain two inner/nested classes, i.e. "VegFood" class and "NonvegFood" class. Now, lets say, NonvegFood class will contain its own logic implementation.
But having one interface, two instance classes (as nested) which will be used in this user control only, could be overdesign. In addition to that, UC does not have driver method where I can call related methods in one if block, like they are "DataBound" and "ItemCreated".
Still, is it possible to have State like pattern inside UC class? Probably two instance inner classes inside UC and somehow if I can delegate call to one of these inner class?
class UC : UserControl
{
class VegFood
{
string DisplayName
{
get
{
return "Rice";
}
}
}
class NonvegFood
{
string DisplayName
{
get
{
return "Chicken";
}
}
}
protected string DisplayName
{
get
{
return Instance.DisplayName;
}
}
/*********** MAGIC Property ****************/
private ? Instance
{
get
{
return ?;
}
}
}
I do not think that having three nested classes is not design overkill if it makes the code easier to maintain.
I would suggest an abstract base State class which defines the contract of your states. Each state would inherit from this.
Extended your code sample:
class UC : UserControl
{
protected string DisplayName
{
get
{
return Instance.DisplayName;
}
}
/*********** MAGIC Property ****************/
private FoodState _instance = null;
private FoodState Instance
{
get
{
if (_instance == null)
{
if (FoodType == "Veg")
{
_instance = new VegFood();
}
else
{
_instance = new NonvegFood();
}
}
return _instance;
}
}
abstract class FoodState
{
abstract public string DisplayName {get;}
}
class VegFood : FoodState
{
public string DisplayName
{
get
{
return "Rice";
}
}
}
class NonvegFood : FoodState
{
public string DisplayName
{
get
{
return "Chicken";
}
}
}
}
You probably don't need the protected DisplayName property on the UserControl directly, as Instance.DisplayName could be used directly by the aspx page.