maartenba / MvcSiteMapProvider

An ASP.NET MVC SiteMapProvider implementation for the ASP.NET MVC framework.
Microsoft Public License
539 stars 218 forks source link

Task<IEnumerable<DynamicNode>> instead of IEnumerable<DynamicNode> #45

Open tugberkugurlu opened 12 years ago

tugberkugurlu commented 12 years ago

While we are working with DynamicNodes, we need to create a new class which derives from DynamicNodeProviderBase abstract class. Inside that class, we need to override one method as follows:

public abstract IEnumerable<DynamicNode> GetDynamicNodeCollection();

There are some cases which takes long time for that collection to load.if there is lots of data inside the database. For example, I have one currently and it takes approx. 400 ms. I am not sure but is there a way for the future releases to make this method's return type as Task<IEnumerable<DynamicNode>> so that it doesn't have to wait, returns the result immediately and builds the sitemap on the background?

I am thinking that this would also cause some problems even if this is possible. Any idea?

maartenba commented 12 years ago

The underlying ASP.NET SiteMap infrastructure will probably go bezerk on this. In theory, it can, but it will result in some users seeing only parts of the sitemap every now and then.

tugberkugurlu commented 12 years ago

So, it is not something possible in practice.

I think you got what I am after. Currently, The output result is cached and this effects the first and the others hits when the cache has been invalidated. I wonder if there is anyway that your think to make this sorts of things better.

mjhilton commented 12 years ago

Hi guys,

I've come across a similar issue, but have taken a different approach to solving it in my fork. The project I'm working on has a page structure something like this:

Home > Projects > Project Details > Edit Project

I wanted to replace the "Project Details" title with the name of the project, so that the breadcrumb would look like this:

Home > Projects > "My First Project" > Edit Project

So that the user could easily see which project they were working on. However, due to the number of projects in the DB and the dynamic nature of their titles, it's not feasible to use DynamicNodeProvider to load them all up at run-time.

Instead, I added a new concept, ISiteMapNodeDynamicTitleProvider, which is an extensibility point where a consumer can create a class which provides an alternative title for a given node at display-time, rather than at site-map-generation-time on initial load.

Would this functionality help with your DB load issues? And would it be of value to pull back into the main repository? I hadn't been able to find an easy way to perform this functionality with the existing codebase, but if I've missed something already built in, please let me know :)

tugberkugurlu commented 12 years ago

@mjhilton That sounds like solution to the problem I faced. I will checked that repository out and give it a try.

mjhilton commented 12 years ago

I haven't put a sample implementation in the MusicStore app yet... I'll put one up when I get a chance so you can see how I've used it :)

tugberkugurlu commented 12 years ago

@mjhilton ah, that would be awesome. thx!

mjhilton commented 12 years ago

Sorry, going away for the weekend so code will have to be in comment; don't have time to update the repo yet.

This is probably not the best implementation, in fact I think the whole set-up needs a bit more work. But basically, an instance of this class will get spun up every page load which includes the "Projects/Details" action, it uses Mvc's DependencyResolver to create an instance of the appropriate repository (you could just new one if you like/need), and pulls the title of that project only.

I don't know if I'm using the "key" attribute correctly, and haven't even thought about caching or anything like that. But you get the idea :)

SiteMapNode looks like this:

<mvcSiteMapNode title="Project Details" controller="Projects" action="Details" preservedRouteParameters="projectId" key="projectId" dynamicTitleProvider="MySolution.Web.Helpers.ProjectSiteMapNodeTitleProvider, MySolution.Web">

Implementation ProjectSiteMapNodeTitleProvider looks like this:

public string GenerateTitle(SiteMapNode node, HttpContext context, IDictionary<string, object> sourceMetadata)
{
    var mvcNode = node as MvcSiteMapNode;
    if (mvcNode == null)
        return node.Title;

    long projectId;
    if (!long.TryParse(mvcNode.RouteValues[mvcNode.Key].ToString(), out projectId))
        throw new InvalidOperationException("Expected key to be projectId");

    var projectRepo = DependencyResolver.Current.GetService<IRepository<Project>>();
    var project = projectRepo.Single(p => p.Id == projectId);

    return string.Format("{0} ({1})", project.Title, project.Id);
}
noocyte commented 11 years ago

This sort of functionality would be great 'out of the box'; ie delay resolving the actual path, but providing an OK default. Did you ever do anything with this?