<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Programming &#8211; Musings of a Strange Loop</title>
	<atom:link href="https://vainolo.com/category/programming/feed/" rel="self" type="application/rss+xml" />
	<link>https://vainolo.com</link>
	<description>Vainolo&#039;s Blog</description>
	<lastBuildDate>Mon, 02 Feb 2026 11:07:34 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://i0.wp.com/vainolo.com/wp-content/uploads/2015/01/test-54a56454v1_site_icon.png?fit=32%2C32&#038;ssl=1</url>
	<title>Programming &#8211; Musings of a Strange Loop</title>
	<link>https://vainolo.com</link>
	<width>32</width>
	<height>32</height>
</image> 
<site xmlns="com-wordpress:feed-additions:1">183507057</site>	<item>
		<title>The Agency of Agents: Why Your AI Agents Aren&#8217;t Following Orders</title>
		<link>https://vainolo.com/2026/02/02/the-agency-of-agents-why-your-ai-agents-arent-following-orders/</link>
					<comments>https://vainolo.com/2026/02/02/the-agency-of-agents-why-your-ai-agents-arent-following-orders/#respond</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Mon, 02 Feb 2026 11:07:24 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Thoughts]]></category>
		<category><![CDATA[agency]]></category>
		<category><![CDATA[agents]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[artificial-intelligence]]></category>
		<category><![CDATA[philosophy]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14395</guid>

					<description><![CDATA[There&#8217;s a recurring complaint: people give AI agents detailed instructions, guides, and specific requirements, only to find the agent does something unexpected that is completely&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">There&#8217;s a recurring complaint: people give AI agents detailed instructions, guides, and specific requirements, only to find the agent does something unexpected that is completely against the instructions. The assumption is the agent is broken. But that&#8217;s wrong. The reason behind this behavior is that agents have <strong>agency</strong>.</p>



<p class="wp-block-paragraph">What is agency? In philosophy, <strong>agency</strong> refers to the capacity to act and make choices in an environment based on goals and beliefs. It&#8217;s not blind obedience &#8211; it&#8217;s the ability to initiate action and adapt, to decide between alternatives in order to achieve a goal (this is a VERY condensed and simplistic definition, there are many nuances and discussions in this area. Go down <a href="https://plato.stanford.edu/entries/agency/">the</a> <a href="https://arxiv.org/pdf/2410.23310">rabbit</a> <a href="https://en.wikipedia.org/wiki/Agency_(philosophy)">hole</a>&#8230; interesting stuff).<a href="https://plato.stanford.edu/entries/agency/" target="_blank" rel="noreferrer noopener"></a></p>



<p class="wp-block-paragraph">When you give an agent instructions, you&#8217;re defining goals, guidance, and tools it can use to achieve those goals. But an agent with agency can deviate if it believes a different approach better serves those goals or adapts better to the environment and can interpret the goal in different ways which don&#8217;t exactly align with your expectations.</p>



<p class="wp-block-paragraph">This is how we behave too. A surgeon ignores a checklist if something unexpected appears. A good employee uses judgment. We call this intelligence and respect it. Yet when agents do it, we&#8217;re frustrated. Your agent might just be exercising the very capability that makes it useful, and that is what makes it so powerful.</p>



<p class="wp-block-paragraph">There are times when agency is a liability. If you need guaranteed, deterministic behavior &#8211; where the process must follow a specific sequence every time &#8211; don&#8217;t rely on instructions. Give the agent tools that enforce the process.</p>



<p class="wp-block-paragraph">A very simple example: if content <em>must</em> be appended to the end of a file and never edited elsewhere, don&#8217;t give the agent an &#8220;edit file&#8221; tool with instructions to append. Give it an &#8220;append to file&#8221; tool that can only do one thing. This <strong>is</strong> more work: you&#8217;re building specific tools instead of general ones. But if consistency is non-negotiable, this is how you achieve it. The constraint is moved from the agent&#8217;s judgment into the tool&#8217;s design.</p>



<p class="wp-block-paragraph">The next time your agent does something unexpected, ask: is it broken, or is it exercising agency? If it&#8217;s pursuing a goal in a way that makes sense given the context, it&#8217;s working correctly. The solution isn&#8217;t to remove agency &#8211; it&#8217;s to better communicate your goals and refine your constraints. Your agents work best when you recognize and leverage their capacity to choose, adapt, and act.</p>



<p class="wp-block-paragraph">But sometimes you agent it is broken, because agents and LLMs are emergent technologies that are evolving at an incredible pace, and this pace sometimes makes them unstable and unpredictable. So also keep this in mind.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2026/02/02/the-agency-of-agents-why-your-ai-agents-arent-following-orders/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14395</post-id>	</item>
		<item>
		<title>Exploring AI-Assisted Software Development – Part 3: Third Time&#8217;s a Charm</title>
		<link>https://vainolo.com/2026/01/25/exploring-ai-assisted-software-development-part-3-third-times-a-charm/</link>
					<comments>https://vainolo.com/2026/01/25/exploring-ai-assisted-software-development-part-3-third-times-a-charm/#respond</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Sun, 25 Jan 2026 19:05:57 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[Artificial Intelligence]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[coding agent]]></category>
		<category><![CDATA[github copilot]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software development]]></category>
		<category><![CDATA[software development methodologies]]></category>
		<category><![CDATA[spec kit]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14378</guid>

					<description><![CDATA[Drawing from my&#160;previous&#160;experiences, I started again from scratch. But this time, I was more methodical with the AI coding agent. I&#8217;ve been exploring AI-assisted coding&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><br>Drawing from my&nbsp;<a href="https://vainolo.com/2025/07/31/exploring-ai-assisted-software-development-part-1/" target="_blank" rel="noreferrer noopener">previous</a>&nbsp;<a href="https://vainolo.com/2025/08/08/exploring-ai-assisted-software-development-part-2-crashed-and-burned/" target="_blank" rel="noreferrer noopener">experiences</a>, I started again from scratch. But this time, I was more methodical with the AI coding agent.</p>



<p class="wp-block-paragraph">I&#8217;ve been exploring AI-assisted coding tools and methodologies, and stumbled upon <a href="https://speckit.org/" target="_blank" rel="noreferrer noopener">Spec Kit</a>, a toolkit for spec-driven development using AI agents. The idea is that for every feature you want to implement, you go through a specification → planning → tasking → implementation workflow fully supported by the AI agent (<a href="https://github.com/github/spec-kit/blob/main/spec-driven.md" target="_blank" rel="noreferrer noopener">read more</a>). As an ex-Product Manager (and a geek for software development methodologies), I loved this idea and was eager to use it.</p>



<p class="wp-block-paragraph">AI agent shine in this process because they can create extremely detailed specifications that are mostly consistent as the project grows. I&#8217;ve seen projects grow and maintaining specs without contradictions can be challenging &#8211; but AI agents do this very well. They still miss things, but humans also miss things. And if I ask the AI agent enough questions, and use separate agents to do the validations, the AI agent has the upper hand here.</p>



<p class="wp-block-paragraph">So, for the past two months, in between meetings and for an hour here and there, I&#8217;ve specified, tested, and reviewed the work of the AI agent towards creating the first part of my project &#8211; a working backgammon web application and playing server. No manual coding allowed.</p>



<p class="wp-block-paragraph">GitHub Copilot has advanced rapidly since I last tried it, so I decided to use all the time, with the &#8220;Auto&#8221; model. I chose this simply because I believe AI should simplify my decisions, not add more. And since it is my default at work, I also made it my default here.</p>



<p class="wp-block-paragraph">This is what I&#8217;ve learned this time around:</p>



<ul class="wp-block-list">
<li>Roughly 60%-70% of the time was spent doing manual validations. Give the AI agent testing tools, and even better, let it generate them. The percentage of time won&#8217;t be reduced, but total time will be.</li>



<li>Follow-up on the first point, the most critical code to review is testing code. And by “tests” I mean anything that the AI agent can use after each coding session to validate their own work &#8211; unit, component, E2E tests, etc. For web apps, tools like <a href="https://playwright.dev/">playwright</a> (or similar) are a must.</li>



<li>Many people have written already, but I will repeat it: <em>keep the context small</em>. Large contexts confuse AI agents.</li>



<li>Use source control (this should be obvious). You <em>will</em> have long conversations with the AI agent doing changes in the middle (because we get carried away), which is bad (see previous point), generating code that you will have to throw away. So make sure you always commit your latest working product.</li>



<li>Customize your AI agent with instructions and prompts. There are many sources for great instructions in GitHub. I&#8217;ve used&nbsp;<a href="https://github.com/cline/prompts">cline/prompts</a>&nbsp;and&nbsp;<a href="https://github.com/github/awesome-copilot">github/awesome-copilot</a> for inspiration. The two instructions that I can&#8217;t do without are&nbsp;thought logging&nbsp;and&nbsp;self-improvement. They are great to help the AI agent know why things were done in the past.</li>
</ul>



<p class="wp-block-paragraph">The AI agent also had a funny (and frustrating) behavior. In one instruction, it was told to maintain a chronological changelog. It rebelled: sometimes it would add the changes at the top, sometimes at the bottom, sometimes it will update previous changes (!!!). Tweaked instructions, tested with different models – kept on happening. Not always, but sometimes. Go figure.</p>



<p class="wp-block-paragraph">Third time&#8217;s the charm: this attempt was much more successful than the previous two, and I now have a working backgammon application that actually plays by the rules (most of the time). The next step of the project is creating the backgammon playing agent, which I&#8217;m sure will be very fun. So stay tuned :-).</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2026/01/25/exploring-ai-assisted-software-development-part-3-third-times-a-charm/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14378</post-id>	</item>
		<item>
		<title>Exploring AI-Assisted Software Development – Part 2: Crashed and Burned</title>
		<link>https://vainolo.com/2025/08/08/exploring-ai-assisted-software-development-part-2-crashed-and-burned/</link>
					<comments>https://vainolo.com/2025/08/08/exploring-ai-assisted-software-development-part-2-crashed-and-burned/#respond</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Fri, 08 Aug 2025 15:41:29 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[coding agent]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[vibe coding]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14256</guid>

					<description><![CDATA[A week later and after many hours in front of the computer, my project is a complete failure and a great success. Let me explain.&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">A week later and after many hours in front of the computer, my project is a complete failure and a great success.</p>



<p class="wp-block-paragraph">Let me explain.</p>



<h2 class="wp-block-heading">The Failure</h2>



<p class="wp-block-paragraph">First the failure &#8211; the project is almost in the same place it was a week ago. The agents and I started working on a small UI interaction where the user selected (clicked) a checker with a valid move on the board, which should have de-highlighted the other checkers with available moves and changed the highlight of the selected checker. Simple, right?</p>



<p class="wp-block-paragraph">We had a board. We had checkers. We had dice. The player could roll the dice and after this the checkers with valid moves were highlighted. All this was implemented by the AI Agent with multiple prompts, instructions, and a detailed description of the game of backgammon. Things were going well.</p>



<p class="wp-block-paragraph">And then we got stuck. No matter how much detail I added to the prompts or how many tests we added, the agent was unable to implement the interaction.</p>



<p class="wp-block-paragraph">That is when I decided to take a look under the hood and see if there is anything I can do to help. Until now I let the AI run without looking at the code in depth, just a look here and there, not really digging into the code as I would in a PR at work.</p>



<p class="wp-block-paragraph">Boy, what a mess! Variables named <code>i</code>, <code>j</code>, <code>k</code>, <code>s</code>; Unused variables and methods all over the place; And then came the worst part &#8211; the AI Agent had implemented the game model and logic in two different places &#8211; once in the UI and the second in the model &#8211; and each implementation was being used by a different part of the application.</p>



<p class="wp-block-paragraph">Tried doing some manual &#8220;intervention&#8221; to salvage the project, but the code was so bad that this will require a lot of work and beats the whole point. I&#8217;m thinking of throwing out all game logic implementation and leaving only the UI which looks good enough (much better than if I would have written it, even if I knew how to write it. I&#8217;m really bad at UI). We&#8217;ll see.</p>



<h2 class="wp-block-heading">Great Success &#8211; Lessons Leaned</h2>



<p class="wp-block-paragraph">Now let&#8217;s talk about the great success. I&#8217;ve learned TONS during this process:</p>



<ol class="wp-block-list">
<li>My prompt writing capabilities have improved tremendously! I&#8217;m also learning new workflows to create the prompts, like asking another AI Agent to write a prompt and having long conversations with the AI Agent before starting implementation to make sure the Agent understand what I want it to do.</li>



<li>It is VERY important to set up the project basics before writing the first line of code: architectural decisions, languages, frameworks, test frameworks, CI pipelines, code conventions, etc. And, obviously, these can be done with the help of AI Agents.</li>



<li>Similar to (2), a good set of system prompts is a MUST HAVE for the AI Agent to perform correctly. This prompt (or many prompts) provides instructions that are given at the start of every session, explaining it how plan the task, system design guidelines, and general information for the AI agent that are relevant for all tasks. There are a number of repos with sample for this &#8211; <a href="https://github.com/dontriskit/awesome-ai-system-prompts">awesome-ai-system-promts</a> stands out with many start (3.5K at the moment), and kind mention also to my past co-worker who pointed me in this direction and also maintains his own <a href="https://github.com/Liad0205/PromptEngineering/">PromptEngineering</a> repo.</li>



<li>My TypeScript and HTML/CSS reading abilities are much better than they were 1 week ago :-).</li>
</ol>



<h2 class="wp-block-heading">Last Thoughts</h2>



<p class="wp-block-paragraph">I&#8217;ve heard many people saying that AI Agents are like junior developers. This comparison does a disservice to the junior developers (and all developers in general). Humans are constantly learning, adapting, and improving through experience and feedback. In contrast, AI agents operate on static models that aren’t retrained after each task. Having <a href="https://docs.cline.bot/prompting/cline-memory-bank">memory banks</a> and <a href="https://github.com/cline/prompts/blob/main/.clinerules/self-improving-cline.md">self-improvement</a> helps but doesn&#8217;t mitigate the issue.</p>



<p class="wp-block-paragraph">Most developers I’ve worked with don’t repeat the same mistake five times without progress. When I offer feedback, they internalize it and apply it moving forward. With AI agents, replicating that kind of learning is still tedious, imprecise, and resource-intensive.</p>



<p class="wp-block-paragraph">Despite the frustrations and setbacks, this &#8220;experiment&#8221; with AI agents has been awesome. My vacation just ended so I&#8217;ll have less time to experiment with this personal project, but I&#8217;m definitely going to apply all the learnings to my daily work and see how it goes.</p>



<p class="wp-block-paragraph">But don&#8217;t worry, the journey continues…</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2025/08/08/exploring-ai-assisted-software-development-part-2-crashed-and-burned/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14256</post-id>	</item>
		<item>
		<title>Exploring AI-Assisted Software Development &#8211; Part 1</title>
		<link>https://vainolo.com/2025/07/31/exploring-ai-assisted-software-development-part-1/</link>
					<comments>https://vainolo.com/2025/07/31/exploring-ai-assisted-software-development-part-1/#comments</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Thu, 31 Jul 2025 05:04:05 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[AI]]></category>
		<category><![CDATA[artificial-intelligence]]></category>
		<category><![CDATA[cline]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[copilot]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[software development]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14227</guid>

					<description><![CDATA[I&#8217;ve been working with AI coding agents for a while now in my professional environment, and overall, they’ve proven to be quite effective. While they&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">I&#8217;ve been working with AI coding agents for a while now in my professional environment, and overall, they’ve proven to be quite effective. While they occasionally fail or lead to inefficiencies, their value becomes clear when used with the right expectations and validation strategies.</p>



<p class="wp-block-paragraph">Recently, there’s been a surge of enthusiasm around the idea that anyone can build an application quickly using AI coding agents. I played a bit with base44 and the results are impressive! Curious to test this narrative myself without intermediaries, I decided to explore the capabilities of these tools in a more &#8220;personal&#8221; setting.</p>



<p class="wp-block-paragraph">I’m now on vacation, so I’ve taken on a side project: recreating an AI-driven backgammon player, something <a href="https://vainolo.com/wp-content/uploads/2019/03/AI-Evolving-a-Backgammon-Player.pdf" data-type="attachment" data-id="12591">I did many years ago</a> (yes, this is what I like to do on vacations, outside of going to the beach, drinking margaritas, doing treks, and other stuff). This time, however, I’m relying entirely on AI agents for the implementation. I’m calling this approach “AI Coding”, a term I prefer over the more ambiguous “vibe coding.” In this experiment, I’m responsible for product specification and high-level architecture, while the AI selects the programming languages and frameworks. I can read most popular languages, so if the agent does really dumb stuff (and it does sometimes), I can fix them. Otherwise, I let it proceed autonomously. </p>



<p class="wp-block-paragraph">Over the past two days, I’ve spent about two hours per day on this project. One of the first things I noticed is how different the time-on-task feels compared to traditional coding. When I write code myself, I usually have a clear sense of the scope and duration of each task. With AI Coding, this predictability disappears. Tasks that seem trivial, like changing the background color of a rectangle, can take multiple iterations. At the same time, more complex tasks, such as animating a pair of dice and triggering a roll on user interaction, are completed correctly in a single attempt. Still trying to understand why.</p>



<p class="wp-block-paragraph">Another key insight is the importance of writing good prompts (as many people have written already). Instructions must be very specific, which sometimes make them very long and tedious. But vague or overly complex prompts often lead to partial or wrong implementations, misinterpretations, or complete failures. This unpredictability can be frustrating.</p>



<p class="wp-block-paragraph">I’m using both GitHub Copilot and Cline, switching between them when one or the other gets stuck and can&#8217;t complete the task. It&#8217;s very important to configure these tools correctly. However, maintaining consistent global settings across the tools is not straightforward. I’m still refining my workflow, and the learning process has been enjoyable.</p>



<p class="wp-block-paragraph">At times, AI coding feels like doomscrolling. You write a prompt, the agent responds with a working solution—great! Then the next prompt breaks everything. You revise it, and things get worse. You revert, try again, and slowly inch toward a solution. What should have taken two minutes ends up consuming half an hour.</p>



<p class="wp-block-paragraph">Am I using the wrong tools? I don’t think so. Many developers report success with the same platforms. Am I using them incorrectly? Possibly. I’ve already seen noticeable improvements in my workflow after just a few hours of focused use. Time will tell &#8211; I&#8217;ve been doing this for a relatively short time, and I think I&#8217;m getting the hang of it. But there is still a lot to learn.</p>



<p class="wp-block-paragraph">Final thoughts: AI-assisted software development is not magic, but it is powerful. It requires a shift in mindset and a willingness to experiment. With the right approach, I&#8217;m sure it can become a great tool, as others have demonstrated.</p>



<p class="wp-block-paragraph">The journey continues&#8230;</p>



<p class="wp-block-paragraph"></p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2025/07/31/exploring-ai-assisted-software-development-part-1/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14227</post-id>	</item>
		<item>
		<title>Learning .NET Aspire – Part 3: Deploying a Simple Web App</title>
		<link>https://vainolo.com/2025/05/18/learning-net-aspire-part-3-deploying-a-simple-web-app/</link>
					<comments>https://vainolo.com/2025/05/18/learning-net-aspire-part-3-deploying-a-simple-web-app/#respond</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Sun, 18 May 2025 19:07:57 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14159</guid>

					<description><![CDATA[In the previous tutorial we created a simple web app using .NET Aspire. Now we will see how to deploy it to Azure. The simplest&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In the <a href="https://vainolo.com/2025/05/02/learning-net-aspire-part-2-creating-a-simple-web-app/" data-type="post" data-id="14129">previous tutorial</a> we created a simple web app using .NET Aspire. Now we will see how to deploy it to Azure.</p>



<p class="wp-block-paragraph">The simplest way to do this is to deploy to Azure Container Apps. To do this, we need to install the [Azure Developer CLI (azd)](<a href="https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/" rel="nofollow">https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/</a>). Ready? Let&#8217;s go!</p>



<p class="wp-block-paragraph">First, initialize the azure development environment for the project:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; azd init
</pre></div>


<p class="wp-block-paragraph">This commands scans the directory where it runs for instances of aspire app hosts. Detecting the one we have, it asks if we want to continue:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
Initializing an app to run on Azure (azd init)

? How do you want to initialize your app? Use code in the current directory

  (✓) Done: Scanning app code in current directory

Detected services:

  .NET (Aspire)
  Detected in: {redacted}\Part3-DeploySimpleWebApp\src\SimpleApp-AppHost\SimpleApp-AppHost.csproj    

azd will generate the files necessary to host your app on Azure.
? Select an option  &#x5B;Use arrows to move, type to filter]
&gt; Confirm and continue initializing my app
  Cancel and exit  
</pre></div>


<p class="wp-block-paragraph">I select to continue. Now I&#8217;m asked for a unique name for the environment. This affects a couple of things: </p>



<ol class="wp-block-list">
<li>the name of the resource group that is created in Azure.</li>



<li>The unique suffix that is given to all resources (using a hash).</li>



<li>The text on the tag(s) that is added to all resource groups used by the environment.</li>



<li>Maybe something else that is not documented and I haven&#8217;t noticed?</li>
</ol>



<p class="wp-block-paragraph">Anyway, choose wisely. I chose <code>Vainolo-Aspire-Part3</code>:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
? Enter a unique environment name: Vainolo-Aspire-Part3

Generating files to run your app on Azure:

  (✓) Done: Generating ./azure.yaml
  (✓) Done: Generating ./next-steps.md

SUCCESS: Your app is ready for the cloud!
You can provision and deploy your app to Azure by running the azd up command in this
directory. For more information on configuring your app, see ./next-steps.md
</pre></div>


<p class="wp-block-paragraph">After the project has been configured, we can deploy the app to azure in one command:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; azd up
</pre></div>


<p class="wp-block-paragraph">I&#8217;m asked to enter the subscription and location for the deployment. The tool asks this only the first time it runs, storing the selections locally:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
? Select an Azure Subscription to use:  &#x5B;Use arrows to move, type to filter]
&gt;  1. {redacted} ({redacted})

? Enter a value for the &#039;location&#039; infrastructure parameter:  &#x5B;Use arrows to move, type to filter]
  53. (US) West US (westus)
  54. (US) West US 2 (westus2)
&gt; 55. (US) West US 3 (westus3)
</pre></div>


<p class="wp-block-paragraph">Here we go!</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
Packaging services (azd package)


Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

Subscription: {redacted} ({redacted})
Location: West US 3

  You can view detailed progress in the Azure Portal:
  https://{redacted}

  (✓) Done: Resource group: rg-Vainolo-Aspire-Part3 (3.467s)
  (✓) Done: Container Registry: acrz44hwzvck46as (15.744s)
  (✓) Done: Log Analytics workspace: law-z44hwzvck46as (19.271s)
  (✓) Done: Container Apps Environment: cae-z44hwzvck46as (2m16.714s)

Deploying services (azd deploy)

  (x) Failed: Deploying service Web1

ERROR: error executing step command &#039;deploy --all&#039;: failed deploying service &#039;Web1&#039;: updating container app service: applying manifest: PUT https://{redacted}
--------------------------------------------------------------------------------
RESPONSE 400: 400 Bad Request
ERROR CODE: ContainerAppInvalidName
--------------------------------------------------------------------------------
{
  &quot;error&quot;: {
    &quot;code&quot;: &quot;ContainerAppInvalidName&quot;,
    &quot;message&quot;: &quot;Invalid ContainerApp name &#039;Web1&#039;. A name must consist of lower case alphanumeric characters or &#039;-&#039;, start with an alphabetic character, and end with an alphanumeric character and cannot have &#039;--&#039;. The length must be between 2 and 32 characters inclusive.&quot;
  }
}
--------------------------------------------------------------------------------

TraceID: 5459bdbc77f6a12c75cd588bd0de35a5
</pre></div>


<p class="wp-block-paragraph">I have a confession to make &#8211; fixing this took me waaaaay longer than it should have. It was not clear which instance of `Web1` was causing the issue, and I was sure it was related to the `SimpleApp-Web1` project name. I was so convinced that I forgot `Web1` was the name I gave the application in the host code 🤦‍♂️🤦‍♂️🤦‍♂️.</p>



<p class="wp-block-paragraph">Changing <code>Web1</code> to <code>web1</code> in the <code>Program.cs</code> file of the <code>SimpleApp-AppHost</code> fixed the issue 👍. I though about adding validation in <code>azd</code>, but alas, the tools is written in Go (☹️ why???). Maybe another time&#8230; Anyway, here, we go again!</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
Packaging services (azd package)


Provisioning Azure resources (azd provision)
Provisioning Azure resources can take some time.

Subscription: {redacted} ({redacted})
Location: West US 3

  (-) Skipped: Didn&#039;t find new changes.

Deploying services (azd deploy)

  (✓) Done: Deploying service web1
  - Endpoint: https://web1.{redacted}.westus3.azurecontainerapps.io/

  Aspire Dashboard: https://aspire-dashboard.ext.{redacted}.westus3.azurecontainerapps.io

SUCCESS: Your up workflow to provision and deploy to Azure completed in 45 seconds.
</pre></div>


<p class="wp-block-paragraph">Dashboard is up and running:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/05/dashboard.png?ssl=1"><img data-recalc-dims="1" fetchpriority="high" decoding="async" width="864" height="308" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/05/dashboard.png?resize=864%2C308&#038;ssl=1" alt="Screenshot of Azure resources dashboard showing running instances named 'web1' and 'web1--r93ibno', along with their respective statuses and source information." class="wp-image-14166" srcset="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/05/dashboard.png?w=864&amp;ssl=1 864w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/05/dashboard.png?resize=300%2C107&amp;ssl=1 300w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/05/dashboard.png?resize=768%2C274&amp;ssl=1 768w" sizes="(max-width: 864px) 100vw, 864px" /></a></figure>



<p class="wp-block-paragraph">And the app also works:</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/05/application.png?ssl=1"><img data-recalc-dims="1" decoding="async" width="186" height="76" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/05/application.png?resize=186%2C76&#038;ssl=1" alt="Screenshot of a web browser displaying the text 'Hello World!' in a terminal-like environment." class="wp-image-14167"/></a></figure>



<p class="wp-block-paragraph">Now for a very important part of this tutorial: removing the test app. Cloud resources can be<br>pretty pricey and usage is charged by the second. The Aspire team did this the right way, with a single command to remove the whole environment:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; azd down

Deleting all resources and deployed code on Azure (azd down)
Local application code is not deleted when running &#039;azd down&#039;.

  Resource(s) to be deleted:

  Resource Group: rg-Vainolo-Aspire-Part3
    • Log Analytics workspace: law-z44hwzvck46as
    • Container Registry: acrz44hwzvck46as
    • Container Apps Environment: cae-z44hwzvck46as
    • Container App: web1

? Total resources to delete: 6, are you sure you want to continue? Yes
Deleting your resources can take some time.e you want to continue? (y/N) y

  (✓) Done: Deleted resource group rg-Vainolo-Aspire-Part3


SUCCESS: Your application was removed from Azure in 18 minutes 4 seconds.
</pre></div>


<p class="wp-block-paragraph">Cool 😎.</p>



<p class="wp-block-paragraph">Next time, a drill down into the deployment process, what is created, and how it can be changed. Or maybe something else. Time will tell.</p>



<p class="wp-block-paragraph">As always, the <a href="https://github.com/vainolo/learning-dotnet-aspire/tree/Part3/Part3-DeploySimpleWebApp">code for this tutorial</a> (and all other tutorials) can be found on my <a href="https://github.com/vainolo" data-type="link" data-id="https://github.com/vainolo">GitHub</a>. Until next time, happy coding!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2025/05/18/learning-net-aspire-part-3-deploying-a-simple-web-app/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14159</post-id>	</item>
		<item>
		<title>Learning .NET Aspire &#8211; Part 2: Creating a Simple Web App</title>
		<link>https://vainolo.com/2025/05/02/learning-net-aspire-part-2-creating-a-simple-web-app/</link>
					<comments>https://vainolo.com/2025/05/02/learning-net-aspire-part-2-creating-a-simple-web-app/#comments</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Fri, 02 May 2025 07:09:11 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[aspire]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14129</guid>

					<description><![CDATA[In the previous tutorial, we took a look at the basic sample Aspire web app works. This time, we&#8217;ll create a new app from scratch.&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">In the <a href="https://vainolo.com/2025/04/18/learning-net-aspire-part-1-the-basics/" data-type="post" data-id="14095">previous tutorial</a>, we took a look at the basic sample Aspire web app works. This time, we&#8217;ll create a new app from scratch. This approach will help us get a better understanding of the basic building blocks of Aspire.</p>



<p class="wp-block-paragraph">First, we create a new Aspire AppHost:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; dotnet new aspire-apphost -n SimpleApp-AppHost
</pre></div>


<p class="wp-block-paragraph">The AppHost is the manager / orchestrator of the distributed application that we are building using the Aspire framework. Since it is an executable application, we can run it as soon as it is created. It will not do much, but does run:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; cd SimpleApp-AppHost&amp;lt;br&gt;&gt; dotnet run&amp;lt;br&gt;Using launch settings from &amp;lt;redacted&gt;\src\SimpleApp-AppHost\Properties\launchSettings.json...&amp;lt;br&gt;Building...&amp;lt;br&gt;info: Aspire.Hosting.DistributedApplication&#x5B;0]&amp;lt;br&gt;      Aspire version: 8.2.2+5fa9337a84a52e9bd185d04d156eccbdcf592f74&amp;lt;br&gt;info: Aspire.Hosting.DistributedApplication&#x5B;0]&amp;lt;br&gt;      Distributed application starting.&amp;lt;br&gt;info: Aspire.Hosting.DistributedApplication&#x5B;0]&amp;lt;br&gt;      Application host directory is: &amp;lt;redacted&gt;\src\SimpleApp-AppHost&amp;lt;br&gt;info: Aspire.Hosting.DistributedApplication&#x5B;0]&amp;lt;br&gt;      Now listening on: https://localhost:17114&amp;lt;br&gt;info: Aspire.Hosting.DistributedApplication&#x5B;0]&amp;lt;br&gt;      Login to the dashboard at https://localhost:17114/login?t=f3f0cf47ebc34c01d5214c2eb0d5cd18&amp;lt;br&gt;info: Aspire.Hosting.DistributedApplication&#x5B;0]&amp;lt;br&gt;      Distributed application started. Press Ctrl+C to shut down.
</pre></div>


<p class="wp-block-paragraph">We can navigate to the dashboard, which is completely empty. But for me, working things are comforting, so this is good :-).</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?ssl=1"><img data-recalc-dims="1" decoding="async" width="1024" height="421" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?resize=1024%2C421&#038;ssl=1" alt="Dashboard of the SimpleApp showing 'No resources found' message." class="wp-image-14132" srcset="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?resize=1024%2C421&amp;ssl=1 1024w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?resize=300%2C123&amp;ssl=1 300w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?resize=768%2C315&amp;ssl=1 768w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?resize=1536%2C631&amp;ssl=1 1536w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?resize=2048%2C841&amp;ssl=1 2048w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/initial-dashboard.png?resize=1200%2C493&amp;ssl=1 1200w" sizes="(max-width: 1000px) 100vw, 1000px" /></a></figure>



<p class="wp-block-paragraph">Turns out that adding a new application is not complicated at all. First thing that we need is create the service defaults project. This project defines the shared settings and configurations for the applications that run with the same host:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; dotnet new aspire-servicedefaults -n SimpleApp-ServiceDefaults
</pre></div>


<p class="wp-block-paragraph">We will also create our web application:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; dotnet new web -n SimpleApp-Web1
</pre></div>


<p class="wp-block-paragraph">There are a couple of &#8220;wires&#8221; that must be connected for these projects (settings, host, app) to work together. Applications that run with the host must reference the same service defaults project. The host needs to reference the applications. First, we&#8217;ll add a reference from the web app to the service defaults project:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; dotnet add .\SimpleApp-Web1\SimpleApp-Web1.csproj reference .\SimpleApp-ServiceDefaults\SimpleApp-ServiceDefaults.csproj
</pre></div>


<p class="wp-block-paragraph">And then a reference from the host to the web app project:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; dotnet add .\SimpleApp-AppHost\SimpleApp-AppHost.csproj reference .\SimpleApp-Web1\SimpleApp-Web1.csproj
</pre></div>


<p class="wp-block-paragraph">Two small code changes are needed to finish the job. First &#8211; add the defaults configuration to the web app for it to run on the Aspire host. This is done in the `Program.cs` file of the web app just after creating the builder:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
var builder = WebApplication.CreateBuilder(args);
builder.AddServiceDefaults();
</pre></div>


<p class="wp-block-paragraph">Finally the app project is added to the host builder so the host executes it. This is done in the `Program.cs` file of the app host project after creating the builder (promise next time to give better names to these files):</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
var builder = DistributedApplication.CreateBuilder(args);
builder.AddProject&amp;lt;Projects.SimpleApp_Web1&gt;(&quot;Web1&quot;).WithExternalHttpEndpoints();
</pre></div>


<p class="wp-block-paragraph">If you read this change carefully, you&#8217;ll notice that the name of the project is `SimpleApp_Web1` and not `SimpleApp-Web1`. This is because `C#` identifiers (and pretty sure most programming languages) don&#8217;t allow `-` as an identifier. Something to take into consideration when naming projects in the future.</p>



<p class="wp-block-paragraph">Let&#8217;s run the host to see the results.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
&gt; dotnet run --project .\SimpleApp-AppHost\SimpleApp-AppHost.csproj
Using launch settings from .\SimpleApp-AppHost\Properties\launchSettings.json...
Building...
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Aspire version: 8.2.2+5fa9337a84a52e9bd185d04d156eccbdcf592f74
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Distributed application starting.
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Application host directory is: &amp;lt;redacted&gt;\src\SimpleApp-AppHost
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Now listening on: https://localhost:17114
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Login to the dashboard at https://localhost:17114/login?t=6e00479dd713c387209238f98db39b32
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Distributed application started. Press Ctrl+C to shut down.
</pre></div>


<p class="wp-block-paragraph">We can navigate to the dashboard, and we see that the app shows up:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-with-web-app.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="369" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-with-web-app.png?resize=1024%2C369&#038;ssl=1" alt="Dashboard displaying resources for SimpleApp, showing the Web1 project with a running state and its start time." class="wp-image-14135" srcset="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-with-web-app.png?resize=1024%2C369&amp;ssl=1 1024w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-with-web-app.png?resize=300%2C108&amp;ssl=1 300w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-with-web-app.png?resize=768%2C277&amp;ssl=1 768w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-with-web-app.png?resize=1200%2C433&amp;ssl=1 1200w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-with-web-app.png?w=1498&amp;ssl=1 1498w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></figure>



<p class="wp-block-paragraph">Last check, click on the link to the app&#8230; Hello World!</p>



<figure class="wp-block-image size-full"><a href="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/web-app.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="703" height="250" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/web-app.png?resize=703%2C250&#038;ssl=1" alt="Screenshot of a web browser displaying the message 'Hello World!' on localhost." class="wp-image-14136" srcset="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/web-app.png?w=703&amp;ssl=1 703w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/web-app.png?resize=300%2C107&amp;ssl=1 300w" sizes="auto, (max-width: 703px) 100vw, 703px" /></a></figure>



<p class="wp-block-paragraph">Thats all I have for today. The process was straightforward, which encourages me to continue investigating Aspire. Next time, I&#8217;m going to learn how to deploy the application to Azure. And from there, who know where the path will take me.</p>



<p class="wp-block-paragraph">As always, you can find the code for this tutorial on my <a href="https://github.com/vainolo/learning-dotnet-aspire/tree/main/Part2-SimpleWebApp" data-type="link" data-id="https://github.com/vainolo/learning-dotnet-aspire/tree/main/Part2-SimpleWebApp">GitHub repo</a>.</p>



<p class="wp-block-paragraph">Until next time, happy coding!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2025/05/02/learning-net-aspire-part-2-creating-a-simple-web-app/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14129</post-id>	</item>
		<item>
		<title>Learning .NET Aspire &#8211; Part 1: The Basics</title>
		<link>https://vainolo.com/2025/04/18/learning-net-aspire-part-1-the-basics/</link>
					<comments>https://vainolo.com/2025/04/18/learning-net-aspire-part-1-the-basics/#comments</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Fri, 18 Apr 2025 06:11:29 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[aspire]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14095</guid>

					<description><![CDATA[.NET Aspire is a new &#8220;stack&#8221; for developing application for the cloud. I&#8217;m usually not into opinionated stacks, or stacks in general, because they create&#8230;]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph"><a href="https://learn.microsoft.com/en-us/dotnet/aspire/" data-type="link" data-id="https://learn.microsoft.com/en-us/dotnet/aspire/">.NET Aspire</a> is a new &#8220;stack&#8221; for developing application for the cloud. I&#8217;m usually not into opinionated stacks, or stacks in general, because they create strong dependencies that later on come and bite you. At the same time, Aspire looks pretty good and maybe worth this downside, so I&#8217;ve decided to take some time to learn how it works.</p>



<p class="wp-block-paragraph">I&#8217;m using <a href="https://learn.microsoft.com/" data-type="link" data-id="https://learn.microsoft.com/">Microsoft Learn</a>, and the official documentation as my baseline, expanding and exploring as I see fit. Hope you enjoy the ride :-).</p>



<p class="wp-block-paragraph">Let&#8217;s start by creating a new .NET aspire by executing:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
&gt; dotnet new aspire-starter -n MyFirstAspireApp
</pre></div>


<p class="wp-block-paragraph">I&#8217;m using the&nbsp;<code>-n</code>&nbsp;flag to give the project a name, otherwise it takes the name of the directory, which in this case is quite ugly.</p>



<p class="wp-block-paragraph">This command creates quite a lot of code:</p>



<ol class="wp-block-list">
<li><code>MyFirstAspireApp.AppHost</code>: the &#8220;orchestration&#8221; project that.. orchestrates stuff? I&#8217;m sure we&#8217;ll learn more about this later.</li>



<li><code>MyFirstAspireApp.ServiceDefaults</code>: the project that contains the configuration for all the applications.</li>



<li><code>MyFirstAspireApp.ApiService</code>: a web api that exposes a service to query weather data.</li>



<li><code>MyFirstAspireApp.Web</code>: a Blazore WebAssembly application that is the UI for a weather application.</li>
</ol>



<p class="wp-block-paragraph">Let&#8217;s see this run:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
&gt; cd MyFirstAspireApp.AppHost
&gt; dotnet run
</pre></div>


<p class="wp-block-paragraph">Since the <code>AppHost</code> project is dependent on the other projects, this builds everything and runs the application. In the console, we can see some traces and also information on how to login to the application dashboard:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: powershell; title: ; notranslate">
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Aspire version: 8.2.2+5fa9337a84a52e9bd185d04d156eccbdcf592f74
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Distributed application starting.
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Application host directory is: &lt;redacted&gt;\learning-dotnet-aspire&gt;\Part1-TheBasics\MyFirstAspireApp.AppHost
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Now listening on: https://localhost:17299
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Login to the dashboard at https://localhost:17299/login?t=c8cd13362afa4b22cc49b897792d9a4f
info: Aspire.Hosting.DistributedApplication&#x5B;0]
      Distributed application started. Press Ctrl+C to shut down.
</pre></div>


<p class="wp-block-paragraph">Navigating to the login dashboard we get a very nice page where we can see a lot of information:</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-main.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="363" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-main.png?resize=1024%2C363&#038;ssl=1" alt="Screenshot of the MyFirstAspireApp dashboard displaying two running projects: apiservice and webfrontend, along with their respective endpoints, state, and start time." class="wp-image-14113" srcset="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-main.png?resize=1024%2C363&amp;ssl=1 1024w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-main.png?resize=300%2C106&amp;ssl=1 300w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-main.png?resize=768%2C272&amp;ssl=1 768w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/dashboard-main.png?w=1046&amp;ssl=1 1046w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></figure>



<p class="wp-block-paragraph">I think a full tutorial is needed only for this dashboard. For now, I&#8217;ll click on the URL of the <code>webfrontend</code> resource to navigate to the web app that was created.</p>



<figure class="wp-block-image size-large"><a href="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/app-landing-page.png?ssl=1"><img data-recalc-dims="1" loading="lazy" decoding="async" width="1024" height="324" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/app-landing-page.png?resize=1024%2C324&#038;ssl=1" alt="A web application interface for 'MyFirstAspireApp' displaying a welcome message with navigation links for Home, Counter, and Weather." class="wp-image-14112" srcset="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/app-landing-page.png?resize=1024%2C324&amp;ssl=1 1024w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/app-landing-page.png?resize=300%2C95&amp;ssl=1 300w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/app-landing-page.png?resize=768%2C243&amp;ssl=1 768w, https://i0.wp.com/vainolo.com/wp-content/uploads/2025/04/app-landing-page.png?w=1034&amp;ssl=1 1034w" sizes="auto, (max-width: 1000px) 100vw, 1000px" /></a></figure>



<p class="wp-block-paragraph">The app has a counter which can be incremented and a weather page that shows data fetched from the weather API (also in the project).</p>



<p class="wp-block-paragraph">To get my hands dirty, I&#8217;m going to change the App so the <code>Summary</code> of the weather is related to the temperature, and not random (I&#8217;m getting -10 C &#8211; Warm, which doesn&#8217;t make sense). The code for the weather API is in the <code>Program.cs</code> file in the <code>ApiService</code> project. I&#8217;m going to replace this code:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: csharp; title: ; notranslate">
var summaries = new&#x5B;]
{
    &quot;Freezing&quot;, &quot;Bracing&quot;, &quot;Chilly&quot;, &quot;Cool&quot;, &quot;Mild&quot;, &quot;Warm&quot;, &quot;Balmy&quot;, &quot;Hot&quot;, &quot;Sweltering&quot;, &quot;Scorching&quot;
};

app.MapGet(&quot;/weatherforecast&quot;, () =&gt;
{
    var forecast = Enumerable.Range(1, 5).Select(index =&gt;
        new WeatherForecast
        (
            DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            Random.Shared.Next(-20, 55),
            summaries&#x5B;Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
});
</pre></div>


<p class="wp-block-paragraph">With this code:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: csharp; title: ; notranslate">
string Summary(int forecast) =&gt; forecast switch
{
    &lt;= 0            =&gt; &quot;Freezing&quot;,
    &gt; 0 and &lt;= 10   =&gt; &quot;Cool&quot;,
    &gt; 10 and &lt;= 20  =&gt; &quot;Mild&quot;,
    &gt; 20 and &lt;= 30  =&gt; &quot;Warm&quot;,
    &gt; 30            =&gt; &quot;Scorching&quot;
};

WeatherForecast GenerateForecast(int index)
{
    var temperature = Random.Shared.Next(-20, 55);
    return new
    (
        DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
        temperature,
        Summary(temperature)
    );
}

app.MapGet(&quot;/weatherforecast&quot;, () =&gt;
{
    var forecast = Enumerable.Range(1, 5).Select(index =&gt; GenerateForecast(index)).ToArray();
    return forecast;
});
</pre></div>


<p class="wp-block-paragraph">Restarting the app, and there we go &#8211; the summary now makes sense 🎉.</p>



<p class="wp-block-paragraph">This is enough for today. There is a LOT to cover going forward. I&#8217;m going to try and take it step by step, understand all the components that make up this huge beast called Aspire.</p>



<p class="wp-block-paragraph">As always, the code for this tutorial can be found on <a href="https://github.com/vainolo/learning-dotnet-aspire/tree/main/Part1-TheBasics">Github</a>.</p>



<p class="wp-block-paragraph">Happy Coding!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2025/04/18/learning-net-aspire-part-1-the-basics/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14095</post-id>	</item>
		<item>
		<title>Fetching Currency Exchange Rates in Excel</title>
		<link>https://vainolo.com/2025/02/01/fetching-currency-exchange-rates-in-excel/</link>
					<comments>https://vainolo.com/2025/02/01/fetching-currency-exchange-rates-in-excel/#respond</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Sat, 01 Feb 2025 21:10:25 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[excel]]></category>
		<category><![CDATA[exchange rate]]></category>
		<category><![CDATA[finance]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=14020</guid>

					<description><![CDATA[While Excel is not a programming language, it is one of those awesome tools that every person should be familiar with. You would be amazed&#8230;]]></description>
										<content:encoded><![CDATA[<p>While Excel is not a programming language, it is one of those awesome tools that every person should be familiar with. You would be amazed at how many things can be achieved with it, even when on the surface it is just a simple spreadsheet. Just ask <a href="https://www.youtube.com/watch?v=SPLzV0-X0lI">this guy</a> :-).</p>
<p>Anyway, let&#8217;s get back to what I want to share today. I manage my expenses using excel, and I have some credit cards for internet purchases that charge in a different currency than the one in which I do my account consolidations. Getting the exchange rate for each transaction was out of the question, so there had to be another option.</p>
<p>Enter the magic of Excel&#8217;s <code><a href="https://support.microsoft.com/en-us/office/stockhistory-function-1ac8b5b3-5f62-4d94-8ab8-7504ec7239a8">STOCKHISTORY</a></code> function. While the function is built for stocks, we can use it to get exchange rates using the <code>&lt;source-currency&gt;:&lt;target-currency&gt;</code> as the name of the stock. For example, to get the exchange rate from USD to EUR, we use &#8220;USD:EUR&#8221;.</p>
<p>In its simplest form, the function receives two arguments &#8211; the stock and a date &#8211; and creates an array containing the matching values for the stock on the date. For example, to get the USD:EUR exchange rate for 2024-01-01, we enter the formula:</p>
<p><code>=STOCKHISTORY("USD:EUR", DATE(2024,1,1))</code></p>
<p>Which adds this data to the worksheet:</p>
<table>
<tbody>
<tr>
<td>Date</td>
<td>Close</td>
</tr>
<tr>
<td>01/01/2024</td>
<td> € 0.91</td>
</tr>
</tbody>
</table>
<p>Good start. For my purpose, I want just one cell containing the exchange rate from the currency of the transaction to my base currency based on the date of the transaction that is also in this row. We can also do that by changing other parameters of the <code>STOCKHISTORY</code> function that lets us tweak what data to fetch and how to return it. First, to get only the exchange rate, we set the <code>Headers</code> argument to <code>0</code>, which removes the headers:</p>
<p><code>=STOCKHISTORY("USD:EUR",DATE(2024,1,1),,,0)</code></p>
<p>Returning:</p>
<table>
<tbody>
<tr>
<td>01/01/2024</td>
<td> € 0.91</td>
</tr>
</tbody>
</table>
<p>Almost there! I only want the value of the exchange rate, so we need a bit more tweaking. There are 5 &#8220;properties&#8221; that can be passed to the <code>STOCKHISTORY</code> function, which define what values it returns. Setting <code>property0</code> to <code>1</code> will ensure that only the closing rate is returned:</p>
<p><code>=STOCKHISTORY("USD:EUR",DATE(2024,1,1),,,0,1)</code></p>
<p>Returning:</p>
<table>
<tbody>
<tr>
<td> € 0.91</td>
</tr>
</tbody>
</table>
<p>Great&#8230; But what happens when we try to get the exchange rate in a day where the market is not open? Even if Excel does not allow it, I do purchase things on Sundays. In these cases, the function will return <code>#VALUE</code>. For example, if we try to fetch the <code>USD:EUR</code> exchange for 2024-01-06, this is what we get:</p>
<p><a href="https://vainolo.com/2025/02/01/fetching-currency-exchange-rates-in-excel/excel-non-trading-day/" rel="attachment wp-att-14027"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter size-full wp-image-14027" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2025/01/excel-non-trading-day.png?resize=261%2C101&#038;ssl=1" alt="" width="261" height="101" /></a></p>
<p>What we can do here is fetch a range of dates for the exchange rate (from a start to an end date) and get the maximum from this range. Let&#8217;s do this in our example, fetching a range of 5 days and getting the maximum value:</p>
<p><code>=MAX(STOCKHISTORY("USD:EUR",DATE(2024,1,6)-2,DATE(2024,1,6),,0,1))</code></p>
<p>Which returns:</p>
<table>
<tbody>
<tr>
<td>0.9138</td>
</tr>
</tbody>
</table>
<p>Excel is awesome <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f60e.png" alt="😎" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2025/02/01/fetching-currency-exchange-rates-in-excel/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">14020</post-id>	</item>
		<item>
		<title>Creating a C# NuGet Package and Publishing it to NuGet.org</title>
		<link>https://vainolo.com/2024/12/16/creating-a-c-nuget-package-and-publishing-it-to-nuget-org/</link>
					<comments>https://vainolo.com/2024/12/16/creating-a-c-nuget-package-and-publishing-it-to-nuget-org/#respond</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Mon, 16 Dec 2024 05:54:26 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[dotnet]]></category>
		<category><![CDATA[dotnetcore]]></category>
		<category><![CDATA[nuget]]></category>
		<category><![CDATA[package]]></category>
		<category><![CDATA[tutorial]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=13970</guid>

					<description><![CDATA[This turned out to be a lot simpler than I thought. First, we start with a C# class library project, which we can create by&#8230;]]></description>
										<content:encoded><![CDATA[<p>This turned out to be a lot simpler than I thought.</p>
<p>First, we start with a <code>C#</code> class library project, which we can create by running <code>dotnet new classlib</code> on the console. This will create a new project that has the name of the directory where the command runs. Many times, this is not what we want so we&#8217;ll either create a directory with the name of the project or use the <code>--name</code> flag to give our project a name (which creates this directory). In this case I&#8217;m going to use <code>dotnet new project or --name MyFirstNuGet</code> which creates a <code>MyFirstNuGet</code> directory containing two files: <code>Class1.cs</code> and <code>MyFirstNuGet.csproj</code>.</p>
<p>At this point, we are ready to create the package, by running <code>dotnet pack</code>. This creates a NuGet package that takes the name of the project for author and package identifier (a unique identifier for all packages, which is also used to reference the package using NuGet), and defaults to version <code>1.0.0</code>.</p>
<p><a href="https://vainolo.com/2024/12/16/creating-a-c-nuget-package-and-publishing-it-to-nuget-org/myfirstnuget-firsttry/" rel="attachment wp-att-13983"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13983" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2024/12/MyFirstNuget-FirstTry.png?resize=278%2C189&#038;ssl=1" alt="" width="278" height="189" /></a>We probably don&#8217;t want that, so let&#8217;s configure things a bit. NuGet properties are set in the <code>csproj</code> file inside a <code>PropertyGroup</code> (like any other <a href="https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties?view=vs-2022">MSBuild</a> property). To me, the most important things we can set there are:</p>
<ul>
<li><code>PackageId</code>: the identifier of the package, which <em>should</em> be different from all other packages in NuGet.org, otherwise we will not be able to publish it there. And giving it a &#8220;catchy&#8221; name may also make it more popular, so choose wisely <img src="https://s.w.org/images/core/emoji/17.0.2/72x72/1f600.png" alt="😀" class="wp-smiley" style="height: 1em; max-height: 1em;" />.</li>
<li><code>Version</code>: a <a href="https://semver.org/">sematic versioning</a> compliant version for the package being created.</li>
<li><code>TargetFramework(s)</code>: a semicolon separated list of <a href="https://learn.microsoft.com/en-us/nuget/reference/target-frameworks">target frameworks</a> that are supported by the package. This list can also have one element, and if you only have on element you can use <code>TargetFramework</code>.</li>
</ul>
<p>Other than these two, we can add a list of Authors, License, Description, Copyright, and <a href="https://learn.microsoft.com/en-us/nuget/reference/msbuild-targets#pack-scenarios">many others</a>.</p>
<p>Let&#8217;s change these settings, run <code>dotnet pack</code>, and our package is ready!</p>
<p><a href="https://vainolo.com/2024/12/16/creating-a-c-nuget-package-and-publishing-it-to-nuget-org/myfirstnuget-final/" rel="attachment wp-att-13984"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13984" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2024/12/MyFirstNuget-Final.png?resize=286%2C212&#038;ssl=1" alt="" width="286" height="212" /></a></p>
<p>As always, the (very small) code for this tutorial can be found in my <a href="https://github.com/vainolo/Vainosamples/tree/master/CSharp/NuGet/MyFirstNuGet">GitHub repo</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2024/12/16/creating-a-c-nuget-package-and-publishing-it-to-nuget-org/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">13970</post-id>	</item>
		<item>
		<title>Generating Code using C# Source Generators</title>
		<link>https://vainolo.com/2022/04/20/generating-code-using-c-source-generators/</link>
					<comments>https://vainolo.com/2022/04/20/generating-code-using-c-source-generators/#respond</comments>
		
		<dc:creator><![CDATA[Vainolo]]></dc:creator>
		<pubDate>Wed, 20 Apr 2022 18:41:41 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[code generation]]></category>
		<category><![CDATA[csharp]]></category>
		<category><![CDATA[programming]]></category>
		<guid isPermaLink="false">https://vainolo.com/?p=13343</guid>

					<description><![CDATA[Code generation is one of those things that divides programmers in two &#8211; either you love it or hate it. After having worked many years&#8230;]]></description>
										<content:encoded><![CDATA[<p>Code generation is one of those things that divides programmers in two &#8211; either you love it or hate it. After having worked many years on a project that used code generation very wisely, I learned how much value it has, but also how dangerous it is. So I understand the haters, but I&#8217;m on the side that loves code generation :-). So I was really excited with the announcement of <a href="https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview">C# Source Generators</a> a while ago, and finally had some time to start looking at this.</p>
<p>I&#8217;m not going to repeat the <a href="https://docs.microsoft.com/en-us/dotnet/csharp/roslyn-sdk/source-generators-overview">official tutorial</a> because it is easy to follow, and it works (which is not the case in many tutorials&#8230;).</p>
<p>Anyway, one small thing that I did add is a way to &#8220;see&#8221; the code that is generated. Why? Mainly because I like to navigate to the code in my editor. The default settings don&#8217;t generate a source file, but after some digging I found you can generate the source files by adding the <code>&lt;EmitCompilerGeneratedFiles&gt;true&lt;/EmitCompilerGeneratedFiles&gt;</code> directive in the project, and voila, the code shows up. Hidden deep down in the compiler directories, but it is there:</p>
<p><a href="https://vainolo.com/2022/04/20/generating-code-using-c-source-generators/codegeneration1/" rel="attachment wp-att-13350"><img data-recalc-dims="1" loading="lazy" decoding="async" class="aligncenter size-full wp-image-13350" src="https://i0.wp.com/vainolo.com/wp-content/uploads/2022/04/CodeGeneration1.png?resize=336%2C185&#038;ssl=1" alt="" width="336" height="185" srcset="https://i0.wp.com/vainolo.com/wp-content/uploads/2022/04/CodeGeneration1.png?w=336&amp;ssl=1 336w, https://i0.wp.com/vainolo.com/wp-content/uploads/2022/04/CodeGeneration1.png?resize=300%2C165&amp;ssl=1 300w" sizes="auto, (max-width: 336px) 100vw, 336px" /></a></p>
<p>You can check out the code for the generator and the program that uses the generator here: <a href="https://github.com/vainolo/Vainosamples/tree/master/CSharp/Generators/MyFirstGenerator">https://github.com/vainolo/Vainosamples/tree/master/CSharp/Generators/MyFirstGenerator</a>.</p>
<p>Happy coding!</p>
]]></content:encoded>
					
					<wfw:commentRss>https://vainolo.com/2022/04/20/generating-code-using-c-source-generators/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">13343</post-id>	</item>
	</channel>
</rss>