Monday, February 8, 2016

Sitecore Pipeline : Add controls to sitecore at runtime through renderContentEditor

If you are looking at customizing page editor and incorporate more settings the way content editor got we can make use of following approaches. The reference links are quite helpful to look more internals of core database and how to built experience editor.

Approach 1- restricted to URL


using System.Web;
using System.Web.UI;
using Sitecore.Pipelines;

namespace Demo.SC.Practical
{
    public class InjectScript
    {
        public void Process(PipelineArgs args)
        {
            var url = HttpContext.Current.Request.Url.AbsolutePath;

          if (url.Contains("field%20editor") || url.Contains("field editor"))
          {
                AddControl("some script tags");
          }
          AddControl("some script tags");
          AddControl("some script tags");         
        }

        private static void AddScript(string headerScript)
        {
            Sitecore.Context.Page.Page.Header.Controls.Add(new LiteralControl(headerScript));
        }
    }
}
Approach 2 - referred from blog reference below. Restricted to configuration.
 
Reference:

https://jammykam.wordpress.com/2014/04/24/adding-custom-javascript-and-stylesheets-in-the-content-editor/

Custom Control
https://jammykam.wordpress.com/2014/04/24/hiding-content-editor-fields-depending-on-selected-values/

Custom Text Field - Limit
http://www.partechit.nl/nl/blog/2013/03/text-fields-with-limited-length-and-feedback-during-editing

Editing Meta Data in Sitecore for SEO- page Editor Mode.

http://www.sitecore.net/learn/blogs/technical-blogs/getting-to-know-sitecore/posts/2012/10/page-editor-secrets-2-editing-meta-data.aspx

https://blog.istern.dk/2015/03/02/running-sitecore-field-editor-from-a-speak-command-in-sitecore-experience-editor/

Adam Conn- Custom Field Editor
http://www.sitecore.net/learn/blogs/technical-blogs/getting-to-know-sitecore/posts/2013/10/field-editor-for-rendering-properties.aspx


Page Editor Blogs

https://pageditor.wordpress.com/



 

Thursday, February 4, 2016

Azure Data Centre Migration and Publish profile online download

While we are about to do lift and shift we realize this going to be very tedious task of migration. Still we are half way and looking for more productive and effective solution to migration azure cloud service from US data centre to Australia data centre.

When we look at this option given in this article, we felt this is what we want to go for however this got lot of caveat and problems based on infrastructure and the way it is done for public azure cloud.



Few things to consider while you try to hook into this solution.

Problem with Download Publish Profile .

Publish profile download link is old and its refer to old reference
Try this https://manage.windowsazure.com/PublishSettings/index?Client=&SchemaVersion=&DisplayTenantSelector=true

Instead of this
https://windows.azure.com/download/publishprofile.aspx


This will act as wiki for me as I progress I will keep adding the problem statement and solution around so that it help others in similar issue.

1. Login to https://manage.windowsazure.com. So that session will ensure you got publish profile established properly.
2.Download Publish profile as per above link. Ensure right subscription and environment is selected.https://windows.azure.com/download/publishprofile.aspx
3. Download code from GitHub https://github.com/persistentsystems/adcms
4. *** Enable Nuget package- Tools- Extensions and Updates
5. *** Ensure all unwanted service is deleted where there is no deployment package .
 

Wednesday, February 3, 2016

Wild Wild West -The only @sitecorejohn


It took me back when I first time heard about sitecore John bid farewell. Every morning I used to read one of his blog and start my to-do’s and work. When I first started my sitecore assignment the very first result in google gave me @SitecoreJohn blog since then it was only John whose blog I book marked and referred to as my sitecore bible however I don't say SDN network resource was not enough but at least John blogs used to give all direction to start with. He is Sitecore Evangelist for me. He is Guru! When I think of .net first name comes to me is Scott Hanselman, when I think of Azure cloud its Scott Guthrie when I think of CLR Maoni Stephen comes to my mind and of course when I think of c# I look upon Anders Hejlsberg likewise when its sitecore it is the only John West.

Nothing change but when someone like John keep contributing it makes big impact to this world. It enables people. They help generate ideas, create synergies and trust me very, very few people capable of doing this.

My standing ovation and salute to this gentleman who is remarkable in his journey of Sitecore.

I know it’s not end though, John will be seen again in different style with lot of conviction.

 All the best John and thanks for giving your best shot till date.

Tuesday, February 2, 2016

Production Support: sitecore Admin Cheat Sheat

Here is the bunch of admin tools that can come handy for any sitecore production incidents and operation management. Any devops lead or team will surely use these tools to make their troubleshooting or house clean up easy.

Caveat:

You may have to configure them or make be disable security access on your instance or box. Be careful when using them.


Rebuild Key Behavior Cache


Install Language


Redeploy Marketing Data


Path Analyzer


Rebuild Reporting Database


Media Hash


Remove Broken Links


Pipeline Profiler


LINQ Scratchpad


Fill Database


Set Application Center Endpoint


Update Installation Wizard


Unlock Admin


Stats


Show Config


Serialization


Restore


Login


Cache


Database browser


Size Status


LogViewer

Add, update and delete Sitecore Items Programmatically

Cheat Sheat

Before we start below are the cheat sheat that can serve as starting point to understand sitecore item at ease

Sitecore.Data Library
  • Context
  • Configuration
  • Factory
  • Database
  • SecurityModel
  • Template
  • TemplateId
  • Items
  • Item
  • Field
  • Sitecore.SecurityModel
  • Sitecore.Configuration.Factory
  • Sitecore.Data.Managers.LanguageManager
  • Sitecore.Context.Language
  • Sitecore.Data.Items.Item
  • Sitecore.Publishing.Pipelines.PublishItem.PublishItemPipeline

***Each item exists in a database, and you can either use use the context database:

Sitecore.Data.Database context = Sitecore.Context.Database;
  • Item item= context.GetItem("/sitecore/content");
  • Sitecore.Data.Items.Item item = context.GetItem(Sitecore.ItemIDs.ContentRoot);

***Or you can explicitly reference a named database, such as the Master database:
Sitecore.Data.Database master = Sitecore.Configuration.Factory.GetDatabase("master");
  • master.GetItem("/sitecore/content");
  • master.Items["/sitecore/content"];
  • master.GetTemplate();

***If needed, you can access a specific version of a specific language:
Sitecore.Data.Items.Item version = context.GetItem(item.ID,
  Sitecore.Data.Managers.LanguageManager.GetLanguage("en"),
  new Sitecore.Data.Version(1));

***You can also retrieve items by URI:
Sitecore.Data.ItemUri homeUri = new Sitecore.Data.ItemUri(
  "sitecore://master/{110D559F-DEA5-42EA-9C1C-8A5DF7E70EF9}?lang=en&ver=1");
Sitecore.Data.Items.Item home = Sitecore.Data.Database.GetItem(uri); 

***To retrieve a child with a specific key:
Sitecore.Data.Items.Item home = item.Children["home"];

1. Create Item Using Tempate
public void CreateItem()
{
  //Again we need to handle security
  //In this example we just disable it
  using (new Sitecore.SecurityModel.SecurityDisabler())
  {
    //First get the parent item from the master database
     Database masterDb = Sitecore.Configuration.Factory.GetDatabase("master");
    
//Get Parent Node.
     Item parentItem = masterDb.Items["/sitecore/content/home"];

 
    //Now we need to get the template from which the item is created
    TemplateItem template = masterDb.GetTemplate("sample/sample item");
 
 
    //Now we can add the new item as a child to the parent
    parentItem.Add("NewItemName", template);

  }
}

2. Update Item Field Value
public void UpdateItem()
{
  //Use a security disabler to allow changes
  using (new Sitecore.SecurityModel.SecurityDisabler())
  {
    //You want to alter the item in the master database, so get the item from there
    Database db = Sitecore.Configuration.Factory.GetDatabase("master");
    Item item = db.Items["/sitecore/content/home"];
 
 
    //Begin editing
    item.Editing.BeginEdit();
    try
    {
      //perform the editing
      item.Fields["Title"].Value = "This value will be stored";
    }
    catch (Exception ex)
    {
       Sitecore.Diagnostics.Log.Error("Could not update item " + item.Paths.FullPath + ": " + ex.Message, this);
       item.Editing.CancelEdit();
    }
    finally
    {
       //Close the editing state
       item.Editing.EndEdit();
    }
  }
}

3. Publish Item
public void PublishItem(Item item)
{
 //We need the target database
        Database webDb = Sitecore.Configuration.Factory.GetDatabase("web");

       //We need to know the language to publish. Here we use the context language
        Language language = Sitecore.Context.Language;

       //We set the publish date to now
        DateTime publishTime = DateTime.Now;
  
       //Now we can create the publish options
        Sitecore.Publishing.PublishOptions options = new PublishOptions(masterDb, webDb, PublishMode.SingleItem, language, publishTime);
 
       //Activate the publishpipeline
        Sitecore.Publishing.Pipelines.PublishItem.PublishItemPipeline.Run(item.ID, options);

}

If cache is a concern above pipeline option is required.
4. Publish with Options
 private void PublishItem(Sitecore.Data.Items.Item item)
{
  // The publishOptions determine the source and target database,
  // the publish mode and language, and the publish date
  Sitecore.Publishing.PublishOptions publishOptions =
    new Sitecore.Publishing.PublishOptions(item.Database,
                                           Database.GetDatabase("web"),
                                           Sitecore.Publishing.PublishMode.SingleItem,
                                           item.Language,
                                           System.DateTime.Now);  // Create a publisher with the publishoptions
  Sitecore.Publishing.Publisher publisher = new Sitecore.Publishing.Publisher(publishOptions);
 
  // Choose where to publish from
  publisher.Options.RootItem = item;
 
  // Publish children as well?
  publisher.Options.Deep = true;
 
  // Do the publish!
  publisher.Publish();
}
 
Key Notes:
  • Droplink vs Droplist-> Droplink store GUID whereas Droplist stores just name
Sitecore 8.0 higher- Multiple version in web database
 
Content testing Enabled.
 
By default the publishVersion pipeline contains two processors in order:
  • Sitecore.ContentTesting.Pipelines.PublishVersion.PublishTestingVersions, Sitecore.ContentTesting
  • Sitecore.Publishing.Pipelines.PublishVersion.Processors.RemoveOtherVersions, Sitecore.Kernel
 
Reference:
http://www.sitecore.net/learn/blogs/technical-blogs/john-west-sitecore-blog/posts/2011/04/accessing-items-in-the-sitecore-aspnet-cms.aspx

Monday, January 11, 2016

Item Bucket And Key Design Challenges.

The Item bucket has been introduced in 7.0 and later version of sitecore. From its inception either very few project must have implemented the concepts and must have realized the true benefits.

Real time case study:-
  • Country /State/City Item bucket.. Locate stores , service centres
  • Articles/blogs etc.
Key Design and Run time Challenges:
  • Sync the Bucket when data is dynamic. It takes time and can impact the performance.
  • Index and Bucket query for large data set is still the problem. Depends what is part of the index provider is it -Lucene or Solr.
  • Sync Strategy of item bucketed collections. Bucket(Sync)
  • The baseline for Bucketing with Index is difficult to achieve as stats varies based on infrastructure.
  • Link providers to understand URL to support SEO.
Create Item Bucket.-For given example. CarTypeFolder and Car template. 
  1. Select standard value item of Car Template and click check box bucketable.
  2. Apply Rules under Settings- Buckets -Item Bucket Settings. For my example I chose rule Specific template- in this case its CarTypeFolder whereas its contain item Car Template is marked bucketable in standard field. Bucket applied on folder with based on ID.
  3. Go to Content tree..select Folder that is part of CarTypefolder and go to configure and click on Bucket and Sync. For reference see the screenshot.
1. Set Car Standard Values =Bucketable

2. Set Rules as per CarTypeFolder template and based on ID -Folder structure
3. Go to content tree, Select Super Car which is part of CarTypeFolder. Go to ribbon Configure and select Bucket and sync.

Still to write about- Indexing with Item bucket Context Query and Implementation.





Custom Workflows in Sitecore

Purpose
Business workflow
  • Content Author- Submit
  • Content Reviewer-Approve/Reject 
  • Final State -Approved.

Technical Workflow 
  • State
  • Command 
  • Action and Validation Action.

Workflow Snapshot


How to create it?
  1. Open Sitecore in desktop mode and go to content Editor Screen. Go to Workflows and create Workflow with State, Command and Action Template.
  2. As per above workflow, create Draft State with Submit action. On Submit action select Data-> Next State Awaiting Approval.
  3. Create Awaiting Approval State with Two command Approve and Reject. Under Approve create three action - Auto publish(Type String : Sitecore.Workflows.Simple.PublishAction, Sitecore.Kernel, Param: Deep=1). SyncCustomDb Action(Reference .net bin dll) and Validation Action to report error , warnings to business users.[Data->Type->Sitecore.Workflows.Simple.ValidatorsAction, Sitecore.Kernel]
  4. What next, you tick mark.suppress comment if you want to do so.
  5. Create final Approved State within Awaiting Approval state. For Final Approved state ensure to mark Final checkbox .
  6. For Reject State select Next state to Draft state.
Template used
  • State
  • Action
  • Command
  • Validation Action
Important Library

  • Sitecore.Workflows.Simple.ValidatorsAction, Sitecore.Kernel
  • Sitecore.Workflows.Simple.PublishAction, Sitecore.Kernel

Publish Parameters
Publish action accepts 6 parameters:
  1. "deep" - controls whether children of the current item will be published. Possible values: "1" - children of the current item will be published; all other values - children of the current item will not be published.
  2. "related" - controls whether related items of the current item will be published. Possible values: "1" - related items of the current item will be published; all other values - related items of the current item will not be published.
  3. "targets" - comma (,) separated list of database names that item will be published to. Note, that this parameter does not expect a list of publishing target names, it expects list of database names.
  4. "alllanguages" - controls whether current item will be published in all languages that exist in source database. Possible values: "1" - current item will be published in all languages that exist in source database; all other values - code uses values of other parameters to determine languages in which current item will be published.
  5. "languages" - comma (,) separated list of languages in which current item will be published.
  6. "itemlanguage" - controls whether current item will be published in its current language. Possible values: "1" - current item will be published in its current language; "0" - current item will not be published in its current language; all other values - current item will published in its current language. Note that even if value of this parameter is "0", current item will still be published in its current language if current language of the item is in "languages" list.
Querystring parameter
deep=1&related=1&alllanguages=1

Auto Publish


Custom Workflow Action: SyncCustomDB
Suppose you want to sync your sitecore CMS data with custom database for Ecommerce database products or promotions if your enterprise solution doesn't provide that. The approach can vary with respect to problem and business requirement.

Here is the quick implementation.
Create Library with Workflow Pipeline processor and create new process .This process requires workflowPipelineArgs
Assign this workflow to the page item and then when business user approves the sitecore content for given item -template the action event will be performed to sync custom database. These can be anything, we can even replace this with any functionality such email notification or anything that needs to be done in case of approve content.


CustomWorkflowActionEvents

using System;
using System.Collections.Generic;
using System.Linq;
using Sitecore.Workflows.Simple;
using Sitecore.Diagnostics;
using Sitecore.Data.Items;
using Sitecore.Configuration;
using Sitecore.Data;

namespace Demo.Sitecore.Practical.CustomWorkflowActionEvents
{
    public class CustomDatabaseSync
    {
        public void Process(WorkflowPipelineArgs args)
        {
            using (var db = new SomeCustomDBContext())
            {
                Item pageItem = args.DataItem;

                if (pageItem.TemplateName == "Promotion")
                {
                    var tbPromotion = db.Promotions.Where(x => x.PromotionID == workFlowItem.ID.Guid);

                    if (tbPromotion.Any())
                    {
                        var tb = tbPromotion.FirstOrDefault();
                        tb.PromotionName = workFlowItem.GetFieldValue("PromotionName");
                        tb.StartDate = workFlowItem.GetDateTime("StartDate");
                        tb.EndDate = workFlowItem.GetDateTime("EndDate");
                        tb.IsEnabled = true;
                        tb.UpdatedDate = DateTime.Now;
                        db.Entry(tb).State = System.Data.EntityState.Modified;
                    }
                    else
                    {
                        db.Promotions.Add(new Promotion
                        {
                            PromotionID = workFlowItem.ID.Guid,
                            PromotionName = workFlowItem.GetFieldValue("PromotionName"),
                            StartDate = workFlowItem.GetDateTime("StartDate"),
                            EndDate = workFlowItem.GetDateTime("EndDate"),
                            IsEnabled = true,
                            CreatedDate = DateTime.Now,
                            UpdatedDate = DateTime.Now
                        });
                    }
                }               
                db.SaveChanges();
            }
        }
    }
}

Snapshot


References
http://www.sitecore.net/learn/blogs/technical-blogs/reinnovations/posts/2014/03/auto-publish-workflow-action-updates.aspx


Sitecore Querystring Param- Cheatsheat

Below are the list of querystring param that comes handy when we are in production deployment and wants to troubleshoot the deployment status in each and every sitecore delivery server. This is very useful querystring parameter at times where there are separate Content managed –Authoring server and several load balanced delivery server, these querystring helps in finding the various behaviour of page and act as troubleshooting tools. 

yes there are various ways to look for sitecore errors such as data folder logs, sitecore analyzer, IIS logs, event logs etc.


Sitecore Querystring param -Cheatsheat


Sr.No
SC param
Description
1.
?Sc_mode= {normal, Edit, Preview}
Change display mode of website
2.
?Sc_lang=
Change website language
Sitecore/system/languages
en-us
3
?Sc_site
Use to change website for multisite single instance.
4
?sc_itemid={123455678-14564-1234-1234-123456789ABC}
Change current item
5
?sc_device={mobile, default etc}
Adaptive design
6
?sc_database={master, web}
Change data in draft vs publish
7
?sc_debug={0,1}
0=false, 1=true
8
?sc_prof={0,1}
Switch on sitecore profiler
9
?sc_trace={0,1}
Switch trace on and off
10
?sc_ri={0,1}
Show hide rendering information

Sunday, January 10, 2016

Sitecore MVC with Dynamic Placeholder

Introduction
This is demo project with Car example.

Technical Use Cases
  • Dynamic Placeholder with configured pipeline.
  • View Rendering and Controller Rendering 
  • Static Placeholder
  • Repository to create Sitecore.Mvc.Presentation.RenderingContext Context.

Sitecore Design Layer

  • Layouts
  • Placeholders
  • Renderings
  • Items
  • Reference -Data collection

Sitecore MVC
  • View- Layouts
  • View- Container 
  • View-TextImage
  • View-Header
  • View-Footer
  • Controller- FooterController
  • Controller- TextImageController
  • Controller- HeaderController
  • Repository for above Controller


Three column Dynamic Placeholder

@Html.Sitecore().DynamicPlaceholder("sub-content-three-column-content-left")
@Html.Sitecore().DynamicPlaceholder("sub-content-three-column-content-middle")
@Html.Sitecore().DynamicPlaceholder("sub-content-three-column-content-right")
Extend Sitecore MVC using SitecoreHelper Sitecorehelper to extend the @Html.Sitecore.Placeholder("")
namespace Demo.Sitecore.CarInfo.WebSite.Utility
{
    public static class SitecoreExtensions
    {
        public static HtmlString DynamicPlaceholder(this SitecoreHelper helper, string key)
        {
            Guid currentRenderingId = RenderingContext.Current.Rendering.UniqueId;
            return helper.Placeholder(string.Format("{0}#{1}", key, currentRenderingId.ToString()));
        }
    }
}

Ultimately this dynamic placeholder fetch the textimage for respective layouts from 
TextImage Controller Rendering.



TextImageRender Repository

using Demo.Sitecore.CarInfo.WebSite.Models;
using Sitecore.Mvc.Presentation;
using Sitecore.Web.UI.WebControls;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace Demo.Sitecore.CarInfo.WebSite.Repository
{
    public class TextImageRepository
    {
        public TextImage GetTextImage()
        {
            var item = RenderingContext.Current.Rendering.Item;
            var textImage = new TextImage()
            {
                Title = new HtmlString(FieldRenderer.Render(item, "Title")),
                Image = new HtmlString(FieldRenderer.Render(item, "Image"))
            };
            return textImage;
        }
    }
}

TextImage Model


namespace Demo.Sitecore.CarInfo.WebSite.Models
{
    public class TextImage
    {
        public HtmlString Title         { get; set; }
        public HtmlString Description   { get; set; }
        public HtmlString Image         { get; set; }
    }
}
TextImage Controller
namespace Demo.Sitecore.CarInfo.WebSite.Controllers
{
    public class TextImageController : SitecoreController
    {
        public ActionResult TextImageDetail()
        {
            TextImageRepository repo = new TextImageRepository();
            return View(repo.GetTextImage());
        }
    }
}

Create Pipeline to Process DynamicPlaceholderRendering

namespace Demo.Sitecore.CarInfo.WebSite.Utility
{
    public class GetDynamicPlaceholderRenderings : GetAllowedRenderings
    {
        public new void Process(GetPlaceholderRenderingsArgs args)
        {
            Item placeholderItem;
            var placeholderKey = string.Join("/", args.PlaceholderKey.Split(new[] { "/" }, StringSplitOptions.RemoveEmptyEntries).Select(x => x.Split('#')[0]));

            using (new DeviceSwitcher(args.DeviceId, args.ContentDatabase))
                placeholderItem = Client.Page.GetPlaceholderItem(placeholderKey, args.ContentDatabase, args.LayoutDefinition);

            List list = null;
            if (placeholderItem != null)
            {
                args.HasPlaceholderSettings = true;
                bool allowedControlsSpecified;
                list = GetRenderings(placeholderItem, out allowedControlsSpecified);

                if (allowedControlsSpecified)
                    args.Options.ShowTree = false;
            }

            if (list == null)
                return;

            if (args.PlaceholderRenderings == null)
                args.PlaceholderRenderings = new List();

            args.PlaceholderRenderings.AddRange(list);
        }
    }
}








Page Editor- Select Allow Controls 

TextImage Renderings



Thursday, January 7, 2016

Sitecore Web API for Angularjs MVC integration

Problem Statement
What if there is CMS system hosted in DMZ server and there is no scope of adding any additional requirement due to some reason and still wants to use Sitecore CMS as an option to port content to your digital interface that can be Mobile or other touch screen device installed in stores. Here is the solution to do so.
Recently we did the same implementation and made Sitecore CMS as source system to give data to digital screens and native Iphone App.

Cloud and Sitecore CMS way.
  1. Sitecore CMS hosted in DMZ corporate infrastructure. Expose api's to access required data.
  2. There will be asp.net spa applicaiton developed using asp.net MVC +angularjs and hosted in cloud to consume this CMS system.
Technology
  1. glass mapper 
  2. sitecore CMS 7.2
  3. asp.net web api
Sitecore CMS Items Implementation
We only going to have content hence i created just reference folder within sitecore structure as per screenshot. Remember to take item id GUID for category to lookup through glass mapper.

Create Website Content under reference. As this is not going to be website path page item.

Create Category page item with category template. Keep the Item ID -Guid for glass mapper mapping with object tree to fetch categories.

Template Category

Add content.




Asp.net Web Api Implementation

The sitecore data item will be consumed via glass mapper ORM and can be modelled to get through API controller.

Here is the snapshot of solution explorer

The reference of nuget glass mapper in include configuration. This helps in ORM with sitecore object mapping.


Create Web api Route with respect to Sitecore

using System.Net.Http.Formatting;
using System.Web;
using System.Web.Http;

namespace MvcApplication1.App_Start
{
    public class RegisterWebApiRoute
    {
        public void Process(PipelineArgs args)
        {
            GlobalConfiguration.Configure(WebApiConfig.Register);
        }

        public void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            // Only JSON response
            config.Formatters.Clear();
            config.Formatters.Add(new JsonMediaTypeFormatter());
            /*
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
            */
        }
    }
}


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Http;

namespace MvcApplication1.App_Start
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            // Web API configuration and services

            // Web API routes
            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );
        }
    }
}

Controller Category to fetch Sitecore Category content


using Glass.Mapper.Sc;
using MvcApplication1.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Web;
using System.Web.Http;

namespace MvcApplication1.Controllers
{
    public class CategoryController : ApiController
    {
        public CategoryList categoryList { get; set; }
        public const string CATEGORY_ROOT_GUID = "{A547EA1E-D414-4521-80E0-A7C794BA3E8C}";
        
        // GET api/values
        [Route("root/api/category")]
        public List GetCategories()
        {
            //return new List();
            var context = new SitecoreContext();
            List categories = new List();
            categoryList = context.GetItem(CATEGORY_ROOT_GUID);
            var categoryBucket = categoryList.Children.Select(a => new Category() 
            { 
                CategoryId = a.CategoryId,
                Title = a.Title, 
                Description = a.Description, 
                SmallImage = a.SmallImage 
            }).ToList().Where(x => x.Title != null);
            foreach (var v in categoryBucket)
            {
                categories.Add(new CategoryItem() { 
                CategoryId=v.CategoryId,
                Title=v.Title,
                Description=v.Description,
                SmallImage=v.SmallImage
                });
            }
            return categories;
        } 
    }
}

Glass Mapper for Category : Children and Sitecore Parent

using Glass.Mapper.Sc.Configuration.Attributes;
using Glass.Mapper.Sc.Fields;
using Sitecore.Data.Fields;
using Sitecore.Data.Items;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcApplication1.Models
{
    public class Category
    {
        [SitecoreId]
        public virtual Guid CategoryId      { get; set; }
        public virtual string Title         { get; set; }
        public virtual string Description   { get; set; }
        public virtual Image SmallImage     { get; set; }
    }
    public class CategoryItem
    {
        public  Guid CategoryId { get; set; }
        public  string Title { get; set; }
        public  string Description { get; set; }
        public  Image SmallImage { get; set; }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MvcApplication1.Models
{
    public class CategoryList
    {
        public virtual IEnumerable Children { get; set; }
    }
}

Required Output.
Ensure you place the DLL in bin folder of sitecore website intance to keep this running.