<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michał Żołnieruk</title>
    <description>The latest articles on DEV Community by Michał Żołnieruk (@miszu).</description>
    <link>https://dev.to/miszu</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F775065%2F92efa9dc-1bc9-46ef-a639-57593068881e.jpg</url>
      <title>DEV Community: Michał Żołnieruk</title>
      <link>https://dev.to/miszu</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/miszu"/>
    <language>en</language>
    <item>
      <title>Handling expired Azure Blob Storage links in a user-friendly way</title>
      <dc:creator>Michał Żołnieruk</dc:creator>
      <pubDate>Thu, 16 Dec 2021 10:50:58 +0000</pubDate>
      <link>https://dev.to/miszu/handling-expired-azure-blob-storage-links-in-a-user-friendly-way-3n75</link>
      <guid>https://dev.to/miszu/handling-expired-azure-blob-storage-links-in-a-user-friendly-way-3n75</guid>
      <description>&lt;p&gt;&lt;strong&gt;📝 Use case:&lt;/strong&gt; your app hosts files in Azure Blob Storage and users can generate expiring links to these files (using SAS tokens)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🤕 Problem:&lt;/strong&gt; when a user opens a link with an expired SAS token, an unfriendly XML is displayed containing a technical error&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;😊 Solution:&lt;/strong&gt; proxy the link with SAS token through an endpoint (Azure Function in my case), which will either redirect to the file (if the token is still valid) or show a descriptive error message&lt;/p&gt;




&lt;p&gt;Recently &lt;a href="https://apps.apple.com/be/app/co-z-tym-seksem/id1526700597"&gt;the sex education app&lt;/a&gt; which we’ve created together with &lt;a href="https://www.instagram.com/kasia_coztymseksem"&gt;Kasia Koczułap&lt;/a&gt;, &lt;a href="https://www.linkedin.com/in/m-majch/"&gt;Marek Majchrzak&lt;/a&gt; and &lt;a href="https://www.linkedin.com/in/rczemerys/"&gt;Radek Czemerys&lt;/a&gt; had a requirement to generate expiring links to files. As we store our files in Azure Blob Storage, using &lt;a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-sas-overview"&gt;SAS tokens&lt;/a&gt; was an obvious choice — for each file requested, our backend generates a link with SAS token valid for 30 minutes:&lt;/p&gt;

&lt;p&gt;https://{blobPath}?sv=2019-02-02&amp;amp;sr=b&amp;amp;sig=6KHcOyMni6PTld/V0WUojJO2ORxcDVdgRgIklH0hV5k=&amp;amp;se=2021-01-10T20:32:58Z&amp;amp;sp=r&lt;/p&gt;

&lt;h4&gt;
  
  
  It works great when the token is valid, but here’s what the user sees after opening an expired link:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6dvwM4HT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nh8jngn44ousagspvsb1.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6dvwM4HT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nh8jngn44ousagspvsb1.jpeg" alt="Expired Azure Blob Storage link error" width="800" height="800"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;More technical users may figure out that the link expired. Others may think that the app is broken or the link got corrupted during copying.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Not only this page does not explain what happened — it also does not provide the next steps.&lt;/strong&gt; Users may feel lost and in effect, they may leave a bad review or ask support for help, even though they could fix this situation by regenerating the link.&lt;/p&gt;

&lt;h3&gt;
  
  
  Fixing the flow
&lt;/h3&gt;

&lt;p&gt;A better UX would be to show a clear &amp;amp; detailed error message in case the link expired. The way I approached this in our app was to proxy the original link with SAS token through a new &lt;strong&gt;HTTP Triggered Azure Function&lt;/strong&gt;. This function checks whether the token is still valid and if yes, then simply redirects to the file. Otherwise, it returns a simple HTML page with a descriptive message.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lGccHI45--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyp5rb06fgbj3tx4n58t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lGccHI45--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qyp5rb06fgbj3tx4n58t.png" alt="Proposed flow of handling the expired blob storage link with Azure Functions" width="880" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fact that I’ve used Azure Function does not mean you can not use the same logic in your WebAPI endpoints (or whatever else you’re using). For us Azure Function was an obvious choice, as we use them heavily in our project 🏋🏻‍♀️&lt;/p&gt;

&lt;h3&gt;
  
  
  How to detect link expiration?
&lt;/h3&gt;

&lt;p&gt;You may have noticed that the link with SAS token has a few parameters:&lt;/p&gt;

&lt;p&gt;https://{blobPath}?sv=2019-02-02&amp;amp;sr=b&amp;amp;sig=6KHcOyMni6PTld/V0WUojJO2ORxcDVdgRgIklH0hV5k=&amp;amp;se=2021-01-10T20:32:58Z&amp;amp;sp=r&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;sv=2019–02–02&lt;/strong&gt; is a version of the API which was used to generate this SAS token&lt;br&gt;&lt;br&gt;
&lt;strong&gt;sr=b&lt;/strong&gt; means that the SAS token was created for a &lt;strong&gt;blob&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
&lt;strong&gt;sig&lt;/strong&gt; is the signature of the token&lt;br&gt;&lt;br&gt;
&lt;strong&gt;sp=r&lt;/strong&gt; means that the token is valid only for &lt;strong&gt;reading&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;… and:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;se=&lt;/strong&gt;2021–01–10T20:32:58Z, which specifies the moment when the SAS token expires. So in order to verify that the token is still valid, we just need to check whether the &lt;strong&gt;se&lt;/strong&gt; parameter contains a date which is in the future — easy peasy! ✨&lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;strong&gt;Code&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;Here’s a proof of concept of all of the stuff described above. If you’d like to run it or you’d need the list of nugets used, check out the full project here: &lt;a href="https://github.com/miszu/expire-sas-token-handling"&gt;https://github.com/miszu/expire-sas-token-handling&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Let me know if you have any doubts or questions. If something above was useful to you, I’d be extremely grateful for any feedback you may have. Good luck with whatever you’re doing! 🙌🏻&lt;/p&gt;

&lt;p&gt;Follow me on Twitter for more insights about Azure 🚀&lt;br&gt;
&lt;/p&gt;
&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--eiDNGXSY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/803944887972466688/bTgspKkb_normal.jpg" alt="Michał Żołnieruk profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Michał Żołnieruk
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @michalzolnieruk
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Your app generates &lt;a href="https://twitter.com/hashtag/Azure"&gt;#Azure&lt;/a&gt; Blob Storage links using SAS tokens? Here's how you can show a descriptive expiration message to your users 👨‍💻 (instead of a harsh XML error) &lt;a href="https://t.co/vg79tfeD7H"&gt;miszu.medium.com/handling-expir…&lt;/a&gt; &lt;a href="https://twitter.com/AzureFunctions"&gt;@AzureFunctions&lt;/a&gt;  &lt;a href="https://twitter.com/hashtag/Microsoft365Dev"&gt;#Microsoft365Dev&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/azurefunctions"&gt;#azurefunctions&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      08:03 AM - 11 Feb 2021
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1359775045640474627" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1359775045640474627" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1359775045640474627" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


</description>
      <category>azure</category>
      <category>azurefunctions</category>
      <category>blobstorage</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating a VR experience for an art exhibition</title>
      <dc:creator>Michał Żołnieruk</dc:creator>
      <pubDate>Thu, 16 Dec 2021 10:50:55 +0000</pubDate>
      <link>https://dev.to/miszu/creating-a-vr-experience-for-an-art-exhibition-3787</link>
      <guid>https://dev.to/miszu/creating-a-vr-experience-for-an-art-exhibition-3787</guid>
      <description>&lt;p&gt;In 2018 a close friend of me — &lt;a href="https://jagnanawrocka.wixsite.com/portfolio"&gt;Jagna Nawrocka&lt;/a&gt; (make sure to check out the portfolio) — was creating an art piece for the &lt;a href="http://www.survival.art.pl/"&gt;Survival&lt;/a&gt; exhibition in Wrocław. She asked me to help out with the technical side of the project and even though my experience with VR was not existent, I was excited to give it a go.&lt;/p&gt;

&lt;p&gt;The event takes place each year in unique places across the city and the 16th edition was no exception — artists were invited to fill the space of &lt;a href="https://visitwroclaw.eu/en/place/palace-of-the-wallenberg-pachaly-family"&gt;&lt;em&gt;Wallenberg-Pachaly Palace&lt;/em&gt;&lt;/a&gt;, a classicist gem from the XVIII century located right in the city centre.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SqVe64K9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pa2lpzr8swttf58jp0mr.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SqVe64K9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pa2lpzr8swttf58jp0mr.jpeg" alt="Wallenberg-Pachaly Palace in Wrocław" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  What we wanted to do
&lt;/h3&gt;

&lt;p&gt;The exhibition’s theme was “&lt;strong&gt;Capital”&lt;/strong&gt;. Jagna envisioned an experience in which visitors physically located inside of an empty, grey room of the Palace (the building is not used at the moment) could be taken into &lt;a href="https://en.wikipedia.org/wiki/Amber_Room"&gt;The Amber Room&lt;/a&gt; — a historical chamber filled with, well, amber and gold of tremendous value, once considered an Eighth Wonder of the World.&lt;/p&gt;

&lt;p&gt;The current whereabouts of the original room remain unknown and although reconstruction of it is open for visitors in Russia, it’s fair to say that the actual Amber Room resides mostly in people’s minds — as a symbol of lost wealth which disappeared in mysterious circumstances.&lt;/p&gt;

&lt;p&gt;The plan was to create a 3D space with two connected rooms — one grey, with textures based on black and white photographs of the original Amber Room. The other one similar, but with coloured pictures. Visitors would start the experience in the grey room and after some time would be “allowed” into the golden room — by flying through a mirror — as simple as that ✨&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S5qN2WUB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpe8glfgzxdy8je266ig.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S5qN2WUB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xpe8glfgzxdy8je266ig.png" alt="VR Scene used in the app" width="800" height="534"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical requirements
&lt;/h3&gt;

&lt;p&gt;After a few discussions with Jagna, we’ve agreed upon the most important technical requirements of our solution — it had to be:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Cheap&lt;/strong&gt; — we had no budget to spend, so using a fancy VR set like Oculus Rift was out of the question&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Accessible&lt;/strong&gt;— this particular exhibition is visited by hundreds of people daily, often in quick waves, so we had to find a way for many people to be able to experience the art piece at once&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Maintenance-free —&lt;/strong&gt; the exhibition lasted few days and we were not able to be on-site all the time, so we hoped to create something which does not need anyone to operate the equipment or explain how it works.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Web VR to the rescue
&lt;/h3&gt;

&lt;p&gt;After considering a few possible frameworks which allow creating VR stuff (including Unity — &lt;a href="https://medium.com/@miszu/your-first-cardboard-vr-experience-in-unity-3d-f61c102d4de9"&gt;check out my other article to see how to use it&lt;/a&gt;), I’ve stumbled upon something I haven’t considered — a web VR framework called &lt;a href="https://aframe.io"&gt;&lt;strong&gt;A-Frame&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt;.&lt;/strong&gt; After checking it out roughly, it turned out to be perfect for our use-case, mostly because:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; It’s &lt;strong&gt;simple&lt;/strong&gt; — going from zero to a nice, interactive scene is really fast (thanks to the fact that there’s plenty of examples, documentation is decent and that the framework is based on HTML and a component approach)&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;The app is a website&lt;/strong&gt; — the experience can be hosted online and users can view it on their devices — there’s no need for fancy VR sets or human-assistance on-site.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Coming up with the code
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;The full solution&amp;amp;demo is here: &lt;a href="https://github.com/miszu/vr-amber-room"&gt;https://github.com/miszu/vr-amber-room&lt;/a&gt;, feel free to ask questions if something is not working for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As I mentioned, A-Frame is a web framework— all 3D objects, components, animations, scripts &lt;em&gt;et cetera&lt;/em&gt; are defined in HTML and JavaScript. &lt;strong&gt;Our app was not complicated and in total it ended up being just 83 lines of HTML, plus some images.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We needed to create a 3D scene with 2 rooms. Designing in A-Frame is quite straight forward, as the framework provides a tool called &lt;strong&gt;Inspector&lt;/strong&gt; (&lt;em&gt;ctrl+option+i&lt;/em&gt;), which is an interactive scene editor. We’ve added all of the needed planes (floors, walls, mirrors, ceilings), and then imported textures for each of them (Jagna has prepared them based on actual photographs of the Amber Room).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BqR8avo9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yf4qa8adebbs4l13znyy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BqR8avo9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yf4qa8adebbs4l13znyy.png" alt="Amber Room recreated in a VR scene" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As for the movement, we’ve decided that users will be able to fly around both rooms, but in a limited manner — if they hold their gaze at one of the circles on the ground (called &lt;strong&gt;checkpoints&lt;/strong&gt; — see the code snippet below to see how it’s configured), they would fly there to see the scene from that perspective.&lt;/p&gt;

&lt;blockquote&gt;

&lt;/blockquote&gt;

&lt;p&gt;Between two rooms there are mirrors — we’ve used them to create a “portal” between them. We wanted the coloured room to be accessible only after some delay, so to each mirror (which connect the rooms) we’ve added two animations — first one is making the mirrors disappear after &lt;strong&gt;10&lt;/strong&gt; seconds, the other one moves them out of the way (that was needed because hidden objects are blocking the gaze-based movement).&lt;/p&gt;

&lt;blockquote&gt;

&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Going public
&lt;/h3&gt;

&lt;p&gt;Okay, the code was ready — how did we make it available for the visitors of the exhibition?&lt;/p&gt;

&lt;p&gt;Thanks to the fact that the app was basically a website, we just needed to host it somewhere. I’ve decided to go simple and use GitHub pages for it, which is a really reasonable hosting option for small apps. The process is simple:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  push the code to GitHub’s repository&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://docs.github.com/en/github/working-with-github-pages/configuring-a-publishing-source-for-your-github-pages-site"&gt;enable GithHub pages&lt;/a&gt; for that repository, which deploys the website to a public endpoint (in our case &lt;a href="https://miszu.github.io/vr-amber-room/"&gt;https://miszu.github.io/vr-amber-room/&lt;/a&gt; — you can visit it on your mobile phone right now and try it out 🤞🏼)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then, to make it accessible for the visitors, on-site of the exhibition we’ve provided:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  few QR codes pointing to the GitHub Pages deployment&lt;/li&gt;
&lt;li&gt;  a few pairs of cheap VR cardboards (we got some from Flying Tiger for about 2 euros for a pair)&lt;/li&gt;
&lt;li&gt;  a few copies of step-by-step instructions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BNLoQ9ln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6ad4u0txecp7yff28ka.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BNLoQ9ln--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/t6ad4u0txecp7yff28ka.png" alt="Image of the phone running our VR experience" width="800" height="533"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  How did the exhibition go?
&lt;/h3&gt;

&lt;p&gt;I was not there to see it sadly (fun fact — I was in Saint Petersburg back then and I got to see the reconstruction of the Amber Room), but from what I’ve heard it was quite a success — a lot of people were visiting “our” room and trying the VR experience on their phones.&lt;/p&gt;

&lt;p&gt;One more cool thing about web-based VR apps is that one can add Google Analytics to track the usage — thanks to that I know that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  On the first day of the exhibition, 123 phones opened our app. The actual number of people experiencing was much higher for sure, as people were sharing phones&lt;/li&gt;
&lt;li&gt;  In total, more than 400 phones opened it during the exhibition&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pP3pcrv4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnenlbzocarojy2yq2e4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pP3pcrv4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hnenlbzocarojy2yq2e4.png" alt="Google Analytics stats for the usage of our VR app on the exhibition" width="800" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In general, I really loved the experience of using new tech for creating something artsy and can’t wait to do it again — maybe AR next, who knows? &lt;strong&gt;Let me know if you’d like to create something together! 🎨&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you’ve learned something new here and/or found the topic interesting, make sure to let me know, I'd really appreciate it 👏🏻 Follow me on Twitter for more insights about VR and other tech 🚀&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--eiDNGXSY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/803944887972466688/bTgspKkb_normal.jpg" alt="Michał Żołnieruk profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Michał Żołnieruk
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @michalzolnieruk
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      Some time ago I helped my friend (Jagna Nawrocka) to create a VR experience for the Survival Art Review in Wrocław - check out how we've used &lt;a href="https://twitter.com/aframevr"&gt;@aframevr&lt;/a&gt; to put people inside of the Amber Room (code&amp;amp;demo included) 🎨 &lt;a href="https://twitter.com/hashtag/VirtualReality"&gt;#VirtualReality&lt;/a&gt; &lt;a href="https://twitter.com/hashtag/aframe"&gt;#aframe&lt;/a&gt; &lt;a href="https://t.co/SZ8IJZG38S"&gt;link.medium.com/vBklExTPH8&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      15:30 PM - 05 Aug 2020
    &lt;/div&gt;


    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1291033754899820545" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1291033754899820545" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1291033754899820545" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


</description>
      <category>vr</category>
      <category>aframe</category>
      <category>art</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Pausing UIImageView animation in Xamarin.iOS</title>
      <dc:creator>Michał Żołnieruk</dc:creator>
      <pubDate>Thu, 16 Dec 2021 10:50:52 +0000</pubDate>
      <link>https://dev.to/miszu/pausing-uiimageview-animation-in-xamarinios-ki1</link>
      <guid>https://dev.to/miszu/pausing-uiimageview-animation-in-xamarinios-ki1</guid>
      <description>&lt;p&gt;First things first — did you know that you can use UIImage to show frame-by-frame animations? It’s actually quite straight forward, all you need to do is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Prepare your frames in png format, name them using an ordering convention (for example “Frame1.png”, “Frame2.png”, …)&lt;/li&gt;
&lt;li&gt;Add these images to your Xamarin.iOS project, let’s say to Resources/Animation folder&lt;/li&gt;
&lt;li&gt;Make sure all of your images are referenced as BundleResource in your csproj:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;ItemGroup&amp;gt;  
  &amp;lt;BundleResource Include="Resources\\Animation\\\*.png" /&amp;gt;  
&amp;lt;/ItemGroup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Load your images as UIImage and pass them to the UIImageView using &lt;a href="https://developer.apple.com/documentation/uikit/uiimageview/1621068-animationimages"&gt;AnimationImages&lt;/a&gt; property:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Add animatedImageView to your controller and here’s what you will see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/Bjfjjyu2qDZyMe2XF5/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/Bjfjjyu2qDZyMe2XF5/giphy.gif" alt="UIImageView animation running on iPhone simualator" width="480" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, it’s alive! 🧟‍♂️ What if you’d like to pause the animation on tap and then resume it after another tap? Sadly, there’s no API for this in the UIImageView, but there is a way to accomplish it using UIImageView’s Layer.&lt;/p&gt;

&lt;p&gt;I’ve found it described in one of the &lt;a href="https://developer.apple.com/library/archive/qa/qa1673/_index.html"&gt;Technical Q&amp;amp;As on developer.apple.com&lt;/a&gt;. This Objective C code may not be so easy to rewrite to C#, especially if you’re just getting started, so below is a working solution in Xamarin.iOS. You may want to polish the code a bit (extracting StopAnimation/StartAnimation extension methods may be a good start).&lt;/p&gt;

&lt;p&gt;Now you should be able to pause/resume the animation with taps:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://i.giphy.com/media/ocRKjbU5yw5bF3nbcq/giphy.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://i.giphy.com/media/ocRKjbU5yw5bF3nbcq/giphy.gif" alt="Animation can now be paused with a tap" width="480" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to add my frames as iOS Assets? It’s kind of tedious with so many files!&lt;/strong&gt;&lt;br&gt;
No, you can just drag and drop the whole folder to Resources, remember to reference files as BundleResource.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The animation is not pausing when I tap it, what’s wrong?&lt;/strong&gt;&lt;br&gt;
You might have forgotten to set UserInteractionEnabled to true on the UIImageView.&lt;/p&gt;

&lt;p&gt;I hope that this quick tutorial was helpful to you. Let me know if something is not clear. Follow me on Twitter for more insights about mobile dev and other tech 🚀&lt;/p&gt;


&lt;blockquote class="ltag__twitter-tweet"&gt;

  &lt;div class="ltag__twitter-tweet__main"&gt;
    &lt;div class="ltag__twitter-tweet__header"&gt;
      &lt;img class="ltag__twitter-tweet__profile-image" src="https://res.cloudinary.com/practicaldev/image/fetch/s--eiDNGXSY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://pbs.twimg.com/profile_images/803944887972466688/bTgspKkb_normal.jpg" alt="Michał Żołnieruk profile image"&gt;
      &lt;div class="ltag__twitter-tweet__full-name"&gt;
        Michał Żołnieruk
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__username"&gt;
        @michalzolnieruk
      &lt;/div&gt;
      &lt;div class="ltag__twitter-tweet__twitter-logo"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ir1kO05j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-f95605061196010f91e64806688390eb1a4dbc9e913682e043eb8b1e06ca484f.svg" alt="twitter logo"&gt;
      &lt;/div&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__body"&gt;
      My first Xamarin article got featured on WeeklyXamarin, thanks &lt;a href="https://twitter.com/kphillpotts"&gt;@kphillpotts&lt;/a&gt; 🙌🏻 if you’re interested, here it is - &lt;a href="https://t.co/8HJu8T64wA"&gt;link.medium.com/UHpfxNXDZeb&lt;/a&gt; &lt;a href="https://t.co/OmGpsI8vLu"&gt;twitter.com/kphillpotts/st…&lt;/a&gt;
    &lt;/div&gt;
    &lt;div class="ltag__twitter-tweet__date"&gt;
      07:05 AM - 01 Apr 2021
    &lt;/div&gt;

      &lt;div class="ltag__twitter-tweet__quote"&gt;
        &lt;div class="ltag__twitter-tweet__quote__header"&gt;
          &lt;span class="ltag__twitter-tweet__quote__header__name"&gt;
            Kym Phillpotts
          &lt;/span&gt;
          @kphillpotts
        &lt;/div&gt;
        You slack off for one week and before you know it, WeeklyXamarin has 40 articles.

Make sure to check out the Easter Edition: https://t.co/0ARPoNcw4v https://t.co/Npf2nyzpX6
      &lt;/div&gt;

    &lt;div class="ltag__twitter-tweet__actions"&gt;
      &lt;a href="https://twitter.com/intent/tweet?in_reply_to=1377517382252498944" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fFnoeFxk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-reply-action-238fe0a37991706a6880ed13941c3efd6b371e4aefe288fe8e0db85250708bc4.svg" alt="Twitter reply action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/retweet?tweet_id=1377517382252498944" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--k6dcrOn8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-retweet-action-632c83532a4e7de573c5c08dbb090ee18b348b13e2793175fea914827bc42046.svg" alt="Twitter retweet action"&gt;
      &lt;/a&gt;
      &lt;a href="https://twitter.com/intent/like?tweet_id=1377517382252498944" class="ltag__twitter-tweet__actions__button"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SRQc9lOp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/twitter-like-action-1ea89f4b87c7d37465b0eb78d51fcb7fe6c03a089805d7ea014ba71365be5171.svg" alt="Twitter like action"&gt;
      &lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/blockquote&gt;


</description>
      <category>xamarin</category>
      <category>xamarinforms</category>
      <category>ios</category>
      <category>mobile</category>
    </item>
    <item>
      <title>How to create a Telegram Bot with Azure Functions (NET 6, isolated process)</title>
      <dc:creator>Michał Żołnieruk</dc:creator>
      <pubDate>Wed, 15 Dec 2021 16:53:25 +0000</pubDate>
      <link>https://dev.to/miszu/how-to-create-a-telegram-bot-with-azure-functions-net-6-isolated-process-4dal</link>
      <guid>https://dev.to/miszu/how-to-create-a-telegram-bot-with-azure-functions-net-6-isolated-process-4dal</guid>
      <description>&lt;p&gt;I’ve written about hosting a python based Telegram bot &lt;a href="https://www.codingwithmiszu.com/2021/12/06/host-a-python-telegram-bot-on-azure-in-30-minutes/" rel="noopener noreferrer"&gt;here&lt;/a&gt; before. This time we’ll take look at doing it with NET 6, C#, Azure Functions V4 and the still fresh execution mode called isolated process. In this mode, each function runs in a separate environment.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/miszu/IsolatedAzureFunctionsTelegramBot" rel="noopener noreferrer"&gt;GitHub repo with the full solution&lt;br&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What we’ll cover&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;creating a sample Azure Functions project and deploying it to your Azure subscription&lt;/li&gt;
&lt;li&gt;creating a Telegram Bot and using it in a webhook configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Prerequisites&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;NET 6 installed&lt;/li&gt;
&lt;li&gt;Azure Functions Core tools 4 installed&lt;/li&gt;
&lt;li&gt;Azure CLI installed&lt;/li&gt;
&lt;li&gt;Azure subscription created&lt;/li&gt;
&lt;li&gt;An IDE may be useful, I’m using Visual Studio Code&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Check out this article for step by step instructions – &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-csharp" rel="noopener noreferrer"&gt;https://docs.microsoft.com/en-us/azure/azure-functions/create-first-function-cli-csharp&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Setting up and deploying blank Azure Functions project
&lt;/h2&gt;

&lt;p&gt;We’ll first create the blank Azure Functions project with a sample HTTP Trigger&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;func init TelegramFunctions --worker-runtime dotnet-isolated
cd TelegramFunctions
func new --name SetUpBot --template "HTTP trigger" --authlevel "anonymous"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The above commands should create all necessary files to run the functions. There’s one manual step you need to do to use the V4 Azure Functions. Open the .csproj file in the TelegramFunctions folder and bump the version manually from v3 to:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;lt;AzureFunctionsVersion&amp;gt;v4&amp;lt;/AzureFunctionsVersion&amp;gt;&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Now you should be ready to run the Functions, do it with this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;func start&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the output, you should see a link to the sample HTTP trigger function called ‘SetUpBot’. It was created above with the func new command. Open the link to make sure that the Function is working properly:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm26uuy1l38q7y419ku2q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fm26uuy1l38q7y419ku2q.png" alt="Image Azure Functions working as expected"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Perfect! 🎊 Now let’s deploy it online. Before doing that, we first need to prepare the needed resources in Azure. Run the following scripts (make sure to update the parameters to your own names):&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;az login

// below creates a resource group in a specified location
az group create --name RESOURCE_GROUP_NAME --location germanywestcentral

// below creates a storage account needed to set up the functions
az storage account create --name STORAGE_ACCOUNT_NAME --location germanywestcentral --resource-group RESOURCE_GROUP_NAME --sku Standard_LRS

// below creates the functions app on a Consumption plan with isolated execution mode
az functionapp create --resource-group RESOURCE_GROUP_NAME --consumption-plan-location germanywestcentral --runtime dotnet-isolated --functions-version 4 --name FUNCTIONS_APP_NAME  --storage-account STORAGE_ACCOUNT_NAME
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;… and then we’ll deploy our project:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;func azure functionapp publish FUNCTIONS_APP_NAME&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;If everything went well (hopefully), in the output you’ll see the link to your publicly available Azure Function – after opening it in your browser, you should see the exact same output as when running it locally. Your sample function is officially alive 🎉&lt;/p&gt;
&lt;h2&gt;
  
  
  Creating a Telegram bot
&lt;/h2&gt;

&lt;p&gt;To start using the bot, we first need to create it, which is super easy:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Open the Telegram app on any device and start a conversation with @ botfather&lt;/li&gt;
&lt;li&gt;Send this command: /newbot&lt;/li&gt;
&lt;li&gt;Answer his questions about the bot’s name and handle&lt;/li&gt;
&lt;li&gt;He’ll responsd with the bot’s token similar to the one below:&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;20323326:AAHgxV73CgPNKxc9lEWa_2XpZ10mf&lt;/p&gt;

&lt;p&gt;We’ll use it in the next steps. Make sure to keep it safe, anyone who has access to it can fully control your bot! 🚨&lt;/p&gt;
&lt;h2&gt;
  
  
  Telegram integration
&lt;/h2&gt;

&lt;p&gt;To make things easier, we’ll use the Telegram.Bot nuget for communication with the Telegram services. Add it to your project with this command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;dotnet add package Telegram.Bot --version 17.0.0&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
Now we’re ready to create 2 HTTP Triggered Azure Functions, we’ll do it in the SetUpBot.cs file which you should already have in your project folder.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;/&lt;strong&gt;setup&lt;/strong&gt; – the first function will setup our bot to operate in a webhooks mode. This means that whenever anyone interacts with the bot, Telegram will send a POST request to the endpoint we specify (as you can see below, we specify the link to the second function, &lt;strong&gt;handleupdate&lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;/&lt;strong&gt;handleupdate&lt;/strong&gt; – this function receives the Update object from Telegram services and reacts accordingly. All of the messages, replies, images etc will arrive to this endpoint. For the purposes of this tutorial, we’ll try to evaluate user’s message as a math expression and will return the result&lt;/li&gt;
&lt;/ul&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;



&lt;p&gt;Both functions are using the _botClient instance, which is created in the class constructor and uses the bot token from the environment variables.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;When functions are run locally, you can specify the value for the TelegramBotToken variable in the local.settings.json file. For the deployed Functions app, you can configure it with the below command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az functionapp config appsettings set --name FUNCTIONS_APP_NAME --resource-group RESOURCE_GROUP_NAME --settings "TelegramBotToken=YOUR_BOT_TOKEN"&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Let’s talk
&lt;/h2&gt;

&lt;p&gt;Deploy the updated project with the same command as before:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;func azure functionapp publish FUNCTIONS_APP_NAME&lt;br&gt;
&lt;/code&gt;&lt;br&gt;
In the output, you’ll see 2 links to our Functions – before talking to the bot, we first need to open the /setup link, which will configure the bot to call our second function.&lt;/p&gt;

&lt;p&gt;Then we should be ready to get some answers from the bot. Start a conversation with it on Telegram and either try to ask some math questions or try to recreate the Space Oddysey scene (at your own risk!) ☺️&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76h46rgll1js1su49mih.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F76h46rgll1js1su49mih.png" alt="Screenshot of a Telegram Bot reacting to our messages"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Things are working as expected, that’s great! I’m positively surprised how fast the interaction is – the questions go through and back the Telegram API &amp;amp; Azure in a blink of an eye as you can see above 👁&lt;/p&gt;
&lt;h2&gt;
  
  
  Clean up
&lt;/h2&gt;

&lt;p&gt;After you’re done, make sure to remove the Azure resources you’ve created, you don’t want to pay for the resources that you don’t use. Deleting the whole resource group can be done with the following command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;az group delete --name RESOURCE_GROUP_NAME&lt;/code&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Where to go from here
&lt;/h2&gt;

&lt;p&gt;Now that you know how to use Azure Functions as the brain for your bots, diving deeper into documentations might give you some nice ideas on what to do next. The API is quite rich, you can create pools, send locations, even accept payments or validate user’s identity with &lt;a href="https://telegram.org/blog/passport" rel="noopener noreferrer"&gt;Telegram Passport&lt;/a&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://core.telegram.org/bots" rel="noopener noreferrer"&gt;Bots: An introduction for developers&lt;/a&gt; (official Telegram website)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://telegrambots.github.io/book/" rel="noopener noreferrer"&gt;Telegram.Bot nuget documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Also before deploying your Bot, it might be wise to think twice about the security of your API. The &lt;strong&gt;setup&lt;/strong&gt; function above should probably be authenticated with a &lt;a href="https://docs.microsoft.com/en-us/azure/azure-functions/security-concepts" rel="noopener noreferrer"&gt;Function access key&lt;/a&gt;. The &lt;strong&gt;handleupdate&lt;/strong&gt; function could also have a password/token in the URL, to make sure that the request comes from Telegram services.&lt;/p&gt;

&lt;p&gt;Let me know if you’d have any questions/problems with creating the bots with Azure Functions, I’d be happy to help 🚀&lt;/p&gt;

&lt;p&gt;Follow me on Twitter for more insights about Azure 🚀&lt;br&gt;
&lt;iframe class="tweet-embed" id="tweet-1359775045640474627-475" src="https://platform.twitter.com/embed/Tweet.html?id=1359775045640474627"&gt;
&lt;/iframe&gt;

  // Detect dark theme
  var iframe = document.getElementById('tweet-1359775045640474627-475');
  if (document.body.className.includes('dark-theme')) {
    iframe.src = "https://platform.twitter.com/embed/Tweet.html?id=1359775045640474627&amp;amp;theme=dark"
  }



&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>azure</category>
      <category>serverless</category>
      <category>telegram</category>
    </item>
  </channel>
</rss>
