What is the best way to assign security logic to a method in ASP.NET WebForms? Where instead of checking under each method if the user is logged in, can't we use method attributes?
Example, instead of doing this:
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (!UserLoggedIn)
{
Response.Redirect("/login");
}
//Do stuff
}
I would like to do something like below. I've seen it done in ASP.NET MVC apps but I wonder if I can pull it off with webforms. And also what would be the best practice for ensuring only an authenticated user can continue and others get redirected to login page?
Ex: Desired. Where Secure is a method attribute:
[Secure]
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
//Do stuff
}
How do I go about creating such method attribute? And if that is not possible, how would you recommend I do it? I have many usercontrols that need this on page_load or oninit and I am looking for a better way to do it.
Declare your attribute
[AttributeUsage(AttributeTargets.Class)]
public class SecureAttribute: Attribute
{
}
Create custom base page class for all forms
public class PageBase: Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
var secureAttr = Attribute.GetCustomAttribute(this.GetType(), typeof (SecureAttribute));
if (secureAttr != null)
{
bool UserLoggedIn = false; // get actual state from DB or Session
if (!UserLoggedIn)
{
Response.Redirect("/login");
}
}
}
}
Inherit all your forms from the PageBase
[Secure]
public partial class Profile: PageBase
{
}
Create similar UserControlBase for user controls.
One possible Solution would be a PageBase helper class to avoid check that condition on every single pages on your ASP.NET web forms and just inherits the page-base in your aspx.cs classes. something like the code below:
for example you want to make sure that some web forms are only accessible by Admin users then you could have a AdminPageBase class to check this condition for all of your web pages.
your base class:
public class AdminPageBase : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
if (!Context.User.Identity.IsAuthenticated ||
!HttpContext.Current.User.IsInRole(Roles.Admin.ToString()))
{
this.RedirectToLogin();
}
}
protected void RedirectToLogin()
{
//...
Response.Redirect("~/SignIn.aspx");
}
}
Note: Roles.Admin.ToString() is an enum, but you can also use a plain string if you like
and in your web form classes you only inherits this base class like this:
e.g. AdminPage1.aspx.cs
public partial class AdminPage1: AdminPageBase
{
//....
}
e.g. AdminPage2.aspx.cs
public partial class AdminPage2: AdminPageBase
{
//....
}
and you could always do the same for all other pages in your solution.
you could also change Page_Init to Page_Load on your PageBase class but the reason I have chosen the Page_Init is because you may need Page_Load event to check other things on your page so it's a good place to check your website security.
In order to intercept method calls, I would recommend utilizing some AOP framework, e.g. PostSharp, which allows easily inject behaviors before and after method execution by declaring custom aspect:
[Serializable]
public class SecureAttribute : OnMethodBoundaryAspect
{
public override void OnEntry(MethodExecutionArgs args)
{
bool UserLoggedIn = false; // get from DB
if (!UserLoggedIn)
{
HttpContext.Current.Response.Redirect("/login");
}
}
}
And applying that attribute to any method
public partial class Profile : Page
{
[Secure]
protected void Page_Load(object sender, EventArgs e)
{
}
[Secure]
protected void Button1_Click(object sender, EventArgs e)
{
}
}
As far as I know, PostSharp incures minor performance hit, or incures no performance hit at all, as PostSharp emits MSIL instructions.
Related
I want to execute a function on Page_load event of every System.Web.UI.Page from which derives my own CustomPage class (which obviously inherits from Page class as well)
what I have done so far it that I created CustomPage class like this:
public class CustomPage : System.Web.UI.Page
{
protected virtual void Page_Load(object sender, EventArgs e)
{
CallTOTheDesiredFunction(); //this is the call to the function I want
}
}
And in the derived Page classes I am doing this:
public class DerivedPage : CustomPage
{
protected override void Page_Load(object sender, EventArgs e)
{
base.Page_Load(sender, e);
//the rest of the page load event which executes from here on
}
}
As it is obvious, this approach is working but it is not the best solution since I have to call base.Page_Load(sender, e) on every derived page.
Is there a better solution to what I am trying to achieve?
Thank you in advance
Yes. It is better to override the Onload method rather than relying on deriving classes to call the base method.
You can still hook on the Load event in every page, but use the method in the base class.
public class CustomPage : System.Web.UI.Page
{
protected override void OnLoad(EventArgs e)
{
CallTOTheDesiredFunction(); //this is the call to the function I want
base.OnLoad(e);
}
}
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 some WebForms, such as First.ascx.cs, Second.ascx.cs, Third.ascx.cs and so on!
Well, I'd like to call a function (let's say, startFunction()) at the PreInit stage, and another one (let's say, endFunction()) and the PreRender stage, for EACH context.
So:
startFunction();
... First.ascx.cs PageLoad execution...
endFunction();
startFunction();
... Second.ascx.cs PageLoad execution...
endFunction();
startFunction();
... Third.ascx.cs PageLoad execution...
endFunction();
without write the same start/end function and copy and paste for each context I need to control. Is there a good strategy with .NET (3.5) and WebForms?
Inheritance!
Create a basecontrol where you attach to those events and then derive from it.
MarkzzzClass .cs
public abstract class MarkzzzClass : System.Web.UI.UserControl
{
//do something
}
BaseControl.cs:
public abstract class BaseControl : MarkzzzClass
{
protected override void OnPreRender(EventArgs e)
{
EndFunction();
base.OnPreRender(e);
}
protected override void OnInit(EventArgs e)
{
StartFunction();
base.OnInit(e);
}
}
First.ascx.cs:
public partial class First : BaseControl
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
Take the following scenario. I have multiple ASPX pages. Login, Logout, Main, Messages, etc... They all inherit from System.Web.UI.Page of course. For all the pages, I want to override the Render method from the Page class. I could easily copy and paste the same code into each page like so:
protected override void Render(HtmlTextWriter writer)
{
//Code Logic Here
}
But if I had many pages, lets say 20, maintaining the code in each page could get very time consuming and error prone.
That made me think a bit and I thought okay lets try this...override the function in each page but call a static function. That way changing the static function would result in a change for every page. Which works fine... But its not really nice and clean, having to override like that on every single page. Anybody have any ideas or thoughts on this one? Perhaps something simple I am overlooking? Thanks
EDIT: Some pages use the System.Web.UI.Page class and some pages inherit from another class called ModifiedPage which inherits and overridies other functions of the System.Web.UI.Page class. So its not as simple as inheriting all the pages from one class.
EDIT2: All pages need this behavior, some already derive from another class, and I am unable to change the implementation or inheritance hierarchy of that other class.
Instead of inheriting from System.Web.UI.Page, have them all inherit from MyProject.MyBasePage which inherits from Page:
public abstract class MyBasePage : System.Web.UI.Page
{
protected override void Render(HtmlTextWriter writer)
{
//Code Logic Here
}
}
and...
public partial class MySpecificPage : MyBasePage
{
}
Edit
Clarification added to the question now points out the real puzzle - the pages which all need this common Render logic have different inheritance paths. That is more tricky in c#, and you won't be able to avoid at least a little bit of redundant plumbing code. There's plenty of different ways to handle this - here's one approach I have taken in the past:
1) Create an interface for this common functionality. For example, IOverrideRender:
public interface IOverrideRender
{
void Register(OverrideRender render);
}
public delegate void OverrideRender(HtmlTextWriter writer, Action<HtmlTextWriter> original);
2) Each page which needs this functionality gets the interface and wires it like so:
public partial class MyPage : Page, IOverrideRender
{
void IOverrideRender.Register(OverrideRender render)
{
this.overrideRender = render;
}
private OverrideRender overrideRender;
protected override void Render(HtmlTextWriter writer)
{
if(overrideRender != nul)
{
overrideRender(writer, base.Render);
}
else
{
base.Render(writer);
}
}
}
3) In an HttpModule, check to see if the handler is IOverrideRender and if so, pass in your custom render method:
public class OverrideRenderModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.PreRequestHandlerExecute += this.HandlePreRequestExecute;
}
private void HandlePreRequestExecute(object sender, EventArgs e)
{
HttpApplication app = (HttpApplication)sender;
IOverrideRender overridable = app.Context.CurrentHandler as IOverrideRender;
if(overridable != null)
{
overridable.Register(
(writer, original) => {
writer.Write("Hello world"); //custom write
original(writer); //calls base.Render
});
}
}
}
You should create a BasePage which inherits from System.Web.UI.Page. Within the BasePage you could override the Render method and then have all your pages inherit from BasePage.
Add a level in your hierarchy and make a BasePage and do your override there, then inherit all other page from BasePage
In ASP.Net Web Forms there are cases that I've come across that create order dependent code. As an obvious code smell I'm looking for solutions to solve this problem.
A pseudo-code example would be:
Calling Code :: Page.aspx
protected void Page_Load(...) {
var control = LoadControl("ControlX.ascx");
// Ugly since the control's constructor is not used by LoadControl
control.SetDependencies(...);
}
Control Code :: ControlX.ascx
public void SetDependencies(...) {
}
protected void Page_Load(...) {
if (dependencies are null)
throw Exception();
else
ContinueProcessing();
}
LoadControl has two signatures, the one used above accepts a string for the control classes physical location and correctly creates the child controls. Whereas the second signature accepts the control class as a class type, and any parameters for the constructor, however the child controls are not created as detailed in TRULY Understanding Dynamic Controls.
So how can I eliminate this order dependency in the cleanest way? My first thought is that if I dynamically created the child controls in ControlX, but then that can be cumbersome for larger controls. Thoughts?
(I hope in understood the problem correctly) You could invert the dependecy like this:
The host of ControlX.ascx (either another control or a page) must implement a certain interface (defined by ControlX). ControlX can then access its dependencies from its host through that interface.
A small example would be this:
public interface IControlXHost
{
// methods, properties that allow ControlX to access its dependencies
int GetStuff();
}
public partial class ControlX : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
var host = (Parent as IControlXHost) ?? (Page as IControlXHost);
if (host == null) {
throw new Exception("ControlX's parent must implement IControlXHost");
}
else {
int number = host.GetStuff();
}
}
}
The host (the page or the control hosting ControlX) would then have to implement that interface, e.g:
public partial class Default4 : System.Web.UI.Page, IControlXHost
{
public int GetStuff() {
return 33;
}
protected void Page_Load(object sender, EventArgs e) {
var control = LoadControl("ControlX.ascx");
}
}
IMO, this approach makes controls easier reusable, since they "automatically" tell you about the requirements that have to be fulfilled to host the control. You don't have to find out which methods of the control you have to call in which order.