Wednesday, September 30, 2015

Managing the Sitecore xDB Contact Card without requiring the Tracker Revisited

Intro

Previously I mentioned how to update the contact card without the session.  I found that I was occasionally still getting locking issues, so I looked into it a bit further.  What I had was a little redundant for saving the update.

Saving Updates

When saving the updates really you do not need to call SaveAndReleaseContact, FlushContactToXdb should do the trick, but you should call it with the overload that takes two parameters and passin a new ContactSaveOptions with release set to true, and a new LeaseOwner.
var manager = Factory.CreateObject("tracking/contactManager"trueas ContactManager;
 
manager.FlushContactToXdb(contact, new ContactSaveOptions(true, new LeaseOwner(AnalyticsSettings.ClusterName, LeaseOwnerType.WebCluster)));
manager.SaveAndReleaseContact(contact);
 

Conclusion

While this is only a short note on the last post, be sure to wrap your contact manager to ensure you maintain the same contact card between your updates and when you flush the card or your changes will be lost, and only identify the contact when absolutely necessary to prevent a chance for potential conflict with locking.

Monday, August 31, 2015

Sitecore Caching Revisited

Previously I wrote about using the Sitecore Custom Cache.  Unfortunately I don’t think I put enough detail in that post.  Some may have been a little confused by it. 

Creating the Cache

Really creating a cache is almost too easy, you simply create a class that inherits from CustomCache and then implement SetObject  and GetObject as I said in my previous post.
public class MyCustomCache : CustomCache
 {
     public MyCustomCache(string name, long maxSize)
         : base(name, maxSize)
     {
     }

     public void SetObject(string key, object value)
     {
         base.SetObject(key, value, Sitecore.Reflection.TypeUtil.SizeOfObject());
     }

     public new object GetObject(object key)
     {
         return base.GetObject(key);
     }
 }

The Cache Manager

The problem with stopping here is though we have the cache we do not have an instance of it created.  This is also a very simple task.  The easiest way to implement it is just to create a static instance of it somewhere.  More properly though would be to create a static cache manager. 
public static class MyCacheManager
{
    private static readonly MyCustomCache Cache = new MyCustomCache(
        "My.NameSpace.Custom.Cache",
        StringUtil.ParseSizeString(Sitecore.Configuration.Settings.GetSetting("My.Custom.Cache.Size.Setting.Name""5MB")));
 
    public static object Get(string key)
    {
        return Cache.GetObject(key);
    }
 
    public static void Set(string key, object value)
    {
        Cache.SetObject(key, value);
    }
}

Clearing the Cache

It really is that easy.  It may be wise though to add a cache clearing mechanism as well maybe add a new static method to the manager.
public static void Clear()
{
    Cache.Clear();
}


Of course you still need to trigger this call using the Sitecore Pipelines which is also very easy, just add the call anywhere Sitecore normally clears the cache.

Managing the Sitecore xDB Contact Card without requiring the Tracker


The Normal Way

When working with a user profile in Sitecore 8, we generally get the contact card by using Tracker.Current.Contact.  Of course if the tracker is null we will call Tracker.Start(), and of course that would also mean the Contact is null so we would also need to call Tracker.Identify().
This works out well in most situations since the tracker is maintained across the session.  If you don’t have a session though this could mean a big headache.  You would normally need to create a Session and an HttpContext, then create and push a tracker into the stack.  While this is not excessively resource intensive when you are doing a lot of calls it can add up quickly.

Getting the Card

There is an alternate way to get the card though.  You can use the ContactManager to load the contact by username, if there is not a contact identified by that username then it will return null and you can then create a new Contact and insert it.
var user = Context.User.Identity.Name;
if (string.IsNullOrEmpty(user)) return null;

var contactManager = Factory.CreateObject("tracking/contactManager"trueas ContactManager;
var contact = contactManager.LoadContactReadOnly(user);

Saving Updates

If you are updating this contact keep in mind that it will not persist across the session so you will need to flush it to the database before the end of the request.  This is also done with the Contact Manager by calling FlushContactToXdb and passing the contact, then by calling SaveAndReleaseContact also passing in the contact. 
var manager = Factory.CreateObject("tracking/contactManager"trueas ContactManager;
 
manager.FlushContactToXdb(contact);
manager.SaveAndReleaseContact(contact);
 

Submitting your Session

Just to be on the safe side of things it is not a bad idea to submit your context.  You may be thinking that that requires a session.  Fortunately Sitecore can create a very lightweight session context for this use.  You can use the SessionContextManager and call GetSession passing in the contact id, an empty guid, and two Boolean true values.  Once you have the session you can call Submit on the SessionContextManager and pass this session in.
var contextManager =
    Factory.CreateObject("tracking/sessionContextManager"trueas SessionContextManagerBase;
 
var session = contextManager.GetSession(c.ContactId, Guid.Empty, truetrue);
contextManager.Submit(session);

While this solution is not perfect, you can expand on this solution to build a robust contact manager that does not depend on there being an active session.

Friday, July 31, 2015

Sitecore Serialization Synchronization Service (S4)

I know most of my posts have been instructional so far, so it is about time I make a bit of an announcement.  I am working on a new tool for Sitecore Development.  I would love input from the community of what their biggest expectations for this tool would be.

This tool is called the Sitecore Serialization Synchronization Service or S4 for short.  Basically it is a synchronization tool that connects to your Sitecore instance and keeps serialized items in sync.  You update an item and the item in the file system will be updated as well, this also goes the other way around.  You pull the latest from source control and it adds or modifies files in your sync folder and it pushes those changes into Sitecore.

At this point the serialization engine is almost complete, the biggest key for me here is performance.  I do not want this tool to take much memory or processor power.  I also do not expect to have any sort of Visual Studio integration, at least not that is required for use of the tool.

I do not plan to implement any sort of Code Gen or Code Deployment in this tool.  Visual Studio (and other IDE's) already have this functionality, so though it might be easier with a tool it is not 100% necessary.  I plan to do a tutorial on Code Gen with serialized Sitecore Items or possibly with S4 as a data provider.

S4 also will not deploy on build since it is not integrated with Visual Studio.  While at first this may sound like a breaking feature, S4 is intended to keep your items in sync at all time so there is no need to deploy the items on build.

If there are any questions, comments or requests with this tool please let me know.  I appreciate all feedback.  If the response is large enough I will push the development of this tool a bit harder.  As it stands right now I should hopefully have a beta ready (likely just base functionality without a friendly UI or anything) in the next month or so, so please check back often for updates.


Leveraging Sitecore's Caching Mechanism

In the time I have been developing in Sitecore I have seen many different approaches to caching, but only once have I seen someone actually use caching based on Sitecore's cache service.  It is in fact almost how scary it is to implement.

Basically all you have to do is create a class that inherits from Sitecore.Caching.CustomCache.  Of course you need to implement a constructor that calls the base constructor, and override the SetObject and GetObject methods.  That is pretty much it though.

This cache will be handled in the same admin page as the other Sitecore caches, and if you install the Cache Admin or Cache Manager shared source modules you can easily use them to monitor and manage the caches without needing to build your own custom admin page.

I highly recommend at least investigating this approach to anyone considering putting in a custom cache on their site.  It is efficient enough for most scenarios as well as being very easy to setup potentially saving you hours of coding.

Monday, June 29, 2015

Getting Started with Sitecore Content Search using Lucene or Solr

Using Sitecore Content Search with Solr is basically identical to that with Lucene at the general use level, with the exception of the configuration.  Solr does have some more advanced features that Lucene does not have. 
To get started though with either all we need is a search context.  We can get this using the context item (or any item for that matter).  We simply cast the item to the SitecoreIndexableItem class and pass it into ContentSearchManager.CreatesearchContext and that will give us our context.

This is generally set up as:
using (var context = ContentSearchManager.CreateSearchContext((SitecoreIndexableItem)item)){
   //search code….
}

From inside this context we can get our search results by calling the generic method GetQueryable that takes all types that derive from SearchResultItem on our context and using Linq to filter our results.

An example where we get all items under the current item:
var results = context.GetQueryable<SearchResultItem>().Where(i => i.Paths.Contains(item.ID));

If you have custom fields you want to search on it is highly recommended that you create a class that derives from SearchResultItem and add your fields as properties.  What is really nice with this is that Sitecore content search will reflect on this class and do the search on those properties.

An example with an item with an author field:
public class MyCustomResultItem: SearchResultItem{
   
public string Author { get; set; }
}
var results = context.GetQueryable<MyCustomResultItem>().Where(i => string.Equals(i.Author,”me”));

At this point you can iterate through results and get the items using .GetItem() on each resulting item.

Using SignalR with Sitecore

If you are unfamiliar with SignalR and need to set it up I will be posting an intro to SignalR on my other blog (Programming Medeley) in a few days.  Otherwise reading this post I will assume that you have a basic understanding of what SignalR is and how it works.
When developing in Sitecore with SignalR there is one major issue that you will run into (aside from basic routing).  That issue is the fact that you do not have a Sitecore site context within your SignalR context.  This causes issues with getting item URLs or using the Glass Mapper.

Missing Site Context

The fix for this is actually quite simple though.  You simply need to set the Sitecore site context on every request. 
To get the SiteContext you simply call Sitecore.Sites.SiteContextFactory.GetSiteContext and pass in the hostname (which can be found within the context of the Hub as this.Context.Request.Url.Host) and an empty path and it will give you a SiteContext. 
Once we have this all we have to do is set the current site to this context by setting Sitecore.Context.Site to this SiteContext. 
I use the single line:
Sitecore.Context.Site = Sitecore.Context.Site ?? SitecontextFactory.GetSiteContext(this.Context.Request.Url.Host, “/”);

Routing

As for the routing issue that you may run into, this is the same as setting up WebApi.  You need to ensure the route is registered in the Application_Start of the Global.asax. 

The command for this is (using the Global Configuration):
GlobalConfiguration.Configuration.Routes.MapHttpRoute(“signalrHub”, “
signalr/{controller}”);