Change date format using .NET Regular Expressions

You can use Regex.Replace to change the format of a date string. For example if your input string is YYYY/MM/DD but you need to change it to YYYY-MM-DD, you can use this small method:

public static string ReformatDate(string input) 
{
   try {
      return Regex.Replace(input, 
            "\\b(?<year>\\d{2,4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})\\b",
            "${year}-${month}-${day}", 
            RegexOptions.IgnoreCase,
            TimeSpan.FromMilliseconds(1000));
   }         
   catch (RegexMatchTimeoutException) {
      return input;
   }
}

Regular expressions are unreadable as usual, but the trick here lies in the way the year, month and day parts are grabbed and stored in “variables” to be used in the replacement part of the Regex.Replace:

  • Pattern: (?\\d{2,4}) grabs 2-4 digits and places them in a variable called “year”. The same goes for month and day.
  • Replacement: ${year} places the value grabbed from the input and places it into the output of the replace function.

With this in mind we can create lots of different search/replace patters:

  • Input: DD/MM/YYYY Output: YYYY-MM-DD
    Pattern: \\b(?<day>\\d{1,2})/(??<month>\\d{1,2})/(??<year>\\d{2,4})\\b
    Replacement: ${year}-${month}-${day}
  • Input: YYYY-MM-DD Output: MM/DD/YYYY
    Patern: \\b(??<year>\\d{2,4})-(??<month>\\d{1,2})-(??<day>\\d{1,2})\\b
    Replacement: ${month}/${day}/${year}

Would you like to change multiple dates from your input? Add RegexOptions.Multiline to the options:

public static string ReformatDate(string input) 
{
   try {
      return Regex.Replace(input, 
            "\\b(?<year>\\d{2,4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})\\b",
            "${year}-${month}-${day}", 
            RegexOptions.Multiline | RegexOptions.IgnoreCase,
            TimeSpan.FromMilliseconds(1000));
   }         
   catch (RegexMatchTimeoutException) {
      return input;
   }
}

Or how about changing dates from within an XML document?

<item>
 <start_date>2019/06/11</start_date>
 <expiration_date>2019/06/17</g:expiration_date>
</item>

Add the < > to the pattern and replacement variables:

public static string ReformatDate(string input) 
{
   try {
      return Regex.Replace(input, 
            ">\\b(?<year>\\d{2,4})/(?<month>\\d{1,2})/(?<day>\\d{1,2})\\b<", 
            ">${year}-${month}-${day}<", 
            RegexOptions.Multiline | RegexOptions.IgnoreCase,
            TimeSpan.FromMilliseconds(1000));
   }         
   catch (RegexMatchTimeoutException) {
      return input;
   }
}

MORE TO READ:

 

Advertisements
Posted in .net, .NET Core, c#, General .NET | Tagged , , | 1 Comment

Calling Azure Functions from JavaScript – The CORS configuration

You cannot call Azure Functions from JavaScript unless you configure the CORS settings for your Function Apps:

Azure Functions CORS Settings

Azure Functions CORS Settings

This is because Microsoft have by default enabled CORS and only allows only some azure domains to access the Function Apps:

Default CORS Settings

Default CORS Settings

So to enable access from your JavaScript you have to add your domain to the list of allowed origins.

If you wish to allow every domain to access your apps, you must remove all domains from the list and add a “*” to the list as the only entry:

Allow all

Allow all

However, this is widely regarded as a bad move, as all security is thrown out of the window. Azure Functions only security measurements are security tokens passed a parameters, and when calling the Azure Function from JavaScript, this token is exposed to the entire world. You should carefully consider the security implications before allowing every hacker access to your Azure Functions.

Happy coding!

MORE TO READ:

Posted in Microsoft Azure | Tagged , , | Leave a comment

Azure Functions CRON expressions

When creating Microsoft Azure Functions, you can have a timer that triggers your function. The time for when the function should run is specified in a CRON expression:

Microsoft Azure CRON Expression

Microsoft Azure CRON Expression

The CRON format is widely used in UNIX environments, so therefore a wide variety of CRON expression validators exist. Unfortunately most of these do not work on the Microsoft Azure version of CRON, as Microsoft decided to add “second” column and to support only a set of the expressions available.

WHICH CRON VALIDATOR DOES WORK?

http://cronexpressiondescriptor.azurewebsites.net/ by Brady Holt will work.

HOW DO YOU BUILD YOUR CRON EXPRESSION:

The expression is a string where each time specification is separated with a space:

{second} {minute} {hour} {day} {month} {day-of-week}

The CRON expression describes both the time when a timer is triggered AND the interval in between the triggers:

  • numbers = The time when a timer is triggered. For example “0” or “30”
  • number/number = The interval between the triggers. For example “0/1” or “*/1”
  • number-number = The exact interval between the triggers. For example “0-5”
  • A * = The asterisk is your “any” or “i don’t care” descriptor.

WHY IS THE EXPRESSION SO HARD TO UNDERSTAND?

Because the CRON expression both describes the time and the interval in one section, you need to understand the difference between the two:

  • “0” means that the section is run when the second/minute/hour/etc is 0.
  • “0/1” means that the section is run when the second/minute/hour/etc is 0 AND every 1 second/minute/hour/…
  • “*” and “*/1” means the same.
  • “0-1” means that the section is run within this interval.
  • Combinations are allowed: 0-12/1 means to run ever 1 between 0 and 12.

EXAMPLES:

0 * * * * * Once every minute, at xx:xx:00
0 0 * * * * Once every hour, at xx:00:00
0 0 0 * * * Once every day, at 00:00:00
0 0 0 0 * * Once every month at 00:00:00 on the first day of the month
0 0 5-7/1 * * * Every hour between 5 and 06:59. Notice this will run 2 times a day, not 3
0 0 0/6 * * * Every 6 hours, at xx:00:00 (00:00:00, 00:06:00, 00:12:00, 00:18:00)

MORE TO READ:

Posted in Microsoft Azure | Tagged , , , | Leave a comment

Sitecore Item Clones is only a thing in the master database

The Sitecore item cloning is a technique in which you can create a copy of an item that inherits the field values of the original items.

In the latest versions of Sitecore (at least from 9.0 and forward) you can ask if an item is a clone:

Database master = Database.GetDatabase("master");
Item item = master.GetItem(someGuid);
bool isClone = item.IsItemClone;

But please notice that the Item.IsItemClone will always return FALSE if you request the item from the WEB database:

Database web = Database.GetDatabase("web");
Item item = web.GetItem(someGuid);
// This value is always false
bool isClone = item.IsItemClone;

This is because the Source and __Source Item fields of an item are the fields on the original item that tells Sitecore that this item is cloned:

Clone from Master database

Clone from Master database

… is not copied to the WEB database when published:

Clone from Web database

Clone from Web database

This is by design. If you would like to know if an item is a clone (to avoid duplicate items in your sitemap, of when creating canonical URL’s, for example), you will need to code a solution yourself.

MORE TO READ:

Posted in c#, Sitecore 8, Sitecore 9 | Tagged , , | Leave a comment

Sitecore start scheduled task manually

Sitecore scheduled tasks are background tasks running on a schedule. But never when you need it, especially when developing the tasks. You can trigger these tasks manually if you please.

THE EASY WAY: INSTALL SITECORE POWERSHELL

The Sitecore PowerShell module have a built in task runner. When installed, you can right click the task you wish to run and click “Run Task Schedule

Powrshell Run Task

Powrshell Run Task

THE FUN WAY: PROGRAM YOUR OWN TASK STARTER:

You can, of course, write your own task runner, create a nice scheduled task page, and display all possible tasks where you can start them individually:

Scheduled Tasks List

Scheduled Tasks List

To get a list of all scheduled tasks:

private const string SCHEDULED_PATH = "/sitecore/system/Tasks//*[@@templatename='Schedule']";
  
foreach (Item item in Sitecore.Context.Database
  .SelectItems(SCHEDULED_PATH)
  .OrderBy(t => t.Parent.Name)
  .ThenBy(t => t.Name))
{
  ScheduleItem scheduleItem = new ScheduleItem(item);
  // Do stuff with the scheduleItem
}

To start a scheduled task:

Sitecore.Tasks.ScheduleItem scheduleItem = new Sitecore.Tasks.ScheduleItem(item);
scheduleItem.Execute();

MORE TO READ:

Posted in .net, c#, General .NET, Sitecore 5, Sitecore 6, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , | Leave a comment

Create Sitecore items using PowerShell

You can use the Sitecore PowerShell Extensions for many trivial tasks. This script creates a “components” folder below all items from a root item:

// Get the root item
$root = Get-ChildItem -Path "master:/sitecore/content/site/root"
// Loop through all children of the root item
foreach ($item in $root) {
    // Skip if the folder already exists
    if (@(Get-Item -Path "master:" -Query "$($item.ItemPath)/components").count -gt 0) {
	    Continue
    // Create new item
	} else {
        New-Item -Path $item.ItemPath -Name "components" -ItemType "/sitecore/templates/Common/Folder"
    }
}

This script was created by my colleague Adam Honore, when I realized that I had forgot to include a “components” folder in my Sitecore master – after I had created my 100+ items. Thanks to Adam for the help.

MORE TO READ:

Posted in Sitecore, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , | Leave a comment

Sitecore get Context from fully qualified URL

One of the basic Sitecore concepts is the concept of a context. The context is resolved from the HTTP Context to Sitecore and determines the database, language, user domain, content start item etc. The context is defined in the App_Config/Sitecore.config configuration file in the <sites> section:

<sites>
  <site name="shell" ... rootPath="/sitecore/content" startItem="/home" language="en" contentLanguage="en" database="core" domain="sitecore" ... />
  ...
  <site name="website_en" ... hostName="www.site.com|www.site.eu|www.site.co.uk" language="en" database="web" domain="extranet" ... />
  <site name="website_da" ... hostName="www.site.dk" language="da" database="web" domain="extranet" ... />
</sites>

The context is resolved from a first-match algorithm where Sitecore goes through the list of sites and finds the first site that matches the criteria.

You can go through the sites list yourself using the Sitecore.Configuration.Factory.GetSiteInfoList() method. So with a little guesswork you can get the context from any URL, assuming that:

  • The url must be fully qualified (i.e. https://www.site.com/url)
  • The site section contains the URL in the hostName property
using Sitecore.Configuration;
using Sitecore.Sites;
using Sitecore.Web;

public static SiteContext GetSiteContext(Uri url)
{
  string hostName = url.Host;

  foreach (SiteInfo site in Factory.GetSiteInfoList())
  {
    foreach(string sitecoreHostName in site.HostName.Split('|'))
    {
      if (string.Equals(sitecoreHostName, hostName, StringComparison.InvariantCultureIgnoreCase))
      {
        return new SiteContext(site);
      }
    }
  }

  return null;
}

WHAT IS THE HostName VS TargetHostName?

Sitecore uses 2 definitions to determine URL’s:

  • The hostName is the incoming URL. You can define a list of incoming URL’s in a pipe separated list, and each URL will be resolved to that site context.
  • The targetHostName is the outgoing URL and determines which URL to create when asking for a fully qualified URL.

MORE TO READ:

Posted in .net, c#, General .NET, Sitecore 6, Sitecore 7, Sitecore 8, Sitecore 9 | Tagged , , , | Leave a comment

Deserialize XML array to string[] and how to allow JSON to be deserialized into the same POCO class

How do you deserialize the classic XML array to an string[] type?

The XML representation of an array is a list of elements:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <MyXml>
      <Id>657467</Id>
	  <MyArray>
	    <element>A</element>
	    <element>B</element>
	    <element>C</element>
	  </MyArray>
   </MyXml>
</root>

And the MyArray would normally be deserialized to an annoying class:

// I don't want this class
[XmlRoot(ElementName="MyArray")]
public class MyArray 
{
  [XmlElement(ElementName="element")]
  public List<string> Element { get; set; }
}

// I Just want a string array:
public string[] MyArray { get; set; }

The solution is to use the XmlArray and XmlArrayItem attributes. These properties specifies that the XmlSerializer must serialize the XML structure as an array:

[XmlArray(ElementName = "MyArray", IsNullable = true)]
[XmlArrayItem(ElementName = "element", IsNullable = true)]
public string[] Myarray 
{
  get; set;
}

The XmlArray attribute determines that the MyArray XML element is an array, and the XmlArrayItem attribute determines that each array element is called element in the XML.

Now, the XmlSerializer will serialize the element to an array:

string contents = "this is my xml string";

XmlSerializer serializer = new XmlSerializer(typeof(MyXml));
using (TextReader reader = new StringReader(contents))
{
  var myclass = (MyXml)serializer.Deserialize(reader);
}

SO WHY IS THIS IMPORTANT?

This is important if you import XML and JSON, because you would rather not have to define this JSON just to cope with the XML array format:

"MyArray": {
  "element": [
    "A",
    "B",
    "C"
  ]

Instead, if you just decorate your POCO class with both XML and JSON properties:

[JsonProperty(PropertyName = "MyArray")]
[XmlArray(ElementName = "MyArray", IsNullable = true)]
[XmlArrayItem(ElementName = "element", IsNullable = true)]
public string[] Myarray 
{
  get; set;
}

You can use the proper JSON array notation:

"MyArray": [    
    "A",
    "B",
    "C"
]

MORE TO READ:

Posted in .net, c#, General .NET | Tagged , , , , | Leave a comment

Read from Azure Queue with Azure WebJobs 3.0 and .NET Core

From WebJobs 2.0 to WebJobs 3.0 Microsoft have completely rewritten the way Azure WebJobs is used. The reasons are probably noble, but they require you to redo your work when upgrading. So I made this template that allows me to start up a Azure WebJob in .NET Core.

STEP 1: THE PROJECT

The project is a .NET Core Console Application.

STEP 2: THE NUGET PACKAGES

These packages change with the next upgrade but for WebJobs 3.0 you will need these packages:

<ItemGroup>
  <PackageReference Include="WindowsAzure.Storage" Version="9.3.3" />
  <PackageReference Include="Microsoft.Azure.WebJobs" Version="3.0.5" />
  <PackageReference Include="Microsoft.Azure.WebJobs.Extensions" Version="3.0.2" />
  <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.Storage" Version="3.0.4" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="2.2.0" />
  <PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" Version="2.2.0" />
  <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="2.2.0" />
  <PackageReference Include="Microsoft.Extensions.Logging" Version="2.2.0" />
  <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="2.2.0" />
  <PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
</ItemGroup>

STEP 3: THE APPSETTINGS.JSON

Remember to include your AzureWebJobsStorage connection string in the appsettings.json:

{
  "ConnectionStrings": {
    "AzureWebJobsStorage": "DefaultEndpointsProtocol=https;AccountName=xxx;AccountKey=xxx=="
  }
}

STEP 4: THE PROGRAM.CS

This program.cs will start your console application as a Azure Webjob:

using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;

namespace FeedTestEventReceiver
{
  class Program
  {
    public static void Main(string[] args)
    {
      var host = new HostBuilder()
        .ConfigureServices(
        (hostContext, services) =>
        {
          services.Configure<HostOptions>(
            option =>
            {
              option.ShutdownTimeout = System.TimeSpan.FromSeconds(20);
            }
          );
        }
        )
        .ConfigureLogging( (context, b) => { b.AddConsole(); })
        .ConfigureWebJobs( c => { c.AddAzureStorage(); } 
        )
        .ConfigureServices( (context, services) => 
        {
          services.AddTransient<QueueService, QueueService>();
        }
      )
      .Build();

      host.RunAsync().Wait();
    }

  }
}

The major differences between 2.0 and 3.0 are:

  • The HostBuilder is used to configure the WebJob
  • Your Webjob endpoints are now configured using ConfigureServices. You  will need to change the highlighted line of code and include your own endpoint.

STEP 5: THE QUEUSERVICE

This is just an example on how to implement a WebJob endpoint. This class is added in the AddTransient line of code in the program.cs and will listen to a queue for events:

using Microsoft.Azure.WebJobs;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using Microsoft.WindowsAzure.Storage;

namespace FeedTestEventReceiver
{
  public class QueueService
  {
    public async Task ReadFromQueue([QueueTrigger("queuename")] string message, ILogger log)
    {
        log.LogInformation($"{message}");
    }
  }
}

STEP 6: THE TEST

To test the WebJob, simply start the console application with F5, and the WebJob will run locally listening for events int the specified queue:

Azure WebJob

Azure WebJob

MORE TO READ:

 

Posted in .NET Core, c# | Tagged , , , | Leave a comment

Read blob file from Microsoft Azure Storage with .NET Core

In order to read a blob file from a Microsoft Azure Blob Storage, you need to know the following:

  • The storage account connection string. This is the long string that looks like this:
    DefaultEndpointsProtocol=https;
    AccountName=someaccounfname;
    AccountKey=AVeryLongCrypticalStringThatContainsALotOfChars==
  • The blob storage container name. This is the name in the list of “Blobs”.
  • The blob file name. This is the name of the blob inside the container. A file name can be in form of a path, as blobs are structured as a file structure inside the container. For ecample: folder/folder/file.extension

You also need this NuGet package:

Windows.Azure.Storage

The code is pretty simple:

using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;

public string GetBlob(string containerName, string fileName)
{
  string connectionString = $"yourconnectionstring";

  // Setup the connection to the storage account
  CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connectionString);
  
  // Connect to the blob storage
  CloudBlobClient serviceClient = storageAccount.CreateCloudBlobClient();
  // Connect to the blob container
  CloudBlobContainer container = serviceClient.GetContainerReference($"{containerName}");
  // Connect to the blob file
  CloudBlockBlob blob = container.GetBlockBlobReference($"{fileName}");
  // Get the blob file as text
  string contents = blob.DownloadTextAsync().Result;
  
  return contents;
}

The usage is equally easy:

GetBlob("containername", "my/file.json");

MORE TO READ:

Posted in .NET Core, Microsoft Azure | Tagged , | Leave a comment