This is possibly very lame question and I lack knowledge about ASP.Net. In this case a link to an article explaining would be very welcome.
I'm working on web-site on ASP.NET with C# as codebehind. My current project involves developing few pages with very similar functionality and a many functions are the same. For example
private void PermissionCheck()
{
if (null == Session["UserID"] ||
null == Session["ProjectID"] ||
null == Session["AssetID"] ||
null == Session["ProjectName"])
{
Response.Redirect("~/Login.aspx");
}
}
Would be the same on 2 pages. Some other things are the same as well. I would like to put this into common base class. But there are other functions that don't really belong to pages at all:
private string GetAttachmentTempPath()
{
return Request.PhysicalApplicationPath + WebConfigurationManager.AppSettings.Get("AttachmentsTempFolder");
}
I would like to move this into Attachment class, but to get the physical path of the application, I need to pass in Request object into that method, which is not really nice, as it couples Attachment class with Page.Request object.
Is there any way to move these functions somewhere else without needing to pass Page.Request objects around??
p.s. The appliction is huge, and there is no scope to change the entire architecture.
For your permission thing you could make a base page class:
class BasePage : Page
{
...
protected override OnInit() {
// do check here
}
}
Now you can implement your page like this class MyOtherPage : BasePage { ... }
The OnInit gets executed everytime your MyOtherPage gets loaded.
You can see a complete page lifecycle here: Link
For your other problem: Consider to implement a global available static tool class
Update
A good approach for making things like web.config easier to access is a Singleton. In asp.net a singleton is only created once and lives until the asp worker process gets stopped . So this values are shared across the whole asp.net application. This is also good for storing data in a global context that you dont want to get out of your database or file anytime a user makes a page request (for example a version number or things like that)
Update 2
To access the request without passing it to every function, use this:
HttpContext.Current.Request
Base page is a good option for reusable code in Page level. Other than that for things like configuration values it's good to come up with utility classes specifically for those methods base don there type of operations.
If you need to avoid passing in Page object into these types of utility methods,
HttpContext
class would be handy because you can access many of the ASP.Net object through static members through this class. HttpConext # MSDN
If you have similar functions behind the page, you can use ASP.NET WEb User Control.
You can create the functions in the usercontrol and use the control in the pages where necessary.
Have look at this article about Web User Control in Asp.Net
Related
I have an application which I must port to asp.net 6. I try to implement the authentication logic with scaffolded default identity UI pages.
The application uses URLs which start with a path component which holds the user’s language, then followed by the concrete path components. Something like:
/{language}/product/{product}
Now I try to establish this url schema also with the asp.net identity default UI pages. For example, the login page url should be look something like this:
/en/login
/fr/login
/it/login
However, up to now I had only little success in doing so. In changing the #page directive in the scaffolded pages I was able to introduce the {language} path component. However, how do I now tell the cookie middleware to integrate the current {language} placeholder into the redirect? Something like this:
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = "/{language}/Login";
});
Is this feasible in some way or another or is there even a more solid way to accomplish the goal?
Update
Up to now I came up with a solution and posted it as an answer, since it works. However if anybody knows a more sophisticated approach, please post it, I feel that the way I did this is really ugly and I cannot believe that there is no cleaner way to accomplish this, since also Microsoft uses the Url schema I try to implement in their websites.
One possibility I've found is to use the CookieAuthenticationOptions.Events-instance. This seems a feasible way, however it seems to me extremely brutish and one has to register to every event which is concerned and every scaffolded page has to be changed (redirects etcetera).
However, as long as no other solution is provided, this may help someone:
builder.Services.ConfigureApplicationCookie(options =>
{
options.LoginPath = "/language/Login";
options.Events.OnRedirectLogin=>(context){
// here would stand some Ajax-checks ...
var myLanguage= ... // detection of the language from the query string
context.Response.Redirect(context.RedirectUri.Replace("/language/", myLanguage));
}
});
The above code is best refactored in a new class which derives from CookieAutenticationEvents, where then proper handling can be done for each event. So the only assigment in the Program.cs file is the assignment of the custom authentication events class. The original class seems a bit quirky and depending on the purpose of the derived class, it is either better to initially assign custom events while constructing the instance or to override the methods which raise the assigned event handlers.
Within the pages, the language can be declared via the page directive:
#page "/{language}/login"
#page "/{language}/loginWith2fa"
etcetera
The code behind then will be changed, for example the signature of the get and set method will be extended with the language-parameter.
public async Task<IActionResult> OnGetAsync(string language,bool rememberMe, string returnUrl = null) {
and additionally, any url references in the code behinds must be changed. Since this way is so ugly, I tried to completely abstain from the default identity ui. In this post I ask for a way to do so.
Imagine you have a page that is of a specific page type (for example normal page, account page etc). The page is represented by a Page object.
My question is, how would you assign a page type to a page?
I see these options:
by using a PageType enum that is set in the Page object.
by using a PageType class, and assigning instances of it in the Page object.
by using page tags, which are simple strings associated with the Page object.
Option 1 is code-only approach, so adding new page types means changing (core) code.
Option 2 is more flexible, but there is additional overhead in having to maintain these page types.
Option 3 is very flexible, because there's no maintenance and it's extendable to other mechanisms than page type. But you can easily break things because there are no constraints.
What would be other objective reasons to choose one over the other?
There is a lack of details regarding a system design and pages requirements, number of different page types to support and difference between pages itself, so hard to make such decision. In such case I would recommend to keep it simple and use Enum.
If pages has own specific business logic you can stick with class per Page type, but do it carefully only when really page-specific logic there.
Think about UserControl/CustomControl feature (assuming you are usign ASP.NET) so you can split page by a set of controls which is responsible on the part of Page functionality, so in this way you'll keep Single Responsibility Principle and build less coupled system.
Some logic should be extracted from Page entities itself into external helpers/factories/repositories and then injected in Page class.
Regarding objectives,
you should define how many pages could be in place potentially and which level of flexibility should be provided. Also keep in mind such things like extensibility and maintenance of a system.
What about option 4?
Creating an (abstract) base class with basic page behavior, and a subclass for each specific page. This is the best design if you expect differences in a lot of different places. It prevents having to write switch statements evaluating the enum in dozens of places.
Prevent using 'magic' strings, so definitely prefer using approach 1 or 2 over 3. Based on your requirements using the strategy pattern to plugin in different behaviors can be a viable option as well. This gives even more flexibility, but initializing your class will become a bit more cumbersome. Of course, this behavior again can be wrapped in a class/factory method doing this work for you.
None of the above.
The obvious question is why you only want to identify the type of page? The identification itself is not useful. You most likely want to do something more with the page.
I would create interfaces for all kinds of pages, like IAccountingPage and then have some kind of repository. If you need to pre process a page before it's displayed create a filter interface like IPagePreFilter<T> where T : IPage and then implement it like:
public class DiscountFilter : IPagePreFilter<ISalesPage>
{
public void Process(ISalesPage page)
{
if (page.Product.Id == 1234)
page.AddParagraph("Product is at amazing 50% off");
}
}
Summary: Don't try to identify pages to have logic like if (page.PageType == PageEnum.Accounting) bla bla because it breaks Liskovs Substitution Principle. Do a more robust solution like the one I suggested.
Currently I'm developing a dashboard for the company that I'm working for. The functionality of this dashboard is not interesting for this problem. This dashboard is build up like:
Asp.net page (with a codebehind ofcourse)
Class where webmethods are defined
Javascript external file (with all the funcitonality of the dashboard, this dashboard works fully clientside)
For the rest I'm working with Visual Studio 2010 Ultimate with a TFS (team foundation server) environment and we make use of the jQuery library and .NET framework 4.0 (C#).
Alright, with that information i hope i can explain my problem. The external javascript file contains three classes. I will name them now ClassMain, ClassSub1, ClassSub2. The classes ClassSub1 and ClassSub2 are derived from ClassMain by doing the following javascript command:
ClassSub1 = new ClassMain();
After this instantiation of the ClassMain other properties and methods of ClassSub1 are loaded. The ClassMain can communicate with the properties and methods of ClassSub1 and ClassSub1 can communicate with ClassMain. So this means that they act like one big class with all kinds of functionality.
I explain this because i think my problem lays here but I'm not sure about it. The classes ClassSub1 and ClassSub2 are getting instantiated in the codebehind of the asp.net page. The following snippet explains it:
StringBuilder javascriptBlockBuilder = new StringBuilder();
javascriptBlockBuilder.AppendFormat("var {0};", this.Id);
javascriptBlockBuilder.AppendFormat("Sys.Application.add_load({0}LoadHandler);", this.Id);
javascriptBlockBuilder.AppendFormat("function {0}LoadHandler() {1}", this.Id, "{");
javascriptBlockBuilder.AppendFormat("{0} = new ClassSub1('{0}');{1}", this.Id, "}");
javascriptBlockBuilder.AppendFormat("var {0};", this.OtherId);
javascriptBlockBuilder.AppendFormat("Sys.Application.add_load({0}LoadHandler);", this.OtherId);
javascriptBlockBuilder.AppendFormat("function {0}LoadHandler() {1}", this.OtherId, "{");
javascriptBlockBuilder.AppendFormat("{0} = new SubClass2('{0}');{1}", this.OtherId, "}");
Page.ClientScript.RegisterStartupScript(this.GetType(), "ClassInitialization", javascriptBlockBuilder.ToString(), true);
In this snippet I create a global variable on the page and assign that class to it. The ClassMain gets the same id as ClassSub1 and ClassSub2 so that they make use of the same variable because like i said a few lines up these classes must act as one class (ClassMain and the ClassSub).
This works also but here comes also the problem. Before executing the above snippet (or after) i have some statements like this:
this.myButton.Attributes.Add("onclick", string.Format("{0}.myJavascriptFunctionality();", this.id));
The functionality gets attached to divisions, buttons, etc.
Ok, now I'm going to render my page and the page loads perfectly, but when I click one of the buttons, divisions, etc. Is it telling me that it requires an object. Somehow my global variables with the ClassSub1 and ClassSub2 are lost and now it can't execute my JavaScript commands.
So my question is, how is it happened that my variables are lost? I hope that my explanation is enough to understand.
It looks like you are calling ClassSub1.myJavascriptFunctionality() in the onclick event of myButton.
ClassSub1 is the function definition / prototype - whatever OOP mechanism you are using. You would have to specify the variable name, not the classname.
like so
this.myButton.Attributes.Add("onclick", String.Format("{0}.myJavascriptFunctionality();", this.Id));
I have found an solution for my problem. The problem occured that my references between the two classes (ClassMain and ClassSub) are referencing to the same variable which results in an error that javascript cannot handle. What did I do to fix this problem?
I have found the answer on this page:
http://www.cristiandarie.ro/asp-ajax/JavaScriptPrototypeInheritance.html
ClassSub1.prototype = ClassMain;
ClassSub1.prototype.constructor = ClassSub1;
And during my construction of the object I did the following call:
ClassMain.call(this, id);
Where 'this' is my current class and I pass an 'id' so that i can reference then to my mainobject.
I'm workng on a new, green-field ASP.Net application. We're implementing a base page which all pages will be, er, based on. The application will be running under Integrate Windows Auth, so I'll have the user's account details. With these, I'll be going to several databases (in which the user will exist) to find out what roles they are assigned to in each db. I'll be holding the role yay/nay in a bool array, and key into it via an enum.
There will be a session object that will hold a few things, and the roles assigned for that user. I'm thinking of making the session object available as a property of the base page, as the code would be something like this:
public SessionObject MasterSessionObject
{
get
{
if (Session["SessionObject"] == null)
{
// Create session object, assign user name, etc.
// Do something with roles...
Session["SessionObject"] = sessionObject;
}
return (SessionObject)Session["SessionObject"]
}
}
In order to control what happens on the (sub-classed) page, I want to provide a CheckSecurity method - e.g. if the user is not authorised to a certain part of a page, it can be hidden / disabled, or they could be booted back to a "not yours" page. The logical place for it is the base page, but seeing as the base page is already exposing the SessionObject that holds the roles permissions, would it not make more sense to Create a DatabaseSecurity type object and have the check on that?
Dealing with the latter approach, I've used abstract base classes to get me so far: I have a DatabaseRoles abstract class which contains the bool array, and a method to retrieve the roles for the user. The concrete implementation holds an Enum (as previously mentioned) to key into the array (in the base class). The abstract class also has the CheckRole method which takes in an int, to which I'm intending use a cast of the enum...
The SessionObject contains several of these DatabaseRoles implementations, and essentially does away with the need for a CheckSecurity in the base page class, leading to code like this in the actual page:
if (MasterSessionObject.SampleDatabaseRoles.Check((int)SampleDatabaseRolesEnum.RoleView))
{
// Do something
}
But, I'm sure you'll agree, it looks sucky...
If there was a CheckSecurity method on the base page, it would have to take a concrete DatabaseRoles object, but also an enum of which role to check, which would also look sucky. And finally, there would be a requirement at a later date to add more databases and their security settings...
I'll add code tomorrow if required... :-s
I dunno, I'm not that thick, but I do have a hard time sometimes binding all this together...
Thank you,
Mike K.
IF you happen to use ASP.Net / ASP.Net MVC, I would say the best place to do this would be via a custom HTTP Module by handling the AuthenticateRequest method & continuing with the request only if the request has been authenticated. There are tons of excellent articles online for this code.
Also - have a look at the Roles & Memberships of ASP.Net - it is pretty good & generally satisfies most requirements or you are always free to extend it. Again - tons of articles on custom membership providers...
unless I am missing something - HTH.
I want to get a type of a "BasePage" object that I am creating. Every Page object is based off BasePage. For instance, I have a Login.aspx and in my code-behind and a class that has a method Display:
Display(BasePage page) {
ResourceManager manager = new ResourceManager(page.GetType());
}
In my project structure I have a default resource file and a psuedo-translation resource file. If I set try something like this:
Display(BasePage page) {
ResourceManager manager = new ResourceManager(typeof(Login));
}
it returns the translated page. After some research I found that page.GetType().ToString() returned something to the effect of "ASP_login.aspx" How can I get the actual code behind class type, such that I get an object of type "Login" that is derived from "BasePage"?
Thanks in advance!
If your code-beside looks like this:
public partial class _Login : BasePage
{ /* ... */
}
Then you would get the Type object for it with typeof(_Login). To get the type dynamically, you can find it recursively:
Type GetCodeBehindType()
{ return getCodeBehindTypeRecursive(this.GetType());
}
Type getCodeBehindTypeRecursive(Type t)
{ var baseType = t.BaseType;
if (baseType == typeof(BasePage)) return t;
else return getCodeBehindTypeRecursive(baseType);
}
After some additional research I found that if I call Page.GetType().BaseType it returns the code-behind type of the Aspx page.
page.GetType().BaseType, it has been said before, but let me elaborate as to why.
Aspx pages inherit from their code-behind pages, meaning that the inheritance hierarchy looks like this:
...
Page
BasePage
Login
ASP_Login
Where the top is the parent and the bottom is the child.
This allows your code behind to be accessible from the aspx page, without requiring all of the generated code related to your actual aspx page to be copied into the base class page.
It depends where you're calling Display() from. If you're calling it from the ASPX, then you'llse "ASP_login.aspx". If you're calling it from the code-behind (i.e. the Page_Load() method) you should get the Login page type.
Instead of passing the Page in, you might consider just using the Page property (i.e. this.Page.GetType()) which should always be the current page/codebehind type, if I recall correctly.
I should also make the point that you might consider moving this sort of stuff out of the ASPX/codebehind and into some sort of service. It's generally a good idea to minimize the amount of things you do in a code behind and, instead, push logic into a presenter class and follow the MVP pattern for ASP.NET Web Forms development.