SiteMap change SiteMapProvider? - asp.net

I've got a custom menu navigation built from a web.sitemap file, the first line of this would be something like:
SiteMapNodeCollection topLevelNodes = SiteMap.RootNode.ChildNodes;
This works - it gets all the top level nodes from the web.sitemap file, and allows me to look through each SiteMapNode and do stuff.
However, now I want to be able to create multiple web.sitemap files, and then programmatically determine which web.sitemap file to use, but I can't seem to find out how to do this. I'm assuming I could either create one custom SiteMapProvider that can perform the logic to determine which web.sitemap file to load, or I have multiple providers, each one with the SiteMapFile property set to a specific *.sitemap file, and then switch providers programmatically before I access SiteMap.RootNode.
I think it's probably easier to have one custom provider, and then override the part where it looks for the actual physical sitemap file location, but I'm unclear how I would do this
I've googled a lot, but most answers seem to be regarding the standard sitemappath controls and so on, and how to set a SiteMapDataSource, which I don't think is relevant to my approach.

First you need to specify all of your sitemap files in your web.config as such:
<siteMap defaultProvider="FNDSiteMap" enabled="true">
<providers>
<add name="FNDSiteMap" type="System.Web.XmlSiteMapProvider" siteMapFile="FND.sitemap" securityTrimmingEnabled="true"/>
<add name="STASiteMap" type="System.Web.XmlSiteMapProvider" siteMapFile="STA.sitemap" securityTrimmingEnabled="true"/>
<add name="TASiteMap" type="System.Web.XmlSiteMapProvider" siteMapFile="TA.sitemap" securityTrimmingEnabled="true"/>
</providers>
</siteMap>
Then in your code-behind you can dynamically assign your SiteMapDataSource (which is bound to your menu) to one of the providers you specified in your web.config:
.aspx
<asp:Menu ID="MenuLevel1" runat="server" Orientation="Horizontal" DataSourceID="SiteMapLevel1"
MaximumDynamicDisplayLevels="0" IncludeStyleBlock="false">
</asp:Menu>
<asp:SiteMapDataSource ID="SiteMapLevel1" runat="server" />
.cs
SiteMapLevel1.SiteMapProvider = "TASiteMap";

Pauli's comment was the answer to my particular requirement:
"You shouldn't switch/change anything... instead you need to access
the RootNode like this all the time
SiteMap.Providers[someProvider].RootNode and the someProvider should
then be resolved at runtime."
I hadn't realised this was possible, but was the correct solution for me.

Related

Transforms for CSS and Views in MVC

I have an MVC application which I am deploying out to a staging server using Team City. I have created a Web.Staging.config transform to handle the different database connection, certificates and service calls.
On this staging server I have had a request to have the title of the Index view to read "TEST SYSTEM" and to have a different colour scheme to signify, at a glance that the user is on the test system.
So far I have handled this by changing the view on the file system in notepad, and swapping the bootstrap.css file to one with a different theme however every time I do a new commit/deploy these changes are wiped and its becoming tiresome.
Is there anyway to handle CSS/view changes per server by using a similar transform system as employed to handle the web.config
There's not really an easy way to transform CSS files like that, but what you could do is have your master CSS file link in your config file, so your view would be something like:
<link href='#ConfigurationManager.AppSettings["MainCSS"]'>
Then your web.Debug (and other transformations) could point to the correct path:
<add key="MainCSS" value="/Content/Site.css" />
And your web.Staging config could point to another:
<add key="MainCSS" value="/Content/Staging/Site.css" />
You can also apply the above logic for your Index view:
public ActionResult Index()
{
string viewName = ConfigurationManager.AppSettings["MainView"];
return View(viewName);
}
Then have in your web.Debug (and others):
<add key="MainView" value="Index" />
And in your web.Staging:
<add key="MainView" value="IndexStaging" />
One solution could be to add a key to the web.config and read it using the WebConfigurationManager.AppSettings. Those settings can be transformed. In your view you can check this setting if you need to change the title and if you need to load an additional css file.
In your web.config:
<appSettings>
<add key="IsTestSystem" value="False" />
</appSettings>
and in as transform:
<appSettings>
<add key="IsTestSystem" value="True" xdt:Locator="Match(key)" xdt:Transform="SetAttributes"/>
</appSettings>
In your view / layout:
if (Boolean.TryParse(WebConfigurationManager.AppSettings["IsTestSystem"] ?? "False", out run)) {
// include css file for test system or modify the title
}
And, if you want, you can just switch between the two bootstrap.css files.

ASP.NET Page naming using master pages

I have two user types: Readers and Authors. And I'm using Reader.Master and Author.Master for authorization purposes.
Then, there are StoriesR.aspx inherited from Reader.Master and StoriesA.aspx inherited from Author.Master. (In StoriesR.aspx page, you able to read the stories and in StoriesA.aspx you able to write the story.) So,
Reader.Master --> StoriesR.aspx
Author.Master --> StoriesA.aspx
Now, the thing is I don't want my users to see StoriesR.aspx?s=3 or StoriesA.aspx?s=3 in their browsers. I only want them to see stories?s=3. (even without the .aspx part)
How can I achieve this?
you can do this using urlMappings from web.config file
add in web.confing
<system.web>
<!--
Set compilation debug="true" to insert debugging
symbols into the compiled page. Because this
affects performance, set this value to true only
during development.
-->
<urlMappings enabled="true">
<add url="~/reader/stories" mappedUrl="~/reader/StoriesR.aspx"/>
<add url="~/author/stories" mappedUrl="~/author/StoriesA.aspx"/>
This will do url mapping.
You could have one aspx page and change the master page programmatically depending on what type of user they are, Author or Reader.
You can do this in the Page_PreInit event of your aspx page.
Check this c# example or this VB example

ASP.NET error: The page Y.ascx cannot use the user control X.ascx

I am getting the error below when trying to build the web site project in Visual Studio 2010:
The page '/WebSite/controls/C2.ascx' cannot use the user control '/WebSite/controls/C1.ascx', because it is registered in web.config and lives in the same directory as the page.
I have 2 web user controls:
controls/C1.ascx
controls/C2.ascx
The controls have been registered in web.config:
<configuration>
<system.web>
<pages>
<controls>
<add src="~/controls/C1.ascx" tagPrefix="my" tagName="C1"/>
<add src="~/controls/C2.ascx" tagPrefix="my" tagName="C2"/>
</controls>
</pages>
</system.web>
</configuration>
C1.ascx contains just a static HTML, C2.ascx is trying to include C1:
C1.ascx contains just some plain static simple HTML. C2.ascx is trying to include C1.ascx:
<%# Control Language="VB" %>
<my:C1 runat="server" />
<p>Hello from C2</p>
When trying to build the project, I am getting the error message at the top. I realise this issue can be fixed by adding another Register directive to C2.ascx...:
<%# Register Src="~/controls/C1.ascx" TagPrefix="ctl" TagName="C1" %>
...but I'm wondering if there's a cleaner solution and why am I getting the error in the first place?
Your only possible solutions are to:
Move the control out of the directory its currently sharing with outer.ascx, or
Re-register the control inside of the outer.ascx like you already mentioned
Re-write them in code as controls in a separate library
I personally think moving is the easiest, if it will work for your solutions. Second would be re-registering, even though annoying. Abstracting them out into a full code library is probably not worth the effort if this is the only reason you are doing it.
You could also put the controls into different folders. But I don't think this is much cleaner or better.
BTW: this behavior is by design, as you can read on this MSDN page (look for the yellow note almost at the end of the page).

asp.net more than one sitemap

I am having an issue with the sitemap control, I have added the hierarchical levels within the web.sitemap file and added the sitemap control to the various masterpages. I have however two homepages which can be viewed depending on the user of the system.
Is there any way to define two sitemap structures within this web.sitemap file or can I just create another sitemap file?
I am getting
Home > Home > View Details
Instead of
Home > View Details (for my first user)
Thanks
Yes you can define two sitemap structures by creating a seperate sitemap file. Once your sitemaps have been created, all you need todo is to state them within your Web.Config file like so:
<siteMap>
<providers>
<add name="Homepage1" type="System.Web.XmlSiteMapProvider" siteMapFile="~/Homepage1.sitemap" />
<add name="Homepage2" type="System.Web.XmlSiteMapProvider" siteMapFile="~/Homepage2.sitemap" />
</providers>
</siteMap>
Then you can choose which sitemap you want to choose by using the SiteMapDataSource control:
<asp:SiteMapDataSource ID="SitemapDS" runat="server" ShowStartingNode="false" SiteMapProvider="Homepage1" />
Hope this helps.

how to bind dataset to a treeview in asp.net c#?

is there a way to bind a asp.net tree view control to a data set?
i am having to build the nodes of the tree by looping through a data set and wanted to clean it up and make life better buy just doing a .databind()
also XML is always an option if its simpler than dataset here...
any ideas?
As Philb28 suggested, you can use a SiteMapProvider to handle this. I used that exact method on an old project. If you have a relatively static set of items for the TreeView, you can do the following:
Add a .sitemap file to your project.
Define <sitemap> and <provider> sections in your Web.config
Add sitemap elements to the provider section.
Here's what one of my Web.config sections looks like:
<siteMap>
<providers>
<add name="Administrators" description="Reads .sitemap XML files." type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" siteMapFile="Common/Sitemaps/Admins.sitemap"/>
<add name="Users" description="Reads .sitemap XML files." type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" siteMapFile="Common/Sitemaps/Users.sitemap"/>
</providers>
</siteMap>
From there, declare a SiteMapDataSource, set its SiteMapProvider property to the name property of one of your provider elements, and bind it. Finally, set your TreeView.DataSource to your SiteMapDataSource, and bind your TreeView as well.
You could look into implementing your own sitemapprovider. You could then build your site map based on your data set and bind this to your tree view.

Resources