• 2021

    The past year has been a weird year. It went by without much me feeling the time passing. Things happened around the world, but something also happened in our personal life.

    2020 was not too bad to be honest. We are positive people and of course 2021 will be even better.
  • Sitecore Application Insights Setup Checklist in Azure App Services

    Collected from different places. For my own references:

    Azure Application Insights
    1. Daily Volume Cap

    Sitecore
    1. App_Config/ConnectionStrings.config
      1. appinsights.instrumentationkey
    2. App_Config/Sitecore/Azure/Sitecore.Cloud.ApplicationInsights.config
    3. App_Config/Sitecore/Azure/Sitecore.Cloud.ApplicationInsights.Counters.config
    4. Web.config
      1. <add key='storeSitecoreCountersInApplicationInsights:define' value='False' />
      2. <add key='useApplicationInsights:define' value='True' />
      3. <system.webServer>
          <remove name='ApplicationInsightsWebTracking' />
          <add name='TelemetryCorrelationHttpModule' type='Microsoft.AspNet.TelemetryCorrelation.TelemetryCorrelationHttpModule, Microsoft.AspNet.TelemetryCorrelation' preCondition='integratedMode,managedHandler' />
          <add name='ApplicationInsightsWebTracking' type='Microsoft.ApplicationInsights.Web.ApplicationInsightsHttpModule, Microsoft.AI.Web' preCondition='managedHandler' />
      4. <system.web>
          <trace enabled='false' requestLimit='50' pageOutput='false' traceMode='SortByTime' localOnly='true' />
      5. <system.diagnostics>
           <trace autoflush='true' indentsize='0'>
              <listeners>
                <add name='myAppInsightsListener' type='Microsoft.ApplicationInsights.TraceListener.ApplicationInsightsTraceListener, Microsoft.ApplicationInsights.TraceListener' />
              </listeners>
            </trace>
          </system.diagnostics>
    5. ApplicationInsights.config

    Sitecore Showconfig
    1. <!-- SERVER ROLE The name for grouping metrics from instances by server role. Default value: Single --><setting name='ApplicationInsights.Role' value='Single' patch:source='Sitecore.Cloud.ApplicationInsights.config'/>
    2. <!-- TELEMETRY TAGS Tags that are included in telemetry data to identify the metrics from an instance. --><setting name='ApplicationInsights.Tag' value='' patch:source='Sitecore.Cloud.ApplicationInsights.config'/>
    3. <!-- DEVELOPER MODE Enables developer mode in Application Insights TelemetryConfiguration. --><setting name='ApplicationInsights.DeveloperMode' value='false' patch:source='Sitecore.Cloud.ApplicationInsights.config'/>
    4. <pipelines> 
           <initialize>
               <processor type='Sitecore.Cloud.ApplicationInsights.Logging.RemoveSitecoreTraceListeners, Sitecore.Cloud.ApplicationInsights' patch:source='Sitecore.Cloud.ApplicationInsights.config'/>
               <processor type='Sitecore.Cloud.ApplicationInsights.TelemertyInitializers.InjectTelemertyInitializers, Sitecore.Cloud.ApplicationInsights' patch:source='Sitecore.Cloud.ApplicationInsights.config'/>
               <processor type='Sitecore.Cloud.ApplicationInsights.TelemertyInitializers.AppInsightsInitializer, Sitecore.Cloud.ApplicationInsights' patch:source='Sitecore.Cloud.ApplicationInsights.config'/>


    Log files
    • App_Data/logs/xxxx/azure.log.2020xxxx.0xxxx5.txt

  • Sitecore Installation Framework and Sitecore Versions Compatibility Table

    Probably not a problem that people typically have, but if you try to install multiple Sitecore versions (before Sitecore 10, which can be done using Docker now) on the same machine, you get weird errors due to incorrect Sitecore Installation Framework(SIF) version. So here is a table to help you to use the right version of SIF.
    Sitecore
    Sitecore Installation Framework
    9.0.x
    1.2.1
    9.1
    2.0.0
    9.1.1
    2.1.0 or later
    9.2.0
    2.1.0 or later
    9.3.0
    2.2.0
    10.0.0
    2.3.0
    And a cheatsheet for SIF.

    Add PowerShell repository for installing SIF
    Register-PSRepository -Name SitecoreGallery -SourceLocation https://sitecore.myget.org/F/sc-powershell/api/v2

    Install the latest version of SIF
    Install-Module SitecoreInstallFramework

    See all the versions of SIF installed
    Get-Module SitecoreInstallFramework –ListAvailable

    Install a specific version of SIF
    Install-Module -Name SitecoreInstallFramework -RequiredVersion x.x.x

    Use a particular version of SIF for installation - this is important when installing
    Import-Module -Name SitecoreInstallFramework -Force -RequiredVersion x.x.x

    There is an official Sitecore KB compatibility page containing the same information:

    And finally, if you haven’t tried, I strongly recommend giving Docker a try for Sitecore 10 at least. It’s super easy!
  • Synonyms Support with Azure Search in Sitecore SXA Search Component

    If you tried to enable Synonyms support with Azure Search in Sitecore, you probably have seen this article:  https://blogs.perficient.com/2019/11/12/programmatically-creating-synonym-maps-in-azure-search-with-sitecore/. Which provided details on how to use Sitecore to store and create the Synonym Map in Azure Index. 

    However, after creating the Synonym maps in Azure, you may find that it doesn't work with the SXA Search component. In this post, I will talk about why and how to resolve the issue in Sitecore SXA, which will help you to understand how non-SXA works too.

    Assume that you have succesfully setup Synonym Map on sxacontent field for  "home resident". When doing a search for "home" using the SXA Search component, Sitecore generate a search query like below:

    &search=sxacontent:(/.*home.*/)&$filter=(latestversion_1 and (path_1/any(t:t eq 'ed5230a06c234cd6a88c73daee6d5b5b')) and searchable)&queryType=full&$skip=0&$top=5

    The problem is that Azure Search does not expand Synonyms on wildcard queries:

    Synonym expansions do not apply to wildcard search terms; prefix, fuzzy, and regex terms aren't expanded.


    The suggestion is to combine the wildcard with a simple fixed query, which means the above query should look like this:

    &search=((sxacontent:(/.*home.*/) OR sxacontent:(home)))&$filter=(latestversion_1 and (path_1/any(t:t eq 'ed5230a06c234cd6a88c73daee6d5b5b')) and searchable)&queryType=full&$skip=0&$top=5

    Note: 
    1. Based on information collected, regular wildcard query also work (which is sxacontent:("*home*")), however, it produces a different result than the regex wildcard, so it's not discussed here.
    2. If queryType is changed to simple in the query, the original query also works. It is not easy to change, so not considered here.

    Now we know what kind of query needs to be generated. The next step is to make Sitecore SXA to generate the query.

    The place to modify is "ContentPredicate" method in Sitecore.XA.Foundation.Search.Services.SearchService. Out of the box code looks like this:

    protected virtual Expression<Func<ContentPage, bool>> ContentPredicate(string content)
        {
            Expression<Func<ContentPage, bool>> expression = PredicateBuilder.True<ContentPage>();
            if (string.IsNullOrWhiteSpace(content))
            {
                return expression;
            }
            foreach (string item in content.Split().TrimAndRemoveEmpty())
            {
                string t = item;
                expression = expression.And((ContentPage i) => i.AggregatedContent.Contains(t));
            }
            return expression;
        }

    A logical solution is just adding "|| i.AggregatedContent == t" but the tricky part is that since AggregatedContent is sxacontent filed in the index, and it's a string array. When you use string comparison on it, it builds the query as a filter instead of what we wanted. Here is an example of what that query looks like if you change the line to "expression = expression.And((ContentPage i) => i.AggregatedContent.Contains(t) || .AggregatedContent == t);"

    &$filter=(latestversion_1 and (search.ismatchscoring('sxacontent:(/.*home.*/)', null, 'full', null) or (sxacontent/any(t:t eq 'home'))) and (path_1/any(t:t eq 'ed5230a06c234cd6a88c73daee6d5b5b')) and searchable)&$top=2147483647

    This causes an exception in Azure Search because sxacontent is not defined as a filterable field. Even if you make sxacontent a filterable, Synonym doesn't work because Azure Search doesn't support expanding it in filters.

    A number of solutions:

    One: If instead of sxacontent field, you have a custom index field that is just a string type, above code works (with a different field name of course)

    Two: you can overwrite Sitecore.ContentSearch.Azure.Query.SearchQueryBuilder.Contains to always use both regex wildcard and normal wildcard with an OR. Since SearchQueryBuilder is not directly exposed in DI, it will take a fair bit amount of work to replace it, it won't be an easy solution.

    An example of how to do this can be referenced in this support ticket:  https://github.com/SitecoreSupport/Sitecore.Support.147386/releases/tag/9.0.1.0. Check out the classes in repo that have to be duplicated, note that it may not be exactly the same to the version of Sitecore you have.

    Three: Use "MatchWildcard" in Linq. The code looks like this:

    public class SearchService : Sitecore.XA.Foundation.Search.Services.SearchService
        {
            protected override Expression<Func<ContentPage, bool>> ContentPredicate(string content)
            {
                var expression = PredicateBuilder.True<ContentPage>();
                if (string.IsNullOrWhiteSpace(content))
                {
                    return expression;
                }
                foreach (var t in content.Split().TrimAndRemoveEmpty())
                {
                    expression = expression.And((ContentPage i) => i.AggregatedContent.Contains(t) || i.AggregatedContent.MatchWildcard(t));
                }
                return expression;
            }
        }

    Above code generates exactly the query we wanted. It may seem a bit weird and even feels like a "bug". But looking at the offcial documentaion on this page ( https://doc.sitecore.com/developers/92/sitecore-experience-manager/en/linq-to-sitecore.html):

    MatchWildcard
    results = queryable.Where(i => i.Template.Where(i => i.Template.MatchWildcard("H?li*m")));

    The intention of MatchWildcard is to accept an expression with custom wildcard defined and just pass it as it is to the query. That's why it worked for our case. To be honest this may not seem the best fit for this method however comparing to the effort having to go through in solution two to overwrite the Sitecore Azure provider, this saves a huge amount of effort and has less potential impact to the site.  I'd prefer this approach out of the three here.

    The solution has been tested with Sitecore 9.2.0 with SXA 1.9 only. However I checked the code in Sitecore 9.3, in theory it should also work, best to double check.

  • Sitecore Website Federated Authentication with Azure AD B2C with OpenID Connect

    Sitecore Identity, Federated Authentication and Federation Gateway

    If you are already familiar with the differences between Sitecore Federated Authentication with Sitecore Identity VS Sitecore Identity as a Federation Gateway, please skip to the next section. Otherwise, it's essential to understand the differences as they are consistently being mixed up.

    Sitecore uses OpenID Connect, so some of the terms are from OpenID Connect 1.0 and OAuth 2.0 - because OpenID Connect extends OAuth. I recommend having some reading if they are also new to you.

    1. To have Federated Authentication with Sitecore, we need to have an Identity Provider.
    2. Sitecore Identity Server is the out of the box Identity Provider that's set up with Sitecore shell site to provide Federated Authentication.
    3. There are two options when integrating a new Identity Provider
      1. Setup the new Identity Provider with Sitecore directly for Federated Authentication
      2. Setup the new Identity Provider with Sitecore Identity where Sitecore Identity act as a Federation Gateway. In this case, Sitecore still has Sitecore Identity Server as the Identity Provider.

    What do those two options look like?
    1. External Identity provider directly setup with Sitecore for Federated Authentication:
      1. This option is more suitable for public websites which mean users come to Sitecore sites and redirected to the external Identity Provider to login and then are redirected back to Sitecore sites.
      2. Sitecore client (shell) can keep on using Sitecore Identity Server. Both can stay behind DMZ if required.
    2. Sitecore Identity Server as the Federation Gateway to external Identity Providers:
      1. This option is more suitable for allowing Sitecore users (like authors) to login to Sitecore client via external Identity providers.
      2. If this option is selected for websites, Sitecore Identity Server must be exposed to the Internet.

    There are other differences, won't go into too many details here. But hopefully, this gives you a good overview of Federated Authentication in the new Sitecore versions.

    This post will be about option 1 - Sitecore Website Federated Authentication with Azure AD B2C. If you are interested in Option 2, which is set up Azure AD B2C with Sitecore Identity, Jason has created an excellent article about this already: Azure AD B2C with Sitecore Identity. He also provided a lot of help when I did this post 🙂


    Sitecore Website Federated Authentication with Azure AD B2C

    Sitecore version used in this is 9.3.0. Here are the steps:

    Note: be sure to replace all single quotes to double quotes after coping the code.

    1. Have an Azure AD B2C instance ready.
    2. Register a new App in Azure AD B2C. Collect the following information:
    AD Tenant Name: Orange.onmicrosoft.com
    Application (Client) ID: xxxxxx-fe0f-4c1a-8101-xxxxxxxx
    1. Create a User Flow Policy of Type 'Sign up and sign in'. Collect the following information
    Custom User Flow Name: B2C_1_signupsignin
    1. You can test accessing below URL to make sure your AD B2C OpenID Connect endpoint is up. This is where you can see all your possible claims too.
    https://Orange.b2clogin.com/tfp/Orange.onmicrosoft.com/B2C_1_signupsignin/v2.0/.well-known/openid-configuration
    1. Please make sure the Sitecore instance has OWIN and Federated Authentication both enabled. Then there are three steps:
      • Setup an Asp.Net project. Below are some main Nuget packages you will need.
      ...  
      <package id='Microsoft.IdentityModel.Protocols.OpenIdConnect' version='5.2.2' targetFramework='net472' />
      <package id='Microsoft.IdentityModel.Tokens' version='5.2.2' targetFramework='net472' />
      <package id='Microsoft.Owin' version='4.0.0' targetFramework='net472' />
      <package id='Microsoft.Owin.Security' version='4.0.0' targetFramework='net472' />
      <package id='Microsoft.Owin.Security.OpenIdConnect' version='4.0.0' targetFramework='net472' />  
      <package id='Owin' version='1.0' targetFramework='net472' />
      <package id='Sitecore.Kernel' version='9.3.0' targetFramework='net472' />
      <package id='Sitecore.Mvc' version='9.3.0' targetFramework='net472' />
      <package id='Sitecore.Mvc.Analytics' version='9.3.0' targetFramework='net472' />
      <package id='Sitecore.Owin.Authentication' version='9.3.0' targetFramework='net472' />
      ...
      • Create a custom IdentityProvidersProcessor that inherits 
    Sitecore.Owin.Authentication.Pipelines.IdentityProviders.IdentityProvidersProcessor
      • Below is a simple implementation that works
    using Microsoft.IdentityModel.Tokens;
    using Microsoft.Owin.Infrastructure;
    using Microsoft.Owin.Security;
    using Microsoft.Owin.Security.OpenIdConnect;
    using Owin;
    using Sitecore.Abstractions;
    using Sitecore.Diagnostics;
    using Sitecore.Owin.Authentication.Configuration;
    using Sitecore.Owin.Authentication.Extensions;
    using Sitecore.Owin.Authentication.Pipelines.IdentityProviders;
    using Sitecore.Owin.Authentication.Services;
    using System.Threading.Tasks;


    namespace AzureB2CSitecoreFederated.Pipelines
    {
        public class AzureB2C : IdentityProvidersProcessor
        {
            public AzureB2C(FederatedAuthenticationConfiguration federatedAuthenticationConfiguration,
                            ICookieManager cookieManager,
                            BaseSettings settings)
                            : base(federatedAuthenticationConfiguration, cookieManager, settings)
            {
            }


            protected override string IdentityProviderName => 'AzureB2C';


            protected override void ProcessCore(IdentityProvidersArgs args)
            {
                Assert.ArgumentNotNull(args, nameof(args));


                var identityProvider = GetIdentityProvider();
                var authenticationType = GetAuthenticationType();


                string tenant = Settings.GetSetting('Sitecore.Feature.Accounts.AzureB2C.Tenant');
                string signupsigninpolicy = Settings.GetSetting('Sitecore.Feature.Accounts.AzureB2C.Policy');
                string clientId = Settings.GetSetting('Sitecore.Feature.Accounts.AzureB2C.ClientId');
                string aadInstanceraw = Settings.GetSetting('Sitecore.Feature.Accounts.AzureB2C.AadInstance');
                var aadInstance = string.Format(aadInstanceraw, tenant, signupsigninpolicy);
                var metaAddress = $'{aadInstance}/v2.0/.well-known/openid-configuration';
                var redirectUri = Settings.GetSetting('Sitecore.Feature.Accounts.AzureB2C.RedirectUri');
                var options = new OpenIdConnectAuthenticationOptions(authenticationType)
                {
                    Caption = identityProvider.Caption,
                    AuthenticationMode = AuthenticationMode.Passive,
                    RedirectUri = redirectUri,
                    ClientId = clientId,
                    Authority = aadInstance,
                    MetadataAddress = metaAddress,
                    UseTokenLifetime = true,
                    TokenValidationParameters = new TokenValidationParameters() { NameClaimType = 'name' },


                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        SecurityTokenValidated = context =>
                        {
                            // Note 1 ------------------------- Please see after all steps
                            var debugClaims = context.AuthenticationTicket.Identity?.Claims;
                            context.AuthenticationTicket.Identity.ApplyClaimsTransformations(new TransformationContext(this.FederatedAuthenticationConfiguration, identityProvider));
                            return Task.CompletedTask;  
                        }
                    }
                };


                args.App.UseOpenIdConnectAuthentication(options);
            }
        }
    }
      • Then create a config file like below. Note the collected information are populated in the settings
    <?xml version='1.0' encoding='utf-8' ?>
    <configuration xmlns:patch='http://www.sitecore.net/xmlconfig/' xmlns:role='http://www.sitecore.net/xmlconfig/role/'>
      <sitecore role:require='Standalone or ContentDelivery or ContentManagement'>
        <settings>
          <setting name='Sitecore.Feature.Accounts.AzureB2C.Tenant' value='Orange.onmicrosoft.com' />
          <setting name='Sitecore.Feature.Accounts.AzureB2C.Policy' value='B2C_1_signupsignin' />
          <setting name='Sitecore.Feature.Accounts.AzureB2C.ClientId' value='xxxxxx-fe0f-4c1a-8101-xxxxxxxx' />
          <setting name='Sitecore.Feature.Accounts.AzureB2C.AadInstance' value='https://Orange.b2clogin.com/tfp/{0}/{1}' />
          <setting name='Sitecore.Feature.Accounts.AzureB2C.RedirectUri' value='https://sitecorewebsite.com/' />
        </settings>

        <pipelines>
          <owin.identityProviders>
            <processor type='AzureB2CSitecoreFederated.Pipelines.AzureB2C, AzureB2CSitecoreFederated' resolve='true' />
          </owin.identityProviders>
        </pipelines>

        <federatedAuthentication type='Sitecore.Owin.Authentication.Configuration.FederatedAuthenticationConfiguration, Sitecore.Owin.Authentication'>
          <identityProvidersPerSites hint='list:AddIdentityProvidersPerSites'>
            <mapEntry name='Azure AD B2C for website' type='Sitecore.Owin.Authentication.Collections.IdentityProvidersPerSitesMapEntry, Sitecore.Owin.Authentication' resolve='true'>
              <sites hint='list'>
                <site>website</site>
              </sites>
              <identityProviders hint='list:AddIdentityProvider'>
                <identityProvider ref='federatedAuthentication/identityProviders/identityProvider[@id='AzureB2C']' />
              </identityProviders>
              <externalUserBuilder type='Sitecore.Owin.Authentication.Services.DefaultExternalUserBuilder, Sitecore.Owin.Authentication' resolve='true'>
                <!-- Note 2 ------------------------- Please see after all steps -->
                <IsPersistentUser>false</IsPersistentUser>
              </externalUserBuilder>
            </mapEntry>
          </identityProvidersPerSites>

          <identityProviders hint='list:AddIdentityProvider'>
            <identityProvider id='AzureB2C' type='Sitecore.Owin.Authentication.Configuration.DefaultIdentityProvider, Sitecore.Owin.Authentication'>
              <param desc='name'>AzureB2C</param>
              <param desc='domainManager' type='Sitecore.Abstractions.BaseDomainManager' resolve='true' />
              <caption>AzureB2C</caption>
              <domain>customerdomain</domain>
              <enabled>true</enabled>
              <transformations hint='list:AddTransformation'>
                <!-- Note 3 ------------------------- Please see after all steps -->
                <transformation type='Sitecore.Owin.Authentication.Services.DefaultTransformation, Sitecore.Owin.Authentication'>
                  <sources hint='raw:AddSource'>
                    <claim name='jobTitle' value='SomeRoleText' />
                  </sources>
                  <targets hint='raw:AddTarget'>
                    <claim name='http://schemas.microsoft.com/ws/2008/06/identity/claims/role' value='CustomDomain\SomeRole' />
                  </targets>
                  <keepSource>true</keepSource>
                </transformation>
              </transformations>
            </identityProvider>
          </identityProviders>

          <sharedTransformations></sharedTransformations>

          <!-- Note 4 ------------------------- Please see after all steps -->
          <propertyInitializer type='Sitecore.Owin.Authentication.Services.PropertyInitializer, Sitecore.Owin.Authentication'>
            <maps hint='list'>
              <map name='email claim' type='Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication' resolve='true'>
                <data hint='raw:AddData'>
                  <source name='emails' />
                  <target name='Email' />
                </data>
              </map>
              <map name='full_name' type='Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication' resolve='true'>
                <data hint='raw:AddData'>
                  <source name='name' />
                  <target name='FullName' />
                </data>
              </map>
              <map name='first_name' type='Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication' resolve='true'>
                <data hint='raw:AddData'>
                  <source name='http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname' />
                  <target name='FirstName' />
                </data>
              </map>
              <map name='last_name' type='Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication' resolve='true'>
                <data hint='raw:AddData'>
                  <source name='http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname' />
                  <target name='LastName' />
                </data>
              </map>
              <map name='streetAddress' type='Sitecore.Owin.Authentication.Services.DefaultClaimToPropertyMapper, Sitecore.Owin.Authentication' resolve='true'>
                <data hint='raw:AddData'>
                  <source name='streetAddress' />
                  <target name='AddressProp' />
                </data>
              </map>
            </maps>
          </propertyInitializer>
        </federatedAuthentication>    
      </sitecore>
    </configuration>

    Note that the integration are using the new b2clogin.com endpoints of Azure AD B2C, not http://login.microsoftonline.com/ since it will be deprecated by the end of 2020 . More details here: https://docs.microsoft.com/en-us/azure/active-directory-b2c/b2clogin

    Also please see the notes in the code and config files (For example, can search 'Note 1' on the page to find its location in the demo code/configs)
    • Note 1:  This section of code is required so this custom Identity Provider Processor picks up the shared transforms that are setup out of box by Sitecore. One of which is the 'idp' claim. If you do not have this section, very likely you can get the error 'idp claim is missing'. Having sharedTransformations/setIdpClaim section does not have any effort on your custom identity provider if it doesn't even try to apply shared transformations.
    • Note 2:  You can choose to persist users or having virtual users. I had virtual users in this demo. 
    • Note 3:  Azure AD B2C has a limitation that it doesn't pass group information in the claims. There are ways to customize the AD side to enable the claim however in this demo it just mapped to some claim and picked up some value to map roles in Sitecore. It could be enough for most use cases.
    • Note 4:  You can also map user profile properties, these are some examples.

    Login Link

    Since this is a website, by default you have no way to test this integration. You can setup a custom page to generate the login link to test the integration:

    In the controller:
    using Sitecore.Abstractions;
    using System.Linq;
    using System.Web.Mvc;


    namespace AzureB2CSitecoreFederated.Controllers
    {
        public class FederatedLoginController : Controller
        {
            private readonly BaseCorePipelineManager _pipelineManager;
            public FederatedLoginController(BaseCorePipelineManager pipelineManager)
            {
                _pipelineManager = pipelineManager;
            }

            public ActionResult Index()
            {
                var args = new Sitecore.Pipelines.GetSignInUrlInfo.GetSignInUrlInfoArgs('website', '/');
                Sitecore.Pipelines.GetSignInUrlInfo.GetSignInUrlInfoPipeline.Run(_pipelineManager, args);
                ViewBag.SignInUrl = args.Result.FirstOrDefault()?.Href;
                return View();
            }
        }
    }

    In the views
    @using System.Web.Mvc;


    @{using (Html.BeginForm(null, null, FormMethod.Post, new { action = ViewBag.SignInUrl }))
        {
            <button type='submit'>
                Login
            </button>
        }
    }


    <div>
        <p>@Sitecore.Security.Authentication.AuthenticationManager.GetActiveUser().LocalName</p>
        <p>Is Authed: @Sitecore.Context.User.IsAuthenticated</p>
        <p>Name: @Sitecore.Context.User.Name</p>
        <p>Localname: @Sitecore.Context.User.LocalName</p>
        <p>Domain: @Sitecore.Context.User.GetDomainName()</p>
        <p>Profile Email: @Sitecore.Context.User.Profile.Email</p>
        <pre>
            @Newtonsoft.Json.JsonConvert.SerializeObject(Sitecore.Context.User, Newtonsoft.Json.Formatting.Indented, new Newtonsoft.Json.JsonSerializerSettings
       {
           ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
       })
        </pre>
    </div>

    Skipped classes and configs for regisering dependencies, you know how to do them. 

    That is all. In general it's pretty easy setup, always check logs and URL requests to identify issues and errors.

  • Evernote, Jekyll Static Site, Azure Storage, Azure CDN, Cloudflare and Azure DevOps

  • Cannot disable QoS in ASUS Wireless Router Web GUI

  • Azure DevOps - Cloud Warmup for Sitecore

  • Sitecore Patch Finder

  • Sitecore Helix Documentation version 2 in ePub format

  • Use one license.xml for all local Sitecore instances with SymbolicLink

  • Where is Site Order stored in Sitecore SXA Site Manager Powershell tool

  • Model Rendering Variant doesnt work with custom Sitecore SXA rendering

  • Common Causes and Troubleshooting Sitecore App Restarts on Azure Web App Services

  • Sitecore 9.1 Initial Release with Identify Server User Boost Feature Patch

  • Sitecore Solr Linq Error RANGE_GOOP while using String CompareTo

  • Missing sxacontent_txm in Sitecore SXA Solr Index with Commerce Installed

  • Generating static 500 error html pages using SXA in Sitecore

  • Whitelist Hosted Agent IP address in AzureDevOps pipeline (For Sitecore Unicorn Sync)

  • Setup Postman with Local Sitecore xConnect services

  • Evil Inline Aspx Pages for Sitecore Development

  • Fast Query return null in Sitecore instances

  • Sitecore Campaign Creator API 500 error caused by Sitecore Instance Manager

  • Delivery instance doesn't clear cache with Sitecore Publishing Service

  • Use the same session database for both Priavte and Shared Session States in Sitecore

  • How to handle different Sitecore Module instllation scenarios with WebDeploy approach

  • All about Sitecore.Cloud.Integration.Bootload

  • Blogging from Evernote

  • TTS with Google Home on Home Assistant stopped working

  • Deploy Sitecore Azure AppService Packages on Local IIS

  • Google Home working with Yeelight with Xiaomi Smart Wireless Switch

  • Thoughts on Sitecore Experience Accelerator

  • Sitecore Consulting in the most down-to-earth way

  • Issues while setting up Continuous Integration and Delivery with Visual Studio Team Services for Xamarin.iOS Apps

  • Warning in Sitecore Media Library Folder Grid View

  • Sitecore Content/MVT Testing doesn't update in Delivery Instances

  • HockeyApp, Azure Mobile Engagement and Visual Studio Application Insights

  • 1 MB file upload size limit for WFFM on CD instance

  • Sitecore web.config include patching sub-folder orders

  • Sitecore Shell Content Testing Web API returns 404/403 error while creating page tests/content tests

  • Hello From The Engine

  • A New Back Engine for Blog

  • AnyoneHue? - Monitor multiple people with WIFI for Philips Hue controlling

  • Converting Chinese to Pinyin/Quanpin in Xamarin IOS development

  • Get Sitecore Item SiteInfo

  • Root Australia Vodafone Samsung Galaxy Note 4(N910G) Android Lollipop 5.0.1

  • Input Method On Galaxy Note 4 Keep Reverting Back To Default

  • Onda v820w flash os - Booting to droidboot.img failed

  • Amazon Unlimited Cloud, Windows Home Server, Netflix and VPN

  • Sitecore session expires(timeout) quickly(1 min) when not logged in

  • Browser requests page twice

  • From mobile

  • Focusing on content

  • Section references in Sitecore config files with ref attribute

  • Powerline Ethernet Adapters

  • TDS project build fail in Teamcity with VS 2012 runner

  • Sonos with Airsonos on Windows and Mac

  • Google Tag Manager causing placeholder issues in IE 8

  • Must have softwares after reinstalling windows

  • Multi-Site solution deployments in Azure

  • Schedule tasks not running on CDS in Sitecore

  • IncludeTemplates and ExcludeTemplates warning for custom index of Sitecore

  • Sitecore Redirect Manager

  • Sitecore Indexes media url with /sitecore/shell

  • IIS Http error 500.19 with web.config

subscribe via RSS