My application is in Asp.net MVC 4. I'm using .aspx page for opening of report. I've implemented custom user rights attribute on all action of application. I want to use it on my .aspx.cs page class or every function that is in .aspx.cs page. How to use it? can i use MVC custom attribute in aspx page
In mvc I'm using like this
[AuthorizeUserControls("urlInventoryReport")]
public ActionResult Inventory(string ReportTitle)
{
}
How to use in .aspx.cs page
public partial class ReportViewer : System.Web.UI.Page
{
[AuthorizeUserControls("urlInventoryReport")] //it's not working
private void ViewInventoryReport()
{
}
}
Attributes are static objects that apply metadata to a type in .NET. They contain no behavior.
The reason why your attribute works in ASP.NET MVC is because MVC has a filter which runs before and after the call to the action method is performed. This filter is called by the MVC framework, which in turn is called by the route handler (a specialized HTTP handler).
The fact that the behavior is defined in the same class as the attribute (yielding an ActionFilterAttribute) is just for convenience. You could just as well separate the attribute from the action filter as is done in this answer.
Following the MVC approach to make your IActionFilter function, would be to use .NET routing for your page and make a specialized IRouteHandler that can scan your page object after it is instantiated using Reflection to determine if the attribute exists, and then execute the behavior in the associated IActionFilter. I suggest if you go this route, you analyze the MVC source code and extract the bits that you need, but it is not for the faint of heart.
Alternatively, you could put the scanning implementation into the Page_Init event, but at that point you might just be better off not bothering with declaring the attribute statically and just executing the behavior locally.
Assuming your attribute derives from ActionFilterAttribute, you could do something like:
protected void Page_Init(object sender, EventArgs e)
{
var attribute = new AuthorizeUserControls("urlInventoryReport");
var filterContext = CreateFakeActionExecutingContext(); // TODO: Implement this.
attribute.OnActionExecuting(filterContext);
}
Related
Using a Asp.Net old project, to access webforms I need to create a custom class Attribute that reads users rights like 'Rights.ViewDashboard' or 'Rights.CanEdit' an so. The class code is:
[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]
public class AuthorizationAttribute : Attribute
{
public AuthorizationAttribute(Rights permission)
{
if (Security.IsAuthorizedTo(permission))
return;
HttpContext.Current.Server.TransferRequest("~", false);
}
}
In the aspx webform I have:
[Authorization(Rights.ViewDashboard)]
public partial class DashboardRisorse : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
When the user calls the webform if he haven't specific right the page is not loaded and site is redirected to the default page. But if he make a refresh of the page the code isn't execute, attribute is ignored and the page is loaded. When debugging I see that this attribute is executed only once.
Where is my fault?
I don't need Net Core solution because the project has old assemblies.
Thanks.
Ingd
I am assuming here that you are trying to define custom attribute similar to ActionFilter Attributes in MVC. Unfortunately ASP.Net does not work in the same way.
You have two options
Create an HttpModule and use one of the events available to build your logic
Write the logic you want to execute in Page Load. Use Page.IsPostBack to identify if it is initial load of the page or if the page is being posted back. Write the logic you need within the if.. else if conditions
In case my assumption was incorrect then please provide more details on your query specifically what is it that you are trying to achieve using the Attribute.
I have a Solution structure like this:
MyApp.Core
--Properties
--References
--bin
--Events
|EventHandlers.cs
--Directory
--Controllers
|DirectoryController.cs
--Helpers
|ContextHelpers.cs
--Models
|DirectoryModel.cs
--AnotherSite
--Controllers
--Helpers
--Models
--Services
--Shared
--Controllers
|HomePageController.cs
--Helpers
|Extensions.cs
|app.config
|packages.config
MyApp.Umbraco
--Properties
--References
--bin
etc........
--Views
--Directory
--Partials
|DirectoryFilters.cshtml
|DirectoryBase.cshtml
|DirectoryHome.cshtml
|FDirectory.cshtml
|SDirectory.cshtml
--Partials
--Shared
|Base.cshtml
|Web.config
etc........
My Umbraco instance uses the models and controllers from my "Core" project. There is nested directory structure, because of multiple websites in one installation, in the "Core", and also in the "Views" directory in the Umbraco instance.
I am still fairly noob to .NET MVC, and I understand route hijacking, but the documentation for Umbraco's routing is slim. I have the following:
EventHandlers.cs
namespace MyApp.Core.Events
{
/// <summary>
/// Registers site specific Umbraco application event handlers
/// </summary>
public class MyAppStartupHandler : IApplicationEventHandler
{
public void OnApplicationInitialized(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
}
public void OnApplicationStarted(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
RegisterCustomRoutes();
}
public void OnApplicationStarting(UmbracoApplicationBase umbracoApplication, ApplicationContext applicationContext)
{
}
private static void RegisterCustomRoutes()
{
// Custom Routes
RouteTable.Routes.MapUmbracoRoute(
"FDirectory",
"fdirectory/{id}",
new
{
controller = "Directory",
action = "FDirectory",
id = UrlParameter.Optional
},
new PublishedPageRouteHandler(1000));
RouteTable.Routes.MapUmbracoRoute(
"SDirectory",
"sdirectory/{id}",
new
{
controller = "Directory",
action = "SDirectory",
id = UrlParameter.Optional
},
new PublishedPageRouteHandler(1001));
RouteTable.Routes.MapUmbracoRoute(
"HomePage",
"",
new
{
controller = "HomePage",
action = "Index",
id = UrlParameter.Optional
},
new PublishedPageRouteHandler(1002));
}
}
public class PublishedPageRouteHandler : UmbracoVirtualNodeRouteHandler
{
private readonly int _pageId;
public PublishedPageRouteHandler(int pageId)
{
_pageId = pageId;
}
protected override IPublishedContent FindContent(RequestContext requestContext, UmbracoContext umbracoContext)
{
if (umbracoContext != null)
{
umbracoContext = ContextHelpers.EnsureUmbracoContext();
}
var helper = new UmbracoHelper(UmbracoContext.Current);
return helper.TypedContent(_pageId);
}
}
}
DirectoryController.cs
namespace MyApp.Core.Directory.Controllers
{
public class DirectoryController : RenderMvcController
{
public DirectoryController() : this(UmbracoContext.Current) { }
public DirectoryController(UmbracoContext umbracoContext) : base(umbracoContext) { }
public ActionResult FDirectory(RenderModel model)
{
return CurrentTemplate(new DirectoryModel(model.Content));
}
public ActionResult SDirectory(RenderModel model)
{
return CurrentTemplate(new DirectoryModel(model.Content));
}
}
}
So Umbraco does not install with an App_Start folder. I would like to know what the best approach is for a multi-site installation of Umbraco for registering the routes to the controllers. My implementation works, but it seems like I shouldn't have to create actions for every single page I am going to have in a site, in every controller. I know Umbraco has its own routing, so using Umbraco concepts, ASP.NET MVC concepts, and whatever else is available, what is the best way to implement this type of solution structure? Should I even worry about using a RouteConfig.cs and create a App_Start directory? Or is what I am doing the best approach? Should I use IApplicationEventHandler or ApplicationEventHandler?
Also, I have to hard code the node ID's. I've read that there is a way to Dynamically? And example of this would be great.
Examples of the best way to implement a structured multi-site Umbraco MVC solution is what I am asking for I guess, in regards to routing the controllers, with some detail, or links to strong examples. I have searched and researched, and there are bits and pieces out there, but not really a good example like what I am working with. I am going to have to create a RouteMap for every single page I create at this point, and I don't know if this is the most efficient way of doing this. I even tried implementing a DefaultController, but didn't see the point of that when your solution is going to have multiple controllers.
I'm not entirely sure what you are trying to achieve with this, but I'll try to explain how it works and maybe you can clarify afterwards.
I assume you have the basics of Umbraco figured out (creating document types + documents based on the document types). This is how Umbraco is normally used and it will automatically do routing for you for each of these "content nodes" (documents) you create in a site.
So create a document named document1 and it will be automatically routed in your site at URL: http://localhost/document1. By default this document will be served through a default MVC controller and it will all take place behind the scenes without you having to do anything.
Route hijacking allows you to override this default behavior and "shove in" a controller that lets you interfere with how the request is handled. To use hijacking you create a RenderMvcController with the alias of your document type. That could be HomePageController : RenderMvcController.
This controller should have an action with the following signature:
public override ActionResult Index(RenderModel model)
In this action you are able to modify the model being sent to the view in any way you like. That could be - getting some external data to add on to the model or triggering some logic or whatever you need to do.
This is all automatically hooked up by naming convention and you will not have to register any routes manually for this to work.
The other type of Umbraco MVC controller you can create is a SurfaceController. This one is usually used for handling rendering of child actions and form submissions (HttpPost). The SurfaceController is also automatically routed by Umbraco and will be located on a "not so pretty" URL. However since it is usually really not used for anything but rendering child actions and taking form submits, it doesn't really matter what URL it is located at.
Besides these auto-routed controllers you are of course able to register your own MVC controllers like in any standard MVC website. The one difference though is that unlike a normal ASP.NET MVC website, an Umbraco site does not have the automagical default registration of controllers allowing the routing to "just work" when creating a new controller.
So if you want to have a plain old MVC controller render in an Umbraco site without it being related to a document/node in Umbraco, you would have to register a route for it like you would do in any other MVC site. The best way of doing that is to hook in and add it to the Routes using an ApplicationEventHandler class. That will automatically be triggered during application startup - essentially allowing you to do what you would normally do in App_Start.
Just to be clear though - if you plan on using data from Umbraco, you should not be using normal MVC controllers and should not require any manual route registration to be done. You usually want to render a template/view in context of a document/node created in Umbraco (where you can modify data/properties of the document) and then the route hijacking is the way to go.
From what it looks like, it could seem that the correct way to do what you are trying to do is to simply create two document types:
FDirectory and SDirectory
You click to allow both of these to be created in root and then you create documents called FDirectory and SDirectory and they will be automatically routed on these URLs. Creating a RenderMvcController's called FDirectoryController : RenderMvcController will then make sure it is used to hijack the routing whenever that page is requested.
If you're simply trying to set up a multi-site solution I would suggest you create a Website document type and create a node for each site you want, in the root of your Umbraco content tree. Right click each of these nodes and edit the hostname to be whatever you need it to be. This can also be some "child url" like /fdirectory or /sdirectory in case you need to test this on localhost without using multiple hostnames.
Hope this gives you the pointers needed, otherwise try to explain what you are trying to do and I'll see if I can refine my answer a bit!
Normally, on a usual aspx file, I can use System.Attribute at the begining of the page, like:
[AuthorizePage()]
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
public class AuthorizePage : System.Attribute
{
public AuthorizePage()
{
//do some stuff to authorize
}
}
And before the page initializes the Attribute's constructor runs and do some stuff to ensure a person is currently logged in, otherwise the attribute constructor Redirects user to a login page.
I wanted to do the same on a HttpHandler (ashx file), but the attribute never initializes when on a ashx page.
[AuthorizePage()]
public class AjaxHandler : MuCustomClassBase, IHttpHandler, IReadOnlySessionState
{
//The interface implementations and some other custom private methods
}
I do an AJAX Call to this ashx page. Could this be the reason why the Attribute doesn't run? Or any other things I must know?
Eventually, I would be extremely happy to know How to run a Custom System.Attribute over an ashx file?
Assuming you are using ASP.Net authentication, you can just add the .ashx to the list of protected pages in web.config and IIS/ASP.Net will take care of the rest:
<location path="AjaxRequests.ashx">
<system.web>
<authorization>
<allow users="?" />
</authorization>
</system.web>
</location>
If you are using a self-built authentication scheme, you could override OnProcessRequest and perform the necessary authentication in that method, redirecting as needed.
Attributes don't do anything by themselves. You can pile 10 random attributes on a class and nothing will really happen. Attributes just provide metadata about the class/method/property.
There should be a piece of code that looks at the metadata and act on it. Since you seem to be using custom AuthorizePageAttribute such piece of code either don't run for handlers or does not expect class that is not derived from Page to have such attribute.
To fix an issue you need to find what handles you custom attribute and fix it. You may need to add similar code to your handlers directly.
The fact that your code in constructor of attribute does something useful for a page class on every request to that page sounds suspicious - I'd expect such attributes to be created once per type instance. Relying on non-trivial code in constructor of an attribute to run per-instance of the class seems dangerous to my.
Well first of all yes you are reinventing the ActionFilterAttribute in Asp.Net MVC. But, I have to ask if you really need to use attribute? I suggest you to use inheritance model. Let me simply explain; you might have a SecurePage : Page class that implements the security operations. You may then pass the security code that is related to the derived page.
And if you insist on using attributes, you should intersect the handler mechanism by writing a base factory handler that routes to the needed handler. This handler should behave like a mediator object.
I would like to add a check for Request.IsAuthenticated into my MasterPage (COntroller? Is there such a thing??). Is this possible? I want to redirect to a NoAccess.aspx page if the check fails.
The concept on MVC is different to web forms where you would do common logic on the master.
In ASP.NET MVC master page must only contain UI related setup.
In MVC you use Action filters: decorate your actions with [Authorize].
Did you create a project using the default MVC project template? It has everything you're looking for already in there. If you didn't go ahead and create one now.
Once you're in there you'll notice the [Authorize] attributes as #Aliostad mentioned. These are custom attributes that do the validation on the controller level.
Check out the MVC tutorial on web form security for a more detailed run-down on how it all meshes together: http://www.asp.net/mvc/tutorials/authenticating-users-with-forms-authentication-cs
You can achieve this by creating your own custom authentication attribute.
Create a new filter folder within your project and add the following class
public class NoAccessDirectAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
filterContext.Result = new RedirectResult("noaccess.aspx");
}
}
then decorate your home controller and other required controllers with the Authorization Attribute
[NoAccessDirectAuthorizeAttribute]
public class HomeController : Controller
This will redirect an unathenticated user to your noaccess.aspx page
I have something issue on how to use Attribute in asp.net page class.
The below code slice is the background:
A method is declared like below in a aspx class page:
[SomeAttribute(Name=”Test”,TargetType=typeof(System.Int32)]
Public void Verify(object obj)
{
//code to verify…
}
And other pages would use the attribute too.
Now I want a Module to do is that it will invoke a method before the Verify method is calling.
Currently, my solution is using a customer IHttpModule implement class to do it by registering the BeginRequest event.
In the method referred to the event, how can I get the method that is calling currently by request in asp.net ? This is the way I could know the request is calling Verify method so that I can do something with the Attribute on it.
I'd recommend checking out PostSharp:
http://www.sharpcrafters.com/
It's got all that goodness, and more, built in.