Blog

Blogging on programming and life in general.

Dynamic Robots.txt file for ASP.NET MVC Sites

Posted in: ASP.NET

Changing the contents of a robots.txt file when a site is moved from staging to a live environment is quite a manual and somewhat cumbersome process. I sometimes have the fear of forgetting to replace the "Disallow: /" line with correct indexable entries required for the website.

To give me one less thing to remember during my pre-live deployments, all my current and upcoming ASP.NET MVC sites will use a dynamic robots.txt file containing different entries depending on whether a site is in stage or live. In order to do this, we need to let the ASP.NET MVC application serve up the robots.txt file. This can be done by the following:

  • Create a new controller called "SEOController"
  • Add a new FileContentResult action called "Robots".
  • Add a new route.
  • Modify web.config.

SEOController

I have created a new controller that renders our "Robots" action as a plain text file. As you can see, my controller is not a type of "ActionResult" but a "FileContentResult". The great thing about "FileContentResult" is that it allows us to return bytes from the controller.

In this example, I am converting bytes from a string using Encoding.UTF8.GetBytes() method. Ideal for what we need to generate a robots.txt file.

[Route("robots.txt")]
[Route("Robots.txt")]
public FileContentResult Robots()
{
    StringBuilder robotsEntries = new StringBuilder();
    robotsEntries.AppendLine("User-agent: *");

    //If the website is in debug mode, then set the robots.txt file to not index the site.
    if (System.Web.HttpContext.Current.IsDebuggingEnabled)
    {
        robotsEntries.AppendLine("Disallow: /");
    }
    else
    {
        robotsEntries.AppendLine("Disallow: /Error");
        robotsEntries.AppendLine("Disallow: /resources");
        robotsEntries.AppendLine("Sitemap: http://www.surinderbhomra.com/sitemap.xml");
    }

    return File(Encoding.UTF8.GetBytes(robotsEntries.ToString()), "text/plain");
}

RouteConfig

Since I add my routing at controller level, I add the "MapMvcAttributeRoutes" method to the RouteConfig.cs file. But if you prefer to add your routes directly here, then this method can be removed.

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapMvcAttributeRoutes(); //Add this line!

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

Web.config

Add a "runAllManagedModulesForAllRequests" attribute to the modules tag in the web.config file to allow our robot.txt text file to be rendered by ASP.NET.

<system.webserver>
  <modules runallmanagedmodulesforallrequests="true"></modules>
</system.webserver>

What's Currently Wrong With Star Trek Franchise?

Posted in: Random Thoughts

NOTE: I write this post as a person who just appreciates the Star Trek movie franchise. Not as a massive fan.

Star Trek has always had a special place in my heart for as long as I can remember. The moment I sat down with my Dad and watched Star Trek III: Search for Spock with fresh new eyes, I was instantly grabbed by the action, ships, characters and vastness of space. It didn't take me long to understand the basic premise of the show even if I didn't completely understand the plot points.

I've dabbled in and out of the franchise over the years. But ever since the reboot in 2009, I have gained a renewed interest and started to look back at the classic movies with much fondness and appreciation. I truly admire how clever and gripping they were. Of course, there are some bad eggs when it came to the sequels (I'm talking about you Star Trek V!), nevertheless, they always managed to have memorable scenes.

Thoughts On The New Trek

I thought the reboot was off to a great start (no matter what the naysayers say), JJ Abrams managed to give Star Trek the kick in the butt it (quite frankly!) needed and looked forward to many more adventures with the characters I have grown to love. Star Trek became exciting again!

Four years later, we were given Star Trek Into Darkness and I remember leaving the cinema quite satisfied. But after I let the film digest within my subconscious, I started to pick holes in the storyline and came to the conclusion the highly anticipated sequel didn't actually offer anything new. It felt like a remake of Star Trek II: The Wrath of Kahn pure and simple, a film that I will always hold dear to my heart. A film that contains themes of revenge, coming of age, friendship and sacrifice.

So what's wrong with the current incarnation of Star Trek?

1) Lack of Continuity Between Films

One of the finest moment of the original films for me was the continuity between films that had an underlying theme that linked them together. Of course, I am talking about movies II - IV. It was quite satisfying seeing the characters develop and grow based on the decisions made from the previous films.

You might be thinking: What am I complaining about? The current reboot hasn't had a chance to grow yet?

Valid point. However, I believe this is something the writers could have done already. Planted the seed to grow in future adventures.

2) The Length of Time Between Sequels

The main problem with the Star Trek franchise is the length of time between installments. The films need to be out more frequently. Currently, the length of time between films is 4 years. This is too long, especially if a film hasn't been as strong in the story department, nor met the expectations of fans. I think it's safe to say Into Darkness was not embraced as positively when compared to the 2009 film.

What impact does this have? A big one. The momentum just disappears and the franchise has the added pressure of having to re-establish itself again to the public.

As it stands, the cast, designs and production are all delivered to a very high standard. But if the likes of Paramount spend too long about the story they wish to tell, they really need to get better script writers and directors with a coherent vision.

Come on Paramount! Pull your finger out!

3) Bring Writers In Who Aren't Fans of The Trek-lore

Some of the best Trek have come from people who aren't avid fans of the world of Star Trek. They have the ability to take a step back in order to create a unique and interesting vision. They take important facets of the characters and then weave Star Trek into the story.

I personally would love to see Nicholas Meyer have the opportunity to write the next installment. Now that would be something to look forward to!

4) Retreading The Same Ground

For those who have watched Star Trek in film or TV form and made a comparison with the current Trek movies, you would get a sense of deja-vu. As I've briefly stated above, there doesn't seem to be anything new being brought to the screens that we haven't already seen before, which is a little disappointing for the Trek veterans.

Into Darkness could have been the film to show something new and original. Retreading old ground in a universe purely built to tell new stories was never going to go down well.

5) No More Spock Prime

I loved seeing Leonard Nimoy reprise his role as Spock Prime in the 2009 reboot. It was pure genius and managed to make a connection with all previous films so that they still remained relevant. This was probably a ploy to get buy in from the proper Star Trek fans. I for one appreciated the sentiment.

However, it was unnecessary bringing him back for a brief appearance in Into Darkness and dare I say...a little cringe worthy.

Final Thoughts

There is so much to explore in the Star Trek universe and the formula to get Star Trek right is not as complex as it may seem. The script writers need to take a good hard look at what made the original films so successful (without plagiarising!) and make us a Trek film where no one has gone before...

Tools Every Azure Developer Should Be Using

Posted in: Azure

Having developed quite a few websites in Azure, there are some key tools I found that made my life easier when accessing all areas of my Azure cloud instance. The great thing about the selection of tools I have listed below is that it gives me access to all the features I need wrapped in a nice interface.

So lets get to it!

Azure Storage Explorer

Azure Storage Explorer is a useful tool for inspecting and altering the data in your Azure storage projects, including the logs of your cloud-hosted applications. This includes:

  • Blobs
  • Queues
  • Tables

Unlike some of the previous storage explorer software I've used in the past, Azure Storage Explorer allows you to preview a blob directly through its interface, such as: Images, Video or Text files. So you don't have to waste time downloading a blob just to check if its been generated correctly. Amazing time saver!

Once you have your storage set up within your Azure account, you can use this application to manage everything: create, view, copy, rename and delete all three types of storage types (listed above).

Azure Storage Explorer

An application as full featured as this shouldn't be free. But luckily for us, it is.

Download: https://azurestorageexplorer.codeplex.com/

Azure User Management Console

Azure User Management Console manages the users and logins of an Azure SQL database. The tool is simply converting your action into T-SQL commands and execute them against an Azure database of your choice.

Azure User Management Console

What some beginner Azure developers do is they use the same master credentials that is assigned to the database on creation within their web application too. Of course, this master user has full "db_owner" privileges against the database. Not a good idea! This application allows you to create a new new user with restricted access access levels really easily.

Download: https://aumc.codeplex.com/

Redgate SQL Azure Backup

One thing I found lacking in Azure SQL databases is the ease of creating a regular backup. There doesn't seem to be an automated way to do this directly through the Azure account.

I've been toying around with Redgate's Azure backup service and that seems to do the job quite nicely. But it does come at a price. For a daily backup on one database will cost around £7 per month.

Full range of backup plans: http://cloudservices.red-gate.com/

Evernote Has Made Me An Extreme Data Hoarder

EvernoteOk. So for those of you have not heard of Evernote (and who hasn't!?), it's an online app/service that allows you to record voice, text and hand written notes that can synchronise across multiple devices and platforms.

Ever since I had my first smartphone, I've always relied on Evernote to record my daily thoughts and reminders. There are numerous note taking apps on the market, which (for me) just doesn't seem to cut the mustard and end up always coming back.

Evernote not only has the functionality, but it also has the infrastructure to make it more than just a "note taking" platform. So much so I'm hoarding major amounts of everyday things. Evernote is starting to act as a repository of things I don't want to let go of.

With the help of IFTTT, I have created numerous recipes that aggregate data from my social platforms such as Instagram and Twitter to importing RSS feeds from websites that interest me. Now Evernote is my one-stop-shop for getting everything I need on a daily basis instead of logging into different platforms individually.

If there is something I happen to like, I just Evernote it. Even if I won't ever need it. Typical sign of a hoarder! But I'm an organised data hoarder, utilising clearly named notebook stacks. Strangely enough, the more notes you add, the more useful Evernote becomes and this maybe the reason why I am hoarding so many things. It's more than a "note taker"!

One feature I didn't expect to be so useful was the ability to take pictures of printed or handwritten documents. I can take quick snapshots and go completely paperless. On top of that, Evernote makes everything searchable. It's even clever enough to search through my rubbishly written notes. I only found out how truly powerful this feature until I was going through the motions of purchasing my first property. At this time of my life, I was in constant note/documentation mode and Evernote helped me organise my thoughts, reminders and record all email correpondence neatly.

What I've done in the past with other note taking apps is delete old notes or files just to be completely sure that I will be able to search what I require quickly and easily, mainly due to the fact that sifting through large volumes of data was a headache! Nowadays, I don't delete anything in Evernote. I can now keep a record of things I previously done and refer to later without any worries at time of need.

It's safe to say my addiction to Evernote will only increase as I find more uses for it. But that's not a bad thing...right?

Update - 12/12/2014

I came across some posts from others with the same issue, which is nice to know that it's not only me with a problem:

What Prismic.io Is Lacking

Posted in: Random Thoughts

WARNING! I may sound like an absolute hypocrite when the contents of this post is compared to my earlier post on first impressions of the Prismic.io platform. So here we go...

I am starting to encounter increasingly longwinded and somewhat frustrating stumbling blocks during the development of a Prismic.io powered website due to lack of basic development related features. Fundamental features that should already be there from the start.

I understand that Prismic.io is a new platform and is still in its infancy, but not having something simple as a time attribute to a date field is unforgivable (which I will explain later).

The idea behind Prismic.io is to empower the developer and gives them the tools to manage the content anyway they want. Sounds great! But how can developers like myself be empowered when the tools that are provided are not up to scratch.

So I have picked a few things lacking in the Prismic.io platform. I'll probably add some more on completion of the project I'm working on.

1) Sorting By Date/Time

Now you'd think if you have a date field, a time field would be not too far away. Wrong! A document only contains a date format field that shows a calendar on selection. This works for general use. But what if you have numerous articles written in a day that are displayed on a page in descending order and you wish to move an article higher up the page? There is no time field to allow for this.

By default when using date ordering, two things happen:

  1. All documents are ordered by the date value defined in the document.
  2. If multiple documents added within a day, they are then ordered by the time it was added in Prismic.

For me, this was a pain.

2) Non-match predicate

Sometimes, you want the ability to exclude documents from a query. In my case, return a list of authors except for one or two. Since Prismic.io predicate language is lacking a "not" operator I had to return a full list of authors and carry out the filtering at application level.

In the grand scheme of things, this isn't a massive flaw. I can see this becoming an issue when you need to exclude items from a larger dataset. It would be faster to do this at Prismic level than application level.

3) Where's the "OR" Operator?

No really, I would like to know!

4) No Required or Validation Fields

It is not possible to make fields compulsory or implement any form of validation. Therefore, up to the developer to make sure suitable checks are put in place where null or incorrect values are present.

To me, this seems a little bit backwards and you're solely relying on the editors to ensure the all data is correct and complete.

5) WYSIWYG Editor Improvements

As I stated in my previous post, that one of main deciding factors to why I used Prismic over Contentful was its easy to use WYSIWYG editor. I still stand by this point. It seems to offer a mish-mash of features that feel very intelligent and basic at the same time.

The WYSIWYG functionality is based on a StructuredText field type, flexible enough to allow an amalgamation of different content, such as embedded object (from social websites), paragraphs, images, etc.

On the surface, StructuredText is really nice to work with but then all of a sudden you encounter a key missing feature: blockquote! The only way I could get around this is by getting editors to insert custom mark up around any text for transformation into a blockquote at application level, like so:

[BlockQuote][Hello. I would like to blockquote this text please.]

This was just the start. There were other instances where further customisation had to be made to meet the editors requirements.

I have to quote Paul Dijou here (link at bottom of post) for describing the additional changes he too had to make in a very theatrical manner:

A writer wanted to have blockquotes: a whole paragraph should be displayed in a custom design and have an author. I had to kill him really fast and bury his body deep. Another one wanted semantic distinction between paragraphs, something like: this one should be red and this one blue just because. Thrown him into a bucket full of piranhas.

6) Technical Support

A platform or technology can only ever be as successful as the infrastructure present to support it. Without it, cracks will form. Currently, there is only one place you can ask a question: https://qa.prismic.io. It's definitely no StackOverflow. You really have to hope and pray for someone to answer your question promptly.

7) Convoluted Production Workflow

There will come a time when additional changes to a live site will be required. Whether it be modifications to a field or addition for a new document. All these changes will have to happen on the live Prismic repository. There is no development > stage > live workflow.

It would be nice to have the ability to duplicate repositories and push new releases.

Thankfully, someone has already raised this. I don't see this addition happening anytime soon.

Summary

My intention is not to give a very negative impression of the Prismic.io platform. It will most likely meet your content management needs. However, it does have its faults and unless modifications are made to some of the points raised from others in their Q&A forum and my post, I will have to question whether I use it again on a project by project basis. It's a CMS platform that just falls short of the mark.

I recommend reading the following blog post written by Paul Dijou, describing his own experiences working with Prismic: http://platformpauldijou.fr/blog/2014/07/17/prismicio-when-happiness-met-disappointment.

NOTE: If I have stated something that I have got completely wrong due to a lack of understanding. Let me know and I'll take everything back! :-)

Caching Static Files Through Web.config

Posted in: ASP.NET

When running my website through Google Page Insights, one of things I didn't do was cache static content, such as CSS, JavaScript and site images. Since I am on a shared hosting plan, I didn't think it was possible to have the option to cache a specific directory without direct IIS access.

Normally, when working on client sites hosted on a dedicated server, I set the cache header within "HTTP Response Headers" area in IIS. But all this actually does is generate a web.config file within the directory you wish to cache:

<!--?xml version="1.0" encoding="UTF-8"?-->
<configuration>
    <system.webServer>
        <httpProtocol>
            <customheaders>
                <add name="Cache-Control" value="public, max-age=604800" />
            </customheaders>
        </httpProtocol>
    </system.webServer>
</configuration>

So if you too are on shared hosting, add a web.config file with similar settings. In this case, I have cached my files for a week.

You can also set the cache settings in your main web.config file by wrapping a location path around the <system.webServer> node:

<location path="resources">
  <system.webServer>
        <httpProtocol>
            <customheaders>
                <add name="Cache-Control" value="public, max-age=604800" />
            </customheaders>
        </httpProtocol>
    </system.webServer>
 </location>

Render Partial View As A String

Posted in: ASP.NET

One of the many nice things of using ASP.NET MVC Razor is that you have full control over how you segregate your HTML markup when building a page through rendering PartialViews. Since becoming an avid MVC developer, I am increasingly noticing how easy it is to make nice neat reusable code, whether it is used server or client-side.

Just today, I found something really useful that is a truly defines this, where markup within PartialViews can be output to a page as string:

/// <summary>
/// Controller extension class that adds controller methods
/// to render a partial view and return the result as string.
///
/// Based on http://craftycodeblog.com/2010/05/15/asp-net-mvc-render-partial-view-to-string/
/// </summary>
public static class ControllerExtension
{
 
  /// <summary>
  /// Renders a (partial) view to string.
  /// </summary>
  /// <param name="controller">Controller to extend</param>
  /// <param name="viewName">(Partial) view to render</param>
  /// <returns>Rendered (partial) view as string</returns>
  public static string RenderPartialViewToString(this Controller controller, string viewName)
  {
    return controller.RenderPartialViewToString(viewName, null);
  }
 
  /// <summary>
  /// Renders a (partial) view to string.
  /// </summary>
  /// <param name="controller">Controller to extend</param>
  /// <param name="viewName">(Partial) view to render</param>
  /// <param name="model">Model</param>
  /// <returns>Rendered (partial) view as string</returns>
  public static string RenderPartialViewToString(this Controller controller, string viewName, object model)
  {
    if (string.IsNullOrEmpty(viewName))
      viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
 
      controller.ViewData.Model = model;
 
      using (var sw = new StringWriter())
      {
        var viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
        var viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
        viewResult.View.Render(viewContext, sw);
 
        return sw.GetStringBuilder().ToString();
      }
    } 
}

I can't take credit for this code. But here is the guy who can: Jan Jonas.

Being able to output PartialViews as a string is actually quite handy, since you could have a paginated news listings page that displays the first page of articles server-side and any additional pages could be loaded in via jQuery Ajax. Each article item would be a PartialView so you could serve the same markup client-side. My code below probably explains things a little better:

Article Listing View

This page will list all my News Articles. As you can see, I am using an "ArticleListItem" as my PartialView.

@model List<Article>

@if (Model.Any())
{
    <div class="article-list">
    @foreach (var a in Model.Select((value, index) => new { value, index }))
    {
        Html.RenderPartial("~/Views/Article/_ArticleListItem.cshtml", new ArticleListItemView { Article = a.value, CssClass = ArticleHtmlHelper.GetItemCssClass((a.index + 1)), IsFullWidth = false});
    }
    </div>
}
else
{
    <div>
        No articles could be returned.
    </div>
}

Article List Item PartialView

My PartialView has quite a bit going on to determine how the markup should be rendered and it's definitely something I wouldn't want to have to duplicate elsewhere just to load in client-side. Nice!

@model Site.Web.Models.Views.ArticleListItemView
@{
    string fullWidthClass = String.Empty;

    if (Model.IsFullWidth)
    {
        fullWidthClass = "full-width";
    }
}
<div class="article-summary @Model.CssClass @fullWidthClass">
    <a href="@Model.Article.PageUrl" class="img">
        @if (Model.CssClass == "large")
        {
        <img src="@Model.Article.Images.ImageCollection[1].Url" />
        }
        else
        {
        <img src="@Model.Article.Images.ImageCollection[0].Url" />
        }
    </a>
    @if (Model.Article.Category != null)
    {
    <span class="cat">@Model.Article.Category.Name</span>
    }
    @if (Model.Article.ReadTime != null)
    {
    <span class="time">@String.Format("{0} read", Model.Article.ReadTime)</span>
    }
    <h2 class="@Model.CssClass"><a href="@Model.Article.PageUrl">@Model.Article.Title</a></h2>
    @if (Model.Article.Author != null)
    {
    <a href="@Model.Article.Author.PageUrl.Url" class="author">
        <img src="@Model.Article.Author.Images.ImageCollection[0].Url" />
        <span>@String.Concat(Model.Article.Author.FirstName, " ", Model.Article.Author.LastName)</span>
    </a>
    }
</div>

GetArticleItems() Controller

This is where the RenderPartialViewToString() method shines! This controller is called within my jQuery Ajax function to get the next page of news articles. I am then calling my "ArticleListItem" PartialView to return the HTML markup as a string through my client-side call.

[HttpPost]
public JsonResult GetArticleItems(DBContext ctx, int pageNo, int pageSize, string categoryId)
{
    ApiDocumentInfo docInfo = DocumentHelper.SearchDocuments(ctx, true, "article", "category", categoryId, pageSize, pageNo, "articles", "date desc");

    List<Article> articles = docInfo.Documents.Select(doc => doc.ToArticle(ctx)).ToList();

    StringBuilder articleHtml = new StringBuilder();

    if (articles.Any())
    {
        for (int a = 0; a < articles.Count; a++)
            articleHtml.Append(this.RenderPartialViewToString("_ArticleListItem", new ArticleListItemView { Article = articles[a], CssClass = ArticleHtmlHelper.GetItemCssClass((a + 1)), IsFullWidth = false } ));
    }

    return Json(articleHtml.ToString());
}

XML Parsing Error In A MVC Razor View

Posted in: ASP.NET

If you set a Controller's response type to "text/xml", you may encounter an: "XML Parsing Error: XML or text declaration not at start of entity". Your View may look something like this:

@{
    Layout = null;
}

<?xml version="1.0" encoding="utf-8" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    @if (Model.Any())
    {
        foreach (SitemapNode node in Model)
        {
            <url>
                <loc>@node.Location</loc>
                <lastmod>@node.LastModified</lastmod>
                <changefreq>monthly</changefreq>
            </url>
        }
    }
</urlset>

In this case, I was creating a sitemap for one of my websites. So I created a Controller and View as I normally would do. However, when generating an XML output, you'll have to do something a little different in MVC:

@{
    Layout = null;
}<?xml version="1.0" encoding="utf-8" ?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
    @if (Model.Any())
    {
        foreach (SitemapNode node in Model)
        {
            <url>
                <loc>@node.Location</loc>
                <lastmod>@node.LastModified</lastmod>
                <changefreq>monthly</changefreq>
            </url>
        }
    }
</urlset>

Can you see what is the difference? You'd be forgiven for not seeing it. But if you look a little closer, you'll see that I pushed up my XML declaration right up next to where I set the Layout block. This is because Razor outputs extra lines within its markup.

So when I left an empty line after my Layout block (as seen my my first code example), this gets rendered as an empty line when you run the page which would not be valid XML.

Update - 28/08/2014

Just found an even better way to get around the same issue from reading Joe Raczkowski blog. All that needs to be done is place the main XML declaration at the top of the page inside the @{} braces:

@{
Layout = null;
Response.ContentType = "text/xml";
Response.Write("<?xml version=\"1.0\" encoding=\"UTF-8\" ?>");
}

So I Rebuilt My Site Again

Posted in: Kentico

Welcome to my new and improved website built in Kentico 8 and MVC Razor 5.

My old site was crying for an upgrade and now seemed like a good opportunity to make quite a few modifications, such as:

  • Upgrading to Kentico 8
  • Ditch ASP.NET Web Forms for MVC Razor 5
  • Refresh the front-end (designed by yours truly!) ;-)
  • Responsive support using Bootstrap
  • Refactored all code to improve website performance and caching

The new build has been a bit of a pet project and allowed me to put into practice everything I've learnt from over the years since my last build.

Still work in progress and more refinements are in the pipeline.

Prismic.io - Content Management for The Masses

Posted in: Random Thoughts

Generally, all Content Management Systems are tightly integrated into the websites they control to serve one key function: publish custom content. Almost as one singular entity. From the moment you choose a CMS, you shall be forever locked down by its required platform and technology.

So in terms of the CMS world, nothing revolutionary has happened to change our perception otherwise...until now...

I have been doing some research into some content management systems that sits externally from a platform (such as a website), giving you freedom to manage the content however you like and it something that's gaining a lot of traction. I am starting to see why.  In fact, I'm in the middle of building a site using one of these "externally" managed CMS platforms.

I would say the the main market players are Contentful and Prismic. They both are very similar in the features they provide and do a great job in delivering content to a platform of your choice through simply querying their native API's to return a nice JSON feed. So from a development perspective, they're both just as easy to integrate as each another and the deciding factors on the one you choose will primarily be:

  • Price
  • Ease of use
  • Editor features

Based on these factors alone, I found Prismic to be the ideal candidate to fulfill my clients needs and adding content was a pleasure. It probably has the nicest interface I've seen in a long time. Very quick, easy and has something Contentful didn't have: a nice WYSIWYG editor. The markdown editor alone in Contentful was a deal breaker and I feared it would add an additional learning curve for non-technical clients.

The only strange thing I noticed about Prismic was that you cannot add any form of validation or set a field to be required. Hopefully, this is something they will add to future releases. When you have other great features like an easy image upload to Amazon Cloud for resizing and cropping, having no validation isn't all that important. :-)

I am already more than halfway through my first Prismic managed website and the implementation couldn't be easier with the help of their forum and starter projects in the technology of your choice.

One of the fears I did have whilst implementing Prismic was how well will my pages load on high demand, especially when the content itself is external from the website. Would there be issues or delays in sending content to my platform? I guess this question is still yet to be answered. So far, the page speed has been better than expected (based on initial testing).

Prismic in a nutshell (stolen from their website):

prismic.io is a developer friendly, API-based approach to CMS. It features a Writing Room for content writers to author, manage and store content, and a Content Query API for developers to integrate managed content. Your content doesn't live "in a website / in websites", your project doesn't live "in a CMS"; rather, your content lives in one place and is shared across your websites, and your project lives absolutely anywhere you want.

;