Blog

Blogging on programming and life in general.

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\" ?>");
}

Prismic.io - Content Management for The Masses

Posted in: General Development

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.

Underestimating The Use of Stored Procedures

Posted in: Databases & SQL

It's a shame that I have come quite late in the game when it comes to fully utilising the benefits of stored procedures. I am more than familiar on the general uses, such as CRUD operations, passing and returning parameters. Standard stuff!

When I decided to work on a new project, I made a conscious decision to place all my database queries within stored procedures for the following reasons:

  • To broaden my current knowledge.
  • Remove all queries from web application level for maintainability.
  • Attempt to use logic in my stored procedures to do the brunt of the processing in one database call.
  • Increase speed of execution and performance for when a procedure is run multiple times.

Out all of the points listed above, my main aim was to try and minimise all my database calls and get the data in a format that can be used directly without any further manipulation at application level.

As you can see from the following stored procedure, I am carrying out checks to ensure specific data elements exist prior to carrying out further database operations. Thus, hopefully improving performance an efficiency.

CREATE PROCEDURE spLogTagActivity
(
    @ItemPrimaryHashtag AS nvarchar(100),
    @Hashtag AS nvarchar(100),
    @TagCategoryID AS int
)
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT OFF;
    
    DECLARE @TagID AS int
    DECLARE @TagIsIgnored AS bit
    DECLARE @ItemID AS int
    DECLARE @ItemTagID AS int
        
    --Get TagID and Tag Ignore value based on the text value
    SELECT @TagID = ID, @TagIsIgnored = IsIgnored FROM Tag WHERE TextLowercase = LOWER(@Hashtag) COLLATE SQL_Latin1_General_CP1_CS_AS
    
    SET @ItemID = (SELECT ID FROM Item WHERE PrimaryHashtag = @ItemPrimaryHashtag)

    --If an Item can be found based on the Primary Hashtag, we will use the data.
    IF (@ItemID IS NOT NULL)
    BEGIN
        IF (@TagID IS NULL AND @TagIsIgnored IS NULL)    
        BEGIN
            --Only insert tags that are not the same as the Item Primary Hashtag
            IF (LOWER(@ItemPrimaryHashtag) <> LOWER(@Hashtag))
            BEGIN
                EXEC spInsertTag @TagCategoryID, @Hashtag, 0, 0, NULL, NULL, NULL, 0, @TagID OUTPUT
            END
                                        
            --Associate new tag to the Item.
            IF (@TagID IS NOT NULL)
                BEGIN
                    EXEC spInsertSingleItemTag @TagID, @ItemID, 1, @ItemTagID OUTPUT
                                                    
                    --Create a new Activity line for the Item.
                    EXEC spInsertTagTracking @ItemTagID
                END
        END    
        ELSE
        BEGIN
            --If a Tag has already been logged, we will create a new Activity line for the Item
            --only if it does not have an ignored status
            IF (@TagID IS NOT NULL AND @TagIsIgnored <> 1)    
            BEGIN
                --Associate the Tag to an Item, if it doesn't already exist.
                SET @ItemTagID = (SELECT ID FROM ItemTag WHERE TagID = @TagID AND ItemID = @ItemID)
                
                IF (@ItemTagID IS NULL)
                BEGIN
                    EXEC spInsertSingleItemTag @TagID, @ItemID, 1, @ItemTagID OUTPUT                                        
                END        
                                    
                EXEC spInsertTagTracking @ItemTagID    
            END
        END
    END
    ELSE
    BEGIN
        IF (@TagID IS NULL AND @TagIsIgnored IS NULL)    
        BEGIN    
            EXEC spInsertTag @TagCategoryID, @Hashtag, 0, 0, NULL, NULL, NULL, 0, @TagID OUTPUT    
        END
    END
END
GO

I won't go into detail on what this sample stored procedure is doing, but I am delivering different outcomes based on the conditional statements. This is something that could have been done at application level, but much nicer in one database call. In other procedures I have utilised CASE and WHILE operators.

The benefits of using stored procedures far outweigh the negatives...Negatives!? Yes negatives...Well I just have one small gripe. If you create a stored procedure that contains quite a bit of meaty logic and find that something is not working (even though syntactically correct), it's quite difficult to debug exactly what point the procedure is failing.

To end the post, here's something surprising I found: The execution time of running a simple SELECT query can be slow when used within stored procedures, even though the query itself is fast. This is something I've encountered myself when wanting to retrieve a single value from one of my tables. The only way to get around this, is by passing you query parameter to a local variable inside the stored procedure. Take a look at this answer on StackOverflow. Strange!

Microsoft Virtual Academy...Something every Microsoft Developer Should Take A Look At!

There are many roads and avenues a tech-head can take to either get a grasp on new technology or prepare for certification. Unfortunately, some methods to get the knowledge on a subject can come at a great cost...especially when it comes to anything Microsoft.

Generally, Microsoft has always had some great forum and blogging communities to enable developers to get the expertise they require. I've always found them to be somewhat divided and looked rough around the edges. Now Microsoft has reworked its community and provided learners with a wide variety of courses freely available to anyone!

While MVA courses are not specifically meant to focus on exam preparation. They should be used as an addition to paid courses, books and online test exams to prepare for a certification. But it definitely helps. It takes more than just learning theory to pass an exam.

So if you require some extra exam training or just want to brush up your skills, give a few topics a go. I myself decided to test my skills by starting right from the beginning and covering courses that relate to my industry. In this case, to name a few:

  • Database Fundamentals
  • Building Web Apps with ASP.NET Jump Start
  • Developing ASP.NET MVC 4 Web Applications Jump Start
  • Programming In C# Jump Start
  • Twenty C# Questions Explained

I can guarantee you'll be stumped by some of the exam questions after covering each topic. Some questions can be quite challenging!

I've been a .NET developer for around 7 years and even I had to go through the learning content more than once. Just because you've been in the technical industry for a lengthy period of time, we are all susceptible to forget things or may not be aware of different coding techniques.

One of the great motivations of using MVA is the ranking system that places you against a leaderboard of other avid learners and seeing yourself progress as you complete each exam. All I can advise is that don't let the ranking system be your sole motivation to just "show-off" your knowledge. The important part is learning. What's the point in making a random attempt to answer each exam without a deep understanding on why you got the answer correct or incorrect.

You can see how far I have progressed by viewing my MVA profile here: http://www.microsoftvirtualacademy.com/Profile.aspx?alias=2181504

All in all: Fantastic resource and fair play to Microsoft for offering some free training!

Get Record Count Grouped By Month and Year

Posted in: Databases & SQL

Grouping records by their respective month and year based on a date column can be done really easily by simply running the following SQL query:

SELECT
       DATEPART(MONTH, DownloadDate) AS Month,
       DATEPART(YEAR, DownloadDate) AS Year,
       COUNT(DownloadID) AS NumberOfItems
FROM
       Download
GROUP BY
       DATEPART(YEAR, DownloadDate), DATEPART(MONTH, DownloadDate)
ORDER BY
       Year DESC, NumberOfItems DESC

As you can see from the query (above), I am using the "DownloadDate" column to group my records and to also get a count of how many records belong to that month and year.

Use Your Strings Wisely

Posted in: C#

When I was first learning to code, I was always told to use my strings in applications wisely. It's very easy to use strings without much thought. I think strings are forgiving compared to any other data type...too forgiving.

I was going to write a full blown blog post on the best way to use the string data type, but I found a good blog post that explains everything and I will use for reference when guiding new developers to my somewhat infinite wisdom. :-)

Zeeshan Umar, wrote a very interesting blog post a few years ago (but still relevant) that I only happened to find, explaining some new interesting ways on how to use strings efficiently. The following approach caught my eye:

string errorCode1 = "ec-1001";

if (String.Compare(errorCode1,"ec-1001",true) == 0)
{
   //Do something...
}

The String.Compare constantly stares me in the face via Visual Studio intellisense but never thought of using it. I will be using this approach if I need to check a string whilst using an conditional statement.

If you happen to find anymore interesting ways to efficiently use strings, please leave a comment.

MVC Custom Extension Methods

Posted in: ASP.NET

I've been toying around with MVC for quite some time now. Initially, I couldn't imagine breaking away from the safety-net that is ASP.NET Web Forms. What many developers are not aware of when moving over to the ASP.NET MVC framework is that you have to write everything from scratch. You will not have the comfort of dragging and dropping event driven controls in a GUI-centric way.

But nowadays, I am itching to build new sites in MVC. I like to be in control of the whole page lifecycle and the mark-up that is generated.

Since there are no pre-built resusable controls, I decided start developing my own library of extensions that I could use in future MVC projects I work on. Ranging from pagination to tag clouds.

Creating custom extensions is really easy. I started off by creating a Category Navigation that returns a IHtmlString (HTML-encoded string that should not be encoded again).

public static IHtmlString CategoryNavigation(this WebViewPage wvp)
{
    StringBuilder navBuilder = new StringBuilder();

    List<CustomCategory> categories = CustomCategoryLogic.GetCategories();

    if (categories.Count > 0)
    {
        navBuilder.Append("<ul class=\"nav\">");
        navBuilder.Append("<li><a href=\"/\">Home</a></li>");

        foreach (CustomCategory cc in categories)
            navBuilder.AppendFormat("<li><a href=\"/{0}\">{1}</a></li>", cc.Slug, cc.Name);

        navBuilder.Append("</ul>");
    }

    return MvcHtmlString.Create(navBuilder.ToString());
}

To display my category navigation in one of my Views, I just need to write:

@this.CategoryNavigation()

How easy is that!?

Some New Custom Form Controls I've Been Working On In Kentico...

Posted in: Kentico

Over the last few projects I've been working on, I started to notice that clients are requiring increased integration with social platforms that give them the ability to display key elements from well known social platforms, such as YouTube, Twitter and Instagram. Hence the reason why in the past I created a YouTube Form Control that would easily retrieve all information information about a video along with their screen caps by simply entering the YouTube URL.

Recently, I've been working on two more form controls involving Twitter and Instagram to further enhance social platform integration within Kentico from a user standpoint, which (I think) is quite neat!

Twitter

Using a combination of OAuth and Twitter's GET statuses/show/:id API endpoint, I was able to store within Kentico all JSON data relating to a tweet by just entering the ID. One major advantage to storing JSON data is that we can display the tweet as many times as we want throughout the site without worrying about breaching API limits.

In addition, individual elements of a tweet, such as the embedded image, hash tags and author information can be used when required.

Tweet Custom Form Control

As you can see (above), I am using Twitter's Embedded Tweet plugin to display the tweet in a nice graphical representation so that the site administrator is able to view contents of the tweet prior to publishing live.

Instagram

Like the Twitter control above, details of an Instagram image is retrieved in a similar fashion, whereby I'm storing all the details in JSON format.  In this case, I'm using a combination of two Instagram API endpoint's:

  • /oembed - to get the core information of an image by passing in the full URL of where the image resides. This will return important piece of information: the true ID of the image.
  • /media/media-id - to get all information about the media or video object. This information will be stored in Kentico.

Unlike Twitter, Instagram's API is a breeze to implement. There are no API limits (at time of writing) and all you need to access the endpoints is to generate a one time only access token.

Instagram Custom Form Control

By copying and pasting the link of an Instagram image will return all object information and display the image/video within CMS Desk.

I will at some point write a blog post on how I created these two controls once I have refactored all the code into one single control. At the moment, some key functionality is segregated into separate class libraries.

Kentico Certified Developer

Posted in: Kentico

A couple days ago I passed my Kentico exam. If anything, I think I've learnt more about Kentico and just how much the platform has to offer. The exam is filled with a wide range of questions from the very simple and straight-forward to the ones that require a more time for deep thought.

In fact, I found the first few set of questions so simple, it got me second guessing myself. I'll admit, I found the exam a little tricky and there are some questions you have to read very carefully, especially ones around K# syntax.

I dedicate this certification to all the awesome guys at Syndicut. I seriously couldn't have done it without them.

I guess I can now display this:

Kentico Certified Developer Logo

;