Check permission on every page - c#

in my web site i need to check permission on every page,
i found my self repeating the same code every page.
this is one of my pages
public partial class KitView : AmsBasePage
{
protected void Page_Load(object sender, EventArgs e)
{
IddUser user = new IddUser();
user = (IddUser)Session["user"];
bool isAdmin = user.roles.Where(IddRole => IddRole.R_ID.Equals(3)).First().IsInRole;
bool isIddTeam = user.roles.Where(IddRole => IddRole.R_ID.Equals(2)).First().IsInRole;
bool isProductionTeam = user.roles.Where(IddRole => IddRole.R_ID.Equals(1)).First().IsInRole;
if (isAdmin)
{
hypAddComponent.Visible = true;
hypAddComponent.NavigateUrl = "AddComponent.aspx?CKID=" + Request.QueryString["CKID"];
}
}
}
how is the best practice to have the roles: isAdmin,isIddTeam,isProductionTeam
in every page but not repeating the code below in every page code
IddUser user = new IddUser();
user = (IddUser)Session["user"];
bool isAdmin = user.roles.Where(IddRole => IddRole.R_ID.Equals(3)).First().IsInRole;
bool isIddTeam = user.roles.Where(IddRole => IddRole.R_ID.Equals(2)).First().IsInRole;
bool isProductionTeam = user.roles.Where(IddRole => IddRole.R_ID.Equals(1)).First().IsInRole;

You should put your authorization code in your Master Page (ASP.NET Web Form) or Layout Page (ASP.NET MVC). That way, your authorization logic will only be placed in one location and runs on every page.

If you want to avoid redundant codes, i would suggest to write your authorization logic in a sepearte class or you can even write the aurthorization logic in a MasterPage if you have any. Then inherit them in your webforms.
Note: in your webforms you will have to override your page_load event so that the authorization from your inherited base class runs first.

if you want to avoid repeating authorization code, you should do it at a central location.
there can be many ways for that, but I can suggest you few
Use Master Page - and write the authorization code in Master Page's OnLoad
Create a HttpModule - Insert your own Module in the ASP.NET Page Events PipeLine and handle all the authorization and authentication logic
Now this is what I did in a multi-million $ Project
Create a PageBase.cs being inherited from System.Web.UI.Page - which you are already doing
Create a constructor of the PageBase, in which you can pass current Page permissions i.e.
public void PageBase(AppActivityEnum PageView, AppActivityEnum PageEdit, AppActivityEnum PageDelete)
{
this.pageView = PageView;
this.pageEdit=PageEdit;
this.PageDelete=PageDelete;
VerifyPermission();
}
where VerifyPermission() is:
public void VerifyPermission()
{
var currentUser= SessionHelper.GetCurrentUser();
var permissions = Utility.GetUserPermissions(currentUser.RoleId);
this.CanView=permissions.Contains((int)this.pageView);
this.CanEdit=permissions.Contains((int)this.pageEdit);
this.CanDelete=permissions.Contains((int)this.pageDelete);
}
now these three variables i.e. CanView, CanEdit, CanDelete are public properties in PageBase, hence available to all your pages(wherever you have inherited).
and you can set your controls(add button, delete button), page visibility based on these variables.
so basically, you create an Activity Table for storing ref of each of the Pages. where Activity table looks like
Id
Name
Value
Parent
a typical entry in this table is like:
1 Module-Master MMaster NULL
2 Module-Master-View MMasterView 1
3 Module-Master-Edit MMasterEdit 1
4 Module-Master-Delete MMasterDelete 1
and you maintain RoleAppActivtyMapping (obviously):
Id RoleId AppActivityId
1 1 2
1 1 3
1 1 4
so RoleId one has all the three permissions.
so GetUserPermissions(RoleId) basically gets all the RoleAppActivityMapping entries corresponding to passed Role.
so on every page you call the PageBase' constructor to verify the view permissions. You pass the current Page's AppActivity Id in the constructor.
and if CanView is false: you redirect to "UnAuthorized" page upon hitting the url.

I added in my AmsBasePage class that all pages inherit from .
this code
private bool _isAdmin;
private bool _isIddTeam;
private bool _isProductionTeam;
protected bool isAdmin
{
get { return _isAdmin; }
set { _isAdmin = value; }
}
protected bool isIddTeam
{
get { return _isIddTeam; }
set { _isIddTeam = value; }
}
protected bool isProductionTeam
{
get { return _isProductionTeam; }
set { _isProductionTeam = value; }
}

check your authorization in the master page. That way, I will be checked once and repeatation can be avoided.

Related

why can't i access a function of a web control?

i have the next question:
I've got an .aspx which contains a lot of web controls, this is the one i care:
//line 5
<%# Register src="Controls/UCAttachments.ascx" tagname="UCAttachments" tagprefix="uc1" %>
//line 430
<uc1:UCAttachments ID="UCAttachments" runat="server" Visible="false" />
On the selected index changed event of a combo box, i need to call a function of the web control, this is the code of the .aspx.cs.
private void cbo_SelectedIndexChanged( object sender, EventArgs e )
{
if(this.op == 1){
UCAttachments.visible=true;
UCAttachments.loadById(this.id); <-this doesnt work.
//Even tho, i can access all the other functions of UCAttachments.
//More infor abkout the error:
//'CONTROL' does not contain a definition for 'loadById'and no accessible //method accepting first argument...
}
}
public partial class Controls_UCAttachments: System.Web.UI.UserControl
{
//lots of functions
public void loadById( string id )
{
string query = "SELECT * FROM table WHERE ID = " +id;
//more code
return ;
}
}
you have to make this method static
public partial class Controls_UCAttachments
{
//lots of functions
static public void loadById(string id)
{
string query = "SELECT * FROM table WHERE ID = " + id;
//more code
return;
}
}
and you can call using this syntax
Controls_UCAttachments.loadById(this.id);
so.. very curious thing.
when you have a form which contains a lot of user controls, you need to wait for the metadata file to reload the new methods you've created.
So i closed my visual studio and re opeened a minutes later and the bug desapeared.

Remove Output Cache for User Controls in ASP.NET Webforms

I have an asp.net webforms SaaS application where multiple ecommerce websites are running. Each website has its own domain (abc.com, xyz.com etc.) and each website's content is fetched from the database based on the domain.
Now, in order to improve home page performance I am implementing Output Cache. Please note that the home page already contains multiple user controls (header, footer, top menu, user menu, mini cart, banners, home products etc.). All the user controls are eligible for Output Cache accept user menu (where logged in usernames are displayed, otherwise signup/login links) and mini cart (where no. of cart items are displayed and on click it shows the list of items in cart).
I added Output cache directive on each user control (that I want to be cached) with VaryByCustom to create separate cache for each domain.
<%# OutputCache Duration="300" VaryByParam="*" VaryByCustom="Host" %>
As VaryByHeader is not an available option for UserControls, I added an override function in Global.asax to return current host.
public override string GetVaryByCustomString(HttpContext context, string arg)
{
if (arg == "Host")
{
return context.Request.Url.Host;
}
return String.Empty;
}
Till now, everything is working perfect. User controls are being cached for different domains (hosts) and are being expired on the specified time.
THE PROBLEM: I want to give an option in the admin panel to the website admin users to manually refresh cache of their websites. For that I created a page (refreshcache.aspx) in the frontend application, and simply open that url (for example: abc.com/refreshcache.aspx) when the admin users click the refresh cache button from the admin panel.
I researched a lot and tried multiple approaches to clear user controls cache but failed. The last thing that I implemented is the following code which I added in the home page aspx which creates an object of StaticPartialCachingControl and adds key dependency on user controls cache.
In Home.aspx, I added the following code which is called in Page_Load
protected void LoadControlsCache()
{
CacheKey = "Host-" + Request.Url.Host;
CacheKeyArray[0] = CacheKey;
if (Cache[CacheKey] == null)
{
AddControlCache(header1);
AddControlCache(footer1);
AddControlCache(banner1);
AddControlCache(products1);
}
}
protected void AddControlCache(UserControl uc)
{
StaticPartialCachingControl pcc = (StaticPartialCachingControl)uc.Parent;
pcc.Dependency = new CacheDependency(null, CacheKeyArray);
Cache.Insert(CacheKey, "value", null, DateTime.Now.AddSeconds(300), Cache.NoSlidingExpiration);
}
And to remove the cache for a particular host, I used Cache.Remove method with the host specific key.
In refreshcache.aspx I added the following code
protected void Page_Load(object sender, EventArgs e)
{
Cache.Remove("Host-" + Request.Url.Host);
Response.Redirect("/");
}
I am not sure what I am missing or doing wrong. Just want a way to clear usercontrols cache for a particular host (domain).
Finally got the issue resolved by creating separate keys for all user controls, and adding dependency on user control object.
protected void LoadControlsCache()
{
string CacheKey = Request.Url.Host;
AddControlCache(header1, "header-" + CacheKey);
AddControlCache(footer1, "footer-" + CacheKey);
AddControlCache(banner1, "banner-" + CacheKey);
AddControlCache(products1, "products-" + CacheKey);
}
protected void AddControlCache(UserControl uc, string CacheKey)
{
if (Cache[CacheKey] == null && uc != null)
{
uc.Cache.Insert(CacheKey, 1);
uc.CachePolicy.Dependency = new System.Web.Caching.CacheDependency(null, new string[] { CacheKey });
}
}
Then to clear the cache, used Cache.Remove() with all the usercontrol keys.
protected void Page_Load(object sender, EventArgs e)
{
string CacheKey = Request.Url.Host;
Cache.Remove("header-" + CacheKey);
Cache.Remove("footer-" + CacheKey);
Cache.Remove("banner-" + CacheKey);
Cache.Remove("products-" + CacheKey);
Response.Redirect("/");
}
Hope it might help someone with a similar question!

In relation to acumatica, is there a way to grab a variable from one table and use it as part of an id for another table?

The 'Customer' form has a variable called AcctReferenceNbr (Variable that I'm trying to grab shown in yellow) which takes a two-letter abbreviation of the customer name. I am currently editing the Projects form, and I want to use this abbreviation as part of the External Ref. Nbr.
The attached image End Result I'm trying to achieve shows what the end result should look like. The number from the QuoteID is appended to the abbreviation.
I am able to successfully grab the QuoteID as it is part of the Projects table, but I am currently unable to grab the AcctReference Nbr from the Customer table.
I have a RowSelected event on the QuoteID field, which is shown below:
namespace PX.Objects.PM
{
public class ProjectEntry_Extension : PXGraphExtension<ProjectEntry>
{
#region Event Handlers
protected void PMProject_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
PMProject row = (PMProject)e.Row;
if (row.ContractCD != null) {
PMProject item = PXSelectorAttribute.Select<PMProject.contractCD>(cache, row) as PMProject;
// The "UP" string is where the abbreviation is supposed to be,
// but I just added two letters to test if the appending works, which it does.
row.ExtRefNbr = "UP" + item.ContractCD;
}
}
#endregion
}
}
What I've tried so far:
Accessing the Customer table namespace to grab the value and pass it to the Projects form, which didn't work because it didn't accept the Customer type in the Projects form.
Adding a PXDefault attribute to the External Ref. Nbr which would try and grab the variable using SQL.
I'm a bit stuck on what else I can try. Any help would be appreciated :)
UPDATED
Below is how I went about trying to grab the AcctReferenceNbr value from the Customer table.
The reason why I tried using the PXSelectorAttribute method was that I added the AcctReferenceNbr as a column to the Quote ID selector (selector is shown in the link above called 'End Result I'm trying to achieve').
So I figured I could try and grab that value in the Customer namespace, as that is where the variable resides, and pass that up to the Project namespace above.
Then, I would call the public method below in the Project namespace to get the required abbreviation:
// instead of this
row.ExtRefNbr = "UP" + item.ContractCD;
// it would be this
row.ExtRefNbr = PX.Objects.AR.CustomerMaint_Extension.getAcctReferenceNbr(cache, e) + item.ContractCD;
namespace PX.Objects.AR
{
public class CustomerMaint_Extension : PXGraphExtension<CustomerMaint>
{
#region Event Handlers
public static string getAcctReferenceNbr(PXCache cache, PXRowSelectedEventArgs e)
{
BAccount row = (BAccount)e.Row;
BAccount item = PXSelectorAttribute.Select<BAccount.acctReferenceNbr>(cache, row) as BAccount;
return item.acctReferenceNbr;
}
}
#endregion
}
}
Is there a proper way to target the actual table?
try this. I haven't tested this but give it a go.
protected void PMProject_RowSelected(PXCache cache, PXRowSelectedEventArgs e)
{
PMProject row = (PMProject)e.Row;
if (row.ContractCD != null && row.CustomerID != null)
{
BAccount ba = (BAccount )PXSelectorAttribute.Select<PMProject.customerID>(cache, row) ;
row.ExtRefNbr = ba.AcctReferenceNbr+ row.ContractCD;
}
}
you certainly don't need to extend the CustomerMaint graph.

Accessing a string variable from one method to another which is declared globally is giving null value

I am working on a web app;ication based on asp.net with c#,I have two methods specified below.
public partial class ClerkReception_CreateRecords : System.Web.UI.Page
{
string patid;
protected void ddryear_textchanged(object sender, EventArgs e)
{
string month = "";
if (ddrmonth.SelectedItem.Text == "Jan")
{
month = "01";
}
else if (ddrmonth.SelectedItem.Text == "Feb")
{
month = "02";
}
else if (ddrmonth.SelectedItem.Text == "Mar")
{
month = "03";
}
string year;
year = ddryear.SelectedItem.Text;
string locid = Session["Location"].ToString();
patid = locid + month + year;//Ex:AT112013
myConnection obj = new myConnection();
//string result = obj.fnDisplayManualRecords(year, month, locid);
string result = obj.fnDisplayManualRecords1(patid);
txtlast.Text = result.ToString();
if (ddrmonth.SelectedItem.Text != null || ddryear.SelectedItem.Text != null)
{
txtlast.Visible = true;
lbllast.Visible = true;
BtnProceed.Visible = true;
}
}
This is a method used when a item is selected from dropdownlist,where the patid returns the value.
I need to access the same value of patid inside a another method shown below,Hence I declared the patid as global variable so that I can access the value in any method.But its giving null.How to retieve the vale from one method to another method?
protected void BtnProceed_Click(object sender, EventArgs e)
{
string x = patid;//shows null
using (SqlConnection cn = new SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
using (SqlCommand cmd = new SqlCommand("select top 1(SUBSTRING(patientid,9,4)) as MaxpatientID from Patient_Data where PatientID like '"+patid+"%' order by PatientID desc;", cn))
{
try
{
cn.Open();
using (SqlDataReader rdr = cmd.ExecuteReader())
{
//int Patcount;
if (rdr.Read())
{
int Patcount = int.Parse(rdr["MaxpatientID"].ToString());
// if(Patcount == 0)
}
}
}
catch (Exception ex)
{
// handle errors here
}
}
}
}
}
The global variables are created / intialized between postback in asp.net and they do not retain the values between postback as http is stateless protocol, you need to use ViewState for that. You can read more about ViewState and Stateless protocol over here.
To set value in ViewState
ViewState["patid"] = locid + month + year;//Ex:AT112013;
To get value from ViewState
string patid = ViewState["patid"].ToString();
View State
View state's purpose in life is simple: it's there to persist state
across postbacks. (For an ASP.NET Web page, its state is the property
values of the controls that make up its control hierarchy.) This begs
the question, "What sort of state needs to be persisted?" To answer
that question, let's start by looking at what state doesn't need to be
persisted across postbacks. Recall that in the instantiation stage of
the page life cycle, the control hierarchy is created and those
properties that are specified in the declarative syntax are assigned.
Since these declarative properties are automatically reassigned on
each postback when the control hierarchy is constructed, there's no
need to store these property values in the view state. You can read
more about viewstate here.
Welcome to the world of post backs, each post back recreates the page (class) variables, so you need to save it before post back or it will be gone.
Use a cache object, such as Session to maintain values between post back and page navigation. Session gives you the power to store and retrieve objects across multiple pages in your application, including just one if you are continually posting back to it.
You can use Session, like this:
Storing value in Session:
Session["ValueToKeep"] = "My important information";
Retrieving value from Session:
// Make sure it is in session cache before we try to get it
if(Session["ValueToKeep"] != null)
{
string valueINeed = Session["ValueToKeep"].ToString();
}
Note: All items stored in Session are Objects thus the usage of .ToString() on the Session item. An item is boxed as an object when inserted into Session, but must be unboxed (cast) when retrieved.
You class level variables are re-created on postback. You will need to persist them somewhere that continues across requests.. such as ViewState, Session, etc.
The best way to interact with two methods / functions / event-function in side class is just declaring its accessible modifiers to public and you can call any object of that class after initialize some value to it.
public void ddryear_textchanged(object sender, EventArgs e) {....}
public void BtnProceed_Click(object sender, EventArgs e) {....}
create one variable inside class like string x; and initialize it in constrictor { x="some text "; } this is how code works...
There are many ways to get the value of global parameter,
one way is to define the parameter as static

LoadControlState not getting fired

I'm having problems with a custom control (which inherits from a user control) - my LoadControlState isn't getting fired.
Well, to be precise: it gets fired normally, but when i override the page's LoadPageStateFromPersistenceMedium and SavePageStateToPersistenceMedium functions, it no longer gets fired.
Are there any typical reasons for the LoadControlState not getting fired that i should look into? Are there any preconditions for when it does get fired?
Thanks
For what it's worth, here's how i'm overriding the Save/LoadPageStateFromPersistenceMedium functions. Basically, it stores the viewstate in the users session, to make the postbacks faster:
// Inspired by: http://aspalliance.com/72
const string ViewStateFieldName = "__VIEWSTATEKEY";
const string ViewStateKeyPrefix = "ViewState_";
const string RecentViewStateQueue = "ViewStateQueue";
const int RecentViewStateQueueMaxLength = 5;
protected override object LoadPageStateFromPersistenceMedium()
{
// The cache key for this viewstate is stored in a hidden field, so grab it
string viewStateKey = Request.Form[ViewStateFieldName] as string;
if (viewStateKey == null) return null;
// Grab the viewstate data using the key to look it up
return Session[viewStateKey];
}
protected override void SavePageStateToPersistenceMedium(object viewState)
{
// Give this viewstate a random key
string viewStateKey = ViewStateKeyPrefix + Guid.NewGuid().ToString();
// Store the viewstate
Session[viewStateKey] = viewState;
// Store the viewstate's key in a hidden field, so on postback we can grab it from the cache
ClientScript.RegisterHiddenField(ViewStateFieldName, viewStateKey);
// Some tidying up: keep track of the X most recent viewstates for this user, and remove old ones
var recent = Session[RecentViewStateQueue] as Queue<string>;
if (recent == null) Session[RecentViewStateQueue] = recent = new Queue<string>();
recent.Enqueue(viewStateKey); // Add this new one so it'll get removed later
while (recent.Count > RecentViewStateQueueMaxLength) // If we've got lots in the queue, remove the old ones
Session.Remove(recent.Dequeue());
}
Since .NET 2.0, it is recommended to put your state persistent logic in a custom class derived from PageStatePersister. So you may try taking that approach.
What are you returning from your LoadPageStateFromPersistenceMedium method implementation? It should probably be an instance of the System.Web.UI.Pair initialized with both the ViewState and the ControlState data:
return new Pair([Restored ControlState], [Restored ViewState]);
The following code fixed it:
PageStatePersister pageStatePersister;
protected override PageStatePersister PageStatePersister
{
get
{
// Unlike as exemplified in the MSDN docs, we cannot simply return a new PageStatePersister
// every call to this property, as it causes problems
return pageStatePersister ?? (pageStatePersister = new SessionPageStatePersister(this));
}
}

Categories