Wednesday 23 October 2013

Powershell File Watcher

Ok so today I had a situation where I needed a simple script to copy some website related artifacts to an output directory that would allow me to view the changes on a website. Now during this process I was making a lot of changes over time and wanted to automate the process.

PowerShell to the rescue.

The script below is fairly simple(and a little unrefined), but it does the job nicely. The script will continue to run until you press a key, at which point it will de-register all of its events and exit

The configurable parts are:

  • You can set the folder to watch with the $inputFolder variable
  • You can set the folder to copy changes to with the $outputFolder variable
  • You can set the extensions of the files that you want to copy with the $filters variable

$inputFolder = Resolve-Path '..\inputDirectory'
$outputFolder = Resolve-Path '..\outputDirectory'
$filters = @('*.css', '*.js', '*.html') 

$messageData = "$inputFolder|$outputFolder"


function RegisterWatcher($fileFilter)
{
    $fsw = New-Object IO.FileSystemWatcher $inputFolder, $fileFilter -Property @{IncludeSubdirectories = $true;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'} 
     
    Register-ObjectEvent $fsw Changed -SourceIdentifier "FileChanged - $fileFilter" -MessageData $messageData -Action { 
        $sourceItem = $Event.SourceEventArgs.FullPath 
        $targetItem = $sourceItem.Replace($Event.MessageData.Split('|')[0], $Event.MessageData.Split('|')[1])

        Copy-Item $sourceItem $targetItem

        Write-Host "Copied $sourceItem"
    } 
}
 
foreach($filter in $filters)
{   
    RegisterWatcher $filter
}

Write-Host "Press any key to exit"

while ($true) {
    if ($Host.UI.RawUI.KeyAvailable) {
        break;
    }
    Start-Sleep -m 1000
}

foreach($filter in $filters)
{
    Unregister-Event "FileChanged - $filter"
}

Thursday 10 October 2013

Webforms MVP and Sitecore 7 POCO/Content Search

Lately I have been doing some work with Sitecore 7 and I had a requirement to work with the webforms rendering engine(as opposed to the MVC rendering engine), while doing this implementation I came across a nice pattern, it turns out Webforms MVP and Sitecore POCO/Content Search play really well together.

Before I get into the details, let me explain what both of these tools are:

  • Webforms MVP is a in implementation of the Model View Presenter pattern that has been floating around the ASP .NET webforms world for a while now. It promotes the separation of rendering and logic concerns in a similar way to MVC. The project website is http://webformsmvp.com/ and there is a bunch more information there.
  • Sitecore POCO/Content Search is the new search API that has come out as part of Sitecore 7. The easiest way of thinking about it, and one if its most useful features, is LINQ to Lucene. This results in a nice strongly typed LINQ/IQueryable syntax for interacting with Lucene indexes, allowing you to bypass the Sitecore databases for a lot of queries, resulting in a faster site.
Now for the bit where these patterns work well together. 

Webforms MVP has been used by a lot of people in Sitecore development for a while, but has traditionally had one major floor in the resulting implementation - a lack of page editor support. With the MVP approach requiring the creation of a "model" class, a lot of developers pass this model up to the rendering layer and render the values using traditional asp .net controls (e.g. asp:literals, asp:hyperlink etc.), as opposed to using Sitecore controls(e.g sc:text, sc:image etc.). While this wasn't explicitly necessary it kind of happened by default, especially if you wanted to use test driven development on your repository/logic layers. 

But, things have changed. Sitecore 7 and its content search API is based around model classes, and facilitates test driven development in a way Sitecore 6 never did.

So if we are now working with model classes how do we use the page editor? Well Sitecore thought of this as they were developing their new API and introduced a class with a particular method: SearchResultItem.GetItem(). This method allows your to retrieve the Item relating to a model as long as it is based on SearchResultItem.

With all of this wired up we have a nice middle ground with somewhat testable code, a nice user experience and a nice separation of concerns.

A sample Model:
    public class SampleModel : SearchResultItem
    {
        public string NonEditableField { get; set; }
    }

A sample presenter with Content Search Query:
    public class SamplePresenter : Presenter<IView<SampleModel>>
    {
        public SamplePresenter(IView<SampleModel> view)
            : base(view)
        {
            this.View.Load += this.Load;
        }
        private void Load(object sender, EventArgs e)
        {
            var item = Sitecore.ContentSearch.ContentSearchManager.GetIndex("sitecore_web_index")
                .CreateSearchContext()
                .GetQueryable<SampleModel>()
                .FirstOrDefault(model => model.NonEditableField == "something");
            this.View.Model = item;
        }
    }

A sample view:
<%@ Control Language="C#"
    AutoEventWireup="true"
    CodeBehind="SampleView.ascx.cs"
    Inherits="Layouts.SampleView" %>
<asp:Literal runat="server" ID="nonEditableField"></asp:Literal>
<sc:Text runat="server" ID="editableField"/>

And its sample code behind:
[PresenterBinding(typeof(SamplePresenter))]
    public partial class SampleView : MvpUserControl<SampleModel>
    {
        protected override void OnPreRender(EventArgs e)
        {
            this.nonEditableField.Text = this.Model.NonEditableField;
            this.editableField.Field = "Editable Field";
            this.editableField.Item = this.Model.GetItem();
        }
    }

How to disable "Add Users" in Sitecore's Platform DXP

 I have seen a few posts going around the community asking how to disable the "Add Users" button in Sitecore Platform DXP.   This ...