<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Elston]]></title><description><![CDATA[Elston]]></description><link>https://blog.elston.co.in</link><generator>RSS for Node</generator><lastBuildDate>Thu, 28 May 2026 01:52:10 GMT</lastBuildDate><atom:link href="https://blog.elston.co.in/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Image Website in Asp.Net Core 6]]></title><description><![CDATA[GitHub Link to the Project
In my pursuit to learn Azure services, I have created a simple Web App in Asp.Net Core 6 to Display Images via an Azure Function.

**I will be using the following services and try to explain as I go ahead **
Blob storage Ac...]]></description><link>https://blog.elston.co.in/image-website-in-aspnet-core-6</link><guid isPermaLink="true">https://blog.elston.co.in/image-website-in-aspnet-core-6</guid><dc:creator><![CDATA[Elston Misquitta]]></dc:creator><pubDate>Tue, 10 Jan 2023 16:54:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1642182650349/_jNj9Al1D.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><a target="_blank" href="https://github.com/ElstonMisquitta88/ProjectNodlehs">GitHub Link to the Project</a></p>
<p>In my pursuit to learn Azure services, I have created a simple Web App in Asp.Net Core 6 to Display Images via an Azure Function.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1642100791433/6pLtFNKZ-.jpeg" alt="Project.jpg" /></p>
<p>**I will be using the following services and try to explain as I go ahead **</p>
<h2 id="heading-blob-storage-account">Blob storage Account</h2>
<h2 id="heading-azure-functions">Azure Functions</h2>
<h2 id="heading-azure-web-app">Azure Web App</h2>
<h2 id="heading-azure-keyvault">Azure KeyVault</h2>
<p>Let's Begin</p>
<h3 id="heading-1-create-a-resource-group">1. Create a resource group</h3>
<pre><code class="lang-bash">az group create -l westindia -n ProjectNodlehs
</code></pre>
<p>This will create a resource group with the name <em>ProjectNodlehs</em></p>
<h3 id="heading-2-create-a-storage-account-and-create-2-containers-in-the-storage-account">2. Create a storage account and create 2 containers in the storage account</h3>
<pre><code class="lang-bash">az storage account create \
  --name treks \
  --resource-group ProjectNodlehs \
  --location westindia \
  --sku Standard_LRS  \
  --kind StorageV2
</code></pre>
<p>Upload some sample images in the containers created.</p>
<h3 id="heading-3-create-an-azure-http-function-to-return-image-url-and-name">3. Create an Azure HTTP Function to return Image URL and name.</h3>
<p>Azure Functions is a serverless solution that allows you to write less code, maintain less infrastructure, and save on costs. Instead of worrying about deploying and maintaining servers, the cloud infrastructure provides all the up-to-date resources needed to keep your applications running.</p>
<p><a target="_blank" href="https://docs.microsoft.com/en-in/azure/azure-functions/functions-overview">Azure Functions Overview</a></p>
<p>(a) Create the Azure function locally in VS code.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1642099052248/sY15KRZNK.png" alt="new01.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1642099063064/nfbswf_vNR.png" alt="new02.png" /></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1642099068582/BOhMM7F8N.png" alt="new03.png" /></p>
<p>Fetch the images stored in a Blob Container using shared access signature (SAS).</p>
<p>(b) Create a Azure Function in portal</p>
<pre><code class="lang-bash">az functionapp create \
--name FetchTreks \
--storage-account treks \
--consumption-plan-location westindia \
--resource-group ProjectNodlehs \
--functions-version 4
</code></pre>
<p>For initial testing purpose we deploy the function directly from VS Code to Azure Function App on the portal.</p>
<h3 id="heading-4-create-an-aspnet-core-web-app-aspnet-core-6">4. Create an ASP.NET Core web app (Asp.NET Core 6)</h3>
<p>In VS code CLI - command to create a new project</p>
<pre><code class="lang-bash">dotnet new webapp -f net6.0
</code></pre>
<p><a target="_blank" href="https://docs.microsoft.com/en-us/learn/modules/create-razor-pages-aspnet-core/">MS Learn Link</a></p>
<p>We will divide the project in Model and Services to consume the API which return the Image URL list as per the name provided.</p>
<p>The model will contain a class with Image list properties.</p>
<p>The service will consume the Azure function to return the image list.</p>
<p>ASP.NET Core supports the dependency injection (DI) software design pattern, which is a technique for achieving Inversion of Control (IoC) between classes and their dependencies. We have implemented in the same in this web app.</p>
<p><a target="_blank" href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-6.0">Fundamentals: Dependency-Injection</a></p>
<p>(a) Create an Interface</p>
<p>(b) Create an implementation for the Interface</p>
<p>In Program.cs we will need to register the custom service to be used.</p>
<pre><code class="lang-csharp"><span class="hljs-comment">// Register Custom Services to used</span>
builder.Services.AddTransient&lt;ITrekService,TrekService&gt;();
</code></pre>
<p>In future, if the Implementation of the Interface changes, we will need to make changes at a single point in the project.</p>
<p>(c) On the Page we call the service which has been registered</p>
<pre><code class="lang-csharp">        <span class="hljs-keyword">public</span> ITrekService _ProductService;
        <span class="hljs-keyword">private</span> <span class="hljs-keyword">readonly</span> ILogger&lt;IndexModel&gt; _logger;

        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">TrekDisplayModel</span>(<span class="hljs-params">ILogger&lt;IndexModel&gt; logger, ITrekService productService</span>)</span>
        {
            _logger = logger;
            _ProductService = productService;
        }

         <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">async</span> Task <span class="hljs-title">OnGetAsync</span>(<span class="hljs-params"></span>)</span>
        {
            <span class="hljs-keyword">try</span>
            {
               <span class="hljs-keyword">var</span> shows = <span class="hljs-keyword">await</span> _ProductService.GetTrekImages(page);
            }
            <span class="hljs-keyword">catch</span>
            {
             }
        }
</code></pre>
<h3 id="heading-5-create-a-web-app-serice-plan-and-web-app-in-azure">5. Create a Web App Serice Plan and Web App in Azure</h3>
<p>(a) App Service Plan</p>
<pre><code class="lang-bash">az appservice plan create --name TrekBucketListApp --resource-group c --sku F1
</code></pre>
<p>(b) Web App</p>
<pre><code class="lang-bash">az webapp create --resource-group ProjectNodlehs --plan TrekBucketListApp --name TrekBucketListApp --runtime <span class="hljs-string">"DOTNET|6.0"</span>
</code></pre>
<p>(c) Creation of app settings in the web app in Az portal</p>
<pre><code class="lang-bash">az webapp config appsettings <span class="hljs-built_in">set</span> --name TrekBucketListApp --resource-group ProjectNodlehs --settings Values:<span class="hljs-built_in">test</span>=<span class="hljs-string">"test123"</span>
</code></pre>
<p>For initial testing purposes, we will deploy the web app directly via Vs Code to Az portal</p>
<h3 id="heading-6-create-a-key-vault-service">6. Create a Key Vault Service</h3>
<p>Instead of saving configuration values in the Azure function and Web App we can make use of the Key vault service to save secrets.</p>
<blockquote>
<p>Azure Key Vault is a cloud service for securely storing and accessing secrets. A secret is anything that you want to tightly control access to, such as API keys, passwords, certificates, or cryptographic keys.</p>
</blockquote>
<p><a target="_blank" href="https://docs.microsoft.com/en-us/azure/key-vault/general/basic-concepts">Key Vault Basics</a></p>
<p>We can create a Key Vault from the Azure portal.</p>
<p>The next step would be to enable system-assigned managed identity on the service which will be consuming the Key Vault Secret. In this scenario, we would have to enable the same on the Function app and Web App.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1642531000331/Dm4MDoWN-.png" alt="01.png" /></p>
<p>After that, on the Key Vault service, we need to provide Access policy rights to the Function App for reading secrets. This is done via</p>
<p>Function App &gt;&gt; Settings &gt;&gt; Access policies &gt;&gt; Add Access policy</p>
<p>After that, we can add your secrets to save in the Key Vault.</p>
<p>Finally, in the last step, we will replace the plain text configuration values set in the Function app with the value fetched from the Key vault.</p>
<p>This is done using</p>
<pre><code class="lang-csharp">@Microsoft.KeyVault(SecretUri=)
</code></pre>
<p>SecretUri is got from the secret created in the key vault.</p>
<p>After saving the values the configuration if successful will be displayed with a green tick.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1642531942321/MfjPgiL3w.png" alt="01.png" /></p>
]]></content:encoded></item><item><title><![CDATA[Creation of a Azure Timer Trigger Function to check every 15 minutes for a available vaccination slot]]></title><description><![CDATA[Creation of a Azure Timer Trigger Function to check every 15 minutes for an available vaccination slot : 
Github Project Link 
Azure Functions is a serverless solution means you don't have to worry about the infrastructure and work on writing code.
 ...]]></description><link>https://blog.elston.co.in/creation-of-a-azure-timer-trigger-function-to-check-every-15-minutes-for-a-available-vaccination-slot</link><guid isPermaLink="true">https://blog.elston.co.in/creation-of-a-azure-timer-trigger-function-to-check-every-15-minutes-for-a-available-vaccination-slot</guid><category><![CDATA[Azure]]></category><category><![CDATA[Microsoft]]></category><category><![CDATA[serverless]]></category><category><![CDATA[functions]]></category><dc:creator><![CDATA[Elston Misquitta]]></dc:creator><pubDate>Sat, 11 Dec 2021 19:51:29 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1639244842443/0njVgDZxlN.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Creation of a Azure Timer Trigger Function to check every 15 minutes for an available vaccination slot : 
<a target="_blank" href="https://github.com/ElstonMisquitta88/Cowin/blob/main/README.md">Github Project Link</a> </p>
<p><strong>Azure Functions</strong> is a serverless solution means you don't have to worry about the infrastructure and work on writing code.
 <a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview">Azure Functions Overview</a> </p>
<p>I will be using the following services : </p>
<ul>
<li><p>Azure Function</p>
</li>
<li><p>SendGrid - For sending email notifications</p>
</li>
<li><p>Application Insights</p>
</li>
</ul>
<p><strong>(1)</strong> The First Step is create a Azure TimerTrigger  Function using VS Code.</p>
<pre><code>        [FunctionName(<span class="hljs-string">"FetchCowinData"</span>)]
        <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">Run</span><span class="hljs-params">([TimerTrigger(<span class="hljs-string">"0 */15 * * * *"</span>)]TimerInfo myTimer, ILogger <span class="hljs-built_in">log</span>)</span>
        </span>{
            <span class="hljs-comment">// Code Here</span>
        }
</code></pre><p>This will be triggered every 15 mins.</p>
<p>The following packages need to be added.</p>
<pre><code>dotnet add package System.Collections <span class="hljs-operator">-</span><span class="hljs-operator">-</span>version <span class="hljs-number">4.3</span><span class="hljs-number">.0</span>
dotnet add package System.Net.Http <span class="hljs-operator">-</span><span class="hljs-operator">-</span>version <span class="hljs-number">4.3</span><span class="hljs-number">.4</span>  
dotnet add package  SendGrid
</code></pre><p>We will call the API  -  <a target="_blank" href="https://apisetu.gov.in/api/cowin">Apisetu</a> for checking the available vaccination slots.
Data will be fetch per district code wise. If data is found an email will be triggered.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639245937711/QbN1-6xkG.png" alt="image.png" /></p>
<p><strong>(2)</strong> Next Step is to create an Azure Fucntion app in the portal and publish the code via Visual Studio.</p>
<p>The Function app is created using a consumption model to minimize the cost.
You're only charged for the time that your function app runs. This plan includes a free grant on a per subscription basis. - <a target="_blank" href="https://docs.microsoft.com/en-us/azure/azure-functions/functions-consumption-costs?tabs=portal">Estimating Consumption plan costs</a> </p>
<p>The Config values used in the function was be set via 
Azure portal &gt;&gt; Function App &gt;&gt; Configuration</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639243377743/fuz6MVtwo.png" alt="image.png" /></p>
<p>The Values in local.settings.json will be overridden by the values in<br />Function App &gt;&gt; Configuration</p>
<p>To make this even more secure we can set these values via an <strong>Azure Key Vault</strong>.</p>
<p><strong>(3)</strong> SendGrid - Email service - You can register for a free account with a daily limit of 100 emails which is quite good for testing and development purposes.</p>
<p>Will be using SendGrid  to send email notifications.The number of emails triggered can be monitored via the SendGrid  dashboard.</p>
<p><strong>(4)</strong> Application Insights-Useful to monitor your applications.
Here we will be using it to monitor the Azure function.
Live metrics is also available for providing real time data.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639244664874/c_rjNKrKw.png" alt="image.png" /></p>
<p>Once the Function is running we get email notification if data is found via the API.
<strong>Sample Email :
</strong>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1639243841944/wZ_54v6fd.png" alt="cowin.png" /></p>
]]></content:encoded></item><item><title><![CDATA[Display Images stored in a Blob Container on a Web App using shared access signature (SAS)]]></title><description><![CDATA[Display Images in a Blob Container using Shared access signature (SAS).
The access level of the container is set to private.
Every SAS is signed with a key. You can sign a SAS in one of two ways:

With a key created using Azure Active Directory (Azur...]]></description><link>https://blog.elston.co.in/display-images-stored-in-a-blob-container-on-a-web-app-using-shared-access-signature-sas</link><guid isPermaLink="true">https://blog.elston.co.in/display-images-stored-in-a-blob-container-on-a-web-app-using-shared-access-signature-sas</guid><category><![CDATA[Azure]]></category><category><![CDATA[Microsoft]]></category><dc:creator><![CDATA[Elston Misquitta]]></dc:creator><pubDate>Thu, 02 Dec 2021 17:24:03 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638465798075/5oZt99uAq.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Display Images in a Blob Container using Shared access signature (SAS).
The access level of the container is set to private.</p>
<p>Every SAS is signed with a key. You can sign a SAS in one of two ways:</p>
<ul>
<li><p>With a key created using Azure Active Directory (Azure AD) credentials. A SAS that is signed with Azure AD credentials is a user delegation SAS.</p>
</li>
<li><p>With the storage account key. Both a service SAS and an account SAS are signed with the storage account key.</p>
</li>
</ul>
<p><strong>Service SAS</strong></p>
<p><a target="_blank" href="Link">https://docs.microsoft.com/en-us/azure/storage/blobs/sas-service-create?tabs=dotnet</a> </p>
<p><strong>Account SAS</strong></p>
<p> <a target="_blank" href="Link">https://docs.microsoft.com/en-us/azure/storage/common/storage-account-sas-create-dotnet?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&amp;tabs=dotnet</a> </p>
<p>Will be using account SAS with the storage account key.</p>
<p>Trying the same using Asp.Net core 6.</p>
<p><strong>Github Link :</strong> https://github.com/ElstonMisquitta88/BlobSASDemo</p>
<p>Create a new ASP.NET Core web app</p>
<pre><code>dotnet <span class="hljs-keyword">new</span> webapp <span class="hljs-operator">-</span>n AzureFriday <span class="hljs-operator">-</span>f net6<span class="hljs-number">.0</span>
dotnet add package Azure.Storage.Blobs <span class="hljs-operator">-</span><span class="hljs-operator">-</span>version <span class="hljs-number">12.10</span><span class="hljs-number">.0</span>
dotnet dev<span class="hljs-operator">-</span>certs https <span class="hljs-operator">-</span><span class="hljs-operator">-</span>trust
</code></pre><p>In appsettings.json we will add the following keys to be used</p>
<pre><code>  <span class="hljs-string">"K_StorageAccountName"</span>: <span class="hljs-string">"demo"</span>,
  <span class="hljs-string">"K_StorageAccountKey"</span>: <span class="hljs-string">"Key Value"</span>,
  <span class="hljs-string">"K_StorageAccountBlobUri"</span>: <span class="hljs-string">"https://&lt;name&gt;.blob.core.windows.net"</span>,
</code></pre><p>Code to Fetch Blobs from the container</p>
<pre><code><span class="hljs-keyword">using</span> <span class="hljs-title">Microsoft</span>.<span class="hljs-title">AspNetCore</span>.<span class="hljs-title">Mvc</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Microsoft</span>.<span class="hljs-title">AspNetCore</span>.<span class="hljs-title">Mvc</span>.<span class="hljs-title">RazorPages</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Azure</span>.<span class="hljs-title">Storage</span>.<span class="hljs-title">Blobs</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Azure</span>.<span class="hljs-title">Storage</span>.<span class="hljs-title">Blobs</span>.<span class="hljs-title">Models</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Azure</span>.<span class="hljs-title">Storage</span>.<span class="hljs-title">Sas</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">System</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">System</span>.<span class="hljs-title">IO</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">System</span>.<span class="hljs-title">Text</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">System</span>.<span class="hljs-title">Threading</span>.<span class="hljs-title">Tasks</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Azure</span>.<span class="hljs-title">Core</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Azure</span>.<span class="hljs-title">Identity</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Azure</span>.<span class="hljs-title">Storage</span>;


namespace AzureFriday.Pages
{
    <span class="hljs-keyword">public</span> class Sample1Model : PageModel
    {
        <span class="hljs-keyword">public</span> List<span class="hljs-operator">&lt;</span><span class="hljs-keyword">string</span><span class="hljs-operator">&gt;</span> LstBlobContents { get; set; }

        <span class="hljs-comment">// requires using Microsoft.Extensions.Configuration;</span>
        <span class="hljs-keyword">private</span> readonly IConfiguration Configuration;

        <span class="hljs-keyword">public</span> Sample1Model(IConfiguration configuration)
        {
            Configuration <span class="hljs-operator">=</span> configuration;
        }

        <span class="hljs-keyword">public</span> void OnGet()
        {
            <span class="hljs-comment">// Create a service level SAS that only allows reading from service level APIs</span>
            AccountSasBuilder sas <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> AccountSasBuilder
            {
                <span class="hljs-comment">// Allow access to blobs</span>
                Services <span class="hljs-operator">=</span> AccountSasServices.Blobs,

                <span class="hljs-comment">// Allow access to the service level APIs</span>
                ResourceTypes <span class="hljs-operator">=</span> AccountSasResourceTypes.All,

                <span class="hljs-comment">// Access expires in 1 hour!</span>
                ExpiresOn <span class="hljs-operator">=</span> DateTimeOffset.UtcNow.AddHours(<span class="hljs-number">1</span>)
            };
            <span class="hljs-comment">// Allow read access</span>
            sas.SetPermissions(AccountSasPermissions.All);

            <span class="hljs-comment">// Create a SharedKeyCredential that we can use to sign the SAS token</span>
            <span class="hljs-keyword">string</span> StorageAccountName <span class="hljs-operator">=</span> Configuration[<span class="hljs-string">"K_StorageAccountName"</span>];
            <span class="hljs-keyword">string</span> StorageAccountKey <span class="hljs-operator">=</span> Configuration[<span class="hljs-string">"K_StorageAccountKey"</span>];
            StorageSharedKeyCredential credential <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> StorageSharedKeyCredential(StorageAccountName, StorageAccountKey);

            <span class="hljs-comment">// Build a SAS URI</span>
            <span class="hljs-keyword">string</span> StorageAccountBlobUri <span class="hljs-operator">=</span> Configuration[<span class="hljs-string">"K_StorageAccountBlobUri"</span>];
            UriBuilder sasUri <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> UriBuilder(StorageAccountBlobUri);
            sasUri.Query <span class="hljs-operator">=</span> sas.ToSasQueryParameters(credential).ToString();

            <span class="hljs-comment">// Create a client that can authenticate with the SAS URI</span>
            <span class="hljs-keyword">string</span> containerName <span class="hljs-operator">=</span> <span class="hljs-string">"data"</span>;
            BlobServiceClient service <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> BlobServiceClient(sasUri.Uri);

            List<span class="hljs-operator">&lt;</span><span class="hljs-keyword">string</span><span class="hljs-operator">&gt;</span> numberList <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> List<span class="hljs-operator">&lt;</span><span class="hljs-keyword">string</span><span class="hljs-operator">&gt;</span>();
            foreach (BlobItem blob in service.GetBlobContainerClient(containerName).GetBlobs())
            {
                BlobClient blobClient <span class="hljs-operator">=</span> service.GetBlobContainerClient(containerName).GetBlobClient(blob.Name);
                numberList.Add(blobClient.Uri.ToString());
            }
            LstBlobContents <span class="hljs-operator">=</span> numberList;
        }
    }
}
</code></pre><p>Code to Render Images on Page</p>
<pre><code>@page
@model AzureFriday.Pages.Sample1Model
@{

    foreach (<span class="hljs-keyword">var</span> item in Model.LstBlobContents)
    {
        <span class="hljs-operator">&lt;</span>p<span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span>img src<span class="hljs-operator">=</span>@item width<span class="hljs-operator">=</span><span class="hljs-string">"200"</span> height<span class="hljs-operator">=</span><span class="hljs-string">"150"</span><span class="hljs-operator">&gt;</span>
        <span class="hljs-operator">&lt;</span><span class="hljs-operator">/</span>p<span class="hljs-operator">&gt;</span>
    }
}
</code></pre>]]></content:encoded></item><item><title><![CDATA[#CloudGuruChallenge: Your resume in Azure]]></title><description><![CDATA[Azure Cloud Resume Challenge
 https://acloudguru.com/blog/engineering/cloudguruchallenge-your-resume-in-azure
The final output 
 https://www.resume.elston.co.in/
GitHub Link :
https://github.com/ElstonMisquitta88/cloudguru-azure-resume
The main purpo...]]></description><link>https://blog.elston.co.in/cloudguruchallenge-your-resume-in-azure</link><guid isPermaLink="true">https://blog.elston.co.in/cloudguruchallenge-your-resume-in-azure</guid><category><![CDATA[Azure]]></category><category><![CDATA[Microsoft]]></category><dc:creator><![CDATA[Elston Misquitta]]></dc:creator><pubDate>Sat, 08 May 2021 15:08:39 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1638465983797/ELsiLiOeF.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Azure Cloud Resume Challenge</p>
<p> https://acloudguru.com/blog/engineering/cloudguruchallenge-your-resume-in-azure</p>
<p>The final output <br />
 https://www.resume.elston.co.in/</p>
<p>GitHub Link :
https://github.com/ElstonMisquitta88/cloudguru-azure-resume</p>
<p><i>The main purpose of taking the challenge was that I am new to Azure and wanted to learn more  and work on Azure services.
This became quite a learning experience.
Trying out the servies and deploying on a live environment was fun.
</i>
</p>

<p>I have divided the work done into the following steps:</p>
<ol>
<li>Create a Static Website. </li>
<li>Custom Domain for the Website. </li>
<li>Workflow in Github for the static website. </li>
<li>Create a Cosmos DB for saving the website visitor count.</li>
<li>Create a Function to Fetch/Update the visitor count.</li>
<li>Create a KeyValult to save the Cosmos DB connection string.</li>
<li>Workflow in Github for the Function.</li>
<li>Create a simple Unit test for the Function</li>
</ol>
<blockquote>
<h4 id="heading-step-1-create-a-static-website">(Step 1) Create a Static Website</h4>
</blockquote>
<ul>
<li><p>Create a Repository in GitHub.
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618073476109/pGGCFOpm9.png" alt="01_GitHub.png" /></p>
</li>
<li><p>Used a website template from  https://templateflip.com/</p>
</li>
<li><p>Added the files to the GitHub Repository.</p>
</li>
<li><p>Installed GitHub Desktop to create a local clone copy.</p>
</li>
<li><p>In Visual Studio via the Source Control Option - Push any changes in the files to GitHub Repository.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618074220131/6zQuNpe88.png" alt="02_VisualStudioCode.png" /></p>
<ul>
<li>Create a Resource Group on Azure Portal Via CLI</li>
</ul>
<p>Prior to this step you need to install Azure CLI or use Via Cloud Shell in Azure Portal</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618079199593/NmKpkakO3.png" alt="03_CloudShel.png" />
In CMD type (this is to login into azure)</p>
<pre><code>az <span class="hljs-keyword">login</span>
</code></pre><p>You will be redirected to a web page for Azure subscription authentication.</p>
<pre><code>az group create <span class="hljs-operator">-</span><span class="hljs-operator">-</span>location   <span class="hljs-operator">-</span><span class="hljs-operator">-</span>name
az group create <span class="hljs-operator">-</span>l westindia <span class="hljs-operator">-</span>n rg_cg_resume
</code></pre><ul>
<li>Next step is to create a Storage Account</li>
</ul>
<pre><code>az <span class="hljs-keyword">storage</span> account create <span class="hljs-operator">-</span><span class="hljs-operator">-</span>name <span class="hljs-operator">-</span><span class="hljs-operator">-</span>resource<span class="hljs-operator">-</span>group
az <span class="hljs-keyword">storage</span> account create <span class="hljs-operator">-</span><span class="hljs-operator">-</span>name cgresume <span class="hljs-operator">-</span><span class="hljs-operator">-</span>resource<span class="hljs-operator">-</span>group rg_cg_resume <span class="hljs-operator">-</span><span class="hljs-operator">-</span>kind StorageV2 <span class="hljs-operator">-</span><span class="hljs-operator">-</span>access<span class="hljs-operator">-</span>tier hot <span class="hljs-operator">-</span><span class="hljs-operator">-</span>location westindia <span class="hljs-operator">-</span><span class="hljs-operator">-</span>sku Standard_LRS
</code></pre><ul>
<li>In Azure portal navigate to the storage account which you have just created.
In that search for Static Website option is the left hand side blade.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618081572499/vicdBoIiy.png" alt="04.png" /></p>
<p>Enable the static Website and add the name of the default page to be used.
Click on Save.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618081877958/V04Q4RliV.png" alt="05.png" /></p>
<p>After saving the Primary endpoint will be generated. You can use this link to view your website.</p>
<blockquote>
<h4 id="heading-step-2-custom-domain-for-the-website">(Step 2) Custom Domain for the Website</h4>
</blockquote>
<ul>
<li>To assign a custom Domain we will need to create first a CDN profile.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618122237309/ySgb68OZB.png" alt="06_CDN.png" /></p>
<ul>
<li>After creating the CDN Profile you will need to create a Endpoint which will point to the storage account holding the static website.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618122422141/z0CGz1Gwa.png" alt="07_CDN_Endpoint.png" /></p>
<ul>
<li><p>Give a name for the endpoint.</p>
</li>
<li><p>Origin Type - Storage static website</p>
</li>
<li><p>Origin Hostname - Enter the Primary endpoint  which was generated from the storage static website(This will be available to select from the dropdown)</p>
</li>
<li><p>After creation of the  endpoint, after sometime you will be able to view your website 
 via the Endpoint hostname. (<em>This will take some time</em>)</p>
</li>
<li><p>Now we will need to assign your custom domain to the endpoint created.</p>
</li>
<li><p>First create a CNAME record will your domain provider pointing to the Endpoint hostname.</p>
</li>
<li><p>After that create a custom domain entry and save.</p>
</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618124492417/7-Xw0VL0t.png" alt="08_CustomDomain.png" /></p>
<ul>
<li>Next Step is to enable HTTPS for the domain.</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1618141708298/NkdPBb9Ih.png" alt="09_Https_enable.png" /></p>
<p>At this point we have our basic website up and running with Https enabled.</p>
<blockquote>
<h4 id="heading-step-3-workflow-in-github-for-the-static-website">(Step 3) Workflow in Github for the static website</h4>
</blockquote>
<ul>
<li><p>We will create a Workflow in GitHub to publish any changes checked in GitHub.</p>
<p>https://docs.microsoft.com/en-us/azure/storage/blobs/storage-blobs-static-site-github-actions</p>
</li>
<li><p>You need to execute this is Azure CLI</p>
</li>
</ul>
<pre><code>az ad sp create<span class="hljs-operator">-</span><span class="hljs-keyword">for</span><span class="hljs-operator">-</span>rbac <span class="hljs-operator">-</span><span class="hljs-operator">-</span>name {myStaticSite} <span class="hljs-operator">-</span><span class="hljs-operator">-</span>role contributor <span class="hljs-operator">-</span><span class="hljs-operator">-</span>scopes <span class="hljs-operator">/</span>subscriptions<span class="hljs-operator">/</span>{subscription<span class="hljs-operator">-</span>id}<span class="hljs-operator">/</span>resourceGroups<span class="hljs-operator">/</span>{resource<span class="hljs-operator">-</span>group} <span class="hljs-operator">-</span><span class="hljs-operator">-</span>sdk<span class="hljs-operator">-</span>auth
</code></pre><ul>
<li>Replace the placeholders with your subscription ID and resource group name. The output is a JSON object with the role assignment credentials that provide access to your storage account similar to below. Copy this JSON object for later.</li>
</ul>
<pre><code>{
    <span class="hljs-string">"clientId"</span>: <span class="hljs-string">"&lt;GUID&gt;"</span>,
    <span class="hljs-string">"clientSecret"</span>: <span class="hljs-string">"&lt;GUID&gt;"</span>,
    <span class="hljs-string">"subscriptionId"</span>: <span class="hljs-string">"&lt;GUID&gt;"</span>,
    <span class="hljs-string">"tenantId"</span>: <span class="hljs-string">"&lt;GUID&gt;"</span>,
    (...)
  }
</code></pre><ul>
<li><p>Configure the GitHub secret</p>
</li>
<li><p>In GitHub, browse your repository.</p>
</li>
<li><p>Select Settings &gt; Secrets &gt; New secret.</p>
</li>
<li><p>Paste the entire JSON output from the Azure CLI command into the secret's value field. Give the secret a name like AZURE_CREDENTIALS.</p>
</li>
<li><p>Go to Actions for your GitHub repository.</p>
</li>
<li><p>Select Set up your workflow yourself.</p>
</li>
<li><p>The file will appear in the .github/workflows folder of your repository</p>
</li>
</ul>
<pre><code><span class="hljs-attribute">name</span>: Blob storage website CI

<span class="yaml"><span class="hljs-attr">on:</span>
    <span class="hljs-attr">push:</span>
        <span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span>]
    <span class="hljs-attr">pull_request:</span>
        <span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span>]

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">ubuntu-latest</span>
    <span class="hljs-attr">steps:</span>            
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@v2</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">uses:</span> <span class="hljs-string">azure/login@v1</span>
      <span class="hljs-attr">with:</span>
          <span class="hljs-attr">creds:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_CREDENTIALS</span> <span class="hljs-string">}}</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Upload</span> <span class="hljs-string">to</span> <span class="hljs-string">blob</span> <span class="hljs-string">storage</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">azure/CLI@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">azcliversion:</span> <span class="hljs-number">2.0</span><span class="hljs-number">.72</span>
        <span class="hljs-attr">inlineScript:</span> <span class="hljs-string">|
            az storage blob upload-batch --account-name &lt;STORAGE_ACCOUNT_NAME&gt; -d '$web' -s .
</span>    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Purge</span> <span class="hljs-string">CDN</span> <span class="hljs-string">endpoint</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">azure/CLI@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">azcliversion:</span> <span class="hljs-number">2.0</span><span class="hljs-number">.72</span>
        <span class="hljs-attr">inlineScript:</span> <span class="hljs-string">|
           az cdn endpoint purge --content-paths  "/*" --profile-name "CDN_PROFILE_NAME" --name "CDN_ENDPOINT" --resource-group "RESOURCE_GROUP"
</span>
  <span class="hljs-comment"># Azure logout </span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">logout</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">|</span>
            <span class="hljs-string">az</span> <span class="hljs-string">logout</span></span>
</code></pre><ul>
<li>Review your deployment</li>
<li>Go to Actions for your GitHub repository.</li>
<li>Open the first result to see detailed logs of your workflow's run.</li>
</ul>
<blockquote>
<h4 id="heading-step-4-create-a-cosmos-db-for-saving-the-website-visitor-count">(Step 4) Create a Cosmos DB for saving the website visitor count.</h4>
</blockquote>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619369542099/2rxmCnGXZ.png" alt="cosmos.png" /></p>
<blockquote>
<h4 id="heading-step-5-create-a-function-to-fetchupdate-the-visitor-count">(Step 5) Create a Function to Fetch/Update the visitor count</h4>
</blockquote>
<ul>
<li>Create a HTTP Trigger Function via Visual Studio Code. 
In that we will be using Input / Output binding to fetch and update value from Cosmos DB.</li>
</ul>
<pre><code><span class="hljs-keyword">using</span> <span class="hljs-title">Microsoft</span>.<span class="hljs-title">Azure</span>.<span class="hljs-title">WebJobs</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Microsoft</span>.<span class="hljs-title">Azure</span>.<span class="hljs-title">WebJobs</span>.<span class="hljs-title">Extensions</span>.<span class="hljs-title">Http</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Microsoft</span>.<span class="hljs-title">AspNetCore</span>.<span class="hljs-title">Http</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Microsoft</span>.<span class="hljs-title">Extensions</span>.<span class="hljs-title">Logging</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">Newtonsoft</span>.<span class="hljs-title">Json</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">System</span>.<span class="hljs-title">Net</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">System</span>.<span class="hljs-title">Net</span>.<span class="hljs-title">Http</span>;
<span class="hljs-keyword">using</span> <span class="hljs-title">System</span>.<span class="hljs-title">Text</span>;

namespace CustomCounter
{
     <span class="hljs-keyword">public</span> class Counter
    {
        [JsonProperty(PropertyName <span class="hljs-operator">=</span> <span class="hljs-string">"id"</span>)]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> Id {get; set;}

        [JsonProperty(PropertyName <span class="hljs-operator">=</span> <span class="hljs-string">"index"</span>)]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">string</span> index {get; set;}


        [JsonProperty(PropertyName <span class="hljs-operator">=</span> <span class="hljs-string">"Count"</span>)]
        <span class="hljs-keyword">public</span> <span class="hljs-keyword">int</span> Count {get;set;}

    }
    <span class="hljs-keyword">public</span> static class ResumeCounterTrigger
    {
        [FunctionName(<span class="hljs-string">"GetResumeCounter"</span>)]
        <span class="hljs-keyword">public</span> static HttpResponseMessage Run(
            [HttpTrigger(AuthorizationLevel.Anonymous , <span class="hljs-string">"get"</span>, Route <span class="hljs-operator">=</span> null)] HttpRequest req,
                     [CosmosDB(
                    databaseName:<span class="hljs-string">"CloudResume"</span>, 
                    collectionName: <span class="hljs-string">"tblCloudResume"</span>,
                    ConnectionStringSetting <span class="hljs-operator">=</span> <span class="hljs-string">"democosmos_DOCUMENTDB"</span>, 
                    Id <span class="hljs-operator">=</span> <span class="hljs-string">"One"</span>, 
                    PartitionKey <span class="hljs-operator">=</span> <span class="hljs-string">"RecordCount"</span>)] Counter Readcounter,  
                    [CosmosDB(
                        databaseName:<span class="hljs-string">"CloudResume"</span>,
                        collectionName: <span class="hljs-string">"tblCloudResume"</span>,
                        ConnectionStringSetting <span class="hljs-operator">=</span> <span class="hljs-string">"democosmos_DOCUMENTDB"</span>,
                        Id <span class="hljs-operator">=</span> <span class="hljs-string">"One"</span>, 
                        PartitionKey <span class="hljs-operator">=</span> <span class="hljs-string">"RecordCount"</span>)] out Counter updatedCounter,            
            ILogger log)
        {
                log.LogInformation(<span class="hljs-string">"GetResumeCounter was triggered."</span>);
                updatedCounter <span class="hljs-operator">=</span> Readcounter;
                updatedCounter.Count <span class="hljs-operator">+</span><span class="hljs-operator">=</span> <span class="hljs-number">1</span>;
           <span class="hljs-keyword">var</span> jsonToReturn <span class="hljs-operator">=</span> JsonConvert.SerializeObject(updatedCounter);
           <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> HttpResponseMessage(HttpStatusCode.OK)
            {
                Content <span class="hljs-operator">=</span> <span class="hljs-keyword">new</span> StringContent(jsonToReturn, Encoding.UTF8, <span class="hljs-string">"application/json"</span>)
            };
        }
    }
}
</code></pre><ul>
<li>Next a create a function App in the Azure Portal. Have selected consumption based function.</li>
<li>Have enabled Application Insights for the same.</li>
<li>You also have to enable CORS (use the URL of the static website) to use the function.</li>
</ul>
<blockquote>
<h4 id="heading-step-6-create-a-keyvalult-to-save-the-cosmos-db-connection-string">(Step 6) Create a KeyValult to save the Cosmos DB connection string</h4>
</blockquote>
<ul>
<li>In order to prevent the Cosmos DB connection string in the function to be plain text we will be using KeyValult by creating a secret.</li>
</ul>
<p>https://docs.microsoft.com/en-us/azure/key-vault/secrets/quick-create-portal</p>
<p>Additional steps to be done </p>
<ul>
<li>Enable Managed Identify in Azure Functions
https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619371224750/z4_L5vSmX.png" alt="01_Function_Identity.png" /></p>
<ul>
<li>In Key vault add access policy for the created Identity</li>
</ul>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619371323199/3q2WkfVMX.png" alt="02+keyvalult.png" /></p>
<ul>
<li>Finally in the function, in Application Settings add the value for the Cosmos DB connection string.</li>
</ul>
<p>https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1619376438651/m7J6ZluxE.png" alt="03_Functions.png" /></p>
<blockquote>
<h4 id="heading-step-7-workflow-in-github-for-the-function">(Step 7) Workflow in Github for the Function.</h4>
<ul>
<li>We will create a workflow for publishing Function code to the Function app.</li>
</ul>
</blockquote>
<pre><code><span class="hljs-attribute">name</span>: WebSiteFunctions

<span class="yaml"><span class="hljs-comment"># Deploy push made from Functions folder.</span>
<span class="hljs-attr">on:</span>
  <span class="hljs-attr">push:</span>
        <span class="hljs-attr">branches:</span> [ <span class="hljs-string">main</span> ]
        <span class="hljs-attr">paths:</span>
        <span class="hljs-bullet">-</span> <span class="hljs-string">'Functions/**'</span>


<span class="hljs-comment"># CONFIGURATION</span>
<span class="hljs-comment"># For help, go to https://github.com/Azure/Actions</span>
<span class="hljs-comment"># 1. Paste the RBAC json into the following secret in your repository:</span>
<span class="hljs-comment">#   AZURE_RBAC_CREDENTIALS</span>
<span class="hljs-comment"># 2. Change these variables for your configuration:</span>

<span class="hljs-attr">env:</span>
  <span class="hljs-attr">AZURE_FUNCTIONAPP_NAME:</span> <span class="hljs-string">&lt;Function</span> <span class="hljs-string">App</span> <span class="hljs-string">Name&gt;</span>  
  <span class="hljs-attr">AZURE_FUNCTIONAPP_PACKAGE_PATH:</span> <span class="hljs-string">'&lt;path to your web app project, defaults to the repository root&gt;'</span>  
  <span class="hljs-attr">DOTNET_VERSION:</span> <span class="hljs-string">'3.1'</span>    <span class="hljs-comment"># dotnet version</span>

<span class="hljs-attr">jobs:</span>
  <span class="hljs-attr">build-and-deploy:</span>
    <span class="hljs-attr">runs-on:</span> <span class="hljs-string">windows-latest</span>
    <span class="hljs-attr">steps:</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">'Checkout GitHub Action'</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/checkout@master</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">'Login via Azure CLI'</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">azure/login@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">creds:</span> <span class="hljs-string">${{</span> <span class="hljs-string">secrets.AZURE_CREDENTIALS</span> <span class="hljs-string">}}</span>

    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">Setup</span> <span class="hljs-string">DotNet</span> <span class="hljs-string">${{</span> <span class="hljs-string">env.DOTNET_VERSION</span> <span class="hljs-string">}}</span> <span class="hljs-string">Environment</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">actions/setup-dotnet@v1</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">dotnet-version:</span> <span class="hljs-string">${{</span> <span class="hljs-string">env.DOTNET_VERSION</span> <span class="hljs-string">}}</span>

  <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">'Run dotnet'</span>
      <span class="hljs-attr">shell:</span> <span class="hljs-string">pwsh</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">|
        pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/API'
        dotnet build --configuration Release --output ./output
        popd
</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">'Run Unit Test'</span>
      <span class="hljs-attr">shell:</span> <span class="hljs-string">pwsh</span>
      <span class="hljs-attr">run:</span> <span class="hljs-string">| 
        pushd './${{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}/Test'
        dotnet test
</span>
    <span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">'Run Azure Functions Action'</span>
      <span class="hljs-attr">uses:</span> <span class="hljs-string">Azure/functions-action@v1</span>
      <span class="hljs-attr">id:</span> <span class="hljs-string">fa</span>
      <span class="hljs-attr">with:</span>
        <span class="hljs-attr">app-name:</span> <span class="hljs-string">${{</span> <span class="hljs-string">env.AZURE_FUNCTIONAPP_NAME</span> <span class="hljs-string">}}</span>
        <span class="hljs-attr">package:</span> <span class="hljs-string">'$<span class="hljs-template-variable">{{ env.AZURE_FUNCTIONAPP_PACKAGE_PATH }}</span>/API/output'</span></span>
</code></pre><blockquote>
<h4 id="heading-step-8-create-a-simple-unit-test-for-the-function">(Step 8) Create a simple Unit test for the Function</h4>
</blockquote>
<p>https://madebygps.com/how-to-use-xunit-with-azure-functions/</p>
<p>https://docs.microsoft.com/en-us/azure/azure-functions/functions-test-a-function#c-in-visual-studio</p>
]]></content:encoded></item></channel></rss>