My Sitecore Journey

2018 is a special year for me both professionally and personally. I attended my first Sitecore Symposium and met lots of bright people in the Sitecore community, absorbed lots of knowledge and information on various topics, and became the ‘bold woman that found six mentors’ (@paige_oneill @francine_tweet @SimpkinsAllison@JulieKoepsell).

boldwoman

This is the year I delivered several talks on Sitecore ORM Glass Mapper 5 in person and online (ATL SUG, SUGChennai, SUGJPRWomenOfSitecore, and a couple more lined up) and became the ‘Glassy Lady’. This year I was invited by a college professor to share career advice as a Sitecore developer to a Computer Science class and introduced Sitecore to them as their first enterprise CMS. This is also the year I got the chance to spend a lot more time as @sitecoreshu on Twitter and LinkedIn witnessing moments of hundreds of Sitecorians, and sharing my experiences with them. I passed the Coveo Developer Certification Exam with 91.1% at the end of 2017, shared my experience taking the exam, and made some awesome Coveo friends (@itinocom @SilaouO @jflh) who are almost as cool as their intelligent search technologies. This year I wrote several articles on my technical blog providing insights on Sitecore and related topics.  I continued to attend every SUG in my home city Atlanta except for the one in May because that day I was in the hospital delivering a baby. 😉 This year is the year I decided to apply for Sitecore MVP to play an even more integral role in the community.

My journey with Sitecore started back when @sitecorejon introduced me to Helix, Ignition, and how to do things the right way. By then I had already taken the Sitecore online training, passed the Sitecore Developer Certification Exam, and read a great book – Professional Sitecore 8 Development – A Complete Guide to Solutions and Best Practices by @LonghornTaco and @philwicklund. Jon and @wendyderstine were the architects on my first Sitecore project; me and a colleague Maria were the developers on the team. Both new to Sitecore at the time, I came with a back end background and Maria was more of a front end developer. I was happy to hear positive feedback having delivered a good quality solution and ahead of schedule.

Being in a consulting firm with a strong Sitecore culture, I remember one day walking into our breakroom and joining the “champaign celebration” for my colleagues @sitecoregeorge and @sitecorey becoming first-time Sitecore MVPs. I knew they both were seasoned Sitecore developers and I thought to myself maybe one day I could become an MVP as well. The best part of being in the Sitecore community is people are so willing and quick to mentor and help one another. I received much advice and encouragement to become an MVP. Shout-out to @sitecorey, @SitecoreChris and @sitecorejon, for pushing me to step on the stage and make my first presentation at the ATL SUG. I am fortunate to work with so many wonderful colleagues in the same company @PRFTDigital. Shout-out to @sitecourtney for studying and co-presenting talks with me. Also shout out to @SitecoreAmy and other panelists for bringing together @womenofsitecore and making a strong representation of women in the Sitecore community.

After my first project I proceeded to develop more complex Sitecore solutions for various clients. I worked with a major law firm and provided them with localization solutions. I also worked with a major healthcare company on a multi-tenant Sitecore Helix solution with cross-site in-session personalization. At the moment I am eight months into a project to rebuild the public-facing site for a major grocery chain. As a major developer on the team, my role allows me to participate in a lot of the decision-making and implementation of the codebase. I receive consistent, positive feedback from the client on the work I’ve done and our Sitecore solutions. It’s good to see customers enthusiastic and excited about adopting Sitecore technology.

Being a Web developer requires me to stay abreast on new technologies. This year I became a big fan of Vue.js and have shared some experience on Vue integration with Sitecore solutions. I find that preparing for certification exams is a good way to immerse myself in a technology. I have passed a few certifications on subjects including developing Azure solutions (70-532) and front end development (70-480). My next certification goal is Exam 70-486: Developing ASP.NET MVC Web Applications.

Now let’s talk more about goals! Aside from continuing to have a strong presence in the community, I have two new goals. First, I want to tap into pre-sales engineering. I know I can do the pure technical side, but I also want to learn to promote and sell good technologies like Sitecore, and enable more clients to see the business value in these technologies. Simply put, I want to be a more well-rounded technologist. Second, I want to utilize my educational background in AI and do some cool AI projects like @unaverhoeven and @maaakstiles. Especially after a chat with Una I felt motivated to work on projects using Cortex!

Most importantly, I’d like to thank one person. I wouldn’t have been able to accomplish so much if I didn’t have a supportive husband looking after our baby at home while I was out Sitecoring. So, thank you Mr. Jackson! Speaking of our baby, he is just several months old and he has already taught me an important life lesson – be true to your heart and never give up on your goals; fight for it, cry for it, scream for it, and be THE BOSS!

jadenbath

jadenme

 

Advertisements

Introducing Vue Router and Vuex to Your Sitecore Solution

Vue.js has been gaining a lot of popularity as a JavaScript framework. There are plenty of blogs out there on Vue.js. In this article I am going to provide some overview on Vue Router and Vuex, and walk through how I made use of these tools in a Sitecore solution.

Use Case

The use case is a Single Page Application for searching product items. The site consists of a sidebar area for category filters and search facets, and a main content area for displaying the product items. Both areas are different (and use different Vue components) for when the user first lands on the Search page, and when the user initiates a search. The search can be applied category filters and other search facets such as size or brand. The product items are pulled with WebAPI calls. The relative URL of a search of ‘sunscreen’ with a category filter ‘skincare’ and a search facet size ‘medium’ looks like: /search/skincare?keyword=sunscreen&facet=size%3A%3Amedium. The site uses Sitecore fields such as header text and background image.

Vue Router Setup

Vue Router is the official router for Vue.js. It has a lot of great features to help build SPAs. Vue Router is modular, which means it can be used to map components to routes. Use <router-view> to let Vue Router know where to render the matching components.

For my solution, I have a Search.cshtml file in which lives the SearchPage.vue component. In SearchPage.vue I have <router-view>s for the sidebar area and the main area to display matching components for each area based on the routes: when the user first lands on the search page (‘/search’), SidebarLanding.vue and MainLanding.vue are matched; when the user initiates a search, SidebarSearch.vue and MainSearch.vue are matched. This is how the SearchPage.vue component’s template looks like:

<router-view name="sidebar" />     
<router-view name="main" />

Inside ‘created()’ of SearchPage.vue I use the addRoutes method on the globally available this.$router  to add route configurations:

created () {
    this.$router.addRoutes(SearchRoutes);
}

In SearchRoutes.js I define the route configurations – which Vue components match a certain path; when a path is requested, those matching components will render in their corresponding outlets. Here is the simplified route configurations inside SearchRoutes.js:

{
    path: '/search',
    components: {
        sidebar: SidebarLanding,
        main: MainLanding
    }
},
{
    path: '/search/:categoryName',
    components: {
        sidebar: SidebarSearch,
        main: MainSearch
    },
    props: {
        sidebar: (route) => ({
            keyword: route.query.keyword,
        }),
        main: (route) => ({
            keyword: route.query.keyword,
            categoryName: route.params.categoryName
        }),
    }
}

‘:categoryName’ in the second path above is a dynamic segment (denoted by a colon), and can match any value at the corresponding segment of a URL of the same structure. When a route is matched, the value of the dynamic segments will be exposed as this.$route.params in every component. Similarly, I can get the query string using this.$route.query.{queryStringName}. As you can see, information (such as keyword and categoryName) contained in the path can be passed as props to the components and used in their containing methods to make WebAPI calls to display the correct search results.

Inside SidebarSearch.vue, <router-link>s are used for navigation. The link URL is specified using the ‘to’ prop. This is how category filters work (simplified):

<router-link :to="getCategoryLink(categoryName)" >{{categoryName}}</router-link>

And the getCategoryLink method:

getCategoryLink (categoryName) {
    searchUrl = { path: '/search/' + category.Name.replace(/[^\w\s]/gi, ''), query: this.$route.query };
    return searchUrl;
}

A URL like “/search/skincare?keyword=sunscreen&facet=size%3A%3Amedium” is constructed by getCategoryLink and passed to <router-link>’s ‘to’ prop, and when the user clicks on that link, Vue Router renders the matching components at the corresponding <router-view>s. Also notice, in the example above, query strings in the route are persisted when constructing the URL using this.$route.query.

Let’s now take a look at how search facets are handled. For facets I have groups of checkboxes that are bound using v-model=”checkedNames”. I have a watcher to push the selected facets to the route query and also navigate to the new route, using this.$router.push.

watch: {
    checkedNames: function () {
        this.$router.push({ query: Object.assign({}, this.$route.query, { facet: this.checkedNames.join('//') }) });
    }
},

On navigating to the new route, MainSearch.vue has logic to pick up the facet from the query of the path using this.$route.query, and the category filter from the dynamic segment (:categoryName) of the path, to make a new WebAPI call to display the updated results that are filtered and faceted.

Sitecore Configuration to Work with History Mode

When using History Mode to get rid of the default Hash Mode, you need some kind of server-side configuration to avoid the 404 error the user gets when directly accessing /search/:categoryName. The search part of my site is a Single Page App; there is only a ‘search’ page in my Sitecore instance and it doesn’t have a child page for the category. Since I am working with Sitecore, I can register custom ASP.NET MVC routes in a way that does not conflict with the default Sitecore routes with a pipeline processor in the initialize pipeline.

public virtual void Process(PipelineArgs args)
{
    RegisterRoutes(RouteTable.Routes);
}
public static void RegisterRoutes(RouteCollection routes)
{
    routes.MapRoute("search", "search/{categoryName}", new { scItemPath = "/Search" });         
}
<sitecore>
    <pipelines>
        <initialize>
            <processor type=" MyNamespace.RegisterCustomRoute, MyAssembly" patch:after="processor[@type='Sitecore.Pipelines.Loader.EnsureAnonymousUsers, Sitecore.Kernel']" />
        </initialize>
    </pipelines>
</sitecore>

Vuex for Passing Sitecore Fields

When you have multiple layers of nested Vue components, it can be cumbersome to pass props from your .cshtml file down the chain to all the related Vue components – Vuex to the rescue! Of course that’s not the only thing Vuex is good for. Vuex is Vue.js’s library for state management. It provides a single object that contains all your application level state, with rules ensuring that the state can only be mutated in a predictable fashion. Other than the situation of nested components, when you catch yourself synchronizing multiple copies of the state via events, it’s probably also a good time to use Vuex. You can divide the Vuex container for all application state (a.k.a. the store) into modules when scaling your application.

For my use case I can register a module for the search functionality (since it’s a part of a bigger solution) and store search related state there, including the Sitecore fields that need to be shared among all related Vue components.

this.$store.registerModule('search', searchStore);
const searchStore = {
    namespaced: true,
    state: {
        header: ''
        …
    }
    mutations: {
     …
    }
    …

And inside each component I can make use of the state using Vuex’s mapState helper in computed:

computed: {
    ...mapState('search’, [
        ‘header’,… ])
}

There are a lot more implementation details omitted here, but this is a quick overview if you are looking for how to make use of Vue Router and Vuex in your Sitecore solution to build Single Page Applications.

h49pHk3ORDWKylIlU7bE_maxresdefault

Glass.Mapper Part 2 of 2 – What is New and Changed in Version 5

In the previous post we talked about What Glass Mapper is and How to Use it. In this post I will talk about What’s New and Changed in Glass Mapper 5. You can find a demo solution here. This series on Glass Mapper has been presented at the Atlanta Sitecore User Group and SUG Chennai by me and my colleague Courtney Dean.

Major Changes at a Glance

  • Changes to NuGet packages
  • SitecoreContext, GlassView, GlassController are obsolete
  • New contexts: IMvcContext, IRequestContext, IWebFormsContext
  • SitecoreService methods parameters updates
  • Changes to LazyLoading
  • A new way of loading Glass configurations when working with Helix

We have covered the changes to NuGet in the previous post, which can save you some hassle if you accidentally forgot to reference sitecore.kernel and sitecore.mvc in your projects.

Obsolete Features

ISitecoreContext, GlassView, GlassContoller are obsolete. You don’t need them any longer. ISitecoreContext was responsible for a mixture of database access and request context. It is replaced with three new Contexts now available (IMvcContext, IRequestContext, IWebFormsContext), as they have much clearer separation of responsibilities and fit closer with Sitecore Architecture.

Any value GlassView and GlassController were providing is available through other means. One of the major function of GlassController, for example, was providing access to SitecoreContext, which is obsolete in the new version. Previously you were getting datasource or rendering parameters off the Glass Controller. Now you can get those from MvcContext.

GlassView allowed you to use helper methods in you .cshtml files to work with the Experience Editor without requiring to specify the model as it implicitly knows about the model property. However it has not been compulsory to use GlassView since V4 and we can access the same features using Html helpers such as Html.Glass.Editable().

Please note, these obsolete features will be removed eventually, so when you move to Glass Mapper 5 please get rid of them soon!

IMvcContext

This is The first one of the three contexts V5 offers, it’s also probably the one you will be working the most with . You used IMvcContext when you are working with MVC, and it’s mainly for Controlling Renderings. This context provides access to DataSourceItem, PageContextItem, RenderingItem, and RederingParamteres. Under the hood, it uses SitecoreService to talk to sitecore. You have seen some examples in the previous post but you can see the full demo solution here.

1

IRequestContext

You use Request Context when you are outside of a controller and do not have a DataSource item available. Common scenarios to use RequestContext include computed fields, pipeline processors, and event handlers. You can get ContextItem, HomeItem the RootItem from this context.

2

You used to have to get these properties and methods from GlassController and not be able to use it elsewhere. With IRequestContext you can inject the service to wherever you need. However, according to the experience of my colleague @SiteCorey, you should never inject it to a pipeline processor, as Sitecore has a bug and will break your code. Instead use Service Locator and you can see an example of that in the demo.

If you take a look at the demo solution you can see (shown below) these services are registered to the container as Scoped – so all contexts use the same instance of SitecoreService and don’t have to create new ones within a Request. SitecoreService is registered using Context.Database, but if you need to access the core database you can create a new SitecoreService for core.

public class GlassMapperConfigurator : IServicesConfigurator
{
public void Configure(IServiceCollection serviceCollection)
{
serviceCollection.AddScoped<ISitecoreService>(sp => new SitecoreService(Context.Database));
serviceCollection.AddScoped<IMvcContext>(sp => new MvcContext(sp.GetService<ISitecoreService>()));
serviceCollection.AddScoped<IRequestContext>(sp => new RequestContext(sp.GetService<ISitecoreService>()));
serviceCollection.AddScoped<IWebFormsContext>(sp => new WebFormsContext(sp.GetService<ISitecoreService>()));
}
}

Same as IMvcContext, this Context uses SitecoreService to communicate with Sitecore.

IWebFormContext

DO NOT USE WEBFORMS!

Changes to ISitecoreService

Quoting from the Glass documentation: “The ISitecoreService interface represents an individual Sitecore database. It provides the ability to perform all basic CRUD functions against the selected Sitecore databases.”  Essentially it is a wrapper for a Sitecore database. A common useful scenario is to access the core database.

3

The big change in V5 is the method parameters of SitecoreService have been replaces with Option classes which allow for configuring all settings for model mapping. This change is because parameters were limiting, every time a parameter was added there would be a ton of overloads added to handle the various situations. Using Options classes allows the ability to add additional configuration without having to change the signature of the method. The old way of passing parameters is still available but is being marked obsolete.

4

Here is a list of types of Options classes:

  • – `GetItemByIdOptions`
  • – `GetItemByItemOptions`
  • – `GetItemByPathOptions`
  • – `GetItemByQueryOptions`
  • – `GetItemOptions`
  • – `GetItemOptionsParams`
  • – `GetKnownOptions`

Alternatively you can use two parameters, with the second one being a configuration map for the attributes you want to include. As an example, what used to be:

sitecoreService.GetItem("/sitecore/Home", inferType:true);

can now be:

service.GetItem("/sitecore/Home",x=>x.InferType());

The attributes can be:

  • InferType
  • Lazy
  • Cache
  • EnforceType
  • TemplateId
  • Version
  • Language

LazyLoading

The LazyLoading attribute has been removed from all property configurations (both attribute and fluent). You can now add the attribute when requesting a model from SitecoreService or when getting the datasource from MvcContext.

Previously you had to manually turn LazyLoading off on each property of the model. Now you add the attribute when you are getting the item from SitecoreService or a context, then all properties will be set accordingly.

Here is an example using SitecoreService:

var service = new SitecoreService(database.Database);
var target = service.GetItem<IModel>("/sitecore/content/parent/target", x=>x.LazyDisabled());

And an example using MvcContext (note the GetKnownOptions which is a new Glass 5 feature mentioned above):

var dataSource = _mvcContext.GetDataSourceItem<DemoArticle>(new GetKnownOptions { Lazy = Glass.Mapper.LazyLoading.Disabled});

LazyLoading is on by default – unless caching is on.

Working with Helix – the Newest Update in V5.1 Oct 10th

As mentioned in the previous post, if you are working with a Helix solution, GlassMapper.Sc should be only installed in an ORM project in the Foundation layer, i.e., the two files generated when installing the main NuGet package should live in the app_start folder in this module.

In Feature and Project layer projects Glass.Mapper.Sc.Core always needs to be installed. Install Glass.Mapper.Sc.Mvc only when needed – when working with MVC and need access to MvcContext.

As mentioned previously, any custom configurations needs to be added to the GlassMapperScCustom.cs file, which lives in the foundation layer. Doing this not only brings the risk of having the custom configuration overwritten when upgrading Glass, but also brings to the solution backward dependency from Foundation layer to Feature layer, which violates Helix principles. In Helix Foundation modules can only reference other Foundation modules; they may not reference Feature modules or project modules.

In V5.1, a new way to load configurations is introduced. Instead of adding the configurations into the custom file in Foundation layer, it can be added using a new Sitecore pipeline. You can find some example code snippet here. Specifically, create a processor that inherits GetGlassLoadersProcessor in the feature module that you are working with and need custom Glass configuration for. The configurations is added to this processor. Then add this processor to the glassMapper.getGlassLoaders pipeline. Thus the Foundation ORM module doesn’t reference and isn’t dependent on your Feature layer. In addition, since there is no need to edit GlassMapperScCustom.cs file – there is no risk of getting it overwritten when upgrading Glass. One stone, two birds.

You can find out more here…

Glass.Mapper Part 1 of 2 – What It Is and How to Use It

In this article I will talk about what Glass Mapper is and how to use it, and in the next article I will talk about what’s new and changed in Glass Mapper 5. You can find a demo solution here. This series on Glass Mapper has been presented at the Atlanta Sitecore User Group and SUG Chennai by me and my colleague Courtney Dean.

What is Glass Mapper/ORM?

Glass Mapper is a Sitecore ORM (Object Relation Mapping) created by Sitecore MVP Mike Edwards. An ORM maps data to the objects in your code. Without an ORM you would end up writing a lot more mapping code than you wanted to. Glass Mapper specifically allows you to map data from Sitecore (figure 1) to strongly-typed C# models. For example, Single-Line Text field can map to string in C# (figure 2).

Figure 1:1

Figure 2:2

Below is an example of accessing Sitecore items without Glass Mapper. You need to call the Sitecore APIs to: 1) query Sitecore, 2) get back results, 3) create new concrete model classes, and 4) map the results into those model classes.

3

That is a lot of code. On the contrary, working with Glass looks like this:

4

Here is another example to make the advantage more obvious. Below is how the Child-Parent relationship has to be mapped using the Sitecore API:

5

With Glass it is just [SitecoreChildren]:

786

Other advantages of using Glass Mapper include: it allows your code to be unit testable; you can choose to do Code Gen or not – you can use tools like TDS or Leprechaun created by my colleague @bllipson to automatically generate models, or you can write the models by yourself.

One thing to keep in mind is GlassMapper is not a total replacement for Sitecore API. There are tasks that can’t be performed using Glass Mapper alone such as locking and unlocking a Sitecore item. For those types of situation you can use the SitecoreItem attribute (shown below), which gives you the ability to get the item you are mapping. This allows you to use Sitecore API without having to write the code to get the item.

9

How to Install Glass Mapper

You install GlassMapper using NuGet. This brings us the first big change in Glass Mapper 5 (supports Sitecore 8.0 and above). In the previous versions, Glass Mapper detects your Sitecore version and install Glass accordingly. If you aren’t referencing sitecore.kernel and sitecore.mvc, Glass cannot be installed properly; you will have to uninstall and reinstall. However for GlassMapper 5, you install by the Sitecore version you are working with. For example if you are working in Sitecore 9. You will need Glass.Mapper.Sc.90.

There are three related packages:

  • Glass.Mapper.Sc.{Version}
  • Glass.Mapper.Sc.{Version}.Mvc
  • Glass.Mapper.Sc.{Version}.Core

If you are developing a Helix solution, install the main Glass.Mapper.Sc package in an ORM module in the foundation layer. In Feature and Project layers, install Glass.Mapper.Sc.Core in all modules, and install Glass.Mapper.Sc.Mvc when you are working with MVC and need to access IMvcContext (covered in Part 2). For more information on Working with Helix please see Part 2 of 2 of this series.

10

When installing Glass Mapper, two files (Figure 3) are generated in the App_Start folder (in the ORM module in your foundation layer, if you are working with Helix).  Two things to keep in mind here: 1. Never change GlassMapperSc.cs. 2. If you are adding custom configurations to GlassMapperScCustom.cs (Figure 4), be aware it will be overwritten with a NuGet update – hopefully this behavior will change in a future version of Glass. 🙂

Figure 3:

12

Figure 4:13

How to Use Glass – Attribute Mapping vs Fluent Configuration

To configure Glass to map your C# models to Sitecore data there are two ways: Attribute Mapping and Fluent Configuration.

As shown below, Attribute Mapping includes [SitecoreType(TemplateId = GUID)] and [SitecoreType(FieldId = GUID)] to map the model and its properties to Sitecore templates and fields on the templates. You also have SitecoreChildren to map relationships, [SitecoreInfo(SitecoreInfoType.Url)] for metadata, SitecoreItem for the item itself, and SitecoreQuery to use queries.

14You do have an AutoMap option to for mapping fields when the Sitecore field name is the same as your C# property on your model, but it is not recommended because if someone changes the Sitecore field name without updating the code, the code will break. Of course, if the names are different you will have to include the mapping configurations (even if the Sitecore field name is the same as the model property name except with space in between words).

For Fluent Configuration you will need to create mapping configurations (Figure 5) and add the mapping to the configuration factory (Figure 6) in GlassMapperScCustom.cs mentioned above. Adding this ties out the model and configuration together so Glass Mapper can map correctly.

Figure 5:15

Figure 6: 0

Both Attribute Mapping and Fluent Configuration are acceptable ways to do it; it is up to you which one you like. There are opinions on which is better. Some people think Attribute Mapping violates Single Responsibility principle as the model represents both data structure and mapping configuration. On the other hand it may be simpler to use than Fluent Configuration.

Working with Experience Editor (EE)

Glass Mapper provides Html helpers that allow you to make fields editable in the EE. Examples include Editable() for fields such as Single Line Text, Date and Time; RenderLink() and BeginRenderLink() for General Link, RenderImage() for Image, and the powerful BeginEditFrame() – it’s the only way to edit certain types of fields in the EE such as multilist fields without using Rendering Parameters. Of course you don’t have to use these Html helpers; you can still use the plain old @Model.{propertyName} if you don’t need to make the field editable in the EE. If you do use the Html Helper, make sure you have SitecoreId on your model because Glass needs the IDs to find and write to the Sitecore items.

17

In the next article I will talk about what’s new and changed in Glass Mapper 5.

My Experience with the Coveo for Sitecore Developer Certification Exam

I have recently passed the Coveo for Sitecore 4.0 Cloud Certified Developer Exam and I’d like to share some of my experience here. It’s a three-hour exam but you probably won’t need that much time. It took me around two hours. You can choose to pause the exam and finish it later.

There are 90 multiple choice questions in total, and the passing mark is 70%. According to the exam guide, you can and are recommended to:

  • Install and experiment with the latest release of Coveo for Sitecore 4.0 with Coveo Cloud before taking the exam
  • Refer to the Coveo for Sitecore 4.0 developer training PDFs
  • Refer to the Coveor online documentation
  • Refer to a working instance of Sitecore with Coveo for Sitecore 4.0 already integrated

That means the exam is ‘open-book’, at least for now. That does Not mean it is an easy test. A good number of the answers don’t live directly in the PDFs and you may not even know where to find them online if you aren’t familiar with Coveo or aren’t well prepared. Here is what I did and would suggest you do in order to get a good score in the exam:

  • Pay attention during the training session and get at least the bulk of the learning in
  • Read patiently through the 400-page training PDF before the exam
  • Have the working instance of Sitecore with Coveo integrated on the side while reading the PDF so you can refer to it/experiment with it
  • Check out the related links in the PDF and at least skim through their content
  • Check the online documentation whenever you come across concepts you don’t quite understand

I attended a live training session provided by Coveo; you can also attend a training course found here. After taking the training, you will receive a unique free exam link via email, which never expires. You do have only one attempt per link and a retake costs US$500. The trial edition Coveo you used during the training does expire but you can probably get an extension by contacting your Coveo account manager or Coveo support.

Be sure to take a look at this site, where you can find important information on the exam including the Topics Covered:

“The certification exam covers many aspects of the Coveo for Sitecore solution including installation, upgrade, features, pricing, architecture, modules, scaling, configuration, fields, search queries, debugging, Coveo Cloud Platform, Coveo Search API, external content, Underscore.js, Coveo JavaScript Search Framework, UI components, resources, and more.”

Thanks, and good luck! 🙂

PFk2GlAV_400x400

ERROR SCRIPTDOM NEEDED FOR SQL PROVIDER

When I was installing Sitecore 9 I got an error ERROR_SCRIPTDOM_NEEDED_FOR_SQL_PROVIDER. This error could appear in other scenarios that involve SQL as well.

I was sure I have all SQL provider dependencies including T-SQL ScriptDom installed. The issue was resolved when I used gacutil on the scriptDom dll with the command below in the command prompt window:

“<C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\gacutil>” /i “<C:\Program Files (x86)\Microsoft Visual Studio 14.0\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\140\Microsoft.SqlServer.TransactSql.ScriptDom.dll>”

Your gacutil and scriptDom dll may be in a different folder as in mine. Before using the command please check and correct the paths if they are different.