Wednesday, June 27, 2018

Tuning web page performance


1.    Why parallel api call?

If the page needs to make multiple web requests (multiple api calls), we might end up in page performance issue (page load time might be higher) if the one of the api is taking longer time and blocking the other of the api calls.

I had also encountered page load time issue in one of my project. Page was consuming 12 different api, 4 api calls were taking longer time (more than a minute) and blocking the execution of the other of the api calls.

To overcome the above issue, I have made use of async and await keywords of C# and Parallel.ForEach method where there were multiple api calls inside for each.

2. Overview of the parallel implementation  


In an async method, tasks are started when they’re created. The await operator is applied to the task at the point in the method where processing can’t continue until the task finishes.

 var result = await WebRequest(url); 

In the above example task is waited as soon as it is created, however you can separate creating the task from awaiting the task if your program has some other task to accomplish in between that doesn’t depend on the completion of the task.

// The following line creates and starts the task.
var task1 = WebRequest(url); 


// While the task is running, you can do other work that doesn't depend 
// on the results of the task1.


// the application of await suspends the rest of this method until the task is complete.
var result = await task1;

1.     Sample example of parallel api call.


Below program starts three asynchronous web api calls and then awaits them in the order in which they’re called. Below web request don’t always finish in the order in which they’re created and awaited. They start to run when they’re created, and one or more of the tasks might finish before the method reaches the await expressions.
        private async Task<int> GetTotalContentLenght()
        {
          HttpClient webClient = new HttpClient();
            Task<int> webRequest1 = GetContentLength("http://msdn.microsoft.com", webClient);
            Task<int> webRequest2 = GetContentLength("Url", webClient);
            Task<int> webRequest3 = GetContentLength("Url", webClient);
            int length1 = await webRequest1;
            int length2 = await webRequest2;
            int length3 = await webRequest3;
            int totalLength = length1 + length2 + length3;
            return totalLength;
        }

        async Task<int> GetContentLength(string url, HttpClient client)
        {
          var byteArray = await client.GetByteArrayAsync(url);          
            return byteArray.Length;
        }

2.     Paralle.ForEach

   List<string> urls = new List<string> {  "URL 1",   "URL2",   "URL 3",   "URL 4",    "URL 5" };
Parallel.ForEach(urls, async m =>
   {    
byte[] urlContents = GetURLContentsAsync(url);  //web api call
int total+= await urlContents.Length;                         
});

3.    References

1.     https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/async/how-to-make-multiple-web-requests-in-parallel-by-using-async-and-await

Redis Cache


1.    What is Redis Cache?

Caching is a state management strategy that can be used to improve the performance of your applications as it helps you to reduce the consumption of resources in your system.

Redis Cache is an open source (BSD licensed), high-speed, NoSQL database. It's fast, and it runs entirely in the memory with negligible performance overhead when reading and writing data. It should be noted that Redis is free for both commercial and non-commercial use under the BSD license.

2. Install and proceed with Redis Cache implementation


Once the Redis database setup is done, we need Redis client to store and retrieve the data to and from the Redis cache.

Step 1>

1.     Install StackExchange.Redis package from nugget package.


Once the StackExchange.Redis installation is done. Please follow the below steps to store and retrieve data to and from the Redis cache.

Step2 >

2.     Open connection to Redis Cache


  Var RedisConnectionString=connection string
 if(RedisConnection.IsConnected)
   {
      Var ServerCache = RedisConnection.GetServer(RedisConnectionString);
      Var DBCache = RedisConnection.GetDatabase();
            HttpContext.Current.Application["RedisDB"] = DBCache;
    }

Step3 >

3.     Set the data in the Redis

Var _database= System.Web.HttpContext.Current.Application["RedisDB "];
   if(_database != null && _database.IsConnected(key))
      {
        ISerializer _serializer = new JsonSerializer();
        _database.StringSet(key, _serializer.Serialize(value), RedisExpireIn);

       }



Step4 >

4.     Get the data from Redis Cache

Var _database= System.Web.HttpContext.Current.Application["RedisDB "];
ISerializer _serializer = new JsonSerializer();
                if (_database != null && _database.IsConnected(key))
                {
                    _serializer.Deserialize<T>(_database.StringGet(key));
                }
               
       

5.     Delete key from Redis Cache


if (_database != null && _database.IsConnected(key))
                {
                   _database.KeyDelete(key);
                }

6.     Extending the Cache key Expiry


Var _database= System.Web.HttpContext.Current.Application["RedisDB "];
_database.KeyExpire(key, RedisExpireIn);

3. Reference


Friday, June 8, 2018

Exm sending email programmatically

Exm is built into Sitecore 9 Experience Platform, You no longer need to install it as a package. 

We can specify target language when sending automated messages through the client API.
To send email programmatically through EXM, follow the below steps.

Step1: Create Exm model with necessary properties as show below.
    public class ExmModel
    {
        public string MessageTemplateId { get; set; }

        public Dictionary<string, object> CustomTokens { get; set; }  

        public string UserName { get; set; }

        public string Email { get; set; }

        public MediaItem Attachment { get; set; }
       
        public string FilePath { get; set; }

        public string FileStream { get; set; }

        public string FileName { get; set; }       

        public string MediaItemID { get; set; }
    }

Step2: Create the instance exm model as below
// Send Mail.
   ExmModel exmModel = new ExmModel();
   exmModel.MessageTemplateId = “email message template id”
   exmModel.MediaItemID =”Sitecore MediaItemID”;

Step3: Add the custom token like (body content for the email) and prepare email content

exmModel.CustomTokens = new Dictionary<string, object>();
exmModel.CustomTokens.Add(token, “heading”);
exmModel.CustomTokens.Add(token, “Address”);
exmModel.CustomTokens.Add(token name, “any content you wish to add”);

Step4: Create the contact and Add recipient
       Create the contact, List Manager in sitecore.
       Please refer the sitecore exm blog post to create the List manager and contacts      

Step5: Create the contract and Add recipient

MessageItem message = Sitecore.Modules.EmailCampaign.Factory.GetMessage(exmModel.MessageTemplateId);
List<RecipientId> recipients = new List<RecipientId>();

Var contact = contactRepository.LoadContactReadOnly(userName);
Var lockAttempt = contactManager.TryLoadContact(contact.ContactId);

GetOrCreateContact(userName, lockAttempt, contactRepository, contactManager, name);
            }­­
                            recipients.Add(RecipientRepository.GetDefaultInstance().ResolveRecipientId("xdb:" + contact.ContactId));




Step6: Replace Custom Tokens.            

Step7: Attachment: Sitecore media item.
a.     Store the attachment as media item in the sitecore
b.     Retrieve the media item from sitecore
                       
exmModel.Attachment = "get the media item from sitecore"
message.Attachments.Add(exmModel.Attachment);
message.FromAddress = exmModel.Email;


Step8: Sending email
      if (recipients != null && recipients.Any())
        {
                           
          foreach (var recipient in recipients)
            {
               New AsyncSendingManager(message).SendStandardMessage(recipient);

             }
          }
2. Piece of code to store uploaded file as a media item in sitecore

     private static MediaItem AddingFile(ExmModel exmModel)
        {

            byte[] fileStreamDecoded = System.Convert.FromBase64String(exmModel.FileStream);


            using (MemoryStream ms = new MemoryStream(fileStreamDecoded))
            {
                StreamWriter writer = new StreamWriter(ms);
                writer.Write(fileStreamDecoded);

                System.Net.Mime.ContentType ct = new System.Net.Mime.ContentType(System.Net.Mime.MediaTypeNames.Application.Pdf);
                System.Net.Mail.Attachment attach = new System.Net.Mail.Attachment(ms, ct);
                // Create the options
                Sitecore.Resources.Media.MediaCreatorOptions options = new Sitecore.Resources.Media.MediaCreatorOptions();
                options.FileBased = false;
                options.IncludeExtensionInItemName = false;

                options.Versioned = false;

                options.Database = ContextDatabase;
                options.Destination =”exm file path”

                Sitecore.Resources.Media.MediaCreator creator = new Sitecore.Resources.Media.MediaCreator();
                using (new Sitecore.SecurityModel.SecurityDisabler())
                {

                    // Item mediaItem = Sitecore.Resources.Media.MediaManager.Creator.CreateFromStream()
                    Item mediaItem = creator.CreateFromStream(ms, exmModel.FilePath, options);
                    mediaItem.Editing.BeginEdit();
                    mediaItem.Name = Path.GetFileNameWithoutExtension(exmModel.FileName);
                    mediaItem.Editing.EndEdit();
                    return mediaItem;
                }
            }


        }
3. Reference