@Shazwazza

Shannon Deminick's blog all about web development

Why Snapshot?

May 18, 2010 19:53
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
In my previous post I introduced a new tool we’re working on here at TheFARM called Snapshot which is a content export engine for Umbraco.

When doing that post I knew that I was going to have to write this one anyway, people were inevitably going to ask “But why?”

I was hoping to have time to do it before anyone did, but alas I was wrong :P.

Here’s a few scenarios which Snapshot aims to be useful in.

The “We Don’t Need a CMS” client

We’ve all had these, it’s “just a small site”, “we don’t change content”, etc. But in the back of your mind you know they will change content and if it’s a static site you’ll have to get the devs to do it. Well with Snapshot you can create a CMS but the client doesn’t have to know.

Shared hosting, virtual folders and medium trust

Yes Umbraco can run in Shared Hosting, yes with 4.1 it can run in a virtual folder and medium trust. But 4.1 isn’t out yet. So you could look at the medium trust patch for 4.0.3, but you may not be comfortable with running a custom version of Umbraco, it does mean that upgrades are off the table.

Since Snapshot generates an ASP.NET site from within itself there’s no need to worry about Umbraco restrictions like that, it comes down to how you’ve coded your site.

Database-less websites

Not every website needs a database, but unfortunately Umbraco requires one even when you’re not editing content. You may not be aware but when you work with the Media API (either via the umbraco.library methods, or though the Media classes) you are going into the database. Yes there are projects which simulate a media cache you can even do this with Examine.
But you’ll still have to have your web server talking to a database.

Snapshot doesn’t require a database form the web server. We’ve got built-in Media caching, a Media API and even replace the umbraco.library XSLT methods so that the Media interaction in an XSLT doesn’t require a database!

Security

Umbraco is reasonably secure, but wherever you have a login you have a vulnerability, it’s just the way of the web. A Snapshot site has no login, has no database, thus it is more secure (yes yes, famous last words :P). With Snapshot you can put your CMS inside your DMZ and never have it expose itself to the outside world. You can then get Snapshot to generate a site from the CMS and you just deployed the generated files.

Speed

As fast as Umbraco is (and the backed just got faster) there’s always room for improvement. When writing Snapshot we came across several places which were not as good as they could have been within the Umbraco API. Take umbraco.library for example. You interact with static methods on the type in XSLT, but for every XSLT macro an instance of the class is created. This means that it can’t really have request-level caching of what you’re interacting with.
Or take NodeFactory, it doesn’t have caching of the node(s) you’ve tried to access; you get a new instance each time.

Now I’m not having a go at Umbraco’s API on this, just pointing out some facts.

In Snapshot we have much improved caching. Since we’re using Dependency Injection (via Autofac) we only create a single instance of our umbraco.library implementation, we also do the same for our ContentService (the NodeFactory replacement) and MediaService (media API replacement).
These have caching built into them as well, so you hardly ever create objects, you get back previously created ones.

In future posts we’ll look more into the new API’s and just how sexy they can be ;).

Because we can

Really, does there need to be any reason other than this! :P

 

 

Hopefully this gives some insight into what we’re trying to achieve and shows you how it could be viable in your scenarios. Keep in mind this isn’t all you can do with Snapshot, it’s just some of the most common reasons why.

Introducing Snapshot

May 18, 2010 18:31
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
Over the past few weeks Shannon and I have been dropping hints on Twitter about an exciting new project we’ve been working on. We’ve now started dropping hints including the name Snapshot.
Well we thought it was about time that we stopped playing the tease and brought more to the table.

What is Snapshot?

In short Snapshot is a tool for Umbraco, giving you the ability to export a full ASP.NET site from the CMS.

Darren Ferguson tweeted about a similar product he’s working on, generating HTML files from Umbraco.

But we’re going up a notch, we’re exporting a fully working ASP.NET website from Umbraco.
This means that macros will work, .NET User Controls will work, everything you’d expect from an Umbraco site.

Just there’s no CMS at all. In fact, you shouldn’t require any of the Umbraco assemblies to run it!

 

Enough talk, here’s a video!

Snapshot introduction from The Farm on Vimeo.

Examine RC2 posted

April 17, 2010 22:08
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
I’ve just released Examine RC2 into the while, you can download it from our CodePlex site.

RC2 fixes a bug in RC1 which wasn’t indexing user fields, only attribute fields.

There’s a few breaking changes with RC2:

  • IQuery.MultipleFields has been removed. Use IQuery.GroupedAnd, IQuery.GroupedOr, IQuery.GroupedNot or IQuery.GroupedFlexible to define how multiple fields are added
  • ISearchCriteria.RawQuery added which allows you to pass a raw query string to the underlying provider
  • ISearcher.Search returns a new interface ISearchResults (which inherits IEnumerable<SearchResult>)
  • New interface ISearchResults which exposes a Skip to support paging and TotalItemCount

 

Will be working on more documentation to explain some of the newly added and obscure features shortly :P.

Examine hits RC1

April 6, 2010 05:04
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
I’m happy to announce that Examine and UmbracoExamine have today hit RC1!FileDownload[1]

The Codeplex site also has more extensive documentation about how to get UmbracoExamine up and running within your Umbraco website.

Go, download your copy today.

Examine’s Fluent Search API – Elevator Pitch

April 1, 2010 05:08
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
I realised that with my blog post about Examine it was fairly in-depth and a lot of people were probably bored before they got to the good bits about how easy searching can be.
So I decided that a smaller, more concise post was in order.

What?

The Fluent Search API is a chainable (like jQuery) API for building complex searches for a data source, in this case Umbraco. It doesn’t require you to know any “search language”, it just works via standard .NET style method calls, with intellisense to help guide you along the way.

How?

This is achieved by combining IQuery methods (search methods) with IBooleanOperation methods (And, Or, Not) to produce something cool. For example:

var query = sc
	.NodeName("umbraco")
	.And()
	.Field("bodyText", "is awesome".Escape())
	.Or()
	.Field("bodyText", "rock".Fuzzy()); 

Examineness can be implemented to do special things to search text, like making it a wild card query, or escaping several terms to have them used as a search sentence.

 

Hopefully this more direct post will engage your attention better and make you want more Examine sexiness.

Examine’s fluent search API

March 26, 2010 06:14
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
As I mentioned in my last blog post we’ve done a lot of work to refactor Examine (and Umbraco Examine) to use a fluent search API rather than a string based search API.

The primary reason for this was to do with how we were handling the string searching and opening up the Lucene.Net search API. In the initial preview version we would take the text which you entered as a search term and then produce a Lucene.Net search against all the fields in your index. This is ok, but it’s not great. The problem came when we wanted to implement a dynamic search query. There were several different search parameters, which were to check against different fields in the index.
It was sort of possible to achieve this, but you needed to understand the internals of Examine and you also needed to understand the Lucene query language, and also that you couldn’t use the AND/ OR/ NOT operators, you had to use +, – or blank.

This is fine if you’re into search API’s, but really, how many people are actually like that? Ok, I must admit that I’m rather smitten with Lucene but I’m not exactly a good example of a normal person..

So I set about addressing this problem, we needed to get a much simpler way in which your average Joe could come and without knowing the underlying technology write complex and useful search queries.
For this we’ve build a set of interfaces which you require:

  • ISearchCriteria
  • IQuery
  • IBooleanOperation

ISearchCriteria

The ISearchCriteria interface is the real workhorse of the API, it’s the first interface you start with, and it’s the last interface you deal with. In fact, ISearchCriteria implements IQuery, meaning that all the query operations start here.

In addition to query operations there are several additional properties for such as the maximum number of results and the type of data being searched.

Because ISearchCriteria is tightly coupled with the BaseSearchProvider implementation it is actually created via a factory pattern, like so:

ISearchCriteria searchCriteria = ExamineManager.Instance.SearchProviderCollection["MySearcher"].CreateSearchCriteria(100, IndexType.Content);

What we’re doing here is requesting that our BaseSearchProvider creates an instance of an ISearchCriteria. It takes two parameters:

  • int maxResults
  • Examine.IndexType indexType

This data can/ should be then used by the search method to return what’s required.

IQuery

The IQuery interface is really the heart of the fluent API, it’s what you use to construct the search for your site. Since Examine is designed to be technology agnostic the methods which are exposed via IQuery are fairly generic. A lot of the concepts are borrowed from Lucene.Net, but they are fairly generic and should be viable for any searcher.

The IQuery API exposes the following methods:

  • IBooleanOperation Id(int id);
  • IBooleanOperation NodeName(string nodeName);
  • IBooleanOperation NodeName(IExamineValue nodeName);
  • IBooleanOperation NodeTypeAlias(string nodeTypeAlias);
  • IBooleanOperation NodeTypeAlias(IExamineValue nodeTypeAlias);
  • IBooleanOperation ParentId(int id);
  • IBooleanOperation Field(string fieldName, string fieldValue);
  • IBooleanOperation Field(string fieldName, IExamineValue fieldValue);
  • IBooleanOperation MultipleFields(IEnumerable<string> fieldNames, string fieldValue);
  • IBooleanOperation MultipleFields(IEnumerable<string> fieldNames, IExamineValue fieldValue);
  • IBooleanOperation Range(string fieldName, DateTime start, DateTime end);
  • IBooleanOperation Range(string fieldName, DateTime start, DateTime end, bool includeLower, bool includeUpper);
  • IBooleanOperation Range(string fieldName, int start, int end);
  • IBooleanOperation Range(string fieldName, int start, int end, bool includeLower, bool includeUpper);
  • IBooleanOperation Range(string fieldName, string start, string end);
  • IBooleanOperation Range(string fieldName, string start, string end, bool includeLower, bool includeUpper);

As you can see all the methods within the IQuery interface return an IBooleanOperator, this is how the fluent API works!

Hopefully it’s fairly obvious what each of the methods are, but the one you’re most likely to use is Field. Field allows you to specify any field in your index, and then provide a word to lookup within that field.

IExamineValue

You’ve probably noticed the IExamineValue parameter which is passable to a lot of the different methods, methods which take a string, but what is IExamineValue?
Well obviously it’s some-what provider dependant, so I’ll talk about it as part of Umbraco Examine, as that’s what I think most initial uptakers will want.

Because Lucene supports several different term modifiers for text we decided it would be great to have those exposed in the API for people to leverage. For this we’ve got a series of string extension methods which reside in the namespace

UmbracoExamine.SearchCriteria

So once you add a using statement for that you’ll have the following extension methods:

  • public static IExamineValue SingleCharacterWildcard(this string s)
  • public static IExamineValue MultipleCharacterWildcard(this string s)
  • public static IExamineValue Fuzzy(this string s)
  • public static IExamineValue Fuzzy(this string s, double fuzzieness)
  • public static IExamineValue Boost(this string s, double boost)
  • public static IExamineValue Proximity(this string s, double proximity)
  • public static IExamineValue Excape(this string s)
  • public static string Then(this IExamineValue vv, string s)

All of these (with the exception of Then) return an IExamineValue (which UmbracoExamine internally handles), and it tells Lucene.Net how to handle the term modifier you required.

I wont repeat what is said within the Lucene documentation, I suggest you read that to get an idea of what to use and when.
The only exceptions are Escape and Then.

Escape

If you’re wanting to search on multiple works together then Lucene requires them to be ‘escaped’, otherwise it’ll (generally) treat the space character as a break in the query. So if you wanted to search for Umbraco Rocks and didn’t escape it you’d match on both Umbraco and Rocks, where as when it’s escaped you’ll then match on the two words in sequence.

Then

The Then method just allows you to combine multiple strings or multiple IExamineValues, so you can boost your fuzzy query with a proximity of 0.1 :P.

IBooleanOpeation

IBooleanOperation allows your to join multiple IQuery methods together using:

  • IQuery And()
  • IQuery Or()
  • IQuery Not()

These are then translated into the underlying searcher so it can determine how to deal with your chaining. At the time of writing we don’t support nested conditionals (grouped OR’s operating like an And).

There’s another method on IBooleanOperation which doesn’t fall into the above, but it’s very critical to the overall idea:

  • ISearchCriteria Compile()

The Compile method will then return an ISearchCriteria which you then pass into your searcher. It’s expected that this is the last method which is called and it’s meant to prepare all search queries for execution.
The reason we’re going with this rather than passing the IQuery into the Searcher is that it means we don’t have to have the max results/ etc into every IQuery instance, it’s not something that is relevant in that scope, so it’d just introduce code smell, and no one wants that.

Bringing it all together

So now you know the basics, how do you go about producing a query?

Well the first thing you need to do is get an instance of your ISearchCriteria:

var sc = ExamineManager.Instance.CreateSearchCriteria();

Now lets do a search for a few things across a few different fields:

var query = sc.NodeName("umbraco").And().Field("bodyText", "is awesome".Escape()).Or().Field("bodyText", "rock".Fuzzy());

Now we’ve got a query across a few different fields, lastly we need to pass it to our searcher:

var results = ExamineManager.Instance.Search(query.Compile());

It’s just that simple!

 

Hopefully the fluent API is clean enough that people can build nice and complex queries and are able to search their websites with not problem. If you’ve got any feedback please leave it here, as we’re working to get an RC out soon.

Examine, but not as you knew it

March 22, 2010 06:07
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
Almost 12 months ago Shannon blogged about Umbraco Examine a Lucene.NET indexer which works nicely with Umbraco 4.x. Since then we’ve done quite a bit of work on Examine, and as people will may be aware we’ve integrated Examine into the Umbraco core and it will be shipped out of the box with Umbraco 4.1.

Something Shannon and I had discussed a few times was that we wanted to decouple Examine from Umbraco so it could be used for indexing on sites other than Umbraco.
You’ll also notice that I keep referring to it as Examine, not Umbraco Examine which most people are more familiar with.
This is because over the last week we have achieved what we’d wanted to do, we’ve decoupled Examine from Umbraco!

So what’s Examine?

Examine is a provider based, config driven search and indexer framework. Examine provides all the methods required for indexing and searching any data source you want to use.

Examine is now agnostic of the indexer/ searcher API, as well as the data source. That’s right Examine has no references within itself to Umbraco, nor does it have any references to Lucene.NET.
We have still maintained a usage of XML internally for passing the data-to-index around, as it’s the easiest construct which we could think to work with and pass around.

You could implement the Examine framework in any solution, to index any data you want, it could be from a SQL server, or it could be from web-scraped content.

Where does that leave Umbraco Examine?

Umbraco Examine still exists, in fact it’s the primary (and currently only) implementer of Examine. Over the last week though we’ve done a lot of refactoring of Umbraco Examine to work with some changes we’ve done to the underlying Examine API.

Changes? What changes?

Last week anyone who follows me on Twitter will have seen a lot of tweets around Umbraco Examine which was about a new search API and the breaking changes we were implementing.

While looking to refactor the underlying API of a large Umbraco site we have running I found that Examine was actually not properly designed if you wanted to search for data in specific fields, or build complex search queries.

This was a real bugger, I had many different parameters I needed to optionally search on, and only in certain fields, but since Umbraco Examine works with just a raw string this wasn’t possible.

So I set about creating a new fluent search API. This has actually turned out quite well, in fact so well that we new have this as the recommended search method, not raw text (which is still available).

The fluent API is part of the Examine API so it’s also available for any implementation, not just Umbraco! Since we’ve used Lucene.NET as the initial support model the API is designed similarly to what you’d expect from Lucene.NET, but we hope that it’s generic enough to look and feel right for any indexer/ searcher.

Here’s how the fluent API looks:

searchCriteria
.Id(1080)
.Or()
.Field("headerText", "umb".Fuzzy())
.And()
.NodeTypeAlias("cws".MultipleCharacterWildcard())
.Not()
.NodeName("home");

All you have to do is pass that into your searcher. That easy, and that beautiful. I’ll do a blog post where we’ll look more deeply into the fluent API separately.

Additionally we’ve done some other changes, because of what the framework new is we’ve renamed our assemblies and namespaces:

  • Examine.dll
    • This was formally UmbracoExamine.Core.dll
    • Root namespace Examine
    • Contains all the classes and methods to create your own indexer and searcher
  • UmbracoExamine.dll
    • This was formally UmbracoExamine.Providers.dll
    • Root namespace UmbracoExamine.dll
    • Contains all the classes and methods of an Umbraco & Lucene.NET

Apologies to any existing implementations of Umbraco Examine, this will result in breaking changes but since we’ve not hit RC yet too bad :P.

There are also some changes to the config, <IndexUserFields /> has become <IndexStandardFields />, and obviously the config registrations are different with the assembly and namspace changes.

The last change is that we’ve moved to the Ms-PL license for Examine, whos source is available on codeplex.

 

Currently we’re working to tidy up the API and the documentation so that we can get the RC release out shortly, so watch this space.

ASP.Net Client Dependency Framework RC1 Released!

March 19, 2010 09:13
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
With the community feedback, bug reports, patches, etc… I’ve managed to find time to upgrade this library to a release candidate status. We do use this framework in many production websites but it was great to hear from other in regards to specific bugs that were found relating to particular environments. These bugs have all been fixed up and this library is looking very stable.

You can download the binaries here.

Better yet, I’ve put together a near complete documentation library on CodePlex here !!

I still think the best way to learn about this project is to download the source code from CodePlex here and have a look at the demo web application included.

Moving forward, the next phase for this library is to add MVC support and another file registration provider called PlaceholderProvider which will give you even more granular control over where dependencies can be rendered in your markup. MVC support should be fairly straight forward and we’ll include a demo project for this as well.

Well definitely be releasing a final version soon after the next Umbraco 4.1 release candidate is released (which will hopefully be fairly soon!)

Happy day! Any and all feedback, bug reports and patches are definitely appreciated!

More on Umbraco, TinyMCE and Flash

February 4, 2010 02:05
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
In a previous post Shannon explained how to customise TinyMCE for what HTML elements Flash actually supports, and he finished off the post with showing how to cleanup line breaks.

To do this he used an XSLT function called normalize-space, which is great if you’re using XSLT!

I was writing a service today which was using LINQ to XML to generate the XML for Flash, but that posed a problem, how do you deal with Flash wanting to do hard breaks on new line constants?

Easy, string.Replace to the rescue!

Here’s a handy little extension method you can drop into your code libraries:

public static string NormalizeSpace(this string s) {
	if(s == null) throw new ArgumentNullException("s");
	return s.Replace("\r\n", string.Empty)
		.Replace("\r", string.Empty)
		.Replace("\n", string.Empty);
}

Nice and easy (and unsurprisingly logical!).

Excluding pages with URL Rewriting

December 24, 2009 02:17
This post was imported from FARMCode.org which has been discontinued. These posts now exist here as an archive. They may contain broken links and images.
Today we had a mini site which the promotion had completed, but the site was to stay live with a few of the content pages staying live for people who come to view it.

Because the site was only a few pages there isn’t a CMS back-end, it’s just flat ASPX pages are stored in a single folder.
The problem is, that the pages which need to be available are also in the folder which the pages which are not longer accessible are.

There is a few ways in which I can take down the pages which people aren’t meant to access, firstly I could just delete them. That’d work, but that’d be a 404 error which isn’t really a good user experience (I could set the 404 redirect to be the home page, but the browser would still receive a 404 HTTP status).

So the next option is URL Redirection, lets crack out our UrlRewriting.config file and set up a rule. We’ll start with a rule like this:

<add name="RedirAllIndexedPagesToDefault" 
   virtualURL="^(.*)/pages/(.*)" 
   destinationUrl="$1/default.aspx" 
   redirectMode="Permanent" 
   redirect="Domain" 
   ignoreCase="true" />

There, that’ll handle everything in our pages folder, but it doesn’t help with the pages which I want accessible. Say the pages I want accessible are TermsAndConditions.aspx and PrivacyPolicy.aspx, but I don’t want Entry.aspx accessible.
It’s just a matter of modifying my virtualURL to be a bit stricter, so now it looks like this:

<add name="RedirAllIndexedPagesToDefault" 
   virtualURL="^(.*)/pages/(?![TP.*])(.*)" 
   destinationUrl="$1/default.aspx" 
   redirectMode="Permanent" 
   redirect="Domain" 
   ignoreCase="true" />

Now you’ll not be able to get to Entry.aspx, but the other two pages will still work just fine.

Sure it’s not great if you’ve got lots of pages (and if you did have lots of pages I’d hope there was a CMS to deal with it), but it’s good for mini sites which you want some pages but not others in a folder accessible.