I need some EXAMPLES or IDEAS on how to created dynamic breadcrumb control which will dynamically generated breadcrumbs for Dynamic Date framework powered by LINQTOSQL
You'll probably need three things:
A hierarchy structure in your database*
A custom SiteMap provider based on the StaticSiteMapProvider to read the hierarchy
A SiteMapPath control to display the Breadcrumb.
* I'd done some hunting around when I wanted something similar for a client site, and decided that storing the path structure in the database would be simplest - I've given the answer previously here for an arbitrary depth site map - note that if you're using SQL2008 you can use the new HierarchyId data type to make this a bit easier.
That being said, if you've got things like categories and products, you can probably get away with a simpler system in your database.
The key functions I needed to create to resolve this were things like:
/// <summary>
/// Gets this SiteMaps children.
/// </summary>
/// <value>The children.</value>
public List<SiteMap> Children {
get {
if (null == m_Children && !m_AttemptedToLoadChildren) {
m_AttemptedToLoadChildren = true;
m_Children = ctx.GetSiteMapChildrenByPath(_Path, 1).ToList();
// Sorts ascending.
m_Children.Sort(( sm1, sm2 ) => sm1.SortOrder.CompareTo(sm2.SortOrder));
// CMS Sorts Descending, so reverse the list.
m_Children.Reverse();
}
return m_Children;
}
}
/// <summary>
/// Gets a value indicating whether this instance has any children.
/// </summary>
/// <value>
/// <c>true</c> if this instance has children; otherwise, <c>false</c>.
/// </value>
public bool HasChildren {
get {
if (null != Children && Children.Any()) {
m_HasChildren = true;
}
return m_HasChildren;
}
}
/// <summary>
/// Gets this SiteMaps parent.
/// </summary>
/// <value>The parent.</value>
public SiteMap Parent {
get {
if (null == m_Parent && null != _ParentId) {
m_Parent = ctx.GetSiteMap(_ParentId);
}
return m_Parent;
}
}
GetSiteMap and GetSiteMapChildrenByPath call into stored procs to build the hierarchy as pulling it out with LINQ was going to be quite complex.
Hi have you had a look at my custom SitMapProvider here
This allows you to get the structure from the metamodel with annotation and a seperate sitemap file for non DD pages.
Related
In Bundling and Minification, I've known that the bundler will move around certain known file types -- so that things like jQuery will be moved to the front.
By default, when files are bundled by ASP.NET they are sorted
alphabetically first, just like they are shown in Solution Explorer.
Then they are automatically shifted around so that known libraries and
their custom extensions such as jQuery, MooTools and Dojo are loaded
before anything else.
-source
But after reading this recent question: ASP.NET MVC - Bundle Config order, which shows how a file is getting moved by the bundler even when the user has specified the load order, I realized I didn't know WHAT these known file types are, or the ORDER they will be listed in.
I've never seen a list explaining this, and in searching, I came up with nothing.
Is there a list the shows what the known file types are and the order they will be rendered in? I would think this is something the ASP.NET team should provide developers as a resource.
Its in the doc comments for BundleCollection.AddDefaultFileOrderings:
/// <summary>
/// Add default file ordering for common popuular script and style libraries.
/// </summary>
/// <param name="list">A collection of <see cref="BundleFileSetOrdering"/> objects to populate with default values.</param>
/// <remarks>
/// The purpose for applying these default file ordering values is to ensure that common libraries such as jquery are always located
/// at or close to the top within a bundle. These values can be all removed with <see cref="ResetAll"/>.
///
/// The default ordering values are as follows:
/// <list type="bullet">
/// <item><description>reset.css</description></item>
/// <item><description>normalize.css</description></item>
/// <item><description>jquery.js</description></item>
/// <item><description>jquery-min.js</description></item>
/// <item><description>jquery-*</description></item>
/// <item><description>jquery-ui*</description></item>
/// <item><description>jquery.ui*</description></item>
/// <item><description>jquery.unobtrusive*</description></item>
/// <item><description>jquery.validate*</description></item>
/// <item><description>modernizr-*</description></item>
/// <item><description>dojo.*</description></item>
/// <item><description>mootools-core*</description></item>
/// <item><description>mootools-*</description></item>
/// <item><description>prototype.js</description></item>
/// <item><description>prototype-*</description></item>
/// <item><description>scriptaculous-*</description></item>
/// <item><description>ext.js</description></item>
/// <item><description>ext-*</description></item>
/// </list>
/// </remarks>
public static void AddDefaultFileOrderings(IList<BundleFileSetOrdering> list) {
if (list == null) {
throw new ArgumentNullException("list");
}
BundleFileSetOrdering css = new BundleFileSetOrdering("css");
css.Files.Add("reset.css");
css.Files.Add("normalize.css");
list.Add(css);
BundleFileSetOrdering jquery = new BundleFileSetOrdering("jquery");
jquery.Files.Add("jquery.js");
jquery.Files.Add("jquery-min.js");
jquery.Files.Add("jquery-*");
jquery.Files.Add("jquery-ui*");
jquery.Files.Add("jquery.ui*");
jquery.Files.Add("jquery.unobtrusive*");
jquery.Files.Add("jquery.validate*");
list.Add(jquery);
BundleFileSetOrdering mod = new BundleFileSetOrdering("modernizr");
mod.Files.Add("modernizr-*");
list.Add(mod);
BundleFileSetOrdering dojo = new BundleFileSetOrdering("dojo");
dojo.Files.Add("dojo.*");
list.Add(dojo);
BundleFileSetOrdering moo = new BundleFileSetOrdering("moo");
moo.Files.Add("mootools-core*");
moo.Files.Add("mootools-*");
list.Add(moo);
BundleFileSetOrdering proto = new BundleFileSetOrdering("prototype");
proto.Files.Add("prototype.js");
proto.Files.Add("prototype-*");
proto.Files.Add("scriptaculous-*");
list.Add(proto);
BundleFileSetOrdering ext = new BundleFileSetOrdering("ext");
ext.Files.Add("ext.js");
ext.Files.Add("ext-*");
list.Add(ext);
}
Is it ok to get/set session variable inside a private/public property?
private List<FileAttachment> fileAttachments;
public List<FileAttachment> FileAttachments
{
get
{
if (Session["key"] != null)
{
fileAttachments = (List<FileAttachment>)Session["key"];
}
return fileAttachments;
}
set
{
fileAttachments = value;
Session["key"] = fileAttachments;
}
}
The goal here is I'd like for the container class (of this user control the property is in) to be able to set the List<T> depending on what entity and show existing attachments that's stored in the database.
That's not very safe; List<T> is not thread-safe.
You can never modify the list after assigning it to the property, since some other request thread might be reading it.
Therefore, you should make it a ReadOnlyCollection<T> rather than List<T>.
(and make sure your FileAttachment class is immutable or thread-safe)
Other than that, it depends where the property is.
If it's on a control or page, it's fine.
I have inherited an ASP.NET/C# project written way back in .NET 1.0. I started programming in .NET 2.0, so some of the antiquated concepts are foreign. I noticed that 80% of the pages have the following snippet or something similar:
#region Component Designer generated code
//Required by the Web Services Designer
private IContainer components = null;
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
connSQL = new System.Data.SqlClient.SqlConnection();
connSQL.ConnectionString = Inventory.Properties.Settings.Default.connectionString;
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion
Although this area is hit in the page load process, commenting it out has no obvious effects on the web page. I can guess that if the connSQL object is used and not initialized elsewhere, then problems can come up, this just hasn't been the case. So, my question is where does this designer generated code come from? I've never seen in it the code behind. Is this another .net 1.0 thing?
I believe it was ASP.NET 2.0 when partial classes were added. Before then, all the designer code had to be included in the code behind. Now, some of that code is separated in a partial class so it doesn't clutter up your code.
I don't know how you created your new pages, but as long as the new init code is working, I wouldn't think you need to hang on to this code.
I'm working on a web-based project that users will access after having been authenticated by Active Directory. My boss controls access to Active Directory, and wants to use groups to handle authentication to the application I'm writing. He's also provided me with a class to connect to pull the information I need from AD (logon name and active directory groups), so that's not a concern here.
Here's my problem: most users belong to more than 20 AD groups. I've never worked with AD before, so I have no idea if this is abnormally high, but I do know that it takes 5-6 seconds for AD to respond to my request for user group lists, so I really want to minimize the number of times I have to request groups, especially since peak use will involve about 200-300 users hitting the page within a few hours.
This application has three separate control groups: users, reviewers, and administrators. Each group has their own collection of pages in their respective folders of the website. Each folder has one entry-point page (i.e., the others will redirect to this page if no pertinent data are found in the Session). This page checks for valid a AD group only if IsPostback == false, and reads from an entry in the Session object to make sure that the user has the proper access.
So (finally), here's my question: Am I handling this in the most efficient way possible, or have I overlooked some simple alternative here?
For your issue above, yes AD sometimes is a bit slow depends on the load but rather than concentrating on that why not change your logic rather than ennumerating all the users groups why not check whether a user is a group member of. To implement it here is the code
/// <summary>
/// Checks if user is a member of a given group
/// </summary>
/// <param name="sUserName">The user you want to validate</param>
/// <param name="sGroupName">The group you want to check the membership of the user</param>
/// <returns>Returns true if user is a group member</returns>
public bool IsUserGroupMember(string sUserName, string sGroupName)
{
UserPrincipal oUserPrincipal = GetUser(sUserName);
GroupPrincipal oGroupPrincipal = GetGroup(sGroupName);
if (oUserPrincipal == null || oGroupPrincipal == null)
{
return oGroupPrincipal.Members.Contains(oUserPrincipal);
}
else
{
return false;
}
}
Or even better if you still want to prefer to use the ennumeration part, why not ennumerate only the groups on a specific OU rather than the whole directory like such
/// <summary>
/// Gets a list of the users group memberships
/// </summary>
/// <param name="sUserName">The user you want to get the group memberships</param>
/// <param name="sOU">The OU you want to search user groups from</param>
/// <returns>Returns an arraylist of group memberships</returns>
public ArrayList GetUserGroups(string sUserName, string sOU)
{
ArrayList myItems = new ArrayList();
UserPrincipal oUserPrincipal = GetUser(sUserName);
PrincipalSearchResult<Principal> oPrincipalSearchResult = oUserPrincipal.GetGroups(GetPrincipalContext(sOU));
foreach (Principal oResult in oPrincipalSearchResult)
{
myItems.Add(oResult.Name);
}
return myItems;
}
/// <summary>
/// Gets the principal context on specified OU
/// </summary>
/// <param name="sOU">The OU you want your Principal Context to run on</param>
/// <returns>Retruns the PrincipalContext object</returns>
public PrincipalContext GetPrincipalContext(string sOU)
{
PrincipalContext oPrincipalContext = new PrincipalContext(ContextType.Domain, sDomain, sOU, ContextOptions.SimpleBind, sServiceUser, sServicePassword);
return oPrincipalContext;
}
Finally as a note if you value security more than speed then I would not suggest IsPostback == false so that if there are any changes on a Security Group Membership of a certain user then you will be able to capture it better on the next process.
For a full implementation of AD Methods please refer here
if you are using .Net 2.0
http://anyrest.wordpress.com/2010/02/01/active-directory-objects-and-c/
or if you are using .Net 3.5 or 4.0
http://anyrest.wordpress.com/2010/06/28/active-directory-c/
I'm using WindowsTokenRoleProvider to determine Active Directory group membership in an ASP.NET web application.
My problem is that performance is not good, especially when a user is in many groups. As an example, I am in 253(!) groups, and WindowsTokenRoleProvider is taking around 150 seconds to determine what groups I am in.
I know I can use caching so that this isn't done on subsequent requests for a user, but obviously it isn't acceptable to take that long on the first hit.
What are my options? Can I force WindowsTokenRoleProvider to only consider certain groups? (I'm only interested in 5).
Some testing has revealed that my problem is that calling:
Roles.IsUserInRole(groupName)
is accessing the method GetRolesForUser in the RoleProvider - which is retrieving details of every role the user is a member of.
But calling:
Roles.Provider.IsUserInRole(groupName)
determines whether or not the user is in the group - without retrieving the details of every role the user is in.
Weird, but it looks like using Roles.Provider.IsUserInRole will solve my problem.
* UPDATE *
It turns out that this is just a partial workaround; if I use imperative permission checks, or 'allow' and 'deny' in web.comfig, then WindowsTokenRoleProvider still goes and slowly gets details of every group the user is a member of :o(
So my question still stands...
* UPDATE *
I solved this by creating a class that extends from WindowsTokenRoleProvider and overriding GetRolesForUser so it only checks for membership of roles specified in the configuration. It includes caching too:
/// <summary>
/// Retrieve the list of roles (Windows Groups) that a user is a member of
/// </summary>
/// <remarks>
/// Note that we are checking only against each system role because calling:
/// base.GetRolesForUser(username);
/// Is _very_ slow if the user is in a lot of AD groups
/// </remarks>
/// <param name="username">The user to check membership for</param>
/// <returns>String array containing the names of the roles the user is a member of</returns>
public override string[] GetRolesForUser(string username)
{
// Will contain the list of roles that the user is a member of
List<string> roles = null;
// Create unique cache key for the user
string key = String.Concat(username, ":", base.ApplicationName);
// Get cache for current session
Cache cache = HttpContext.Current.Cache;
// Obtain cached roles for the user
if (cache[key] != null)
{
roles = new List<string>(cache[key] as string[]);
}
// Was the list of roles for the user in the cache?
if (roles == null)
{
roles = new List<string>();
// For each system role, determine if the user is a member of that role
foreach (SystemRoleElement role in WebConfigSection.Settings.SystemRoles)
{
if (base.IsUserInRole(username, role.Name))
{
roles.Add(role.Name);
}
}
// Cache the roles for 1 hour
cache.Insert(key, roles.ToArray(), null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
}
// Return list of roles for the user
return roles.ToArray();
}