design guidance please :user controls and centralizing roles-related display stuff

G

Guest

I'm looking for some design guidance on a collection of projects I'm working
on.

The project involves a bunch of websites constructed out of a collection of
user controls. Different user populations with different access rights and
"roles" will be visiting the site. I will be using ASP.NET 2.0's membership,
roles, and profiles stuff to manage access.

User controls need to be visible or not visible depending on user role. In
some cases, one user role will see one "facet" of a control, while another
user role will see a different aspect of it.

The user controls are often going to be placed at runtime, and have their
properties adjusted at runtime.

What I am wondering now is the best way to centralize the code that manages
the display of these user controls based on role. What I don't want is
"if-else" junk spread throughout my code.

The project is large but not huge, and I am the sole developer for the
project. I have a few ideas for how this might work.

One might be to write a huge function: public static bool IsElementDisplayed
(string roleName, string userControlName) and have visibility of various
elements constantly checking this.

Another might be to use some form of inheritance. User controls can't
inherit from each other, but maybe they can inherit functionality from
somewhere else.

Another might be to encode this knowledge in some kind of structured data. A
database would be a disaster, but XML might be better.

Any suggestions and guidance out there?

Thanks,
-KF
..
 
S

Steven Cheng[MSFT]

Hello KF,

As for the role based user-interface, I think there're two possible
scenarios:

** all the controls be put on the page and you control the visibility
dynamically

** the page's layout and controls constructure is not determined at
design-time on page. All the usercontrols are dynamically created and added
into page/container at runtime(based on some structure info from database
or in configuration file).

I assume you're using the second approach, correct? If so, since dynamic
controls need to be created and added into page control structure in each
page request and to make sure all the control lifecycle features works
well, it is recommended that the dynamic control instancing code be put in
Page's Init event(or load). Then, if you want to make the control
structure initializing code contralized, you can consider the following
approaches:

** define a helper class which parsing the configuration schema from
database or xml configuration file and create dynamic controls and add it
into page(get the reference of the page at its construct time). and this
class will be used in each page(which need such dynamic role based UI )'s
Init event.

** Define a base page class and override Page's OnInit methods and add the
dynamic UI parsing and constructing code logic there. And those concrete
pages which need dynamic role based UI can derive from this base page class.

What's your opinion or have you any other ideas on this?

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



==================================================

Get notification to my posts through email? Please refer to
http://msdn.microsoft.com/subscriptions/managednewsgroups/default.aspx#notif
ications.



Note: The MSDN Managed Newsgroup support offering is for non-urgent issues
where an initial response from the community or a Microsoft Support
Engineer within 1 business day is acceptable. Please note that each follow
up response may take approximately 2 business days as the support
professional working with you may need further investigation to reach the
most efficient resolution. The offering is not appropriate for situations
that require urgent, real-time or phone-based interactions or complex
project analysis and dump analysis issues. Issues of this nature are best
handled working with a dedicated Microsoft Support Engineer by contacting
Microsoft Customer Support Services (CSS) at
http://msdn.microsoft.com/subscriptions/support/default.aspx.

==================================================



This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

Lot of ways to skin a cat on this one. I'd consider a Generic List of type
"ControlDisplay" which would be a small class that describes each control's
layout and display characteristics for a specific role. The key to the List
could be something like a concatenation of the site + controlId +role (or
something to that effect).
Then, when you are about to add a dynamic control to a page, you need only
look up the site+controlId in your List (which could be stored as static in
Global), compare to the current user's role(s), and you would have everything
you need for your display business logic.
Peter
 
K

Ken Fine

Thank you, Peter. Very helpful.

Could I ask you to elaborate just a bit on what you're thinking about when
you suggest "....that describes each control's layout and display
characteristics for a specific role"?

I'm curious to what extent you're thinking the layout and display
characteristics could/should be described in such a lookup class.

I am also curious if there is a "special" characteristic or quality of the
Generic List/Generic that I am not catching here that might make it
especially useful for this application. I am fairly new to C#, lists,
generics, OO, etc and the subtleties of good design is a long process.

Thanks again for your suggestion,
-KF
 
G

Guest

Ken,
Well at a minimum you would have a ShowControl boolean that would describe
whether the control should be displayed, based on the "role" provided. I
don't know what other characteristics you need (positioning, etc).

The Generic List could be a Hashtable. Generics simple provide a strongly
typed Collection and avoid the overhead of boxing to and from type object in
a "1.1" style collection.
Peter

--
Site: http://www.eggheadcafe.com
UnBlog: http://petesbloggerama.blogspot.com
Short urls & more: http://ittyurl.net
 
G

Guest

Thanks for bearing with me, Peter. I want to continue to explore this idea a
little further, and I hope you'll allow me a little more public embarassment
here.

So one interpretation of what you've been suggesting is to make a small
class -- let's call it UwnControl -- and attach various properties to that
class that describe name and visibility. And then I could conceivably write
code that would instantiate class instances, one for each control name that
I want to check for visiblity:
UwnControl uwnc = new UwnControl();
uwnc.App_Page_ControlName = inthemedia_overviewdotaspx_admininterface;
uwnc.IsVisibleToAdmins = true;
uwnc.IsVisibleToHoldersOfUwNetIds = false;
uwnc.IsVisibleToPublic = false;

UwnControl uwnc2 = new UwnControl();
uwnc2.App_Page_ControlName = inthemedia_overviewdotaspx_publicoverview;
uwnc2.IsVisibleToAdmins = true;
uwnc2.IsVisibleToHoldersOfUwNetIds = true;
uwnc2.IsVisibleToPublic = true;

And then I could put all of those in objects in a type-safe List, and then
do lookups against the list by name in conjunction with a function that
would evaluate and return whether a given control should be visible to a
given role or not.

If I've misunderstood you -- particularly in terms of building a collection
of simple objects as shown above -- then it's possible that this fairly
simple solution will perform badly in production, and that's why I'm running
this past you again.

I like the verbosity of using a collection of objects versus a collection of
other datatypes: it's very obvious what the data says and does.

If there are better and more elegant ways to manage this while still
retaining the general simplicity of the approach you suggested initially,
please let me know. If anyone else has thoughts or insults, feel free to
chime in.

-KF
 
S

Steven Cheng[MSFT]

Hi KF,

I think those custom class(represent each control's visibility info against
roles) should be made as lightweight as possible. Also, since these object
List should be generated from a configuration file(XML file that store the
role based control/page layout info), you can cache those list in
Application cache and make the cache dependent on the XML configuration
file. Thus, whenever the xml file is modified, the cached list will be
invalidated. And the list should be accessed by an wrapper class which use
on-demand patter to initialize the list. e.g.

public list GetList()
{
if(Cache["_list"] == null)
{
GenerateListFromConfigurationFile();
}

return Cache["_list"];
}

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead


This posting is provided "AS IS" with no warranties, and confers no rights.
 
G

Guest

This is very good, thank you Steven.

So I need just one other code sample or example before I run off this and
actualize it: can you (or someone) give me a brief example of how you could
use references in XML to instantiate a list, as you seem to describe?

Will those XML entries each instantiate a lightweight object, and then
you'll have a list of objects, or were you contemplating some other data
structure as "holders" of the information?

Thanks again. I really appreciate the opportunity to learn these practices.

-KF
 
S

Steven Cheng[MSFT]

Thanks for your reply KF,

For example of generating a list of class objects from XML file, you can
simply use the .net framework's XML Serialization feature. Generally,
simple custom class or generic collection class support XML serialization.
e.g., the following code demonstrate serialize a custom object's List into
xml file and deserialize it back to memory:


===============================
static void Serialize()
{
XmlSerializer serializer = new
XmlSerializer(typeof(List<TestClass>));

List<TestClass> objs = new List<TestClass>();

for (int i = 0; i < 5; i++)
{
TestClass to = new TestClass();
to.ID = "id_" + i;
to.Visible = i % 2 == 0 ? true : false;

objs.Add(to);
}

StreamWriter sw = new StreamWriter("output.xml", false,
System.Text.Encoding.UTF8);

serializer.Serialize(sw, objs);

sw.Close();


}

static void Deserialize()
{
XmlSerializer serializer = new
XmlSerializer(typeof(List<TestClass>));

StreamReader sr = new StreamReader("output.xml",
System.Text.Encoding.UTF8);

List<TestClass> objs = serializer.Deserialize(sr) as
List<TestClass>;

sr.Close();


foreach(TestClass to in objs)
{
Console.WriteLine("id: {0}, visible: {1}", to.ID,
to.Visible);
}


}
===============================

Hope this helps.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead



This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,995
Messages
2,570,235
Members
46,821
Latest member
AleidaSchi

Latest Threads

Top