Adding nodes to mvcsitemap in code - mvcsitemapprovider

I am building a simple CMS that stores the navigation/sitemap/site structure in a database table. When the app starts up I can create my sitemap nodes dynamically based on the data from that table.
The problem I am having is when a new record is added to the table or an existing one is updated while the app is running I need to rebuild the sitemap structure. Seems simple enough but I cannot figure out how.

There is no built-in support of clearing/rebuilding the sitemap on-the-fly.
But you could implement this yourself quite easily by implementing a custom sitemapprovider deriving from MvcSiteMapProvider.DefaultSiteMapProvider, and create a method used to clear the cache, using the protected Clear() method. Example:
public class CustomSiteMapProvider : DefaultSiteMapProvider
{
public void ClearSiteMap()
{
Clear();
}
}
I haven't tried it but it should work. Remember to changed the web.config file to use the custom sitemapprovider instead of DefaultSiteMapProvider.

Related

Orchard Content Parts that Don't Store Information in the Database

I'm trying to create a content part in Orchard that will perform a request to a web server and display the results of the request. The problem I'm running into is that my part requires no user input and thus I have left the part and part record classes empty. I have a Migrations.cs file that adds a description to the part and makes it attachable as well as creates a content item with the part attached to it. When I go to create a new instance of my content type it tries writing to the database and fails. How do you create a content part in orchard that doesn't try to save to the database? Thank you.
The actual error I receive is:
null id in Orchard.ContentManagement.Records.ContentTypeRecord
I'm pretty sure you don't need to create new table since there are many parts which don't have any in Orchard. Try to remove MyCustomPartRecord.cs and change MyCustomPart.cs
public class MyCustomPart : ContentPart<MyCustomPartRecord>
to
public class MyCustomPart : ContentPart
Then just add driver and view and you should be good without extra tables ... In theory :D
The answer to my problem is even when your part ins't actually saving anything in the database you still need to include a table for the part so it can store the id. I just added the following to my Migrations.cs file and it fixed the problem.
SchemaBuilder.CreateTable("MyCustomPartRecord",
table => table
.ContentPartRecord()
);

adding config items in Orchard Module

I was wondering on how to add configurable items in a Orchard module (analogous to appsettings key-value in a webapp). Could anyone me point to the right source/url in the web ?
Orchard has a rich settings infrastructure. It is not as simple to implement as the appsettings.config, but is a lot more powerful. You can add settings to the site (shown in the main 'settings' section of the dashboard) or for a specific content type, content part, field or even a part when it is attached to a specific content type. You can define custom settings parts so that your settings can be managed by end users through the dashboard.
For an example of both site settings and content type settings you can look at the Orchard.Comments module. There are also some good blog posts on creating your own custom settings in your module:
http://www.szmyd.com.pl/blog/how-to-add-settings-to-your-content-parts-and-items
http://www.szmyd.com.pl/blog/using-custom-settings-in-orchard-part-2-content-type-settings
I think the proper way to achieve this is to create a Record and leverage orchards database migration functionality. Orchard does the heavy lifting and you end up with a strongly typed object and repository! I believe the examples on the Orchard site use this technique for the custom Content Types but you can create them without just create your model
public class Item {
public string Key {get;set;}
public string Value {get;set;}
}
Then in the migration define your table with a table name equal to your model name
SchemaBuilder.CreateTable("Item",
table => table
.Column<string>("Key",column => column.PrimaryKey().Identity())
.Column<string>("Value", column => column.NotNull()
.WithLength(30)
Then you can inject a repository where yu need it
public class MyDriver : ContentFieldDriver<MyPart>
{
public MyDriver(IRepository<Item> itemRepository) {... }
Thats it!

Customized Tridion Search Index Handler: Custom vs Standard field for page url?

I was playing around with custom Search Indexing Handlers for SDL Tridion 2011 (GA). I got something working, using the very helpful information provided by Arjen, however I am not sure if my execution is the best option.
The requirement is to be able to search for pages in the CMS by url (eg www.example.com/news/index.html). In order to do this I have the created a class using the ISearchIndexingHandler interface (code below). I am indexing the url in the ContentText field of the item, however I am not sure if this would normally contain something else for a page (I think a page only has metadata so this should be OK). The advantage of using this over a custom field is that I can simply type the url in the search box without having to use <url> IN <fieldname> or something like that.
So my question is, is there any reason not to use ContentText for Pages, and is there any advantage in using a custom field? Also bonus marks go to anyone with good ideas on how to handle BluePrinting (if I create a page in a parent publication, I want the local urls also to be indexed in the child publications), and the case where a Structure group path is altered (I guess I can somehow trigger a re-index of child page items from within my indexing handler).
The code:
using System;
using Tridion.ContentManager.Search;
using Tridion.ContentManager.Search.Indexing.Handling;
using Tridion.ContentManager.Search.Indexing.Service;
using Tridion.ContentManager.Search.Indexing;
using Tridion.ContentManager.Search.Fields;
namespace ExampleSearchIndexHandler
{
public class PageUrlHandler : ISearchIndexingHandler
{
public void Configure(SearchIndexingHandlerSettings settings)
{
}
public void ExtractIndexFields(IdentifiableObjectData subjectData, Item item, CoreServiceProxy serviceProxy)
{
PageData data = subjectData as PageData;
if (data != null)
{
PublishLocationInfo info = data.LocationInfo as PublishLocationInfo;
string url = GetUrlPrefix(data) + info.PublishLocationUrl;
item.ContentText = url;
}
}
private string GetUrlPrefix(PageData page)
{
//hardcoded for now, but will be read from publication metadata
return "www.example.com";
}
}
}
You can store the url in the ContextText Property. Thies field is used to index Template content data.
Tridion does not index shared item(s) of child publication.
Indexing is triggered on Item modification(create, update, delete, localize and unlocalize).
Or you can use reindexing tool to reindex ur item. but there is no way to index shared items in child publication.
I don't think you can include the URL prefix in neither your search query as the indexed item. Because shared items are not indexed, you will probably index the Page from the Website Structure layer, which is never published.
When a Structure Group is moved you would have to make an event handler that triggers re-indexing all child pages using a protected method of the TOM.NET API. This method is not part of the public API, so posting the code for that solution would probably declare me a persona non grata with R&D :)
Before you re-index anything you should store the original publish location url of the Structure Group in the TcmEventArgs.ContextVariables property, so you can verify whether or not a re-indexing action is necessary.

Azure TableStorage HowTo?

I want to store Contacts on to Azure table(name and gender as a property). so I basically two classes . the one which derives from the TableSerivceContext and the other from TableServiceEntity. now I cant connect the pieces. What I will really do at the cotroller(I use MVC3)
tnx for any hint?
im assuming that you are receiving the properties (name and gender) via post from a view.
so your controller might be like this
public ActionResult DoSomething(User model)
{
}
so what you need to do is.. that. make a new ofject of the class thats derived from the TableServiceEntity. and assign the Properties.
like this
var tableUser = new TableUser(){Name = model.Name, Gender=model.Gender}
then from the class derived from TableServiceContext make an object. and use AddObject() method to add the user to the table
http://msdn.microsoft.com/en-us/library/system.data.services.client.dataservicecontext.addobject.aspx
This is what I have done recently to create a very simple MVC3 + Windows Azure Table sample application:
Created a Model Class DataEntity inherit from TableServiceEntity which include all the table properties needed to store along with PartitionKey and RowKey
Created another Model class DataContext inherit from TableServiceConext which includes IQueryable sets up the Table
Created a Controller class which creates HTTPGet and HTTPPost method type ViewResult returning View. The controller also have code to create the Table first using Model DataContext type and then added code to call AddObject as DataEntity type as below:
DataContext context = new DataContext(storageAccount.TableEndpoint.AbsoluteUri, storageAccount.Credentials);
context.AddObject("DataEntryTable", dataEntity);
context.SaveChanges();
Finally you can create views from the controllers.
You would need to inherit ‘Contact’ from TableServiceEntity and a context class from TableServiceContext to provide all the methods to manage your ‘Contact’ entities. You can then invoke methods on the ‘Context’ class from anywhere (including the controller).
I have written an alternate Azure table storage client, Lucifure Stash, which does away with having to inherit from any base calls and supports additional abstractions over azure table storage. Lucifure Stash supports large data columns > 64K, arrays & lists, enumerations, composite keys, out of the box serialization, user defined morphing, public and private properties and fields and more.
It is available free for personal use at http://www.lucifure.com or via NuGet.com.
Download the Windows Azure Platform Training Kit and do the lab on Windows Azure Storage. In 15 minutes you will have a working prototype.

Automapper: Mapping hierarchy

For my ASP.NET web application, I'm currently using Automapper to map from models (DTOs) -> view models. My view models have all string properties, because I'm using Mustache, a logic-less template engine.
I'm exposing an API to my website (via JSON, etc.), and what I'd like to do is perform the following mapping:
Model -> Base ViewModel -> Web ViewModel
Then, "Base ViewModel" can be serialized for my API (eg. with numerical values for currency). From there, I'll do a simple mapping for my "Web ViewModel" (eg. with formatted currency value strings, links, etc).
Problem is, I can't seem to get this to work. Defining the Model -> Base ViewModel mapping and Base ViewModel -> Web ViewModel mappings seperately isn't enough it seems to get my Web ViewModel, and if I explicitly add the Model -> Web ViewModel mapping, Automapper just tries to map directly, skipping the intermediate step which I rely on.
Can/should Automapper be used like this? I realize that I could probably explicitly just do two sequential conversions to achieve the correct result, but I thought I'd ask here to see whether I can get Automapper to handle the conversion in one step.
Well, I don't believe (or to be honest I don't know how) it could be possible.
But you could try
Create your Mappings
Model.CreateMap<Model, BaseViewModel>()...
Model.CreateMap<BaseViewModel, WebViewModel>()...
and try a generic helper like this, to be changed for your needs
public static void TwoStepMapping<TSource, TIntermediate, TDest>(TSource source, TDest dest) where TIntermediate : new()
{
Mapper.Map(Mapper.Map(source, new TIntermediate()), dest);
}
call :
TwoStepMapping<Model, BaseViewModel, WebViewModel>(model, webViewModel);

Resources