Página 3 de 3

Sitecore Geo IP Services (SC 9.3)

Many businesses require to implements GEO IP Services. Business Rules differ between locations. As Developers, Sitecore makes our lives easier by providing a Service that we can use to obtain the location of the website’s visitor.

The IP Geolocation provides information like country, state, city, and every visitor’s registered company name as well. Based on geodata, we can build modules that interact with our visitors and provide accurate information depending on where they are.

Installation and Configuration

Here you will find the official link to activate and set up the Sitecore IP Geolocation: Set up Sitecore IP Geolocation

In your Siecore Solution ensure you add the following Nuget Packages:

  • Sitecore.Kernel
  • Sitecore.Analytics

Solution

Sometimes when you work with lower environments or your local environment Geo IP is not available. I developed the following simple class to get the visitor’s country and city. We can add the next file to setup a city and country code when Sitecore IP Geolocation is not available for your local. I used Sitecore 9.3.


<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/" xmlns:env="http://www.sitecore.net/xmlconfig/env/">
  <sitecore>
    <settings env:require="Local">
      <setting name="Dev.IPGeolocation.IsDevMode" value="true"/>
      <setting name="Dev.IPGeolocation.City" value="Boston"/>
      <setting name="Dev.IPGeolocation.CountryCode" value="US"/>
    </settings>
  </sitecore>
</configuration>

The next class contains a method GetUserGeolocation to get user location information.

public class IPGeolocationService
    {
         /// <summary>
        /// Get User IP form Request Context.
        /// </summary>
        /// <returns>(string) IP Address</returns>
        private static string GetUserIP()
        {
            var ip = (HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != null
                      && HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"] != "")
                ? HttpContext.Current.Request.ServerVariables["HTTP_X_FORWARDED_FOR"]
                : HttpContext.Current.Request.ServerVariables["REMOTE_ADDR"];
            if (ip.Contains(","))
                ip = ip.Split(',').First().Trim();

            return ip.Trim();
        }

        /// <summary>
        ///   Fetch country from Sitecore IP Geolocation Service check 
        ///   setup at https://doc.sitecore.com/developers/93/sitecore-experience-manager/en/set-up-sitecore-ip-geolocation.html
        /// </summary>
        /// <returns></returns>
        public static GeoData GetUserGeolocation()
        {
            GeoData geoData;
            bool IsDevEnviroment = Settings.GetBoolSetting("Dev.IPGeolocation.IsDevMode", false);
            if (!IsDevEnviroment)
            {
                var millisecondsTimeout = 2000;
                
                try
                {
                    var options = new GeoIpOptions(IPAddress.Parse(GetUserIP()), millisecondsTimeout);
                    var result = GeoIpManager.GetGeoIpData(options);
                    if (result.ResolveState == GeoIpResolveState.Resolved &&
                        result.WhoIsInformation != null)
                    {
                        geoData = new GeoData()
                        {
                            City = result.WhoIsInformation.City,
                            CountryCode = result.WhoIsInformation.Country
                        };
                    }
                    else
                    {
                        throw new Exception("GeoIP whoIsInformation is null");
                    }
                }
                catch (Exception e)
                {
                    Log.Error("Error Getting IPAddress",e, typeof(IPGeolocationService));
                    if (Tracker.Current != null && Tracker.Current.Interaction != null && Tracker.Current.Interaction.GeoData != null)
                    {
                        geoData = new GeoData()
                        {
                            City = Tracker.Current.Interaction?.GeoData?.City,
                            CountryCode = Tracker.Current.Interaction?.GeoData?.Country
                        };

                    }
                    else
                    {
                        Log.Error("IPGeolocation: There is an issue with IP Geolocation Service", typeof(IPGeolocationService));
                        geoData = new GeoData()
                        {
                            City = null,
                            CountryCode = Settings.GetSetting("LocationEngine.IPGeolocation.CountryCode")
                        };
                    }
                }

            }
            else
            {
                Log.Info("IPGeolocation: Dev Mode is enabled", typeof(IPGeolocationService));
                geoData = new GeoData()
                {
                    City = Settings.GetSetting("Dev.IPGeolocation.City"),
                    CountryCode = Settings.GetSetting("Dev.IPGeolocation.CountryCode")
                };
            }
            Log.Info($"IPGeolocation: Country Code is {geoData.CountryCode}", typeof(IPGeolocationService));
            return geoData;
        }
    }

Finally, GeoData is a model class that contains the location information.


 public class GeoData
    {
        public string CountryCode { get; set; }
        public string City { get; set; }
    }

I hope this information will be usefully when you work with Sitecore Geo IP Services.

Read more

How to integrate API’s with Sitecore using Swagger

In this blog post I will talk about how to integrate APIs with Sitecore using Swagger.

What is Swagger?

Swagger is an open-source tool that uses Open API Specification, the initiative was started in 2015 by Linux Foundation. In my opinion, this tool saves a lot of time, it will support your development lifecycle starting with Design, Building, and Documentation.

Design Phase:

Swagger Editor will help you to design your API.

In the following example, we can appreciate that /store/inventory is a GET http method which is part of "store" section. The definition is clear and easy to understand. You can read what is the possible responses as 200 code that responds an object (Dictionary<string,int>).

Once you design the definition you are ready to go to the next phase.

Build Phase:

Swagger provides Swagger CodeGen to generate any Client or Server code base, this provides the interfaces where you can implement to add the API’s business logic.

Swagger editor also provide you a tab in the interface to generate this client / server code. This blog post will show you how to implement Swagger Client API with an existing Sitecore MVC Solution. In order to generate the client you will need to select from Generate client tab -> csharp.

It will generate a C# Project. That contains the following folder structure:

  • API: Contains all Entity Interfaces, in our previous example, we had an operation GetInventory which is part of the store group. Swagger will generate a class per group, Example: StoreApi
  • Client: The folder contains all classes to build the client. Basically, you will find classes like ApiCall, Configuration, Exceptions.
  • Model: This is the model folder that contains all entities used in your APIs, like Pet, ApiResponse, Catalog, Product, etc.

Move API, Client and Model folder to your Sitecore Solution Project.

Prepare your solution

Install the following NuGet packages on your solution:

  • RestSharp
  • Newtonsoft.Json
  • System.ComponentModel
  • System.ComponentModel.Annotations
  • Sitecore.Kernel

Configure your solution

After installing all packages that are required and moved the files into the solution edit Client\Configuration.cs class in order to setup the Base URL.

  /// <summary>
        /// Initializes a new instance of the <see cref="Configuration" /> class
        /// </summary>
        public Configuration()
        {
            UserAgent = "Swagger-Codegen/1.0.0/csharp";
            BasePath = Sitecore.Configuration.Settings.GetSetting("PetStoreConnector.BaseUrl");
            DefaultHeader = new ConcurrentDictionary<string, string>();
            ApiKey = new ConcurrentDictionary<string, string>();
            ApiKeyPrefix = new ConcurrentDictionary<string, string>();

            // Setting Timeout has side effects (forces ApiClient creation).
            Timeout = 100000;
        }

Change the constructor class to include Sitecore.Configuration.Settings.GetSetting("PetStoreConnector.BaseUrl") and create a config file on Sitecore like PetStoreConnector.config

<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/" xmlns:env="http://www.sitecore.net/xmlconfig/env/">
    <sitecore>
        <settings>
            <setting name="PetStoreConnector.BaseUrl" value="YOUR_BASE_PATH"/>
        </settings>
    </sitecore>
</configuration>

In your Controller you can add some code to call the API´s endpoints, here there are an example:

  public class InventoryController : Controller
    {
        public ActionResult Index()
        {
            IStoreApi api = new StoreApi();
            var inventory = api.GetInventory();
            return Json(inventory, JsonRequestBehavior.AllowGet);
        }


    }

Finally build your solution and deploy your changes and you are ready to consume your API on Sitecore using Swagger.

This approach could reduce your development time, you can easily integrate your logic with another system building a robust C# client solution.

I had the opportunity to talk in Sitecore User Group Ecuador Session 15 in the following YouTube link you can watch the session (in Spanish).

Read more

How to install Solr?

This guide is about how to install apache Solr in Windows 10.

Requirements

  1. Download Apache Solr
  2. Download NSSM
  3. Install Java JDK

Steps

  1. Create a folder named Solr in your C:/ root.
  2. Extract the zip folder in your Solr folder.
  1. In C:\Solr\solr-8.4.0\server\etc add the following Powershell script and save it as solrssl.ps1:
param(
	[string]$KeystoreFile = 'solr-ssl.keystore.jks',
	[string]$KeystorePassword = 'secret',
	[string]$SolrDomain = 'localhost',
	[switch]$Clobber
)

$ErrorActionPreference = 'Stop'

### PARAM VALIDATION
if($KeystorePassword -ne 'secret') {
	Write-Error 'The keystore password must be "secret", because Solr apparently ignores the parameter'
}

if((Test-Path $KeystoreFile)) {
	if($Clobber) {
		Write-Host "Removing $KeystoreFile..."
		Remove-Item $KeystoreFile
	} else {
		$KeystorePath = Resolve-Path $KeystoreFile
		Write-Error "Keystore file $KeystorePath already existed. To regenerate it, pass -Clobber."
	}
}

$P12Path = [IO.Path]::ChangeExtension($KeystoreFile, 'p12')
if((Test-Path $P12Path)) {
	if($Clobber) {
		Write-Host "Removing $P12Path..."
		Remove-Item $P12Path
	} else {
		$P12Path = Resolve-Path $P12Path
		Write-Error "Keystore file $P12Path already existed. To regenerate it, pass -Clobber."
	}
}

try {
	$keytool = (Get-Command 'C:\Program Files\Java\jdk1.8.0_261\bin\keytool.exe').Source
} catch {
	$keytool = Read-Host "keytool.exe not on path. Enter path to keytool (found in JRE bin folder)"

	if([string]::IsNullOrEmpty($keytool) -or -not (Test-Path $keytool)) {
		Write-Error "Keytool path was invalid."
	}
}

### DOING STUFF

Write-Host ''
Write-Host 'Generating JKS keystore...'
& $keytool -genkeypair -alias solr-ssl -keyalg RSA -keysize 2048 -keypass $KeystorePassword -storepass $KeystorePassword -validity 9999 -keystore $KeystoreFile -ext SAN=DNS:$SolrDomain,IP:127.0.0.1 -dname "CN=$SolrDomain, OU=Enginnering, O=Verndale, L=Quito, ST=Pichincha, C=EC"

Write-Host ''
Write-Host 'Generating .p12 to import to Windows...'
& $keytool -importkeystore -srckeystore $KeystoreFile -destkeystore $P12Path -srcstoretype jks -deststoretype pkcs12 -srcstorepass $KeystorePassword -deststorepass $KeystorePassword

Write-Host ''
Write-Host 'Trusting generated SSL certificate...'
$secureStringKeystorePassword = ConvertTo-SecureString -String $KeystorePassword -Force -AsPlainText
$root = Import-PfxCertificate -FilePath $P12Path -Password $secureStringKeystorePassword -CertStoreLocation Cert:\LocalMachine\Root
Write-Host 'SSL certificate is now locally trusted. (added as root CA)'

Write-Host ''
Write-Host '########## NEXT STEPS ##########' -ForegroundColor Green
Write-Host ''
Write-Host '1. Copy your keystore to $SOLR_HOME\server\etc (MUST be here)' -ForegroundColor Green

if(-not $KeystoreFile.EndsWith('solr-ssl.keystore.jks')) {
	Write-Warning 'Your keystore file is not named "solr-ssl.keystore.jks"'
	Write-Warning 'Solr requires this exact name, so make sure to rename it before use.'
}

$KeystorePath = Resolve-Path $KeystoreFile
Write-Host ''
Write-Host '2. Add the following lines to your solr.in.cmd:' -ForegroundColor Green
Write-Host ''
Write-Host "set SOLR_SSL_KEY_STORE=etc/solr-ssl.keystore.jks" -ForegroundColor Yellow
Write-Host "set SOLR_SSL_KEY_STORE_PASSWORD=$KeystorePassword" -ForegroundColor Yellow
Write-Host "set SOLR_SSL_TRUST_STORE=etc/solr-ssl.keystore.jks" -ForegroundColor Yellow
Write-Host "set SOLR_SSL_TRUST_STORE_PASSWORD=$KeystorePassword" -ForegroundColor Yellow
Write-Host ''
Write-Host 'Done!'

You need to replace C:\Program Files\Java\jdk1.8.0_261\bin\keytool.exe path that match your installed Java JDK.

  1. Then you need to run the following powershell script that is located at C:\Solr\solr-8.4.0\server\etc
.\solrssl.ps1
  1. When execution is done, you will see solr-ssl.keystore.jks and solr-ssl.keystore.p12 files generated.

  2. Edit C:\Solr\solr-8.4.0\bin\solr.in.cmd file and uncomment the following lines:

set SOLR_SSL_KEY_STORE=etc/solr-ssl.keystore.jks
set SOLR_SSL_KEY_STORE_PASSWORD=secret
set SOLR_SSL_TRUST_STORE=etc/solr-ssl.keystore.jks
set SOLR_SSL_TRUST_STORE_PASSWORD=secret
set SOLR_SSL_KEY_STORE_TYPE=JKS
set SOLR_SSL_TRUST_STORE_TYPE=JKS

  1. Extract NSSM zip file into C:\nssm-2.24

8. Add NSSM_HOME in your Enviroment variables:

  1. Finally, run the following command
nssm install

10. Fill the form with the following information:

11. Open your browser to check Solr installed at the following url: https://localhost:8983/solr/#/

And that’s all you have Solr successfully installed in your development machine.

Read more
Verndale Hero

My experience at Verndale

I started at Verndale in December 2019. In my job interview, I mentioned that I didn’t have much experience in C# .NET MVC, because I worked in many projects in PHP with Laravel which is an MVC Framework, it’s not the same but… dude concepts are concepts. To avoid making it long, I talked about my amazing experiences in my previous company Umpacto Soluciones and all international competitions that I participated in during my university career. Including competitions in Bogotá, Shanghai, Abu Dhabi, and many others in my natal city Quito.

In a few words, I considered that I love design patterns and programming concepts. In my personal opinion, this is why I see that programming is like an art, you could express all your ideas through your designs and code. Another important thing to mention is that I love challenges.

Verndale is a company that creates customer experiences, so I’m very happy to be part of this company. In my onboarding process, I learn many things about Verndale, and my first steps at Verndale was learning a new Platform called Sitecore.

Sitecore is an Experience Digital Platform (XDP), which includes powerful features like Personalization, Marketing Automatization, A/B Testing.

I got my Sitecore Developer Certification in my first month at the company and I love it. I love the way to do modules, the simplicity. The modules that I develop in Sitecore are semantic and clean.

Another important thing to mention is that I learned about Sitecore Content Hub, this is a Digital Asset Management (DAM), Content Marketing Platform (CMP), Marketing Resource Management (MRM). In my personal opinion I see this out of this world, Can you image manage all your digital assets in one platform?, and all images are automatically tagged by Azure Cognitive Services, and also integrated with Photoshop, Sitecore, One Drive, and many other services. So I recommended this platform for all companies that need to handle huge digital assets.

Finally, I could say that I’m happy in what I do. I’m going to post more about my experiences and troubleshooting in those technologies. Happy coding.

Read more