I have recently inherited a large .NET project, which needs role implementation to be patched in it. Different roles have different access to the site, and some elements need to be hidden accordingly in relation to the role of the current user.
Given the somewhat flexible and modular architecture, this was easy enough to implement when users try to access portions of the site they do not have access to. However, I ran into problems when authenticating the visibility of controls.
Many of the controls have been implemented through their own project-specific controls, however links are mostly implemented through HtmlAnchors, and some others fields that fall into the restricted category are also generic html elements.
Is there a way I can patch this with a generic adapter, or do I have to rummage through the vast array of controls and elements present in the project and make them inherit a common base where this can be implemented singularily? Manual labor in this case would mean a lot of work, and I am not exactly sure if it is even the right approach in the end.
Basically, is there a way to make all controls and elements of the page run a check whether or not they should be rendered visible, or not in an .NET 4.0 Web Project? And can I somehow manage to patch it so that all elements have the capacity to accept and process a new attribute which describes their 'restriction level'?
Yes, you can do that sort of thing. Two ASP.NET features come to mind that might help you out here:
ASP.NET Tag Mapping. This feature lets you change the type of the object that is instantiated when the parser finds a particular ASP.NET tag (so you can, for instance, replace all HtmlAnchors with SpecialHtmlAnchors that inherit from some base class of your choice). You just need to add a tagMapping section underneath /system.web/pages/ in your web.config. (I have not tested this sample, but it should be close to correct. It's a starting point, anyway.)
<system.web>
<pages>
<tagMapping>
<add tagType="System.Web.UI.HtmlControls.HtmlAnchor, System.Web"
mappedTagType="My.Special.HtmlAnchor, MyAssembly"/>
</tagMapping>
</pages>
</system.web>
ASP.NET Control Adapters. You can tell ASP.NET to attach an output adapter to each instantiated control of a particular type. The feature was originally intended to facilitate output adaptation for particular browsers or browser types (e.g. desktop vs. mobile), but you can do pretty much whatever you want with them. To use them, you create a .browsers file in your App_Browsers folder (if it does not exist, right-click on your web project in VS, mouse over "Add ASP.NET Folder" and select and select "App_Browsers." Then, add your .browsers file to this folder via the "Add New Item..." dialog. Register your custom control adapter by modifying your .browsers file to look something like this:
<browsers>
<browser refID="Default"> <!-- all browsers -->
<controlAdapters>
<adapter controlType="System.Web.UI.HtmlControls.HtmlAnchor"
adapterType="My.Custom.RolesAwareControlAdapter, MyAssembly" />
</controlAdapters>
</browser>
</browsers>
Control adapters inherit from System.Web.UI.Adapters.ControlAdapter, which has almost all of the same rendering methods that an ordinary control has. The ControlAdapter takes complete control of the rendering for the control, but can delegate rendering back to the Target control if it wishes.
Regarding adding new attributes to your controls: if you're already going to go through the existing code and add attributes, why not just change the tag type to refer to a custom control while you're at it? Public properties of custom controls get automatically promoted to markup attributes so that you can specify their values at design time.
Another good WebForms approach--although it won't fix the tedium of editing hundreds of pages and user controls--is to use a LoginView, since it's designed to solve problems like yours.
Let me know if you've got any questions; I'll be glad to clarify.
Related
I am looking for solution which would allow me to serve different templates depends on what is set in session (middleware will set it based on the domain).
What I al looking for is that when the theme is set up, when some view suppose to be rendered, mvc would render the view from particular theme.
How can I do that with net core 2,mvc and razor? It would be great if adding theme wouldn't require recompilation (e.g. similar to Wordpress - upload zip file with all required files).
I really have no idea where to start...
I was trying to Google some solutions but I found only one which is outdated totally.
Basically, you just need to customize the list of directories that Razor searches for views. By default, those are Views\{controller} and Views\Shared. You just need to make it so those are instead (or maybe as well as, to have fallback to a "base" theme if a particular theme chooses not to provide a view) {theme}\Views\{controller} and {theme}\Views\Shared, or something similar.
Unfortunately, the documentation doesn't provide much support here. All you get is:
You can customize the default convention for how views are located within the app by using a custom IViewLocationExpander.
As the name implies, that's an interface that Razor uses to get a list of locations to search for views in. In other words, you'd simply need to create your own implementation and then inject that. Something like LanguageViewLocationExpander should give you an idea of what you need to do, since the basic principle at play is the same. It's used for localization and provides the ability to have views nested under language specific-folders.
We're having a restructuring on our application and currently the idea is to break the codes into Core library codes + customized codes for our developer.
I'm thinking of the possibility to have a folder (i.e. 'custom') that is empty by default, and when the developer need to customize any codes either from existing asp pages or new pages, they just need to put them into the folder and it will work. Example:
Lets say core folder store the default asp pages.
core\customer\createCustomer.asp <-- the default page
And when the developer want to overwrite that page, he needs to copy that asp page to the custom folder, like
custom\customer\createCustomer.asp <-- modified asp page
The application will automatically load the one in the custom folder rather the one in the core folder.
Is this doable in C#?
This MSDN article explains how to use an IHttpModule implementation to intercept HTTP requests and perform custom actions (they point out logging, but since you're intercepting the request you might as well fetch some different content, such as your 'customized' code).
You can use a VirtualPathProvider to load a different file than the "actual requested one". This works well with IIS and caching for instance as well.
Basically you inherit the VirtualPathProvider and override the FileExists, GetFile, and DirectoryExists, GetDirectory methods (there's an example in the linked page). Then, in your AppInitialize, register the provider with
HostingEnvironment.RegisterVirtualPathProvider(sampleProvider);
By the way, don't forget to have a different (non-editable) page so the user can revert any changes that was made, in order to restore a potential misedit so to speak. I would probably have a simple version control system and use commit whenever the user made changes, and allow the user to revert to a previous changeset.
I am creating a new support center and "self-help" customer service module for an application. The CIO really likes the flow of eBay's "Contact Us" pages, that basically work like this:
First, you select a specific topic from a group of topics (e.g. Buying, Selling, Account on eBay)
You're then presented with what appears to be one of three variable types of information, based on the topic you picked (names are just what I'm calling them in some preliminary sketches):
"Descriptive": displays rich text with possible links to other parts of the application.
"Choice": Displays a list of additional topics
"Action": Lets the user look up an item and do some action (e.g. cancel)
From some experimentation, a choice can list to other choices, or to a descriptive block of text, or to an action section.
I'm turning up blanks as to the proper architecture for this. My platform of choice is ASP.NET (WebForms, sadly; we have no desire to touch MVC here) so the "Action" areas would have to be a user control that's dynamically loaded into a placeholder, but I'm more concerned with a possible database structure for this. I would need a way to know if each topic leads to one of the three types above and then on the page dynamically load either the content, list of links, or user control which makes things a bit trickier, nevermind the fact that a non-technical user will have to update and add the information from some kind of administrative panel.
Any suggestions for doing something like this? I'm not on a tight deadline, but I can't take too long or I'll be considered to be wasting time and not producing results.
If you can store the "tree of knowledge" in some way, like a custom XML file which would organize all options / possible actions, descriptions etc. Then you can "walk" it based on user's selections and display appropriate user control with content generated on the fly based on the contents of the XML node you're currently at.
Your "admin tool" would then need to update/modify the XML file, and your "public" CMS would render user controls inside an ASPX form.
One of the projects I worked on used this methodology for intranet's user menu - effectively a knowledge base of hyperlinks / actions split in to categories so they can be drilled-down to. Each element can contain links to other elements - so you have a spider-web like navigatable chain / workflow.
Just make sure each element has a unique ID (trivial to implement) and you can always get at it through xpath.
By having users modify a "working copy" and keeping backups of the live XML file when changes are published you also get versioning / roll-back which would be difficult to do in a DB.
If I personally was doing this I would just roll some MVC3 controllers that handle the work flow steps as needed. That seems to be out for you however.
With webforms, I would most likely consider handling this using Windows Workflow Foundation (the learning curve is moderately steep on this). Here's a pretty good example on using WF Flexible Web UI Workflow application through ASP.NET MVC & Windows Workflow Foundation. It's built on MVC however you could easily replace the return Views() with return UserControls.
Following a model like this would defacto give you the MVC pattern. The controller dictating flow matches very well for a workflow scenario.
Edit: Since this even seems out of the question, at this point you're best option is just writing a controller class that will manage the flow manually (probably a bunch of state / if checks) and then redirect users or return the appropriate user control.
I recently inherited a solution with about 10 projects in it. 6 of these projects are individual websites that are basically copy/pastes of the original.
This means that any changes that need to be made must be made to each project in order to update all the websites.
What I want to do is have one project for the website code and be able to deploy that code and some configuration settings to create a new website. That way when I make updates to the main Web project I can just deploy to all the websites.
How do people normally approach this? I'll outline my thoughts on it and hopefully some of you can point out better ways to accomplish this or at least give me some affirmation that I am on the right track.
Have a master markup with very general containers.
Allow the users/people setting up the site add widgets to the site which will be assigned to widget placeholders at the top and bottom of all the generic containers.
All styling and colors will be controlled with a stylesheet that can be swapped out.
I know there is some kind of theming you can do. Does this just swap out groups of css and let you configure which one to use in the webconfig?
For elements that will be the same across all sites such as footer images have a naming convention. So if I want Site A to have some footer image I just replace the footer.jpg in the project when I deploy.
Your approach is good.
You should use master markup
Your web system will be CMS
You can use themes to define styles of different projects or you can link css files dynamically
if they are really copies of each other than you can make it very general by defining all of them as one website and put all the settings of css images markups in database
If you don't want to make everything very generic you can make web user controls and load them dynamically at run time according to the project (Remember, you can load WebUserControls at runtime using the LoadControl method)
That's unfortunately a question that is likely to get the response 'It depends' as each of those approaches could be used or not used dependent on the needs of the project. If the projects only vary by presentation then master pages combined with CSS would make a reasonable solution.
We have a bunch of user controls we would like to pull out of a web application and into a separate assembly/library, and I thought it would be as simple as creating a class library and pulling the ascx and ascx.cs files into the project, and compiling a DLL to be reused among our applications.
This was not the case, however.
Our ultimate goal is to have a single distributable DLL (similar to how Telerik distributes their controls) that we can throw into any web application. The steps here: Turning an .ascx User Control into a Redistributable Custom Control were very simple to follow, however this results in many files named controlname.ascx.guid.dll, which is not the desired result. I couldn't even get these to work anyways, since we have additional classes that need to be compiled into the assembly.
Has anyone successfully created a web user control library in .NET (we're using 3.5 here)? I can't seem to find a nice step-by-step guide.
I realize this is an old topic, but if anyone is looking for a solution for creating reusable user control libraries, it turns out it's fairly simple. Here are two good step-by-step guides along with source code:
From MSDN: Turning an .ascx User Control into a Redistributable Custom Control
From Code Project: Straight way to create ASP.NET user controls library
The second link provides a solution to the multiple dlls created by the first link.
Edit- (2) Seems to be a dead link. Here's the new link
https://www.codeproject.com/Articles/30247/Straight-way-to-create-ASP-NET-user-controls-libra
If you want to share controls among project, my experience has shown that the best way is to build custom asp.net server controls instead of usercontrols. User controls are good for sharing within the same project, but not over multiple ones.
For this purpose I suggest you to build a set of custom server controls inside a class library and use that on all of your projects.
This book does quite a good job at explaining the basics of creating server controls
Edit:
I'm currently developing a .net web server control library. I actually didn't follow any step-by-step guide. I mostly considered using the book I mentioned above and the MSDN library + Reflector, which is a great tool for inspecting existing MS server controls and learning from them.
I found the tutorial Creating and Using User Control Libraries but it seems like a bit of a hack as it relies on a post-build command line event to copy the user controls from one project to another.
Somewhat late, I admit.
To create a re-usable library of user controls; create a new Web Application Project, delete all the scaffolding, add a (number of) user control(s). Create a Web Deployment Project from the Web Application Project, in the WDP properties choose the option to Merge all control output and assign a name for the library and ensure that Allow this website to be updatable is NOT checked.
Build the WDP and use Reflector to examine the generated library; you'll see that it contains an ASP namespace and the types you carefully crafted have been renamed i.e. usercontrol_ascx. In your target website(s) add references to BOTH the output dlls from your WDP, add a system.web/pages/controls node to web.config using the namespace ASP and the name of the assembly that you defined in the WDP.
Now when you use the library in a page (for example) you must use the alias that you defined in web.config and the typename as seen in Reflector i.e.
<ucl:usercontrol_ascx ... />
I found it useful to add a dependancy for the website(s) on the WDP so that the WDP is built before the websites; now I can change the user controls in the WAP without having to remember to build the WAP before building the website(s).
I hope that someone finds this useful as it cost me a few grey hairs getting to this stage and still have VS do its 'automagically' thing.