Thursday, November 19, 2015

File upload in Resource (.resx)


I was working on Azure web job wherein I had to put an excel in the solution and use it after getting deployed. I was struggling with finding the path of the file, tried with “~”, “..\” and all other options suggested over the internet to vain. Later I was introduced to uploading a file in the .resx and fetching/accessing the file just like any other resource.
Below is the step by step procedure for doing so –
a.      Add .resx file in your solution, if not already





b.      Instead of Strings, select Files for upload



c.      Click on Add Resource, select All Files and add file. Save the resx. You will see the uploaded file in the solution under Resource folder
In the below screenshot, you will see that I have added .xlsx file.



d.      The next most important step here is to right click on the file which we have uploaded and click on Properties, set the “Build Action” to “Embedded Resource”. This step will make sure that the executing assembly has the information of this file.



e.      Now the next step would be to access this file in the code. Below is the code for the same,
Assembly assembly = Assembly.GetExecutingAssembly();
Stream st = assembly.GetManifestResourceStream("<SolutionName>.Resources.<FileNameWithExtension>");
           
if (st.CanSeek)
{
  st.Position = 0;
}
Note:
a.      The GetManifestResourceStream method needs an exact path of the file in the form of a hierarchy ie SolutionName.Resources.FileName.FileNameExtension
The data in the uploaded file is now available in the stream. We can now use it as per our need.
Please leave your feedback and queries in the comments section. Thank you!

Wednesday, October 7, 2015

Azure - Blob storage – Working with file(s)

Introduction
Blob storage is an azure service to store large size/amount of data in unstructured way in form of binaries in the cloud. This opens up the whole world of files and all their extensions which can be uploaded in the blobs.
This post does not talk about the creation of blobs, connections but explains step by step in uploading the files, downloading the files and moving the files from one blob to another.

Upload file
The first step in the process of uploading a file to Blob is to create Objects of the CloudStorageAccount and the BlobClients in it.

// Retrieve storage account from connection string.
CloudStorageAccount storageAccount = CloudStorageAccount.Parse(UnityConfiguration.GetConfigurationValue("ConfigKey"));

// Create the blob client object from the storage account
CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

You may want to add Retry policy to this blobClient which will retry to access the client in an exponential time if there is any problem encountered in the first try
blobClient.DefaultRequestOptions.RetryPolicy = new ExponentialRetry(TimeSpan.FromSeconds(retryInterval), retryCount);

It is always a best practice to check if the Blob exists with a container, this way you can throw an exception that blob does not exists or create one with the container reference.

// Returns an reference for a given container of the blob
CloudBlobContainer blobContainer = blobClient.GetContainerReference(
UnityConfiguration.GetConfigurationValue("ContainerName"));

// Create container if it doesn’t exists
blobContainer.CreateIfNotExists();


Now that we have completed all the pre-requisites, the next step is to create reference of the CloudBlockBlob and then upload the file

// Create the reference of the block blob from the container
CloudBlockBlob blockBlob = blobContainer.GetBlockBlobReference(this.AddLocationInfo("Blobname"));

using (var inputStream = new MemoryStream())
{
     document.Save(inputStream); // document is a file object(could be xml, image, etc)
     inputStream.Flush();
     inputStream.Position = 0;

     blob.UploadFromStream(inputStream);
}

Note:
    a.  For XmlDocument document -> document.Save(inputStream)
    b.  For other type of files (.docx, .xlsx, etc) need to save into a stream so that it can be uploaded to blob.

Download file
Downloading a file is simple, you can download a file content into a Stream or as a string or even as a byte array.
The CloudBlockBlob object has method to download the file

// Download the file as memory stream
using (var blobStream = blockBlob.OpenRead())
{
      MemoryStream contentStream = new MemoryStream();
      blobStream.CopyTo(contentStream);
}

// Download the file as string
Encoding encoding;
blockBlob.DownloadText(encoding);

// Download the file into byte array
byte[] content;
using (var memoryStream = new MemoryStream())
{
     blockBlob.DownloadToStream(memoryStream);
     content = memoryStream.ToArray();
}


Moving file from one Blob to another
To move a file from one blob to another, simply use the inbuilt method of the CloudBlockBlob object.

CloudBlockBlob source;
CloudBlockBlob target;

using (var sourceStream = source.OpenRead())
{
     target.UploadFromStream(sourceStream);
}


Please leave your feedback and queries in the comments section. Thank you!

Thursday, September 24, 2015

Compare Object List – Determine Insert, Update and Delete data


I was working on this scenario and breaking my head to come up with simple solution to compare two large list of object (List<object>) and get the result as new (Insert), update and delete data. Found out that there is simple solution and I thought will publish it so that it can help others.

I have put generic code which anyone can copy and start using right away.

New data
/// <summary>
/// Returns the newly added
/// </summary>
/// <param name="existingData">Existing data</param>
/// <param name="newData">New data</param>
/// <returns>List of objects which are newly added</returns>
public List<object> GetInsertData(List<object> existingData, List<object> newData)
{
    // Local objects
    List<object> returnList = null;

    // Prepare the list which has the data to be inserted
    returnList = (from New in newData
                  join Existing in existingData on New.ID equals Existing.ID
                  into DataAdded
                  from dataOld in DataAdded.DefaultIfEmpty()
                  where dataOld == null
                  select New).ToList<object>();

    // Return the data list
    return returnList;
}


Updated data
/// <summary>
/// Returns the data updated
/// </summary>
/// <param name="existingData">Existing data</param>
/// <param name="newData">New data</param>
/// <returns>List of objects which are updated</returns>
public List<object> GetUpdateData(List<object> existingData, List<object> newData)
{
    // Local objects
    List<object> returnList = null;

    returnList = (from New in newData
                  join Existing in existingData on New.ID equals Existing.ID
                  into DataUpdated
                  from dataOld in DataUpdated.DefaultIfEmpty()
                  where dataOld!= null && (New.<Field1>!= dataOld.<Field1> || New.<Field2> != dataOld.<Field2>)
                  select new object
                  {
                       Field1 = New.Value1,
                        Field2 = New.Value2,
                        Field3 = dataOld.Value3,
                        Field4 = dataOld.Value4,
                   }).ToList<object>();

            // Return the data list
            return returnList;
        }


Delete data
/// <summary>
/// Returns the deleted rows
/// </summary>
/// <param name="existingData">Existing data</param>
/// <param name="newData">New data</param>
/// <returns>List of schools which needs to be deleted</returns>
public List<object> GetDeleteData(List<object> existingData, List<object> newData)
{
    // Local objects
    List<object> returnList = null;

    // Prepare the list which has the data to be deleted
    returnList = (from Existing in existingData
                     join New in newData on Existing.ID equals New.ID
                     into NewWithNullForDeleted
                     from subNew in NewWithNullForDeleted.DefaultIfEmpty()
                     where subNew == null
                     select Existing).ToList<School>();

     // Return the data list
     return returnList;
}



Please leave your feedback and queries in the comments section. Thank you!

Tuesday, August 25, 2015

Azure – Application Insights – Configuration & Usage


I still remember the good old days where we had a huge instrumentation database wherein developers would log all the data – URLs, user navigation path, query parameters, exceptions, browser information, region information, etc to help in debugging the issues and generating required reports. Application Insights offers all these capabilities and much more with simple configuration and ready to use detailed reports.

This post is divided into two parts –
a.      Installation & configuration
b.      Usage of the reports 

Installation & configuration

Prerequisites
·        Visual Studio 2013 or later version(s)
·        Subscription to Microsoft Azure
Visual Studio Application Insights has Free, Standard & Premium pricing tiers. 

             1.      Login to Azure portal and create a new Application Insight resource by selecting ASP.Net Web Application



2.      Make a note of the Instrumentation key
            
            Note: Intentionally erased the details 

These first two steps creates a resource and now it is ready for any application to be configured for monitoring.

3.      Install the SDK 

a.      Right click on your Project and install ApplicationInsights NuGet package




b.      Search for Microsoft.ApplicationInsights.Web and install


               
Note: If “Application Insights for Visual Studio” extension is installed, then on right click of the project you will see an option “Add Application Insights” which is another way of configuring Application Insights.


c.      ApplicationInsights.config file will be added by the NuGet installation. Edit this file and add the below tag just before the file end.

<InstrumentationKey>Your instrumentation key here</InstrumentationKey>

 Note: This above configuration in the ApplicationInsights.config will write the logistics from all the available environments. If the requirement is to configure different Application Insights for each environment then the best solution is to configure the Instrumentation Key in Cloud.config and write the below statement in Global.asax.cs to fetch the key based on environment.

Microsoft.ApplicationInsights.Extensibility.TelemetryConfiguration.Active.InstrumentationKey = CloudConfigurationManager.GetSetting("InstrumentKeyName");
At this point we are done with the installation & configuration. Running the project (debug mode/release mode/published code) will start writing the logs.

 Usage of the reports

          1.      Login to Azure portal and browse to Applications Insight.
 



2.      Click through the applications and then through the available reports to see more details.



Various reports are already created based on the ApplicationInsights data log –
·        Failures

This reports all the failures with exception details happened in last 24 hours along with giving additional details about the % of each exception against the total number of exceptions logged.

One great thing about this report –

It digs down from the URL to method name to operating system to even browser version for a generated exception. This is like a whole universe of data points for debugging the issue. This detailed information has helped our team more than once to find the root cause sooner.  

·        Performance

Gives performance number against each URL which will help in determining the low performance pages.

·        Browser

Gives the details about the browser & their versions used to access the application.

This post will not get into the details of each of the report. I request the readers to explore other reports & options.
Add Client side monitoring (Web browsers)

               The SDK installed from NuGet sends the monitoring data from server side code. To add monitoring on client side for web browsers,  
a.      Download the Javascript snippet from Azure portal and put it in every page or the Master Page.

The code snippet will have the Instrumentation Key. 
Please leave your feedback and queries in the comments section. Thank you!