Code Inside Blog Code Inside Blog - Code Inside Team https://blog.codeinside.eu https://blog.codeinside.eu Tue, 03 Mar 2026 21:31:38 +0000 Tue, 03 Mar 2026 21:31:38 +0000 1800 Taming Big .NET Solutions: Centralizing Build Settings and NuGet Versions <p>Many .NET projects start as a small prototype, but after a few iterations they grow into a sizable Visual Studio solution with dozens — sometimes hundreds — of projects. At this point, managing common project settings becomes painful:</p> <p>A NuGet package needs an update → you touch multiple project files. A new .NET version is released → update every project manually. Metadata like company name or product name starts to drift across projects.</p> <p>If this sounds familiar, this guide is for you.</p> <h2 id="the-root-of-the-problem-the-csproj-file">The Root of the Problem: The .csproj File</h2> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;Project Sdk="Microsoft.NET.Sdk.Web"&gt; &lt;PropertyGroup&gt; &lt;LangVersion&gt;13.0&lt;/LangVersion&gt; &lt;TargetFramework&gt;net8.0&lt;/TargetFramework&gt; &lt;Nullable&gt;enable&lt;/Nullable&gt; &lt;ImplicitUsings&gt;enable&lt;/ImplicitUsings&gt; &lt;AssemblyVersion&gt;1.0.0.0&lt;/AssemblyVersion&gt; &lt;FileVersion&gt;1.0.0.0&lt;/FileVersion&gt; &lt;InformationalVersion&gt;1.0.0.0&lt;/InformationalVersion&gt; &lt;Company&gt;Cool Company&lt;/Company&gt; &lt;Product&gt;Cool Product&lt;/Product&gt; &lt;Copyright&gt;...&lt;/Copyright&gt; &lt;/PropertyGroup&gt; &lt;ItemGroup&gt; &lt;PackageReference Include="Swashbuckle.AspNetCore" Version="6.6.2" /&gt; &lt;PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="8.0.3" /&gt; &lt;/ItemGroup&gt; &lt;/Project&gt; </code></pre></div></div> <p>Common pain points:</p> <ul> <li>Hard-coded compiler settings (target framework, language version, nullable settings).</li> <li>Metadata drift (company, product, copyright).</li> <li>NuGet versions spread across all projects.</li> </ul> <p>Luckily, .NET provides clean solutions using: <strong>Directory.Build.props</strong>, <strong>Directory.Build.targets</strong>, and <strong>Directory.Packages.props</strong>.</p> <h2 id="directorybuildprops">Directory.Build.props</h2> <p>This file is loaded before the build starts and allows you to define default settings for all projects in the solution. Values can still be overridden inside individual .csproj files.</p> <p>Example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;Project&gt; &lt;PropertyGroup&gt; &lt;LangVersion&gt;latest&lt;/LangVersion&gt; &lt;TreatWarningsAsErrors&gt;true&lt;/TreatWarningsAsErrors&gt; &lt;Nullable&gt;enable&lt;/Nullable&gt; &lt;AssemblyVersion&gt;1.0.0.0&lt;/AssemblyVersion&gt; &lt;FileVersion&gt;1.0.0.0&lt;/FileVersion&gt; &lt;InformationalVersion&gt;1.0.0.0&lt;/InformationalVersion&gt; &lt;Company&gt;Cool Company&lt;/Company&gt; &lt;Product&gt;Cool Product&lt;/Product&gt; &lt;Copyright&gt;...&lt;/Copyright&gt; &lt;/PropertyGroup&gt; &lt;!-- or if you want to set a global output directory --&gt; &lt;PropertyGroup&gt; &lt;OutDir&gt;C:\output\$(MSBuildProjectName)&lt;/OutDir&gt; &lt;/PropertyGroup&gt; &lt;/Project&gt; </code></pre></div></div> <p><strong>How MSBuild Locates Directory.Build.props</strong></p> <p>MSBuild <a href="https://learn.microsoft.com/en-us/visualstudio/msbuild/customize-by-directory">searches the directory tree upwards</a> from the project location until it finds a file with that name. It stops at the first match, unless you explicitly chain them, which can be useful - depending on your directory structure.</p> <h2 id="directorybuildtargets">Directory.Build.targets</h2> <p>While .props files provide early defaults, .targets files are loaded later, making them ideal for:</p> <ul> <li>Extending build steps</li> <li>Overriding MSBuild targets</li> <li>Inserting Before<em>/After</em> hooks</li> <li>Running custom build logic</li> </ul> <p>Example:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;Target Name="BeforePack"&gt; &lt;Message Text="Preparing NuGet packaging for $(MSBuildProjectName)" /&gt; &lt;/Target&gt; </code></pre></div></div> <p><strong>Real-world Example: Muting Warnings:</strong></p> <p>When you build older branches of a big solution, NuGet may raise vulnerability warnings (NU1901–NU1904). If the solution uses TreatWarningsAsErrors=true, the build will fail — even though the old state is intentional. Solution using Directory.Build.targets:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;Project&gt; &lt;PropertyGroup&gt; &lt;!-- Mute all vulnerabilities and don't escalate warnings as errors --&gt; &lt;!-- Uncomment these lines if you need to build an older version (with open vulnerabilities!): &lt;TreatWarningsAsErrors&gt;false&lt;/TreatWarningsAsErrors&gt; &lt;NoWarn&gt;NU1901, NU1902, NU1903, NU1904&lt;/NoWarn&gt; --&gt; &lt;/PropertyGroup&gt; &lt;/Project&gt; </code></pre></div></div> <h2 id="directorypackagesprops">Directory.Packages.props</h2> <p>This file might be the most important - this enabled <a href="https://learn.microsoft.com/en-us/nuget/consume-packages/central-package-management">Central NuGet Package Management</a>.</p> <p>The idea is, that you add all your needed NuGet packages in a <code class="language-plaintext highlighter-rouge">Directory.Packages.props</code> file like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;Project&gt; &lt;PropertyGroup&gt; &lt;ManagePackageVersionsCentrally&gt;true&lt;/ManagePackageVersionsCentrally&gt; &lt;/PropertyGroup&gt; &lt;ItemGroup&gt; &lt;PackageVersion Include="Newtonsoft.Json" Version="13.0.1" /&gt; &lt;/ItemGroup&gt; &lt;/Project&gt; </code></pre></div></div> <p>Inside your actual <code class="language-plaintext highlighter-rouge">myProject.csproj</code> you just reference the package, but <strong>without the actual version number</strong>!</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>... &lt;ItemGroup&gt; &lt;PackageReference Include="Newtonsoft.Json" /&gt; &lt;/ItemGroup&gt; </code></pre></div></div> <p>This way you have one central file to update your NuGet package and don’t need to scan all existing <code class="language-plaintext highlighter-rouge">.csproj</code>-files. This way, you update a package version <strong>once</strong>, and every project in your solution automatically picks it up.</p> <p><strong>Note:</strong> You can add multiple <code class="language-plaintext highlighter-rouge">Directory.Packages.props</code> in your directory tree.</p> <p><strong>How to deal with exceptions - e.g. one project needs an older/newer package?</strong></p> <p>If you have this scenario, you always can define an <code class="language-plaintext highlighter-rouge">VersionOverride</code> inside your <code class="language-plaintext highlighter-rouge">.csproj</code> like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>&lt;PackageReference Include="Microsoft.Extensions.Logging" VersionOverride="9.0.6" /&gt; </code></pre></div></div> <h2 id="tooling">Tooling</h2> <p>The Visual Studio UI is work with the <code class="language-plaintext highlighter-rouge">Directory.Packages.props</code> as well. If you want to start, just try these <code class="language-plaintext highlighter-rouge">.NET CLI</code> helper:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet new buildprops dotnet new buildtargets dotnet new packagesprops </code></pre></div></div> <p>There is also a <a href="https://github.com/Webreaper/CentralisedPackageConverter">tool</a> to convert an existing solution automatically using:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet tool install CentralisedPackageConverter --global central-pkg-converter /SomeAwesomeProject </code></pre></div></div> <p>From my experience: In our complex solution it worked <code class="language-plaintext highlighter-rouge">ok-ish</code>. 80% was migrated, not sure what the problem was. I guess nowadays you can assign an AI to write this file :)</p> <h2 id="summary">Summary</h2> <p>With just three small files, even a complex multi-project .NET solution becomes cleaner and easier to maintain:</p> <ul> <li><strong>Directory.Build.props:</strong> Defines shared defaults like language version, company name, or build settings.</li> <li><strong>Directory.Build.targets:</strong> Extends and customizes the build pipeline — ideal for automation and global rules.</li> <li><strong>Directory.Packages.props:</strong> Centralizes NuGet version management and prevents version drift across projects.</li> </ul> <p>The migration effort is small, but the payoff in structure and maintainability is huge.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2026/03/03/directory-build-props-and-directory-build-targets/ https://blog.codeinside.eu/2026/03/03/directory-build-props-and-directory-build-targets Tue, 03 Mar 2026 23:59:00 +0000 How to debug Microsoft Teams Apps <h1 id="debugging-microsoft-teams-apps-a-practical-guide">Debugging Microsoft Teams Apps: A Practical Guide</h1> <p>You’ve built a Microsoft Teams app.<br /> It installs fine, loads correctly — and yet something behaves <em>not quite</em> as expected.</p> <p>Welcome to debugging Teams apps.</p> <p>Because Teams apps are essentially web applications running inside a host (Teams), debugging them is <em>mostly</em> web debugging — with a few Teams-specific twists. This article walks through a practical approach, from the easiest options to the most powerful (and least documented) ones.</p> <hr /> <h2 id="start-simple-debugging-in-teams-web">Start Simple: Debugging in Teams Web</h2> <p>The easiest way to debug a Teams app is by using <strong>Teams in the browser</strong>.</p> <p>Why?</p> <ul> <li>You get direct access to standard browser developer tools</li> <li>Console logs, network requests, and DOM inspection work exactly as expected</li> <li>You can attach your debugger directly to your own web application</li> </ul> <p>For many issues — especially UI problems, authentication flows, or API calls — this is often all you need.</p> <h2 id="when-the-issue-only-happens-in-the-desktop-app">When the Issue Only Happens in the Desktop App</h2> <p>Unfortunately, not all problems reproduce in Teams Web.</p> <p>Some issues only appear in the <strong>Windows desktop client</strong>, for example:</p> <ul> <li>Differences in authentication behavior</li> <li>Embedded browser quirks</li> <li>Desktop-specific Teams APIs</li> <li>Caching or storage behavior</li> </ul> <p>In these cases, browser dev tools alone won’t get you very far.</p> <p>So what are your options?</p> <hr /> <h2 id="option-1-enable-the-teams-public-preview">Option 1: Enable the Teams Public Preview</h2> <p>If <strong>Public Preview</strong> is enabled for your account, Teams exposes additional debugging options.</p> <p>To turn on the <strong>Public Preview</strong> go to <code class="language-plaintext highlighter-rouge">Settings -&gt; About Teams</code>:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2025-12-13/public-preview.png" alt="x" title="active public preview" /></p> <p>After that a new item in the tray menu appears:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2025-12-13/public-preview-tray.png" alt="x" title="Tray Menu with public preview" /></p> <p><strong>Pros:</strong></p> <ul> <li>Access to a built-in debug menu</li> <li>Easier inspection of app behavior inside Teams</li> </ul> <p><strong>Cons:</strong></p> <ul> <li>Public Preview may not be allowed in many organizations</li> <li>It can introduce unrelated UI or behavior changes</li> <li>Not ideal for production-like debugging</li> </ul> <p>Because of these trade-offs, Public Preview is not always a viable solution — especially in enterprise environments.</p> <hr /> <h2 id="option-2-enable-engineering-tools-most-powerful">Option 2: Enable Engineering Tools (Most Powerful)</h2> <p>If you need full insight into what the <strong>Teams client</strong> is doing, this is the most powerful (and least advertised) option.</p> <p>By enabling the internal <strong>Engineering Tools</strong>, you get access to advanced debugging capabilities directly in the desktop client.</p> <p>I discovered this method in an <a href="https://techcommunity.microsoft.com/blog/microsoftteamsblog/announcing-general-availability-of-the-new-microsoft-teams-app-for-windows-and-m/3934603/replies/3947306#M13303">MS Support forum</a> — so it’s somewhat documented :-).</p> <h3 id="how-to-enable-engineering-tools-in-the-teams-client-windows">How to Enable Engineering Tools in the Teams Client (Windows)</h3> <ol> <li>Navigate to the following folder: <code class="language-plaintext highlighter-rouge">%localappdata%\Packages\MSTeams_8wekyb3d8bbwe\LocalCache\Microsoft\MSTeams</code> (Yes - the path is weird, but it’s real)</li> <li>Create a file named <code class="language-plaintext highlighter-rouge">configuration.json</code></li> <li>Add the following content:</li> </ol> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w"> </span><span class="nl">"core/devMenuEnabled"</span><span class="p">:</span><span class="w"> </span><span class="kc">true</span><span class="w"> </span><span class="p">}</span><span class="w"> </span></code></pre></div></div> <p>After this restart Microsoft Teams and right-click the Teams icon in the system tray and you should see <strong>“Engineering Tools”</strong>.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2025-12-13/engineering-tools.png" alt="x" title="Engineering Tools" /></p> <p>This menu offers much more options (and is probably used for the MS Teams Development and Support Teams). For my needs the “Open Dev Tools” was “good enough”.</p> <p><strong>Be aware:</strong> Some options might be dangerous. It’s called “Engineering Tools” for a reason. Use at your own risk.</p> <h2 id="summary">Summary</h2> <p>Debugging Teams apps mostly relies on familiar web development tools. The challenge is finding the right way to activate them inside the Teams environment.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2025/12/13/how-to-debug-teams-apps/ https://blog.codeinside.eu/2025/12/13/how-to-debug-teams-apps Sat, 13 Dec 2025 23:59:00 +0000 Understanding stdin, stdout and stderr in .NET <p><strong>Confession time:</strong><br /> It’s almost embarrassing to admit this — but after years of writing .NET code and using the terminal daily, I recently discovered that you can redirect the <em>error output</em> of a program using <code class="language-plaintext highlighter-rouge">2&gt;</code>.</p> <p>So I decided to write this post — partly as a note to my future self, and partly for anyone else who’s ever thought:<br /> “Wait… why are there <em>two</em> output streams?”</p> <h1 id="overview">Overview</h1> <p>When you build console applications or CLI tools in .NET, sooner or later you’ll encounter these basic “input”/”output”-streams:</p> <ul> <li><strong>stdin</strong> — standard input (like keyboard, files, or pipes) or in C# <code class="language-plaintext highlighter-rouge">Console.In</code>, <code class="language-plaintext highlighter-rouge">Console.ReadLine()</code></li> <li><strong>stdout</strong> — standard output or in C# <code class="language-plaintext highlighter-rouge">Console.Out</code>, <code class="language-plaintext highlighter-rouge">Console.WriteLine()</code></li> </ul> <p>Besides the “standard output” there is a special output just for errors or warnings:</p> <ul> <li><strong>stderr</strong> - Error or diagnostic messages or in C# <code class="language-plaintext highlighter-rouge">Console.Error</code>, <code class="language-plaintext highlighter-rouge">Console.Error.WriteLine()</code></li> </ul> <p>Having a dedicated error stream means your program can separate <em>data output</em> (for other programs or files) from <em>diagnostic messages</em> (for humans).</p> <h1 id="a-simple-example">A Simple Example</h1> <p>Let’s build a small C# program that reads from stdin, writes to stdout, and reports problems on stderr.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">using</span> <span class="nn">System</span><span class="p">;</span> <span class="k">class</span> <span class="nc">Program</span> <span class="p">{</span> <span class="k">static</span> <span class="k">void</span> <span class="nf">Main</span><span class="p">()</span> <span class="p">{</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"== Start =="</span><span class="p">);</span> <span class="kt">string</span><span class="p">?</span> <span class="n">line</span><span class="p">;</span> <span class="kt">int</span> <span class="n">lineCount</span> <span class="p">=</span> <span class="m">0</span><span class="p">;</span> <span class="c1">// Read from stdin</span> <span class="k">while</span> <span class="p">((</span><span class="n">line</span> <span class="p">=</span> <span class="n">Console</span><span class="p">.</span><span class="nf">ReadLine</span><span class="p">())</span> <span class="p">!=</span> <span class="k">null</span><span class="p">)</span> <span class="p">{</span> <span class="n">lineCount</span><span class="p">++;</span> <span class="c1">// Normal output</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"[</span><span class="p">{</span><span class="n">lineCount</span><span class="p">}</span><span class="s">] </span><span class="p">{</span><span class="n">line</span><span class="p">}</span><span class="s">"</span><span class="p">);</span> <span class="c1">// Print errors separately</span> <span class="k">if</span> <span class="p">(</span><span class="n">line</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="s">"error"</span><span class="p">,</span> <span class="n">StringComparison</span><span class="p">.</span><span class="n">OrdinalIgnoreCase</span><span class="p">))</span> <span class="p">{</span> <span class="n">Console</span><span class="p">.</span><span class="n">Error</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">$"Line </span><span class="p">{</span><span class="n">lineCount</span><span class="p">}</span><span class="s">: contains the word 'error'"</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> <span class="n">Console</span><span class="p">.</span><span class="nf">WriteLine</span><span class="p">(</span><span class="s">"== End =="</span><span class="p">);</span> <span class="p">}</span> <span class="p">}</span> </code></pre></div></div> <p>When you run it and type some lines and include the word error, the output will look like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>== Start == [1] Hello [2] error found Line 2: contains the word 'error' [3] test == End == </code></pre></div></div> <h1 id="why-2-means-stderr">Why 2&gt; means stderr</h1> <p>If you run the same app like this with the same input:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.\SampleConsoleApp.exe 2&gt; err.txt </code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">Line 2: contains the word 'error'</code> will be redirected into the <code class="language-plaintext highlighter-rouge">err.txt</code>.</p> <h1 id="input-as-file">Input as file</h1> <p>Let’s say you have a file that should be used as an input, then you could invoke the program like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.\SampleConsoleApp.exe &lt; input.txt </code></pre></div></div> <h1 id="input-with-pipes">Input with pipes</h1> <p>You can also use the <code class="language-plaintext highlighter-rouge">|</code> operator to use this as input stream:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>"error" | .\SampleConsoleApp.exe 2&gt; err.txt </code></pre></div></div> <h1 id="final-thoughts">Final thoughts</h1> <p>The standard streams are one of those Unix-era ideas that aged perfectly. They make it easy to connect programs like Lego bricks — and .NET gives you full access to them.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2025/11/05/understanding-stdin-stdout-and-stderr-in-dotnet/ https://blog.codeinside.eu/2025/11/05/understanding-stdin-stdout-and-stderr-in-dotnet Wed, 05 Nov 2025 23:59:00 +0000 MSI and MST files <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know – thanks!</em></p> <h1 id="what-is-an-msi">What is an MSI?</h1> <p>Let’s start simple: An <strong>MSI</strong> (Microsoft Installer) is a package used to install software on Windows. The MSI contains everything needed to install the software, such as files, registry changes, and custom actions.</p> <p>An MSI also includes <em>properties</em>—for example, the install location or custom values that need to be applied during installation.</p> <p>You can install an MSI interactively (by double-clicking it) or by using the <code class="language-plaintext highlighter-rouge">msiexec</code> command.</p> <p>A more complex <code class="language-plaintext highlighter-rouge">msiexec</code> command can look like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msiexec /qb /i "installer.msi" APPLICATIONFOLDER="C:\Program Files\customSoftware" SOMEPROP="SomeValue" SOMEOTHERPROP="SomeOtherValue" </code></pre></div></div> <h1 id="ok-and-what-is-an-mst">Ok… and what is an MST?</h1> <p>An <strong>MST</strong> (Microsoft Transform) is a file that contains a set of modifications for an MSI installation. All those properties (and more) that you would pass via command line can be “baked into” an MST file.</p> <p>You can apply an MST during installation like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>msiexec /i setup.msi TRANSFORMS=custom.mst /qn </code></pre></div></div> <h1 id="pros--cons">Pros / Cons</h1> <p><strong>Pros:</strong></p> <p>If you want to apply the same settings across multiple installations and keep them stored in one place, an MST is a good solution.</p> <p><strong>Cons:</strong></p> <p>The MST file, like the MSI itself, is a binary file and can only be edited with tools like <a href="https://learn.microsoft.com/en-us/windows/win32/msi/orca-exe">Orca</a>.</p> <p>Both file formats are quite old, but I recently learned that <strong>MST</strong> files are still a thing—and quite useful if you’re dealing with automated or enterprise software deployments.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2025/08/05/msi-and-mst-files/ https://blog.codeinside.eu/2025/08/05/msi-and-mst-files Tue, 05 Aug 2025 23:59:00 +0000 Fuslogvw.exe - blast from the past. <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <h1 id="fuslogvwexe--wait-what-ohhh">Fuslogvw.exe – Wait, What? Ohhh!</h1> <p>This might sound like a blast from the .NET past – but <a href="https://learn.microsoft.com/en-us/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer">this little tool</a> actually saved our day during a real customer issue.</p> <p>Here’s the situation: We had a good old .NET Framework app (yes, still alive and kicking!) that worked perfectly everywhere – except on a few mysterious machines. Right on startup: Crash. No clear error, just some DLL failing to resolve its dependencies.</p> <p>But! The error message <em>did</em> mention something called <code class="language-plaintext highlighter-rouge">Fuslogvw.exe</code> (<a href="https://learn.microsoft.com/en-us/dotnet/framework/tools/fuslogvw-exe-assembly-binding-log-viewer">Docs</a>) – a tool I had never actually used before. So let’s take a look.</p> <h2 id="what-does-fuslogvwexe-do">What does Fuslogvw.exe do?</h2> <p>In short: it logs how assemblies are loaded, where they were found, and – more importantly – where they <strong>weren’t</strong>.</p> <p>If you have Visual Studio installed, you can start it via the developer prompt and type: <code class="language-plaintext highlighter-rouge">fuslogvw</code>.</p> <p>The tool itself looks like it hasn’t changed since the Windows XP days, but hey – it gets the job done:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2025-05-01/screenshot.png" alt="x" title="fuslogvw" /></p> <p>At the end, you get handy little reports like this one:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>*** Assembly Binder Log Entry (3/5/2007 @ 12:54:20 PM) *** The operation failed. Bind result: hr = 0x80070002. The system cannot find the file specified. Assembly manager loaded from: C:\WINNT\Microsoft.NET\Framework\v2.0.50727\fusion.dll Running under executable C:\Program Files\Microsoft.NET\FrameworkSDK\Samples\Tutorials\resourcesandlocalization\graphic\cs\graphicfailtest.exe --- A detailed error log follows. === Pre-bind state information === LOG: DisplayName = graphicfailtest.resources, Version=0.0.0.0, Culture=en-US, PublicKeyToken=null (Fully-specified) LOG: Appbase = C:\Program Files\Microsoft.NET\FrameworkSDK\Samples\Tutorials\resourcesandlocalization\graphic\cs\ LOG: Initial PrivatePath = NULL LOG: Dynamic Base = NULL LOG: Cache Base = NULL LOG: AppName = NULL Calling assembly : graphicfailtest, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null. === LOG: Processing DEVPATH. LOG: DEVPATH is not set. Falling through to regular bind. LOG: Policy not being applied to reference at this time (private, custom, partial, or location-based assembly bind). LOG: Post-policy reference: graphicfailtest.resources, Version=0.0.0.0, Culture=en-US, PublicKeyToken=null LOG: Attempting download of new URL file:///C:/Program Files/Microsoft.NET/FrameworkSDK/Samples/Tutorials/resourcesandlocalization/graphic/cs/graphicfailtest.resources.DLL. LOG: Attempting download of new URL file:///C:/Program Files/Microsoft.NET/FrameworkSDK/Samples/Tutorials/resourcesandlocalization/graphic/cs/graphicfailtest.resources/graphicfailtest.resources.DLL. LOG: Attempting download of new URL file:///C:/Program Files/Microsoft.NET/FrameworkSDK/Samples/Tutorials/resourcesandlocalization/graphic/cs/graphicfailtest.resources.EXE. LOG: Attempting download of new URL file:///C:/Program Files/Microsoft.NET/FrameworkSDK/Samples/Tutorials/resourcesandlocalization/graphic/cs/graphicfailtest.resources/graphicfailtest.resources.EXE. LOG: All probing URLs attempted and failed. </code></pre></div></div> <p>And in our case, that was exactly what we needed: One of the machines had an old, incorrect DLL sitting in the Global Assembly Cache (GAC) – something that shouldn’t have been there at all. It got loaded, messed everything up, and was a pain to track down… until Fuslogvw pointed us right to it.</p> <h2 id="what-about-net-core--modern-net">What about .NET Core / modern .NET?</h2> <p><code class="language-plaintext highlighter-rouge">Fuslogvw</code> won’t help you there – things work differently in the new world. But there are other tools like <a href="https://learn.microsoft.com/en-us/dotnet/core/diagnostics/dotnet-trace"><code class="language-plaintext highlighter-rouge">dotnet trace</code></a> that can help with similar issues.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2025/05/01/fuslogvw/ https://blog.codeinside.eu/2025/05/01/fuslogvw Thu, 01 May 2025 23:59:00 +0000 Update an old SPFX Project <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>Last week I had to upgrade an old SharePoint Framework (SPFX) project, and surprisingly, the process was smoother than expected.</p> <p>For those unfamiliar, SPFX is a framework for building extensions for SharePoint Online. Here is an example of an SPFX extension: <a href="https://learn.microsoft.com/en-us/sharepoint/dev/spfx/extensions/get-started/build-a-hello-world-extension">Microsoft Docs</a>.</p> <p>The upgrade approach I took was a combination of:</p> <ul> <li>Creating a completely new SPFX project to see the latest project structure.</li> <li>Using the <a href="https://pnp.github.io/cli-microsoft365/cmd/spfx/project/project-upgrade">M365 CLI</a> to generate a step-by-step upgrade guide.</li> </ul> <p>Overall, it turned out to be a pretty smooth experience and the CLI was quite new for me, and I wanted to document it here.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2025/03/11/update-an-old-spfx-project/ https://blog.codeinside.eu/2025/03/11/update-an-old-spfx-project Tue, 11 Mar 2025 23:59:00 +0000 Handling Multiple ASP.NET Core Policies with Manual Authorization Checks <h1 id="aspnet-core-policies">ASP.NET Core Policies</h1> <p><a href="https://learn.microsoft.com/en-us/aspnet/core/security/authorization/policies">ASP.NET Core policies</a> provide a structured and reusable way to enforce authorization rules across your application. The built-in features are very flexible, but we had trouble with one scenario - but depending how you write your “Requirements” this might even be possible with the built-in features. Our approach was to use the authorization service to check certain policies manually - which works quite good!</p> <h1 id="the-challenge-combining-policies-with-or-logic">The Challenge: Combining Policies with OR Logic</h1> <p>In one of our API use cases, we needed to allow access <strong>either</strong> for certain clients (e.g., specific admininstrative applications) <strong>or</strong> for certain users in the database. The two approaches differ:</p> <ul> <li><strong>Client Authorization</strong>: This is relatively straightforward and can be handled using the built-in <code class="language-plaintext highlighter-rouge">RequireClaim</code> approach.</li> <li><strong>User Authorization</strong>: This required checking database permissions, meaning a <strong>custom authorization requirement</strong> was necessary.</li> </ul> <p>Since both authorization paths are valid, they need to be evaluated using <strong>OR logic</strong>: if <strong>either</strong> condition is met, access should be granted.</p> <h1 id="solution-using-the-authorization-service-for-manual-policy-checks">Solution: Using the Authorization Service for Manual Policy Checks</h1> <p>Instead of relying solely on <code class="language-plaintext highlighter-rouge">[Authorize]</code> attributes, we can leverage the <strong><code class="language-plaintext highlighter-rouge">IAuthorizationService</code></strong> to manually check policies in our code.</p> <h2 id="step-1-define-the-authorization-policies">Step 1: Define the Authorization Policies</h2> <p>In <code class="language-plaintext highlighter-rouge">Program.cs</code>, we define multiple policies:</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">builder</span><span class="p">.</span><span class="n">Services</span><span class="p">.</span><span class="nf">AddAuthorization</span><span class="p">(</span><span class="n">options</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">options</span><span class="p">.</span><span class="nf">AddPolicy</span><span class="p">(</span><span class="n">KnownApiPolicies</span><span class="p">.</span><span class="n">AdminApiPolicyForServiceAccount</span><span class="p">,</span> <span class="n">policy</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">policy</span><span class="p">.</span><span class="nf">RequireClaim</span><span class="p">(</span><span class="s">"scope"</span><span class="p">,</span> <span class="s">"admin-client"</span><span class="p">);</span> <span class="p">});</span> <span class="n">options</span><span class="p">.</span><span class="nf">AddPolicy</span><span class="p">(</span><span class="n">KnownApiPolicies</span><span class="p">.</span><span class="n">AdminApiPolicyForLoggedInUserAdministrator</span><span class="p">,</span> <span class="n">policy</span> <span class="p">=&gt;</span> <span class="p">{</span> <span class="n">policy</span><span class="p">.</span><span class="n">Requirements</span><span class="p">.</span><span class="nf">Add</span><span class="p">(</span><span class="k">new</span> <span class="nf">DbRoleRequirement</span><span class="p">(</span><span class="n">Custom</span><span class="p">.</span><span class="n">UserAdminInDatabase</span><span class="p">));</span> <span class="p">});</span> <span class="p">});</span> </code></pre></div></div> <h2 id="step-2-manually-validate-user-authorization">Step 2: Manually Validate User Authorization</h2> <p>Using <code class="language-plaintext highlighter-rouge">IAuthorizationService</code>, we can manually check if the user meets <strong>either</strong> of the defined policies.</p> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">private</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">AuthorizationResultType</span><span class="p">&gt;</span> <span class="nf">ValidateUserAuthorization</span><span class="p">()</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">user</span> <span class="p">=</span> <span class="n">User</span><span class="p">;</span> <span class="kt">var</span> <span class="n">serviceAccountAuth</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_authorizationService</span><span class="p">.</span><span class="nf">AuthorizeAsync</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">KnownApiPolicies</span><span class="p">.</span><span class="n">AdminApiPolicyForServiceAccount</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">serviceAccountAuth</span><span class="p">.</span><span class="n">Succeeded</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">AuthorizationResultType</span><span class="p">.</span><span class="n">ServiceAccount</span><span class="p">;</span> <span class="p">}</span> <span class="kt">var</span> <span class="n">userAuth</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_authorizationService</span><span class="p">.</span><span class="nf">AuthorizeAsync</span><span class="p">(</span><span class="n">user</span><span class="p">,</span> <span class="n">KnownApiPolicies</span><span class="p">.</span><span class="n">AdminApiPolicyForLoggedInUserAdministrator</span><span class="p">);</span> <span class="k">if</span> <span class="p">(</span><span class="n">userAuth</span><span class="p">.</span><span class="n">Succeeded</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="n">AuthorizationResultType</span><span class="p">.</span><span class="n">LoggedInUser</span><span class="p">;</span> <span class="p">}</span> <span class="k">return</span> <span class="n">AuthorizationResultType</span><span class="p">.</span><span class="n">None</span><span class="p">;</span> <span class="p">}</span> </code></pre></div></div> <h2 id="step-3-apply-the-authorization-logic-in-the-controller">Step 3: Apply the Authorization Logic in the Controller</h2> <div class="language-csharp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">[</span><span class="n">HttpGet</span><span class="p">]</span> <span class="k">public</span> <span class="k">async</span> <span class="n">Task</span><span class="p">&lt;</span><span class="n">ActionResult</span><span class="p">&lt;...&gt;&gt;</span> <span class="nf">GetAsync</span><span class="p">()</span> <span class="p">{</span> <span class="kt">var</span> <span class="n">authResult</span> <span class="p">=</span> <span class="k">await</span> <span class="nf">ValidateUserAuthorization</span><span class="p">();</span> <span class="k">if</span> <span class="p">(</span><span class="n">authResult</span> <span class="p">==</span> <span class="n">AuthorizationResultType</span><span class="p">.</span><span class="n">None</span><span class="p">)</span> <span class="p">{</span> <span class="k">return</span> <span class="nf">Forbid</span><span class="p">();</span> <span class="c1">// Return 403 if unauthorized</span> <span class="p">}</span> <span class="k">using</span> <span class="nn">var</span> <span class="n">contextScope</span> <span class="p">=</span> <span class="n">authResult</span> <span class="k">switch</span> <span class="p">{</span> <span class="n">AuthorizationResultType</span><span class="p">.</span><span class="n">ServiceAccount</span> <span class="p">=&gt;</span> <span class="c1">// ... do something with the result,</span> <span class="n">AuthorizationResultType</span><span class="p">.</span><span class="n">LoggedInUser</span> <span class="p">=&gt;</span> <span class="c1">// ...,</span> <span class="n">_</span> <span class="p">=&gt;</span> <span class="k">throw</span> <span class="k">new</span> <span class="nf">UnauthorizedAccessException</span><span class="p">()</span> <span class="p">};</span> <span class="k">return</span> <span class="nf">Ok</span><span class="p">(</span><span class="n">_userService</span><span class="p">.</span><span class="nf">GetUsers</span><span class="p">(...));</span> <span class="p">}</span> </code></pre></div></div> <h1 id="recap">Recap</h1> <p>We use the <code class="language-plaintext highlighter-rouge">IAuthorizationService.AuthorizeAsync</code> method to check multiple policies and depending on the outcome, we can handle it depending on our needs. This approach retains the same overall structure as the “default” policy-based authorization in ASP.NET Core but provides more flexibility by allowing policies to be evaluated dynamically via the service.</p> <p>Keep in mind (as mentioned at the beginning): This is just one way of handling authorization. As far as we know, it works well without drawbacks while offering the flexibility we need.</p> https://blog.codeinside.eu/2025/02/25/aspnetcore-authorizationservice-to-validate-policies/ https://blog.codeinside.eu/2025/02/25/aspnetcore-authorizationservice-to-validate-policies Tue, 25 Feb 2025 00:30:00 +0000 Azure Resource Groups are not just dumb folders <h2 id="general">General</h2> <p>An Azure Resource Group is more or less one of the first things you need to create under your Azure subscription because most services need to be placed in an Azure Resource Group.</p> <p>A resource group has a name and a region, and it feels just like a “folder,” but it’s (sadly) more complicated, and I want to showcase this with App Service Plans.</p> <h2 id="what-is-an-app-service-plan">What is an App Service Plan?</h2> <p>If you run a Website/Web Service/Web API on Azure, one option would be <a href="https://azure.microsoft.com/en-us/products/app-service/web"><strong>Web Apps-Service</strong></a>.</p> <p>If you are a traditional IIS developer, the “Web Apps-Service” is somewhat like a “Web Site” in IIS.</p> <p>When you create a brand-new “Web Apps-Service,” you will need to create an “App Service Plan” as well.</p> <p>The “App Service Plan” is the system that hosts your “Web App-Service.” The “App Service Plan” is also what actually costs you money, and you can host multiple “Web App-Services” under one “App Service Plan.”</p> <p>All services need to be created in a resource group.</p> <h2 id="recap">Recap</h2> <p>An “App Service Plan” can host multiple “Web App-Services.” The price is related to the instance count and the actual plan.</p> <p>Here is a screenshot from one of our app plans:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2025-01-29/app-service.png" alt="x" title="App Service Plan" /></p> <p>So far, so good, right?</p> <p>A few months later, we created another resource group in a different region with a new app plan and discovered that there were more plans to choose from:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2025-01-29/more-plans.png" alt="x" title="More Plans" /></p> <p>Especially those memory-optimized plans (“P1mV3” etc.) are interesting for our product.</p> <h2 id="the-problem">The problem</h2> <p>So we have two different “App Service Plans” in different resource groups, and one App Service Plan did not show the option for the memory-optimized plans.</p> <p>This raises a simple question: Why and is there an easy way to fix it?</p> <h2 id="things-that-wont-work">Things that won’t work</h2> <p>First, I created a <strong>new</strong> “App Service Plan” within the same resource group as the “old” “App Service Plan,” but this operation failed:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2025-01-29/error.png" alt="x" title="Error" /></p> <p>Then I tried to just move the existing “App Service Plan” to a new resource group, but even then, I <strong>could not change</strong> the SKU to the memory-optimized plan.</p> <h2 id="the-reason--solution">The “reason” &amp; solution</h2> <p>After some frustration - since we had existing services and wanted to maintain our structure - I found this <a href="https://learn.microsoft.com/en-us/azure/app-service/app-service-configure-premium-tier">documentation site</a>.</p> <blockquote> <p>Scale up from an unsupported resource group and region combination</p> <p>If your app runs in an App Service deployment where Premium V3 isn’t available, or if your app runs in a region that currently does not support Premium V3, you need to re-deploy your app to take advantage of Premium V3. Alternatively newer Premium V3 SKUs may not be available, in which case you also need to re-deploy your app to take advantage of newer SKUs within Premium V3. …</p> </blockquote> <p>It seems the behavior is “as designed,” but I would say that the design is a hassle.</p> <p>The documentation points out two options for this, but in the end, we will need to create a new app plan and recreate all “Web App-Services” in a new resource group.</p> <h2 id="lessons-learned">Lessons learned?</h2> <p>At first glance, I thought that “resource groups” acted like folders, but underneath—depending on the region, subscription, and existing services within that resource group—some options might not be available.</p> <p>Bummer, but hey… at least we learned something.</p> https://blog.codeinside.eu/2025/01/29/azure-resource-groups-are-not-just-dumb-folders/ https://blog.codeinside.eu/2025/01/29/azure-resource-groups-are-not-just-dumb-folders Wed, 29 Jan 2025 23:30:00 +0000 WinINet, WinHTTP and the HttpClient from .NET <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>A customer inquiry brought the topic of “<a href="https://learn.microsoft.com/en-us/windows/win32/wininet/about-wininet">WinINet</a>” and “<a href="https://learn.microsoft.com/en-us/windows/win32/winhttp/winhttp-start-page">WinHTTP</a>” to my attention. This blog post is about finding out what this is all about and how and whether or not these components are related to the HttpClient of the .NET Framework or .NET Core.</p> <h2 id="general">General</h2> <p>Both WinINet and WinHTTP are APIs for communication via the HTTP/HTTPS protocol and Windows components. A detailed comparison page can be found <a href="https://learn.microsoft.com/en-us/windows/win32/wininet/wininet-vs-winhttp">here</a>.</p> <h2 id="wininet">WinINet</h2> <p>WinINet is intended in particular for client applications (such as a browser or other applications that communicate via HTTP). In addition to pure HTTP communication, WinINet also has configuration options for proxies, cookie and cache management.</p> <p>However, WinINet is not intended for building server-side applications or very scalable applications.</p> <h2 id="winhttp">WinHTTP</h2> <p>WinHTTP is responsible for the last use case, which even runs a “kernel module” and is therefore much more performant.</p> <h2 id="net-httpclient">.NET HttpClient</h2> <p>At first glance, it sounds as if the HttpClient should access WinINet from the .NET Framework or .NET Core (or .NET 5, 6, 7, …) - but this is <strong>not</strong> the case.</p> <p><strong>Instead:</strong></p> <p>The .NET Framework relies on <strong>WinHTTP</strong>. Until .NET Core 2.1, the substructure was also based on <strong>WinHTTP</strong>.</p> <p>Since .NET Core 2.1, however, a platform-independent “<a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.socketshttphandler">SocketsHttpHandler</a>” works under the HttpClient by default. However, the HttpClient can partially read the <strong>Proxy settings from the WinINet</strong> world.</p> <p>The “<a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.winhttphandler">WinHttpHandler</a>” is still available as an option, although the use case for this is unknown to me.</p> <p>During my research, I noticed this <a href="https://github.com/dotnet/runtime/issues/1384">GitHub issue</a>. This issue is about the new SocketsHttpHandler implementation not being able to access the same WinINet features for cache management. The topic is rather theoretical and the issue is already several years old.</p> <h2 id="summary">Summary</h2> <p>What have we learned now? Microsoft has implemented several Http stacks and in “modern” .NET the HttpClient uses its own handler.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2025/01/09/wininet-winhttp-and-the-dotnet-httpclient/ https://blog.codeinside.eu/2025/01/09/wininet-winhttp-and-the-dotnet-httpclient Thu, 09 Jan 2025 00:30:00 +0000 Microsoft Defender Performance Analyzer <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>A customer notified us that our product was slowing down their Microsoft Office installation at startup. Everything on our side seemed fine, but sometimes Office took 10–15 seconds to start.</p> <p>After some research, I stumbled upon this: <a href="https://learn.microsoft.com/en-us/defender-endpoint/tune-performance-defender-antivirus">Performance analyzer for Microsoft Defender Antivirus</a>.</p> <h1 id="how-to-run-the-performance-analyzer">How to run the Performance Analyzer</h1> <p>The best part about this application is how easy it is to use (as long as you have a prompt with admin privileges). Simply run this PowerShell command:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>New-MpPerformanceRecording -RecordTo recording.etl </code></pre></div></div> <p>This will start the recording session. After that, launch the program you want to analyze (e.g., Microsoft Office). When you’re done, press <code class="language-plaintext highlighter-rouge">Enter</code> to stop the recording.</p> <p>The generated <code class="language-plaintext highlighter-rouge">recording.etl</code> file can be complex to read and understand. However, there’s another command to extract the “Top X” scans, which makes the data way more readable.</p> <p>Use this command to generate a CSV file containing the top 1,000 files scanned by Defender during that time:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(Get-MpPerformanceReport -Path .\recording.etl -Topscans 1000).TopScans | Export-CSV -Path .\recording.csv -Encoding UTF8 -NoTypeInformation </code></pre></div></div> <p>Using this tool, we discovered that Microsoft Defender was scanning all our assemblies, which was causing Office to start so slowly.</p> <p>Now you know: If you ever suspect that Microsoft Defender is slowing down your application, just check the logs.</p> <p><strong>Note:</strong> After this discovery, the customer adjusted their Defender settings, and everything worked as expected.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/11/21/microsoft-defender-perf-analyzer/ https://blog.codeinside.eu/2024/11/21/microsoft-defender-perf-analyzer Thu, 21 Nov 2024 23:59:00 +0000 OpenAI API, LM Studio and Ollama <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>I had the opportunity to attend the <a href="https://www.dd-dotnet.de/">.NET User Group Dresden</a> at the beginning of September for the exciting topic “<a href="https://www.dd-dotnet.de/treffen/2024/09/04/hands-on-open-source-llms-nutzen.html">Using Open Source LLMs</a>” and learned a couple of things.</p> <h1 id="how-to-choose-an-llm">How to choose an LLM?</h1> <p>There are tons of LLMs (= Large Language Models) that can be used, but which one should we choose? There is no general answer to that - of course - but there is a <a href="https://lmarena.ai/?leaderboard">Chatbot Arena Leaderboard</a>, which measures the “cleverness” between those models. Be aware of the license of each model.</p> <p>There is also a <a href="https://huggingface.co/chat/">HuggingChat</a>, where you can pick some models and experiment with them.</p> <p>For your first steps on your local hardware: <a href="https://huggingface.co/microsoft/Phi-3-mini-4k-instruct">Phi3</a> does a good job and is not a huge model.</p> <h1 id="lm-studio">LM Studio</h1> <p>Ok, you have a model and an idea, but how to play with it on your local machine?</p> <p>The best tool for such a job is: <strong><a href="https://lmstudio.ai/">LM Studio</a></strong>.</p> <p>The most interesting part was (and this was “new” to me), that you run those local models in an <strong>local, OpenAI compatible (!!!) server</strong>.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-09-17/lmstudio.png" alt="x" title="png" /></p> <h1 id="openai-compatible-server">OpenAI Compatible server?!</h1> <p>If you want to experiment with a lightweight model on your system and interact with it, then it is super handy, if you can use the <strong>standard OpenAI client</strong> and just run against your local “OpenAI”-like server.</p> <p>Just start the server, use the localhost endpoint and you can use a code like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>using OpenAI.Chat; using System.ClientModel; ChatClient client = new(model: "model", "key", new OpenAI.OpenAIClientOptions() { Endpoint = new Uri("http://localhost:1234/v1") }); ChatCompletion chatCompletion = client.CompleteChat( [ new UserChatMessage("Say 'this is a test.'"), ]); Console.WriteLine(chatCompletion.Content[0].Text); </code></pre></div></div> <p>The <code class="language-plaintext highlighter-rouge">model</code> and the <code class="language-plaintext highlighter-rouge">key</code> don’t seem to matter that much (or at least I worked on my machine). The <code class="language-plaintext highlighter-rouge">localhost:1234</code> service is hosted by LM Studio on my machine. The actual model can be configured in LM Studio and there is a huge choice available.</p> <p>Even streaming is supported:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>AsyncCollectionResult&lt;StreamingChatCompletionUpdate&gt; updates = client.CompleteChatStreamingAsync("Write a short story about a pirate."); Console.WriteLine($"[ASSISTANT]:"); await foreach (StreamingChatCompletionUpdate update in updates) { foreach (ChatMessageContentPart updatePart in update.ContentUpdate) { Console.Write(updatePart.Text); } } </code></pre></div></div> <h1 id="ollama">Ollama</h1> <p>The obvious next question is: How can I run my own LLM on my own server? LM Studio works fine, but it’s just a development tool.</p> <p>One answer could be: <strong><a href="https://ollama.com/">Ollama</a></strong>, which can run large language models and has a <a href="https://ollama.com/blog/openai-compatibility">compatibility to the OpenAI API</a>.</p> <h1 id="is-there-an-ollama-for-net-devs">Is there an Ollama for .NET devs?</h1> <p>Ollama looks cool, but I was hoping to find an “OpenAI compatible .NET facade”. I already played with <a href="https://blog.codeinside.eu/2024/05/15/llamasharp-run-a-chatgpt-like-system-on-your-hardware-for-dummies/">LLamaSharp</a>, but <code class="language-plaintext highlighter-rouge">LLamaSharp</code> <a href="https://github.com/SciSharp/LLamaSharp/issues/269">doesn’t offer currently a WebApi, but there are some ideas around</a>. My friend <a href="https://github.com/GregorBiswanger">Gregor Biswanger</a> released <a href="https://github.com/GregorBiswanger/OllamaApiFacade">OllamaApiFacade</a>, which looks promising, but at least it doesn’t offer a real OpenAI compatible .NET facade, but maybe this will be added in the future.</p> <h1 id="acknowledgment">Acknowledgment</h1> <p>Thanks to the .NET User Group for hosting the meetup, and a special thanks to my good friend <a href="https://github.com/oliverguhr"><strong>Oliver Guhr</strong></a>, who was also the speaker!</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/09/17/openai-api-lmstudio-ollama/ https://blog.codeinside.eu/2024/09/17/openai-api-lmstudio-ollama Tue, 17 Sep 2024 23:59:00 +0000 Entity Framework Core 8.0 Breaking Changes & SQL Compatibility Level <p>We recently switched from .NET 6 to .NET 8 and encountered the following Entity Framework Core error:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Microsoft.Data.SqlClient.SqlException: 'Incorrect syntax near the keyword 'WITH'.... </code></pre></div></div> <p>The EF code uses the <code class="language-plaintext highlighter-rouge">Contains</code> method as shown below:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var names = new[] { "Blog1", "Blog2" }; var blogs = await context.Blogs .Where(b =&gt; names.Contains(b.Name)) .ToArrayAsync(); </code></pre></div></div> <p>Before .NET 8 this would result in the following Sql statement:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT [b].[Id], [b].[Name] FROM [Blogs] AS [b] WHERE [b].[Name] IN (N'Blog1', N'Blog2') </code></pre></div></div> <p>… and with .NET 8 it uses the <code class="language-plaintext highlighter-rouge">OPENJSON</code> function, which is <strong>not supported on older versions like SQL Server 2014 or if the compatibility level is below 130 (!)</strong></p> <ul> <li>See <a href="https://devblogs.microsoft.com/dotnet/announcing-ef8-preview-4/">this blogpost</a> for more information about the <code class="language-plaintext highlighter-rouge">OPENJSON</code> change.</li> </ul> <h1 id="the-fix-is-simple">The fix is “simple”</h1> <p>Ensure you’re not using an unsupported SQL version <strong>and</strong> that the <code class="language-plaintext highlighter-rouge">Compatibility Level</code> is at least on <strong>level 130</strong>.</p> <p>If you can’t change the system, then you could also enforce the “old” behavior with a setting like this (not recommended, because it is slower!)</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>... .UseSqlServer(@"&lt;CONNECTION STRING&gt;", o =&gt; o.UseCompatibilityLevel(120)); </code></pre></div></div> <h1 id="how-to-make-sure-your-database-is-on-compatibility-level-130">How to make sure your database is on Compatibility Level 130?</h1> <p>Run this statement to check the compatibility level:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>SELECT name, compatibility_level FROM sys.databases; </code></pre></div></div> <p>We updated our test/dev SQL Server and then moved all databases to the latest version with this SQL statement:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>DECLARE @DBName NVARCHAR(255) DECLARE @SQL NVARCHAR(MAX) -- Cursor to loop through all databases DECLARE db_cursor CURSOR FOR SELECT name FROM sys.databases WHERE name NOT IN ('master', 'tempdb', 'model', 'msdb') -- Exclude system databases OPEN db_cursor FETCH NEXT FROM db_cursor INTO @DBName WHILE @@FETCH_STATUS = 0 BEGIN -- Construct the ALTER DATABASE command SET @SQL = 'ALTER DATABASE [' + @DBName + '] SET COMPATIBILITY_LEVEL = 150;' EXEC sp_executesql @SQL FETCH NEXT FROM db_cursor INTO @DBName END CLOSE db_cursor DEALLOCATE db_cursor </code></pre></div></div> <h1 id="check-ef-core-breaking-changes">Check EF Core Breaking Changes</h1> <p>There are other breaking changes, but only the first one affected us: <a href="https://learn.microsoft.com/en-us/ef/core/what-is-new/ef-core-8.0/breaking-changes#sqlserver-contains-compatibility">Breaking Changes</a></p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/09/08/ef-core-8-breaking-changes-and-sql-compatibility-level/ https://blog.codeinside.eu/2024/09/08/ef-core-8-breaking-changes-and-sql-compatibility-level Sun, 08 Sep 2024 23:59:00 +0000 Connection Resiliency for Entity Framework Core and SqlClient <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>If you work with SQL Azure you might find this familiar:</p> <blockquote> <p>Unexpected exception occurred: An exception has been raised that is likely due to a transient failure. Consider enabling transient error resiliency by adding ‘EnableRetryOnFailure’ to the ‘UseSqlServer’ call.</p> </blockquote> <h1 id="ef-core-resiliency">EF Core Resiliency</h1> <p>The above error already shows a very simple attempt to “stabilize” your application. If you are using Entity Framework Core, this could look like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder .UseSqlServer( @"Server=(localdb)\mssqllocaldb;Database=EFMiscellanous.ConnectionResiliency;Trusted_Connection=True;ConnectRetryCount=0", options =&gt; options.EnableRetryOnFailure()); } </code></pre></div></div> <p>The <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.entityframeworkcore.infrastructure.sqlserverdbcontextoptionsbuilder.enableretryonfailure?view=efcore-8.0">EnableRetryOnFailure-Method</a> has a couple of options, like a retry count or the retry delay.</p> <p>If you don’t use the <code class="language-plaintext highlighter-rouge">UseSqlServer</code>-method to configure your context, there are other ways to enable this behavior: <a href="https://learn.microsoft.com/en-us/ef/core/miscellaneous/connection-resiliency">See Microsoft Docs</a></p> <h1 id="microsoftdatasqlclient---retry-provider">Microsoft.Data.SqlClient - Retry Provider</h1> <p>If you use the “plain” <code class="language-plaintext highlighter-rouge">Microsoft.Data.SqlClient</code> NuGet Package to connect to your database have a look at <a href="https://learn.microsoft.com/en-us/sql/connect/ado-net/configurable-retry-logic?view=sql-server-ver16">Retry Logic Providers</a></p> <p>A basic implementation would look like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>// Define the retry logic parameters var options = new SqlRetryLogicOption() { // Tries 5 times before throwing an exception NumberOfTries = 5, // Preferred gap time to delay before retry DeltaTime = TimeSpan.FromSeconds(1), // Maximum gap time for each delay time before retry MaxTimeInterval = TimeSpan.FromSeconds(20) }; // Create a retry logic provider SqlRetryLogicBaseProvider provider = SqlConfigurableRetryFactory.CreateExponentialRetryProvider(options); // Assumes that connection is a valid SqlConnection object // Set the retry logic provider on the connection instance connection.RetryLogicProvider = provider; // Establishing the connection will retry if a transient failure occurs. connection.Open(); </code></pre></div></div> <p>You can set a <code class="language-plaintext highlighter-rouge">RetryLogicProvider</code> on a <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnection.retrylogicprovider?view=sqlclient-dotnet-standard-5.2">Connection</a> and on a <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlcommand.retrylogicprovider?view=sqlclient-dotnet-standard-5.2">SqlCommand</a>.</p> <h1 id="some-more-links-and-tips">Some more links and tips</h1> <p>These two options seem to be the “low-level-entry-points”. Of course could you wrap each action with a library like <a href="https://github.com/App-vNext/Polly">Polly</a>.</p> <p>During my research I found a good overview: <a href="https://learn.microsoft.com/en-us/dotnet/architecture/microservices/implement-resilient-applications/"><strong>Implementing Resilient Applications</strong></a>.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/09/02/connection-resiliency-for-ef-core-and-sql-data/ https://blog.codeinside.eu/2024/09/02/connection-resiliency-for-ef-core-and-sql-data Mon, 02 Sep 2024 23:59:00 +0000 UrlEncode the Space Character <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>This might seem trivial, but last week I noticed that the <a href="https://learn.microsoft.com/en-us/dotnet/api/system.web.httputility.urlencode?view=net-8.0">HttpUtility.UrlEncode(string)</a> encodes a space ` ` into <code class="language-plaintext highlighter-rouge">+</code>, whereas the JavaScript <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURI">encodeURI(string)</a> method encodes a space as <code class="language-plaintext highlighter-rouge">%20</code>. This brings up the question:</p> <h1 id="why">Why?</h1> <p>It seems that in the early specifications, a space was encoded into a <code class="language-plaintext highlighter-rouge">+</code>, see this <a href="https://en.wikipedia.org/wiki/Percent-encoding">Wikipedia</a> entry:</p> <blockquote> <p>When data that has been entered into HTML forms is submitted, the form field names and values are encoded and sent to the server in an HTTP request message using method GET or POST, or, historically, via email.[3] The encoding used by default is based on an early version of the general URI percent-encoding rules,[4] with a number of modifications such as newline normalization and replacing spaces with + instead of %20. The media type of data encoded this way is application/x-www-form-urlencoded, and it is currently defined in the HTML and XForms specifications. In addition, the CGI specification contains rules for how web servers decode data of this type and make it available to applications.</p> </blockquote> <p>This convention has persisted to this day. For instance, when you search something on Google or Bing with a space in the query, the space is encoded as a <code class="language-plaintext highlighter-rouge">+</code>.</p> <p>There seems to be some rules however, e.g. it is only “allowed” in the query string or as form parameters.</p> <p>I found the <a href="https://stackoverflow.com/questions/1634271/url-encoding-the-space-character-or-20">question &amp; answers on StackOverflow</a> quite informative, and <a href="https://stackoverflow.com/a/72833702">this answer</a> summarizes it well enough for me:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>| standard | + | %20 | |---------------+-----+-----| | URL | no | yes | | query string | yes | yes | | form params | yes | no | | mailto query | no | yes | </code></pre></div></div> <h1 id="what-about-net">What about .NET?</h1> <p>If you want to always encode spaces as <code class="language-plaintext highlighter-rouge">%20</code>, use the <code class="language-plaintext highlighter-rouge">UrlPathEncode</code> method, see <a href="https://learn.microsoft.com/en-us/dotnet/api/system.web.httputility.urlencode?view=net-8.0">here</a>.</p> <blockquote> <p>You can encode a URL using with the UrlEncode method or the UrlPathEncode method. However, the methods return different results. The UrlEncode method converts each space character to a plus character (+). The UrlPathEncode method converts each space character into the string “%20”, which represents a space in hexadecimal notation. Use the UrlPathEncode method when you encode the path portion of a URL in order to guarantee a consistent decoded URL, regardless of which platform or browser performs the decoding.</p> </blockquote> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/08/20/urlencoding-the-space-char/ https://blog.codeinside.eu/2024/08/20/urlencoding-the-space-char Tue, 20 Aug 2024 23:59:00 +0000 dsregcmd, WAM and 'Connected to Windows'-Accounts <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>I was researching if it is possible to have a “real” single-sign-on experience with Azure AD/Entra ID and third-party desktop applications and I stumbled across a few things during my trip.</p> <h1 id="real-sso">“Real” SSO?</h1> <p>There are a bunch of definitions out there about SSO. Most of the time, SSO just means: You can use the same account in different applications.</p> <p>But some argue that a “real” SSO experience should mean: You log in to your Windows Desktop environment, and that’s it - each application should just use the existing Windows account.</p> <h1 id="problems">Problems</h1> <p>With “Integrated Windows Auth,” this was quite easy, but with Entra ID, it seems really hard. Even Microsoft seems to struggle with this task, because even Microsoft Teams and Office need at least a hint like an email address to sign in the actual user.</p> <h1 id="solution">Solution?</h1> <p>I _didn’t__ found a solution for this (complex) problem, but I found a few interesting tools/links that might help achieve it.</p> <p><em>Please let me know if you find a solution 😉</em></p> <h1 id="dsregcmd">“dsregcmd”</h1> <p>There is a tool called <a href="https://learn.microsoft.com/en-us/entra/identity/devices/troubleshoot-device-dsregcmd">dsregcmd</a>, which stands for “Directory Service Registration” and shows how your device is connected to Azure AD.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS C:\Users\muehsig&gt; dsregcmd /? DSREGCMD switches /? : Displays the help message for DSREGCMD /status : Displays the device join status /status_old : Displays the device join status in old format /join : Schedules and monitors the Autojoin task to Hybrid Join the device /leave : Performs Hybrid Unjoin /debug : Displays debug messages /refreshprt : Refreshes PRT in the CloudAP cache /refreshp2pcerts : Refreshes P2P certificates /cleanupaccounts : Deletes all WAM accounts /listaccounts : Lists all WAM accounts /UpdateDevice : Update device attributes to Azure AD </code></pre></div></div> <p>In Windows 11 - as far as I know - a new command was implemented: <code class="language-plaintext highlighter-rouge">/listaccounts</code></p> <h1 id="dsregcmd-listaccounts">dsregcmd /listaccounts</h1> <p>This command lists all “WAM” accounts from my current profile:</p> <p><em>The <code class="language-plaintext highlighter-rouge">...xxxx...</code> is used to hide information</em></p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS C:\Users\muehsig&gt; dsregcmd /listaccounts Call ListAccounts to list WAM accounts from the current user profile. User accounts: Account: u:a17axxxx-xxxx-xxxx-xxxx-1caa2b93xxxx.85c7xxxx-xxxx-xxxx-xxxx-34dc6b33xxxx, user: [email protected], authority: https://login.microsoftonline.com/85c7xxxx-xxxx-xxxx-xxxx-34dc6b33xxxx. Accounts found: 1. Application accounts: Accounts found: 0. Default account: u:a17axxxx-xxxx-xxxx-xxxx-1caa2b93xxxx.85c7xxxx-xxxx-xxxx-xxxx-34dc6b33xxxx, user: [email protected]. </code></pre></div></div> <h1 id="what-is-wam">What is WAM?</h1> <p>It’s <strong>not</strong> the cool x-mas band with the fancy song (that we all love!).</p> <p>WAM stands for <strong>Web Account Manager</strong> and it integrates with the Windows <strong>Email &amp; accounts</strong> setting:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-08-06/wam.png" alt="x" title="WAM" /></p> <p>WAM can also be used to <a href="https://learn.microsoft.com/en-us/entra/identity-platform/scenario-desktop-acquire-token-wam">obtain a Token</a> - which might be the right direction for my SSO question, but I couldn’t find the time to test this out.</p> <h1 id="connected-to-windows">“Connected to Windows”</h1> <p>This is now pure speculation, because I couldn’t find any information about it, but I think the “Connected to Windows” hint here:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-08-06/login.png" alt="x" title="Login" /></p> <p>… is based on the <strong>Email &amp; accounts</strong> setting (= WAM), and with <code class="language-plaintext highlighter-rouge">dsregcmd /listaccounts</code> I can see diagnostic information about it.</p> <h1 id="seamless-single-sign-on">“Seamless single sign-on”</h1> <p>I found <a href="https://learn.microsoft.com/en-us/entra/identity/hybrid/connect/tshoot-connect-sso">this troubleshooting guide</a> and it seems that there is a thing called “seamless single sign-on”, but I’m not 100% sure if this is more a “Development” topic or “IT-Pro” topic (or a mix of both).</p> <h1 id="til">TIL</h1> <p>I (and you!) have learned about a tool called <code class="language-plaintext highlighter-rouge">dsregcmd</code>.</p> <p>Try out the <code class="language-plaintext highlighter-rouge">dsregcmd /status</code>, it’s like <code class="language-plaintext highlighter-rouge">ipconfig /all</code>, but for information about AD connectivity.</p> <p><code class="language-plaintext highlighter-rouge">WAM</code> plays an important part with the “Email &amp; accounts” setting and maybe this is the right direction for the actual SSO topic.</p> <h1 id="open-questions">Open questions…</h1> <p>Some open questions:</p> <ul> <li>Why does <code class="language-plaintext highlighter-rouge">dsregcmd /listAccounts</code> only list one account when I have two accounts attached under the “WAM” (see screenshot - a Azure AD account AND an Microsoft account)?</li> <li>Where does “Connected to Windows” come from? How does the browser know this?</li> <li>What is “seamless single-sign-on”?</li> </ul> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/08/06/dsregcmd-wam-and-connected-to-windows-accounts/ https://blog.codeinside.eu/2024/08/06/dsregcmd-wam-and-connected-to-windows-accounts Tue, 06 Aug 2024 23:59:00 +0000 SQL ConnectionString: Encrypt & Trust Server Certificate <p><em>This is more of a “Today-I-Learned” post and not a “full-blown How-To article.” If something is completely wrong, please let me know - thanks!</em></p> <p>In our product, we store all data in an MS SQL database. One of our clients had issues with the SQL connection, and I want to share what I learned about SQL Encryption and how (some) properties of the Connection String affect the behavior.</p> <h1 id="basic-sql-connection-string">Basic SQL Connection String</h1> <p>In general, we have a pretty easy setup:</p> <p>Our application reads a typical connection string that looks like this <code class="language-plaintext highlighter-rouge">Data Source=your-sql-server.yourcorp.local;Initial Catalog=database_x;User ID=username;Password=password_here;MultipleActiveResultSets=True;Encrypt=False</code> or (for Windows Authentication) <code class="language-plaintext highlighter-rouge">Integrated Security=true</code> instead of <code class="language-plaintext highlighter-rouge">User ID=username;Password=password_here</code>, and uses the (new) Microsoft.Data.SqlClient to connect to the database.</p> <p>Let’s look at all applied properties:</p> <ul> <li><a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.datasource?view=sqlclient-dotnet-standard-5.2">Data Source</a> points to the actual network address of the SQL Server instance.</li> <li><a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.initialcatalog?view=sqlclient-dotnet-standard-5.2">Initial Catalog</a> points to the actual database.</li> <li><a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.multipleactiveresultsets?view=sqlclient-dotnet-standard-5.2">MultipleActiveResultSets</a> is a good topic for another blogpost. I always enabled it in the past because of some Entity Framework issues, but it seems <a href="https://learn.microsoft.com/en-us/dotnet/framework/data/adonet/sql/multiple-active-result-sets-mars">MARS</a> is only needed and useful in certain <a href="https://stackoverflow.com/questions/59607616/when-should-i-use-multipleactiveresultsets-true-when-working-with-asp-net-core-3">scenarios</a>.</li> <li>The auth part is handled via <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.integratedsecurity?view=sqlclient-dotnet-standard-5.2">IntegratedSecurity</a> or <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.userid?view=sqlclient-dotnet-standard-5.2">User-Id</a></li> </ul> <p>Since <a href="https://github.com/dotnet/SqlClient/blob/main/release-notes/4.0/4.0.0.md#breaking-changes">Version 4.0</a> of the Microsoft.Data.SqlClient the <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.encrypt?view=sqlclient-dotnet-standard-5.2">Encrypt</a> property defaults to <strong>true</strong> instead of <strong>false</strong>, and now we are entering the field of encryption…</p> <h1 id="encryption">Encryption</h1> <p>We usally use <code class="language-plaintext highlighter-rouge">Encrypt=False</code>, because in most cases, there is no proper certificate installed on the SQL Server - at least this is our experience with our clients. If a client has a proper setup, we recommend using it, of course, but most of the time there is none.</p> <p>With <code class="language-plaintext highlighter-rouge">Encrypt=True</code>, the data between the client and the server is TLS encrypted (and this is a good thing, and the breaking change therefore had a good intention).</p> <p><em>If you are interested how to set it up, this might be a good starting point for you: <a href="https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/configure-sql-server-encryption?view=sql-server-ver15">Configure SQL Server Database Engine for encrypting connections</a></em></p> <p>In some cases, your client might not be able to trust the server certificate (e.g. there is just a self-signed cert installed on the SQL server). Then you can disable the certification validation via <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.trustservercertificate?view=sqlclient-dotnet-standard-5.2">TrustServerCertification</a>, but this <strong>shouldn’t</strong> be used (at least in production) or handled with care. If the certificate doesn’t match the name of the <code class="language-plaintext highlighter-rouge">Data Source</code>, then you can use <a href="https://learn.microsoft.com/en-us/dotnet/api/microsoft.data.sqlclient.sqlconnectionstringbuilder.hostnameincertificate?view=sqlclient-dotnet-standard-5.2">HostNameInCertificate</a>.</p> <h1 id="what-have-i-learned">What have I learned?</h1> <p>I already knew about <code class="language-plaintext highlighter-rouge">Encrypt=True</code> or <code class="language-plaintext highlighter-rouge">Encrypt=False</code>, but the behavior of <code class="language-plaintext highlighter-rouge">TrustServerCertification</code> (and when to use it) was new for me. This <a href="https://stackoverflow.com/questions/3674160/using-encrypt-yes-in-a-sql-server-connection-string-provider-ssl-provider">Stackoverflow-question</a> helped me a lot to discover it.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/07/22/sql-connectionstring-encrypt-and-trustservercertificate/ https://blog.codeinside.eu/2024/07/22/sql-connectionstring-encrypt-and-trustservercertificate Mon, 22 Jul 2024 23:59:00 +0000 LLamaSharp: Run a ChatGPT like system on your hardware for dummies <p><em>TL;DR summary: Check out the <a href="https://github.com/SciSharp/LLamaSharp">LLamaSharp Quick Start</a> and you will find everything that you need to know</em></p> <p>ChatGPT (and all those Microsoft Copilots out there that were build on top of this) is currently the synonym for AI based chat systems. As a dev you can just use the Azure OpenAI Services and integrate this in your app - I blogged about this <a href="https://blog.codeinside.eu/2023/03/23/first-steps-with-azure-openai-and-dotnet/">last year</a>.</p> <p>The only “downside” is, that you rely on a cloud system, that costs money and you need to trust the overall system and as a tech nerd it is always “cool” to host stuff yourself. Of course, there are a lot of other good reasons why hosting such a system yourself is a good idea, but we just stick with “it is cool” for this blogpost. (There are tons of reasons why this is a stupid idea as well, but we might do it anyway just for fun.)</p> <h1 id="is-there-something-for-net-devs">Is there something for .NET devs?</h1> <p>My AI knowledge is still quite low and I’m more a “.NET <a href="https://datascientest.com/en/all-about-back-end">backend developer</a>”, so I was looking for an easy solution for my problem and found “<a href="https://github.com/SciSharp/LLamaSharp">LLamaSharp</a>”.</p> <p>This blogpost and my experiment was inspired by Maarten Balliauws blog post <a href="https://blog.maartenballiauw.be/post/2023/06/15/running-large-language-models-locally-your-own-chatgpt-like-ai-in-csharp.html">“Running Large Language Models locally – Your own ChatGPT-like AI in C#”</a>, which is already a year old, but still a good intro in this topic.</p> <h1 id="llamasharp">LLamaSharp</h1> <p>From their <a href="https://github.com/SciSharp/LLamaSharp">GitHub Repo</a>:</p> <blockquote> <p>LLamaSharp is a cross-platform library to run 🦙LLaMA/LLaVA model (and others) on your local device. Based on llama.cpp, inference with LLamaSharp is efficient on both CPU and GPU. With the higher-level APIs and RAG support, it’s convenient to deploy LLM (Large Language Model) in your application with LLamaSharp.</p> </blockquote> <p><strong>Be aware:</strong> This blogpost is written with LLamaSharp version 0.12.0 - Maartens blogpost is based on version 0.3.0 and the model he was using is not working anymore.</p> <p>This sounds really good - let’s checkout the <a href="https://scisharp.github.io/LLamaSharp/0.12.0/QuickStart/">quick start</a></p> <p>The basic steps are easy: Just add the <a href="https://www.nuget.org/packages/LLamaSharp">LLamaSharp</a> and <a href="https://www.nuget.org/packages/LLamaSharp.Backend.Cpu">LLamaSharp.Backend.Cpu</a> NuGet package to your project and then search for a model… but where?</p> <h1 id="the-model">The model</h1> <p>From the quick start:</p> <blockquote> <p>There are two popular format of model file of LLM now, which are PyTorch format (.pth) and Huggingface format (.bin). LLamaSharp uses GGUF format file, which could be converted from these two formats. To get GGUF file, there are two options:</p> <p>Search model name + ‘gguf’ in Huggingface, you will find lots of model files that have already been converted to GGUF format. Please take care of the publishing time of them because some old ones could only work with old version of LLamaSharp.</p> <p>Convert PyTorch or Huggingface format to GGUF format yourself. Please follow the instructions of this part of llama.cpp readme to convert them with the python scripts.</p> <p>Generally, we recommend downloading models with quantization rather than fp16, because it significantly reduce the required memory size while only slightly impact on its generation quality.</p> </blockquote> <p>Okay… I ended up using the <a href="https://huggingface.co/models?search=gguf">huggingface-search-approach</a> and picked the <a href="https://huggingface.co/microsoft/Phi-3-mini-4k-instruct-gguf">Phi-3-mini-4k-instruct-gguf</a>, because I heard about it somewhere.</p> <h1 id="code">Code</h1> <p>After the initial search and download I could just copy/paste the quick start code in my project and hit run:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>using LLama.Common; using LLama; string modelPath = @"C:\temp\Phi-3-mini-4k-instruct-q4.gguf"; // change it to your own model path. var parameters = new ModelParams(modelPath) { ContextSize = 1024, // The longest length of chat as memory. GpuLayerCount = 2 // How many layers to offload to GPU. Please adjust it according to your GPU memory. }; using var model = LLamaWeights.LoadFromFile(parameters); using var context = model.CreateContext(parameters); var executor = new InteractiveExecutor(context); // Add chat histories as prompt to tell AI how to act. var chatHistory = new ChatHistory(); chatHistory.AddMessage(AuthorRole.System, "Transcript of a dialog, where the User interacts with an Assistant named Bob. Bob is helpful, kind, honest, good at writing, and never fails to answer the User's requests immediately and with precision."); chatHistory.AddMessage(AuthorRole.User, "Hello, Bob."); chatHistory.AddMessage(AuthorRole.Assistant, "Hello. How may I help you today?"); ChatSession session = new(executor, chatHistory); InferenceParams inferenceParams = new InferenceParams() { MaxTokens = 256, // No more than 256 tokens should appear in answer. Remove it if antiprompt is enough for control. AntiPrompts = new List&lt;string&gt; { "User:" } // Stop generation once antiprompts appear. }; Console.ForegroundColor = ConsoleColor.Yellow; Console.Write("The chat session has started.\nUser: "); Console.ForegroundColor = ConsoleColor.Green; string userInput = Console.ReadLine() ?? ""; while (userInput != "exit") { await foreach ( // Generate the response streamingly. var text in session.ChatAsync( new ChatHistory.Message(AuthorRole.User, userInput), inferenceParams)) { Console.ForegroundColor = ConsoleColor.White; Console.Write(text); } Console.ForegroundColor = ConsoleColor.Green; userInput = Console.ReadLine() ?? ""; } </code></pre></div></div> <p>The result is a “ChatGPT-like” chat bot (maybe not so smart, but it runs quick ok-ish on my Dell notebook:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-05-15/result.png" alt="x" title="Result" /></p> <h1 id="summary">Summary</h1> <p>After some research which model can be used with LLamaSharp it went really smoothly (even for a .NET dummy like me).</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/05/15/llamasharp-run-a-chatgpt-like-system-on-your-hardware-for-dummies/ https://blog.codeinside.eu/2024/05/15/llamasharp-run-a-chatgpt-like-system-on-your-hardware-for-dummies Wed, 15 May 2024 23:59:00 +0000 dotnet dev-certs https - How .NET Issues Your Local Dev HTTPS Certificate <p>If you start developing a ASP.NET Core application you will notice that your site is running under “http <strong>s</strong> ://localhost:1234” and that your browser is happy to accept it - so there are some questions to be asked.</p> <h1 id="why-https-on-your-local-dev-box">Why HTTPS on your local dev box?</h1> <p>The first question might be: Why is HTTPS on your local dev box even needed?</p> <p>At least two reasons for this (from my perspective):</p> <ul> <li>Browsers love HTTPS nowadays. There are some features, like websockets, that refuse to work with HTTP. I’m not 100% aware of all the problems, but running a webapp under HTTP in 2024 is painful (and rightfully so!).</li> <li>Integration with other services is mostly forbidden. If you rely on a 3rd party authentication system (e.g. Microsoft/Facebook/Google/Apple Login) they might accept “localhost” as a reply address, but might deny HTTP addresses.</li> </ul> <p>I wouldn’t count “security” as an issue here, because you are developing on your own system. If there is something on your machine HTTPS won’t help you at that point.</p> <h1 id="how-does-aspnet-core-issues-a-valid--trusted-cert">How does ASP.NET Core issues a valid &amp; trusted cert?</h1> <p>I’m not exactly sure when this happens, as it was already installed on my development machine.</p> <p>Either when you install the Visual Studio workload for ASP.NET Core or if you create your very first ASP.NET Core application the dev cert for localhost will be issued.</p> <h2 id="but-how">But how?</h2> <p>The .NET SDK ships with a CLI tool called <code class="language-plaintext highlighter-rouge">dotnet dev-certs https</code> and this tool issues the certificate. The output of this command will look like this if a valid and trusted certificate is found::</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS C:\Users\muehsig&gt; dotnet dev-certs https A valid HTTPS certificate is already present. </code></pre></div></div> <h2 id="dev-certs-https">dev-certs https</h2> <p>There are other options available:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS C:\Users\muehsig&gt; dotnet dev-certs https --help Usage: dotnet dev-certs https [options] Options: -ep|--export-path Full path to the exported certificate -p|--password Password to use when exporting the certificate with the private key into a pfx file or to encrypt the Pem exported key -np|--no-password Explicitly request that you don't use a password for the key when exporting a certificate to a PEM format -c|--check Check for the existence of the certificate but do not perform any action --clean Cleans all HTTPS development certificates from the machine. -i|--import Imports the provided HTTPS development certificate into the machine. All other HTTPS developer certificates will be cleared out --format Export the certificate in the given format. Valid values are Pfx and Pem. Pfx is the default. -t|--trust Trust the certificate on the current platform. When combined with the --check option, validates that the certificate is trusted. -v|--verbose Display more debug information. -q|--quiet Display warnings and errors only. -h|--help Show help information </code></pre></div></div> <h1 id="what-happens-when-the-cert-is-no-longer-valid">What happens when the cert is no longer valid?</h1> <p>This is an interesting one, because I had this experience just this week (and that’s the reason for this blogpost).</p> <p>A certificate needs to be in the certification store to be considered trusted. That means your “localhost”-dev cert will be stored in your personal certification store (at least on Windows):</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-03-15/devcerts.png" alt="x" title="Dev Cert in Certification Store" /></p> <p>As you can see, the command <code class="language-plaintext highlighter-rouge">dotnet dev-certs https --check --trust</code> will return something like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>A trusted certificate was found: E7A2FB302F26BCFFB7C21801C09081CF2FAAAD2C - CN=localhost - Valid from 2024-03-13 11:12:10Z to 2025-03-13 11:12:10Z - IsHttpsDevelopmentCertificate: true - IsExportable: true </code></pre></div></div> <p>If the certificate is stale, then your browser won’t accept it anymore and your web application will start, but can’t be viewed because your browser will refuse it.</p> <h1 id="how-to-repair-invalid-certificates">How to repair invalid certificates?</h1> <p>Use the two commands and it should work again:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet dev-certs https --clean </code></pre></div></div> <p>…which will remove the old certification and…</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet dev-certs https --trust </code></pre></div></div> <p>… to issue a new cert and invoke the trust dialog from Windows.</p> <h1 id="if-it-works">If it works…</h1> <p>There are some more options, e.g. to export the certificate, which can be useful in certain scenarios, but if you can use HTTPS on your local development machine and everything works you shouldn’t have to bother. If you want to learn more, checkout the <a href="https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-dev-certs">dotnet dev-certs</a> documentation.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/03/15/dotnet-dev-certs-https/ https://blog.codeinside.eu/2024/03/15/dotnet-dev-certs-https Fri, 15 Mar 2024 23:59:00 +0000 .NET Upgrade Assistant <p>For those facing the challenge of migrating their .NET Framework-based application to the modern .NET stack, Microsoft’s <a href="https://dotnet.microsoft.com/en-us/platform/upgrade-assistant">“Upgrade Assistant”</a> is highly recommended:</p> <iframe width="660" height="371" src="https://www.youtube.com/embed/3mPb4KAbz4Y" title="Upgrade Your .NET Projects Faster with Visual Studio" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <h1 id="what-is-the-upgrade-assistant">What is the “Upgrade Assistant”?</h1> <p>The “Upgrade Assistant” is a tool that can integrate into Visual Studio or be accessed <a href="https://learn.microsoft.com/en-us/dotnet/core/porting/upgrade-assistant-overview?WT.mc_id=dotnet-35129-website#upgrade-with-the-cli-tool">via CLI</a>. If you install the <a href="https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.upgradeassistant"><strong>extension</strong></a> for Visual Studio you will have a new option “Upgrade project” available in your Solution Explorer.</p> <h1 id="net-framework-to-new-and-more">.NET Framework to “new” and more…</h1> <p>Its main use case is upgrading .NET Framework-based WPF, WinForms, class libraries, or web applications to the newest .NET version. Besides this, the tool offers some other migration paths as well, e.g. from UWP to WinUI 3.</p> <p>You even can use the tool to migrate from an older .NET Core version to a newer version (but - to be honest: those upgrades are quite easy in contrast to the .NET Framework to .NET Core migration).</p> <p>Depending on the project type, the assistant allows for an “In-Place Upgrade,” “Side-by-Side,” or “Side-by-Side Incremental” upgrade.</p> <ul> <li>“In-Place Upgrade” means that the existing code is directly modified.</li> <li>“Side-by-Side” means that a new project is created and migration to the latest version is based on a copy.</li> <li>“Side-by-Side Incremental,” to my knowledge, is only available for ASP.NET web applications. Here, a new .NET Core project is added in parallel, and a sort of “bridge” is built in the original .NET project. This seems to me to be clever on the one hand but also very risky on the other.</li> </ul> <p>You can see those upgrade methods in the video above.</p> <h1 id="is-it-good">Is it good?</h1> <p><a href="https://primesoft-group.com/en/">We</a> have used (or at least tested) the Assistant for upgrading WPF and class libraries to .NET Core and it helps to identify problems (e.g. if a NuGet package or any “old” framework code is not compatible). My verdict: If you need to upgrade your code, you should give it a try. In a more complex code base, it will sometimes mess with the code, but it still helps to give directions.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/03/07/upgrade-assistant/ https://blog.codeinside.eu/2024/03/07/upgrade-assistant Thu, 07 Mar 2024 23:59:00 +0000 WinUI 3 Community Toolkit and the Template Studio <p>In my last post <a href="https://blog.codeinside.eu/2024/02/12/first-steps-with-winui3/">“First steps with WinUI 3”</a> I already mentioned the <a href="https://apps.microsoft.com/detail/9p3jfpwwdzrc">“WinUI 3 Gallery”-App</a>, but I missed mentioning two great resources.</p> <p>If you take a deeper look at the “Home” page, you will spot the <a href="https://apps.microsoft.com/detail/9nblggh4tlcq">Community Toolkit Gallery (another app)</a> and the <a href="https://marketplace.visualstudio.com/items?itemName=TemplateStudio.TemplateStudioForWinUICs">“Template Studio for WinUI”</a>.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/winui3gallery.png" alt="x" title="WinUI 3 Gallery" /></p> <h1 id="what-is-the-community-toolkit">What is the Community Toolkit?</h1> <p>The Community Toolkit is a community-driven collection of components and other helpers.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/community-toolkit.png" alt="x" title="WinUI 3 Gallery" /></p> <p>The “home” of the Community Toolkit can be found on <a href="https://github.com/CommunityToolkit/Windows">GitHub</a></p> <p>As of today, the Community Toolkit seems “alive” with recent commits in February 2024.</p> <p>Interesting fact: The controls from the toolkit seems to work with the <a href="https://platform.uno/">Uno Platform</a> as well.</p> <h1 id="what-is-the-template-studio">What is the Template Studio?</h1> <p>Template Studio is an addin for Visual Studio and can be installed <a href="https://marketplace.visualstudio.com/items?itemName=TemplateStudio.TemplateStudioForWinUICs">from the Marketplace</a>.</p> <p>This adds the ‘Template Studio for WinUI’ template to Visual Studio:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio.png" alt="x" title="Template Studio" /></p> <p>After the usual “pick a name and location” you will be greeted with this Wizard:</p> <p>The first step is to select a “Project type”:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio-1.png" alt="x" title="Template Studio - Project Type" /></p> <p>In the next step you choose a “Design pattern” - which has only one item… well.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio-2.png" alt="x" title="Template Studio - Design pattern" /></p> <p>In “Pages” you can create your “views/pages” based on a given layout:</p> <p>Some pages can only be added once (e.g. the “Settings”), but most pages can be added multiple times.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio-3.png" alt="x" title="Template Studio - Pages" /></p> <p>In “Features” you can add some WinUI 3 related features:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio-4.png" alt="x" title="Template Studio - Features" /></p> <p>In the last setting you can decide if you want to add an MSTest project as well:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio-5.png" alt="x" title="Template Studio - Testing" /></p> <p>The result is the following Visual Studio solution, which includes two projects and a number of <code class="language-plaintext highlighter-rouge">TODO</code> items:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio-vsproject.png" alt="x" title="Template Studio - Solution" /></p> <p>If you run the code a pretty simple app with your configured pages will be found:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-24/template-studio-result.png" alt="x" title="Template Studio - Result" /></p> <p><strong>Warning:</strong> Such code generators might be a good starting point, but (as always with such generators) the code might be “too stupid” or “too complicated” - depending on your needs.</p> <h1 id="any-other-useful-resource">Any other useful resource?</h1> <p>I’m a newbie with WinUI 3. The Community Toolkit looks promising and even the Template Studio looks good - at least from a few minutes playtime. If anyone has other useful resource: Please let me know (e.g. in the comments or via email).</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/02/24/winui3-with-community-toolkit-and-template-studio/ https://blog.codeinside.eu/2024/02/24/winui3-with-community-toolkit-and-template-studio Sat, 24 Feb 2024 23:59:00 +0000 First steps with WinUI 3 <p>Developing desktop apps <strong>for</strong> Windows is quite complex in 2024. There are some “old school” frameworks like WPF or WinForms (or even older stuff) and there is this confusing UWP (but I think it’s dead). The “modern stack” seems to be <code class="language-plaintext highlighter-rouge">WinUI</code> - so let’s take a look.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-12/winui.png" alt="x" title="WinUI" /></p> <p><em>See <a href="https://learn.microsoft.com/en-us/windows/apps/develop/">here</a></em></p> <h1 id="what-is-winui">What is WinUI?</h1> <p>WinUI is the “modern” version of WPF without the (dumb?) constraints from UWP. You can of course use your typical “Windows” programming languages (like C# or C++).</p> <p>If you heard of UWP. The “Universal Windows Platform” was a good idea but failed, because - at least from my limited testing - the platform was very strict and you couldn’t do the same stuff that you can do with WPF/WinForms.</p> <p>WinUI 1 and 2 were targeted at UWP (if I remember correctly) and with WinUI 3 Microsoft decided to lift those UWP constraints and with it we get a modern desktop stack based on the “known” XAML.</p> <p>In summary:</p> <p>WinUI 3 apps can be used for apps that run on Windows 11 and Windows 10 and can be distributed via the Microsoft Store and you can do the same crazy stuff that you love about WPF/WinForms.</p> <h1 id="does-anybody-outside-of-microsoft-use-winui">Does anybody outside of Microsoft use WinUI?</h1> <p>WinUI is used in Windows 11, e.g. the settings or the new explorer - which is nice, but it would be good, if we found a non-Microsoft app that uses this tech, right?</p> <p>Thankfully last week Apple decided to release <a href="https://apps.microsoft.com/detail/9PFHDD62MXS1">Apple Music</a> (and <a href="https://twitter.com/OrderByAsync/status/1755598050641526902">other apps</a>) as a native Windows app and it seems (<a href="https://twitter.com/mixen/status/1757085072115773473">confirmed</a>) like it was written with WinUI:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-12/applemusic.png" alt="x" title="Apple Music" /></p> <p>If Apple uses this tech, it seems “safe enough” for some exploration.</p> <h1 id="how-to-get-started">How to get started?</h1> <p>You will need <a href="https://visualstudio.microsoft.com/vs/">Visual Studio 2022</a>. Be aware, that even if you check all those desktop related workloads in the installer the WinUI 3 templates <strong>are still missing</strong>.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-12/vsinstall.png" alt="x" title="Visual Studio Workloads" /></p> <p>For the WinUI 3 templates you will need to install the <strong><a href="https://learn.microsoft.com/en-us/windows/apps/windows-app-sdk/">Windows App SDK</a></strong>.</p> <h1 id="visual-studio-templates">Visual Studio Templates</h1> <p>After the Windows App SDK is installed we finally have the templates in Visual Studio:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-12/vstemplates.png" alt="x" title="Visual Studio Templates" /></p> <p>The default <code class="language-plaintext highlighter-rouge">Blank App, Packaged (WinUI 3 in Desktop)</code> is… well… quite blank:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-12/solution.png" alt="x" title="Visual Studio Solution" /></p> <p>If you start the application, you will see this:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-12/startapp.png" alt="x" title="Blank Application" /></p> <h1 id="packaged-vs-unpacked">Packaged vs. Unpacked</h1> <p>If you check the toolbar, you will notice the <code class="language-plaintext highlighter-rouge">App 6 (Package)</code> debug button. <code class="language-plaintext highlighter-rouge">Packaged Apps</code> can access some Windows APIs (e.g. custom context menu extensions) that <code class="language-plaintext highlighter-rouge">Unpackaged Apps</code> can’t. <code class="language-plaintext highlighter-rouge">Unpackaged Apps</code> on the other hand act like WPF apps - e.g. they have a “normal” <code class="language-plaintext highlighter-rouge">.exe</code> and can be distributed like any <code class="language-plaintext highlighter-rouge">.exe</code>-file.</p> <p><a href="https://learn.microsoft.com/en-us/windows/apps/get-started/intro-pack-dep-proc#packaged-or-unpackaged">This documentation page</a> should cover this topic.</p> <p>Let’s say we want to have a “proper” <code class="language-plaintext highlighter-rouge">myApp.exe</code> app, then the <code class="language-plaintext highlighter-rouge">Unpackaged App</code> is the way to go. If you choose the <code class="language-plaintext highlighter-rouge">App 6 (Unpackaged)</code> debug option you might see this weird error:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>XamlCheckProcessRequirements(); Exception Unhandled: System.DllNotFoundException: 'Unable to load DLL 'Microsoft.ui.xaml.dll' or one of its dependencies: The specified module could not be found. (0x8007007E)' </code></pre></div></div> <p>To fix this, you will need to add this to the <code class="language-plaintext highlighter-rouge">.csproj</code>:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> &lt;PropertyGroup&gt; ... &lt;WindowsPackageType&gt;None&lt;/WindowsPackageType&gt; ... &lt;/PropertyGroup&gt; </code></pre></div></div> <p>After that the debug button should start the application and you should be able to start the <code class="language-plaintext highlighter-rouge">.exe</code>.</p> <h1 id="samples">Samples</h1> <p>Ok, the most basic steps are done - now what?</p> <p>To get a feeling about what is possible and what not, you should install the <a href="https://apps.microsoft.com/detail/9P3JFPWWDZRC?">WinUI 3 Gallery</a> app.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-02-12/winuisample.png" alt="x" title="WinUI 3 Gallery" /></p> <p>This application should give a some guidiance.</p> <p>Hope this helps!</p> <p><em>Note: I’m a beginner with WinUI 3 and just want to show other people the first few steps - if I miss something, just write me a comment! Thanks &lt;3</em></p> https://blog.codeinside.eu/2024/02/12/first-steps-with-winui3/ https://blog.codeinside.eu/2024/02/12/first-steps-with-winui3 Mon, 12 Feb 2024 23:55:00 +0000 How Windows locates an executable via PATH or App Paths <p>If you’ve ever worked with the Windows operating system, especially in a programming context, you might have used the <code class="language-plaintext highlighter-rouge">Process.Start(yourapp)</code> (e.g. <code class="language-plaintext highlighter-rouge">Process.Start(Outlook)</code>) method in languages like C#. This method is used to start a process - essentially to run an executable file. But have you ever stopped to think about how Windows knows where to find the executables you’re trying to run? Let’s dive into the inner workings of Windows and uncover this mystery.</p> <h1 id="understanding-the-path-environment-variable">Understanding the PATH Environment Variable</h1> <p>One of the first things that come into play is the <code class="language-plaintext highlighter-rouge">PATH</code> environment variable. This variable is crucial for the operating system to locate the executables.</p> <p><strong>What is the PATH Variable?</strong></p> <p>The <code class="language-plaintext highlighter-rouge">PATH</code> environment variable is a system-wide or user-specific setting that lists directories where executable files are stored. When you run a command in the command prompt or use <code class="language-plaintext highlighter-rouge">Process.Start(...)</code>, Windows looks through these directories to find the executable file.</p> <p>The <code class="language-plaintext highlighter-rouge">PATH</code> environment variable can be viewed via the system settings:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-01-17/environmentsettings.png" alt="x" title="System Settings" /></p> <p>… there is also a nice editor now build into Windows for the <code class="language-plaintext highlighter-rouge">PATH</code> environment variable:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-01-17/pathedit.png" alt="x" title="Path Edit" /></p> <p><strong>How Does PATH Work?</strong></p> <p>If the executable is not in the current directory, Windows searches through each directory specified in the <code class="language-plaintext highlighter-rouge">PATH</code> variable. The order of directories in <code class="language-plaintext highlighter-rouge">PATH</code> is important - Windows searches them in the order they are listed. If it finds the executable in one of these directories, it runs it.</p> <p>However, the <code class="language-plaintext highlighter-rouge">PATH</code> variable isn’t the only mechanism at play here.</p> <h1 id="the-role-of-app-paths-in-the-windows-registry">The Role of App Paths in the Windows Registry</h1> <p>Another less-known but equally important component is the “<strong><a href="https://learn.microsoft.com/en-us/windows/win32/shell/app-registration">App Paths</a></strong>” registry key. This key is located in <code class="language-plaintext highlighter-rouge">HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths</code>.</p> <p><strong>Understanding App Paths</strong></p> <p>The <code class="language-plaintext highlighter-rouge">App Paths</code> key is used to specify paths to specific applications. Each application can have its entry under the <code class="language-plaintext highlighter-rouge">App Paths</code> key, which means that Windows can find and run these applications even if their directories are not listed in the <code class="language-plaintext highlighter-rouge">PATH</code> variable.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2024-01-17/apppaths.png" alt="x" title="App path" /></p> <p><strong>How Do App Paths Work?</strong></p> <p>When you use <code class="language-plaintext highlighter-rouge">Process.Start(...)</code> and specify an application name like “OUTLOOK”, Windows first checks the App Paths registry key before it checks the <code class="language-plaintext highlighter-rouge">PATH</code> variable. If it finds an entry for the application here, it uses this path to start the application. This is particularly useful for applications that are not in common directories or have multiple executables in different locations.</p> <h1 id="conclusion">Conclusion</h1> <p>Both <code class="language-plaintext highlighter-rouge">PATH</code> and <code class="language-plaintext highlighter-rouge">App Paths</code> play significant roles. While <code class="language-plaintext highlighter-rouge">PATH</code> is great for general-purpose directory searching (especially for system utilities and command-line tools), <code class="language-plaintext highlighter-rouge">App Paths</code> is more specific and tailored for individual applications.</p> <p>There are probably even more options out there besides <code class="language-plaintext highlighter-rouge">PATH</code> and <code class="language-plaintext highlighter-rouge">App Paths</code> - Windows is full of hidden gems like this 😉.</p> <p>Fun fact: I only discovered <code class="language-plaintext highlighter-rouge">App Paths</code> while debugging a problem. We use <code class="language-plaintext highlighter-rouge">Process.Start(OUTLOOK)</code> to start Microsofts Outlook Client and I was wondering why this even works.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/01/17/windows-path-and-app-paths/ https://blog.codeinside.eu/2024/01/17/windows-path-and-app-paths Wed, 17 Jan 2024 23:55:00 +0000 .NET ('.NET Core') and Proxy Settings <p>If your .NET (“.NET Core”) program is running on a system that specifies strict proxy settings, you must either handle these settings in your application itself or use these environment variables.</p> <p>Since I had this problem from time to time and the procedure was not 100% clear to me, I am now recording it here on the blog.</p> <p><strong>“DefaultProxy”</strong></p> <p>If you don’t specify any proxy, then the <code class="language-plaintext highlighter-rouge">DefaultProxy</code> is used and depending on your operation system the following will be used:</p> <p>(Copied from <a href="https://learn.microsoft.com/en-us/dotnet/api/system.net.http.httpclient.defaultproxy?view=net-8.0">here</a>)</p> <blockquote> <p>For Windows: Reads proxy configuration from environment variables or, if those are not defined, from the user’s proxy settings.</p> <p>For macOS: Reads proxy configuration from environment variables or, if those are not defined, from the system’s proxy settings.</p> <p>For Linux: Reads proxy configuration from environment variables or, in case those are not defined, this property initializes a non-configured instance that bypasses all addresses. The environment variables used for DefaultProxy initialization on Windows and Unix-based platforms are:</p> <p>HTTP_PROXY: the proxy server used on HTTP requests. HTTPS_PROXY: the proxy server used on HTTPS requests. ALL_PROXY: the proxy server used on HTTP and/or HTTPS requests in case HTTP_PROXY and/or HTTPS_PROXY are not defined. NO_PROXY: a comma-separated list of hostnames that should be excluded from proxying. Asterisks are not supported for wildcards; use a leading dot in case you want to match a subdomain. Examples: &gt; NO_PROXY=.example.com (with leading dot) will match www.example.com, but will not match example.com. NO_PROXY=example.com (without leading dot) will not match www.example.com. This behavior might be &gt; revisited in the future to match other ecosystems better.</p> </blockquote> <p><strong>Scenario: Web-App that needs external &amp; “internal” Web-APIs</strong></p> <p>We often had the following problem: Our web application needs to contact external services. This means, that we <strong>must use</strong> the proxy. At the same time, our web application also wants to communicate with other web APIs on the same machine, but the proxy does not allow this (the proxy can’t return the request to the same machine - not sure why).</p> <p>It should be noted that the “IIS account” or “Network Service” did NOT have a proxy setting itself, i.e. the “User Proxy Settings” were always empty.</p> <p><strong>Solution:</strong></p> <p>We used the following proxy settings and it worked:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ALL_PROXY = proxyserver.corp.acme.com NO_Proxy = internalserver.corp.acme.com </code></pre></div></div> <p>Our web application and our internal web api were running on “internalserver.corp.acme.com”. Each request to external services were routed through the proxy and each “internal” request didn’t touch the proxy.</p> <p><strong>IE-Proxy Settings:</strong></p> <p>This solution should work fine on “Server-Environments”. If you have a desktop application, then the “Default Proxy” handling should do the trick. In some special cases the “IE proxy setting” handling might be needed. If you want to learn more about this, read this blogpost: <a href="https://blog.codeinside.eu/2022/03/28/how-to-use-ie-proxy-settings-with-httpclient/">How to use IE proxy settings with HttpClient</a>.</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2024/01/12/dotnetcore-and-proxy-settings/ https://blog.codeinside.eu/2024/01/12/dotnetcore-and-proxy-settings Fri, 12 Jan 2024 22:55:00 +0000 Limit Active Directory property access <p><strong>Be aware:</strong> I’m not a full time administrator and this post might sound stupid to you.</p> <h1 id="the-problem">The Problem</h1> <p>We access certain Active Directory properties with our application, and on one customer domain, we couldn’t retrieve any data via our Active Directory component.</p> <h1 id="solution">Solution</h1> <p>After some debugging and doubts about our functionality, the customer admin and I found the reason: Our code was running under a Windows account that was very limited and couldn’t read those properties.</p> <p>If you have similar problems, you might want to look into the AD User &amp; Group management.</p> <p>First step: You need to active the advanced features:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-09-20/advanced_features.png" alt="x" title="Advanced Features" /></p> <p>Now navigate to your “user OU” or the target users and check the security tab. The goal is to grant your service account the permission to read the needed property. To do that, go to the advanced view, and add a new permission or change an existing one:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-09-20/settings.png" alt="x" title="Settings" /></p> <p>Here you should be able to see a huge dialog with <strong>all available properties</strong> and grant the read permission for the target property for your service account.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-09-20/details.png" alt="x" title="Details" /></p> <h1 id="solution-via-cmd">Solution via CMD</h1> <p>The UI is indeed quite painful to use. If you know what you are doing you can use <a href="https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2012-R2-and-2012/cc771151(v=ws.11)">dsacls.exe</a>.</p> <p>To grant the read permission for <code class="language-plaintext highlighter-rouge">tokenGroups</code> for a certain service account you can use the tool like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dsacls "OU=Users,DC=company,DC=local" /I:S /G "service_account":rp;tokenGroups;user </code></pre></div></div> <p>Hope this helps!</p> https://blog.codeinside.eu/2023/09/20/limit-active-directory-property-access/ https://blog.codeinside.eu/2023/09/20/limit-active-directory-property-access Wed, 20 Sep 2023 23:55:00 +0000 Zip deployment failed on Azure <h1 id="the-problem">The Problem</h1> <p>We are using <a href="https://learn.microsoft.com/en-us/azure/app-service/">Azure App Service</a> for our application (which runs great BTW) and deploy it automatically via <a href="https://learn.microsoft.com/en-us/azure/app-service/deploy-zip">ZipDeploy</a>. This basic setup was running smoth, but we noticed that at some point the deployment failed with these error messages:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>2023-08-24T20:48:56.1057054Z Deployment endpoint responded with status code 202 2023-08-24T20:49:15.6984407Z Configuring default logging for the app, if not already enabled 2023-08-24T20:49:18.8106651Z Zip deployment failed. {'id': 'temp-b574d768', 'status': 3, 'status_text': '', 'author_email': 'N/A', 'author': 'N/A', 'deployer': 'ZipDeploy', 'message': 'Deploying from pushed zip file', 'progress': '', 'received_time': '2023-08-24T20:48:55.8916655Z', 'start_time': '2023-08-24T20:48:55.8916655Z', 'end_time': '2023-08-24T20:49:15.3291017Z', 'last_success_end_time': None, 'complete': True, 'active': False, 'is_temp': True, 'is_readonly': False, 'url': 'https://[...].scm.azurewebsites.net/api/deployments/latest', 'log_url': 'https://[...].scm.azurewebsites.net/api/deployments/latest/log', 'site_name': '[...]', 'provisioningState': 'Failed'}. Please run the command az webapp log deployment show 2023-08-24T20:49:18.8114319Z -n [...] -g production </code></pre></div></div> <p>or this one (depending on how we invoked the deployment script):</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Getting scm site credentials for zip deployment Starting zip deployment. This operation can take a while to complete ... Deployment endpoint responded with status code 500 An error occured during deployment. Status Code: 500, Details: {"Message":"An error has occurred.","ExceptionMessage":"There is not enough space on the disk.\r\n","ExceptionType":"System.IO.IOException","StackTrace":" </code></pre></div></div> <h1 id="there-is-not-enough-space-on-the-disk">“There is not enough space on the disk”?</h1> <p>The message <code class="language-plaintext highlighter-rouge">There is not enough space on the disk</code> was a good hint, but according to the File system storage everything should be fine with only 8% used.</p> <p>Be aware - this is important: We have multiple apps on the same App Service plan!</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-09-05/file-system-storage.png" alt="x" title="File System Storage" /></p> <h1 id="kudu-to-the-rescure">Kudu to the rescure</h1> <p>Next step was to check the behind the scene environment via the “Advanced Tools” Kudu and there it is:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-09-05/kudu.png" alt="x" title="Kudu local Storage" /></p> <p>There are two different storages attached to the app service:</p> <ul> <li><code class="language-plaintext highlighter-rouge">c:\home</code> is the “File System Storage” that you can see in the Azure Portal and is quite large. App files are located here.</li> <li><code class="language-plaintext highlighter-rouge">c:\local</code> is a <strong>much</strong> smaller storage with ~21GB and if the space is used, then ZipDeploy will fail.</li> </ul> <h1 id="who-is-using-this-space">Who is using this space?</h1> <p><code class="language-plaintext highlighter-rouge">c:\local</code> stores “mostly” temporarily items, e.g.:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Directory of C:\local 08/31/2023 06:40 AM &lt;DIR&gt; . 08/31/2023 06:40 AM &lt;DIR&gt; .. 07/13/2023 04:29 PM &lt;DIR&gt; AppData 07/13/2023 04:29 PM &lt;DIR&gt; ASP Compiled Templates 08/31/2023 06:40 AM &lt;DIR&gt; Config 07/13/2023 04:29 PM &lt;DIR&gt; DomainValidationTokens 07/13/2023 04:29 PM &lt;DIR&gt; DynamicCache 07/13/2023 04:29 PM &lt;DIR&gt; FrameworkJit 07/13/2023 04:29 PM &lt;DIR&gt; IIS Temporary Compressed Files 07/13/2023 04:29 PM &lt;DIR&gt; LocalAppData 07/13/2023 04:29 PM &lt;DIR&gt; ProgramData 09/05/2023 08:36 PM &lt;DIR&gt; Temp 08/31/2023 06:40 AM &lt;DIR&gt; Temporary ASP.NET Files 07/18/2023 04:06 AM &lt;DIR&gt; UserProfile 08/19/2023 06:34 AM &lt;SYMLINKD&gt; VirtualDirectory0 [\\...\] 0 File(s) 0 bytes 15 Dir(s) 13,334,384,640 bytes free </code></pre></div></div> <p>The “biggest” item here was in our case under <code class="language-plaintext highlighter-rouge">c:\local\Temp\zipdeploy</code>:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> Directory of C:\local\Temp\zipdeploy 08/29/2023 04:52 AM &lt;DIR&gt; . 08/29/2023 04:52 AM &lt;DIR&gt; .. 08/29/2023 04:52 AM &lt;DIR&gt; extracted 08/29/2023 04:52 AM 774,591,927 jiire5i5.zip </code></pre></div></div> <p>This folder stores our <code class="language-plaintext highlighter-rouge">ZipDeploy</code> package, which is quite large with ~800MB. The folder also contains the extracted files - remember: We only have 21GB on this storage, but even if this zip file and the extracted files are ~3GB, there is still plenty of room, right?</p> <h1 id="shared-resources">Shared resources</h1> <p>Well… it turns out, that <strong>each App Service</strong> on a <strong>App Service plan</strong> is using this storage and if you have multiple App Services on the same plan, than those 21GB might melt away.</p> <p>The “bad” part is, that the space is shared, but each App Services has it’s own <code class="language-plaintext highlighter-rouge">c:\local</code> folder (which makes sense). To free up memory we had to clean up this folder on each App Service like that:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>rmdir c:\local\Temp\zipdeploy /s /q </code></pre></div></div> <h1 id="tldr">TL;DR</h1> <p>If you have problems with ZipDeploy and the error message tells you, that there is not enough space, check out the <code class="language-plaintext highlighter-rouge">c:\local</code> space (and of course <code class="language-plaintext highlighter-rouge">c:\home</code> as well) and delete unused files. Sometimes a reboot might help as well (to clean up temp-files), but AFAIK those ZipDeploy files will survive that.</p> https://blog.codeinside.eu/2023/09/05/zip-deployment-failed-on-azure-and-how-to-fix-it/ https://blog.codeinside.eu/2023/09/05/zip-deployment-failed-on-azure-and-how-to-fix-it Tue, 05 Sep 2023 23:55:00 +0000 First steps with Azure OpenAI and .NET <p>The AI world is rising very fast these days: <a href="https://chat.openai.com/">ChatGPT</a> is such an awesome (and scary good?) service and Microsoft <a href="https://blogs.microsoft.com/blog/2023/01/23/microsoftandopenaiextendpartnership/">joined the ship with some partner announcements and investments</a>. The result is of these actions is, that OpenAI is now a “first class citizen” on Azure.</p> <p>So - for the average Microsoft/.NET developer this opens up a wonderful toolbox and the first steps are really easy.</p> <p><strong>Be aware:</strong> You need to <a href="https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu">“apply” to access the OpenAI service</a>, but it took less then 24 hours for us to gain access to the service. I guess this is just a temporary thing.</p> <p><strong>Disclaimer:</strong> I’m not an AI/ML engineer and I only have a very “glimpse” knowledge about the technology behind GPT3, ChatGPT and ML in general. If in doubt, I always ask my buddy <a href="https://www.oliverguhr.eu/">Oliver Guhr</a>, because he is much smarter in this stuff. Follow him on <a href="https://twitter.com/oliverguhr">Twitter</a>!</p> <h1 id="1-step-go-to-azure-openai-service">1. Step: Go to Azure OpenAI Service</h1> <p>Search for “OpenAI” and you will see the “Azure OpenAI Service” entry:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-23/openai-service.png" alt="x" title="Step 1" /></p> <h1 id="2-step-create-a-azure-openai-service-instance">2. Step: Create a Azure OpenAI Service instance</h1> <p>Create a new Azure OpenAI Service instance:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-23/create.png" alt="x" title="Step 2" /></p> <p>On the next page you will need to enter the subscription, resource group, region and a name (typical Azure stuff):</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-23/create-details.png" alt="x" title="Step 2 - details" /></p> <p><strong>Be aware:</strong> If your subscription is not enabled for OpenAI, you need to <a href="https://customervoice.microsoft.com/Pages/ResponsePage.aspx?id=v4j5cvGGr0GRqy180BHbR7en2Ais5pxKtso_Pz4b1_xUOFA5Qk1UWDRBMjg0WFhPMkIzTzhKQ1dWNyQlQCN0PWcu">apply here</a> first.</p> <h1 id="3-step-overview-and-create-a-model">3. Step: Overview and create a model</h1> <p>After the service is created you should see something like this:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-23/overview.png" alt="x" title="Step 3 - overview" /></p> <p>Now go to “Model deployments” and create a model - I choosed “text-davinci-003”, because I <em>think</em> this is GPT3.5 (which was the initial ChatGPT release, GPT4 is currently in preview for Azure and you need to <a href="https://azure.microsoft.com/en-us/blog/introducing-gpt4-in-azure-openai-service/">apply again</a>.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-23/model.png" alt="x" title="Step 3 - model" /></p> <p>My guess is, that you could train/deploy other, specialized models here, because this model is quite complex and you might want to tailor the model for your scenario to get faster/cheaper results… but I honestly don’t know how to do it (currently), so we just leave the default.</p> <h1 id="4-step-get-the-endpoint-and-the-key">4. Step: Get the endpoint and the key</h1> <p>In this step we just need to copy the key and the endpoint, which can be found under “Keys and Endpoint”, simple - right?</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-23/keys-and-endpoint.png" alt="x" title="Step 4" /></p> <h1 id="5-step-hello-world-to-our-azure-openai-instance">5. Step: Hello World to our Azure OpenAI instance</h1> <p>Create a .NET application and add the <a href="https://www.nuget.org/packages/Azure.AI.OpenAI/">Azure.AI.OpenAI</a> NuGet package (currently in preview!).</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>dotnet add package Azure.AI.OpenAI --version 1.0.0-beta.5 </code></pre></div></div> <p>Use this code:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>using Azure.AI.OpenAI; using Azure; Console.WriteLine("Hello, World!"); OpenAIClient client = new OpenAIClient( new Uri("YOUR-ENDPOINT"), new AzureKeyCredential("YOUR-KEY")); string deploymentName = "text-davinci-003"; string prompt = "Tell us something about .NET development."; Console.Write($"Input: {prompt}"); Response&lt;Completions&gt; completionsResponse = client.GetCompletions(deploymentName, prompt); string completion = completionsResponse.Value.Choices[0].Text; Console.WriteLine(completion); Console.ReadLine(); </code></pre></div></div> <p><strong>Result:</strong></p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Hello, World! Input: Tell us something about .NET development. .NET development is a mature, feature-rich platform that enables developers to create sophisticated web applications, services, and applications for desktop, mobile, and embedded systems. Its features include full-stack programming, object-oriented data structures, security, scalability, speed, and an open source framework for distributed applications. A great advantage of .NET development is its capability to develop applications for both Windows and Linux (using .NET Core). .NET development is also compatible with other languages such as </code></pre></div></div> <p>As you can see… the result is cut off, not sure why, but this is just a simple demonstration.</p> <h1 id="summary">Summary</h1> <p>With these basic steps you can access the OpenAI development world. Azure makes it easy to integrate in your existing Azure/Microsoft “stack”. Be aware, that you could also use the same SDK and use the endpoint from OpenAI. Because of billing reasons it is easier for us to use the Azure hosted instances.</p> <p>Hope this helps!</p> <h1 id="video-on-my-youtube-channel">Video on my YouTube Channel</h1> <p>If you understand German and want to see it in action, check out my video on my <a href="https://www.youtube.com/@CodeInsideCasts">Channel</a>:</p> <iframe width="560" height="315" src="https://www.youtube.com/embed/VVNHT4gVxDo" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> https://blog.codeinside.eu/2023/03/23/first-steps-with-azure-openai-and-dotnet/ https://blog.codeinside.eu/2023/03/23/first-steps-with-azure-openai-and-dotnet Thu, 23 Mar 2023 23:55:00 +0000 How to fix: 'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine <p>In our product we can interact with different datasource and one of these datasources was a Microsoft Access DB connected via <code class="language-plaintext highlighter-rouge">OLEDB</code>. This is really, really old, but still works, but on one customer machine we had this issue:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>'Microsoft.ACE.OLEDB.12.0' provider is not registered on the local machine </code></pre></div></div> <h1 id="solution">Solution</h1> <p>If you face this issue, you need to install the provider from <a href="https://www.microsoft.com/en-us/download/details.aspx?id=13255">here</a>.</p> <p><strong>Be aware:</strong> If you have a different error, you might need to install the newer provider - this is labled as “2010 Redistributable”, but still works with all those fancy Office 365 apps out there.</p> <p><strong>Important:</strong> You need to install the provider in the correct bit version, e.g. if you run under x64, install the x64.msi.</p> <p>The solution comes from this <a href="https://stackoverflow.com/questions/6649363/microsoft-ace-oledb-12-0-provider-is-not-registered-on-the-local-machine">Stackoverflow question</a>.</p> <h1 id="helper">Helper</h1> <p>The best tip from Stackoverflow was these powershell commands to check, if the provider is there or not:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>(New-Object system.data.oledb.oledbenumerator).GetElements() | select SOURCES_NAME, SOURCES_DESCRIPTION Get-OdbcDriver | select Name,Platform </code></pre></div></div> <p>This will return something like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>PS C:\Users\muehsig&gt; (New-Object system.data.oledb.oledbenumerator).GetElements() | select SOURCES_NAME, SOURCES_DESCRIPTION SOURCES_NAME SOURCES_DESCRIPTION ------------ ------------------- SQLOLEDB Microsoft OLE DB Provider for SQL Server MSDataShape MSDataShape Microsoft.ACE.OLEDB.12.0 Microsoft Office 12.0 Access Database Engine OLE DB Provider Microsoft.ACE.OLEDB.16.0 Microsoft Office 16.0 Access Database Engine OLE DB Provider ADsDSOObject OLE DB Provider for Microsoft Directory Services Windows Search Data Source Microsoft OLE DB Provider for Search MSDASQL Microsoft OLE DB Provider for ODBC Drivers MSDASQL Enumerator Microsoft OLE DB Enumerator for ODBC Drivers SQLOLEDB Enumerator Microsoft OLE DB Enumerator for SQL Server MSDAOSP Microsoft OLE DB Simple Provider PS C:\Users\muehsig&gt; Get-OdbcDriver | select Name,Platform Name Platform ---- -------- Driver da Microsoft para arquivos texto (*.txt; *.csv) 32-bit Driver do Microsoft Access (*.mdb) 32-bit Driver do Microsoft dBase (*.dbf) 32-bit Driver do Microsoft Excel(*.xls) 32-bit Driver do Microsoft Paradox (*.db ) 32-bit Microsoft Access Driver (*.mdb) 32-bit Microsoft Access-Treiber (*.mdb) 32-bit Microsoft dBase Driver (*.dbf) 32-bit Microsoft dBase-Treiber (*.dbf) 32-bit Microsoft Excel Driver (*.xls) 32-bit Microsoft Excel-Treiber (*.xls) 32-bit Microsoft ODBC for Oracle 32-bit Microsoft Paradox Driver (*.db ) 32-bit Microsoft Paradox-Treiber (*.db ) 32-bit Microsoft Text Driver (*.txt; *.csv) 32-bit Microsoft Text-Treiber (*.txt; *.csv) 32-bit SQL Server 32-bit ODBC Driver 17 for SQL Server 32-bit SQL Server 64-bit ODBC Driver 17 for SQL Server 64-bit Microsoft Access Driver (*.mdb, *.accdb) 64-bit Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb) 64-bit Microsoft Access Text Driver (*.txt, *.csv) 64-bit </code></pre></div></div> <p>Hope this helps! (And I hope you don’t need to deal with these ancient technologies for too long 😅)</p> https://blog.codeinside.eu/2023/03/18/microsoft-ace-oledb-12-0-provider-is-not-registered/ https://blog.codeinside.eu/2023/03/18/microsoft-ace-oledb-12-0-provider-is-not-registered Sat, 18 Mar 2023 23:55:00 +0000 Resource type is not supported in this subscription <p>I was playing around with some Visual Studio Tooling and noticed this error during the creation of a “Azure Container Apps”-app:</p> <p><code class="language-plaintext highlighter-rouge">Resource type is not supported in this subscription</code></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-11/error.png" alt="x" title="Error" /></p> <h1 id="solution">Solution</h1> <p>The solution is quite strange at first, but in the super configurable world of Azure it makes sense: You need to activate the <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types"><strong>Resource provider</strong></a> for this feature on your subscription. For <code class="language-plaintext highlighter-rouge">Azure Container Apps</code> you need the <code class="language-plaintext highlighter-rouge">Microsoft.ContainerRegistry</code>-resource provider <strong>registered</strong>:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-03-11/solution.png" alt="x" title="Solution" /></p> <p>It seems, that you can create such resources via the Portal, but if you go via the API (which Visual Studio seems to do) the provider needs to be registered at first.</p> <p>Some resource providers are “enabled by default”, other providers needs to be turned on manually. Check out this list for a list of <a href="https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-services-resource-providers">all resource providers and the related Azure service</a>.</p> <p><strong>Be careful:</strong> I guess you should only enable the resource providers that you really need, otherwise your attack surface will get larger.</p> <p>To be honest: This was completly new for me - I do Azure since ages and never had to deal with resource providers. Always learning ;)</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2023/03/11/resource-type-is-not-supported-in-this-subscription/ https://blog.codeinside.eu/2023/03/11/resource-type-is-not-supported-in-this-subscription Sat, 11 Mar 2023 23:55:00 +0000 Azure DevOps Server 2022 Update <h1 id="azure-devops-server-2022---onprem">Azure DevOps Server 2022 - OnPrem?</h1> <p>Yes I know - you can get everything from the cloud nowadays, but <a href="https://primesoft-group.com/">we</a> are still using our OnPrem hardware and were running the “old” <a href="https://blog.codeinside.eu/2020/11/30/update-onprem-azuredevops-server-2019-to-azuredevops-server-2019-update1/">Azure DevOps Server 2020</a>. The <em>_Azure DevOps Server 2022</em> was released <a href="https://learn.microsoft.com/en-us/azure/devops/server/release-notes/azuredevops2022?view=azure-devops-2022">last december</a>, so an update was due.</p> <h1 id="requirements">Requirements</h1> <p>If you are running am Azure DevOps Server 2020 the <a href="https://learn.microsoft.com/en-us/azure/devops/server/requirements?view=azure-devops-2022&amp;viewFallbackFrom=azure-devops">requirements</a> for the new 2022 release are “more or less” the same <strong>except</strong> the following important parts:</p> <ul> <li>Supported server operation systems: <strong>Windows Server 2022 &amp; Windows Server 2019</strong> vs. the old Azure DevOps Server 2020 could run under a Windows Server 2016</li> <li>Supported SQL Server versions: <strong>Azure SQL Database, SQL Managed Instance, SQL Server 2019, SQL Server 2017</strong> vs. the old Azure DevOps Server supported SQL Server 2016.</li> </ul> <h1 id="make-sure-you-have-a-backup">Make sure you have a backup</h1> <p>The last requirement was a suprise for me, because I thought the update should run smoothly, but the installer removed the previous version and I couldn’t update, because our SQL Server was still on SQL Server 2016. Fortunately we had a VM backup and could rollback to the previous version.</p> <h1 id="step-for-step">Step for Step</h1> <p>The update process itself was straightforward: Download the <a href="https://learn.microsoft.com/en-us/azure/devops/server/download/azuredevopsserver?view=azure-devops-2022">installer</a> and run it.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step1.png" alt="x" title="Step 1" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step2.png" alt="x" title="Step 2" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step3.png" alt="x" title="Step 3" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step4.png" alt="x" title="Step 4" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step5.png" alt="x" title="Step 5" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step6.png" alt="x" title="Step 6" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step7.png" alt="x" title="Step 7" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step8.png" alt="x" title="Step 8" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step9.png" alt="x" title="Step 9" /></p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-15/step10.png" alt="x" title="Step 10" /></p> <p><em>The screenshots are from two different sessions. If you look carefully on the clock you might see that the date is different, that is because of the SQL Server 2016 problem.</em></p> <p>As you can see - everything worked as expected, but after we updated the server the search, which is powered by ElasticSearch was not working. The “ElasticSearch”-Windows-Service just crashed on startup and I’m not a Java guy, so… we fixed it by removing the search feature and reinstall it. We tried to clean the cache, but it was still not working. After the reinstall of this feature the issue went away.</p> <h1 id="features">Features</h1> <p>Azure Server 2022 is just a minor update (at least from a typical user perspective). The biggest new feature might be “Delivery Plans”, which are nice, but for small teams not a huge benefit. Check out the <a href="https://learn.microsoft.com/en-us/azure/devops/server/release-notes/azuredevops2022?view=azure-devops#azure-devops-server-2022-rc1-release-date-august-9-2022">release notes</a>.</p> <p>A nice - nerdy - enhancement, and not mentioned in the release notes: “<a href="https://mermaid.js.org/">mermaid.js</a>” is now supported in the Azure DevOps Wiki, yay!</p> <p>Hope this helps!</p> https://blog.codeinside.eu/2023/02/15/azure-devops-server-2022-update/ https://blog.codeinside.eu/2023/02/15/azure-devops-server-2022-update Wed, 15 Feb 2023 23:15:00 +0000 Use ASP.NET Core and React with Vite.js <h1 id="the-cra-problem">The CRA Problem</h1> <p>In my <a href="https://blog.codeinside.eu/2023/01/25/aspnet-core-and-react/">previous post</a> I showed a simple setup with ASP.NET Core &amp; React. The React part was created with the “CRA”-Tooling, which is kind of <a href="https://twitter.com/t3dotgg/status/1616918838830059520">problematic</a>. The “new” state of the art React tooling seems to be <a href="https://vitejs.dev/">vite.js</a> - so let’s take a look how to use this.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-11/vitejs.png" alt="x" title="Vitejs Logo" /></p> <h1 id="step-for-step">Step for Step</h1> <p><strong>Step 1: Create a “normal” ASP.NET Core project</strong></p> <p>(I like the ASP.NET Core MVC template, but feel free to use something else - same as in the <a href="https://blog.codeinside.eu/2023/01/25/aspnet-core-and-react/">other blogpost</a>)</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-11/step1.png" alt="x" title="Step 1: Create a normal ASPNET Core project" /></p> <p><strong>Step 2: Install vite.js and init the template</strong></p> <p>Now move to the root directory of your project with a shell and execute this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm create vite@latest clientapp -- --template react-ts </code></pre></div></div> <p>This will install the latest &amp; greatest vitejs based react app in a folder called <code class="language-plaintext highlighter-rouge">clientapp</code> with the <code class="language-plaintext highlighter-rouge">react-ts</code> template (React with Typescript). Vite itself isn’t focused on React and supports many <a href="https://vitejs.dev/guide/#trying-vite-online">different frontend frameworks</a>.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-11/step2.png" alt="x" title="Step 2: Init vitejs" /></p> <p><strong>Step 3: Enable HTTPS in your vite.js</strong></p> <p>Just like in the “CRA”-setup we need to make sure, that the environment is served under HTTPS. In the “CRA” world we needed to different files from the original ASP.NET Core &amp; React template, but with vite.js there is a much simpler option available.</p> <p>Execute the following command in the <code class="language-plaintext highlighter-rouge">clientapp</code> directory:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>npm install --save-dev vite-plugin-mkcert </code></pre></div></div> <p>Then in your <code class="language-plaintext highlighter-rouge">vite.config.ts</code> use this config:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' import mkcert from 'vite-plugin-mkcert' // https://vitejs.dev/config/ export default defineConfig({ base: '/app', server: { https: true, port: 6363 }, plugins: [react(), mkcert()], }) </code></pre></div></div> <p>Be aware: The <code class="language-plaintext highlighter-rouge">base: '/app'</code> will be used as a sub-path.</p> <p>The important part for the HTTPS setting is that we use the <code class="language-plaintext highlighter-rouge">mkcert()</code> plugin and configure the server part with a port and set <code class="language-plaintext highlighter-rouge">https</code> to <code class="language-plaintext highlighter-rouge">true</code>.</p> <p><strong>Step 4: Add the Microsoft.AspNetCore.SpaServices.Extensions NuGet package</strong></p> <p>Same as in the other blogpost, we need to add the <a href="https://www.nuget.org/packages/Microsoft.AspNetCore.SpaServices.Extensions">Microsoft.AspNetCore.SpaServices.Extensions</a> NuGet package to glue the ASP.NET Core development and React world together. If you use .NET 7, then use the version 7.x.x, if you use .NET 6, use the version 6.x.x - etc.</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-11/step4.png" alt="x" title="Step 4: Add NuGet Package" /></p> <p><strong>Step 5: Enhance your Program.cs</strong></p> <p>Back to the <code class="language-plaintext highlighter-rouge">Program.cs</code> - this is more or less the same as with the “CRA” setup:</p> <p>Add the <code class="language-plaintext highlighter-rouge">SpaStaticFiles</code> to the services collection like this in your <code class="language-plaintext highlighter-rouge">Program.cs</code> - be aware, that vite.js builds everything in a folder called <code class="language-plaintext highlighter-rouge">dist</code>:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllersWithViews(); // ↓ Add the following lines: ↓ builder.Services.AddSpaStaticFiles(configuration =&gt; { configuration.RootPath = "clientapp/dist"; }); // ↑ these lines ↑ var app = builder.Build(); </code></pre></div></div> <p>Now we need to use the SpaServices like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>app.MapControllerRoute( name: "default", pattern: "{controller=Home}/{action=Index}/{id?}"); // ↓ Add the following lines: ↓ var spaPath = "/app"; if (app.Environment.IsDevelopment()) { app.MapWhen(y =&gt; y.Request.Path.StartsWithSegments(spaPath), client =&gt; { client.UseSpa(spa =&gt; { spa.UseProxyToSpaDevelopmentServer("https://localhost:6363"); }); }); } else { app.Map(new PathString(spaPath), client =&gt; { client.UseSpaStaticFiles(); client.UseSpa(spa =&gt; { spa.Options.SourcePath = "clientapp"; // adds no-store header to index page to prevent deployment issues (prevent linking to old .js files) // .js and other static resources are still cached by the browser spa.Options.DefaultPageStaticFileOptions = new StaticFileOptions { OnPrepareResponse = ctx =&gt; { ResponseHeaders headers = ctx.Context.Response.GetTypedHeaders(); headers.CacheControl = new CacheControlHeaderValue { NoCache = true, NoStore = true, MustRevalidate = true }; } }; }); }); } // ↑ these lines ↑ app.Run(); </code></pre></div></div> <p>Just like in the original blogpost. In the development mode we use the <code class="language-plaintext highlighter-rouge">UseProxyToSpaDevelopmentServer</code>-method to proxy all requests to the vite.js dev server. In the real world, we will use the files from the <code class="language-plaintext highlighter-rouge">dist</code> folder.</p> <p><strong>Step 6: Invoke npm run build during publish</strong></p> <p>The last step is to complete the setup. We want to build the ASP.NET Core app <strong>and</strong> the React app, when we use <code class="language-plaintext highlighter-rouge">dotnet publish</code>:</p> <p>Add this to your <code class="language-plaintext highlighter-rouge">.csproj</code>-file and it should work:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code> &lt;PropertyGroup&gt; &lt;SpaRoot&gt;clientapp\&lt;/SpaRoot&gt; &lt;/PropertyGroup&gt; &lt;Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish"&gt; &lt;!-- As part of publishing, ensure the JS resources are freshly built in production mode --&gt; &lt;Exec WorkingDirectory="$(SpaRoot)" Command="npm install" /&gt; &lt;Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" /&gt; &lt;!-- Include the newly-built files in the publish output --&gt; &lt;ItemGroup&gt; &lt;DistFiles Include="$(SpaRoot)dist\**" /&gt; &lt;!-- Changed to dist! --&gt; &lt;ResolvedFileToPublish Include="@(DistFiles-&gt;'%(FullPath)')" Exclude="@(ResolvedFileToPublish)"&gt; &lt;RelativePath&gt;%(DistFiles.Identity)&lt;/RelativePath&gt; &lt;!-- Changed! --&gt; &lt;CopyToPublishDirectory&gt;PreserveNewest&lt;/CopyToPublishDirectory&gt; &lt;ExcludeFromSingleFile&gt;true&lt;/ExcludeFromSingleFile&gt; &lt;/ResolvedFileToPublish&gt; &lt;/ItemGroup&gt; &lt;/Target&gt; </code></pre></div></div> <h1 id="result">Result</h1> <p>You should now be able to use Visual Studio Code (or something like this) and start the frontend project with <code class="language-plaintext highlighter-rouge">dev</code>. If you open a browser and go to <code class="language-plaintext highlighter-rouge">https://127.0.0.1:6363/app</code> you should see something like this:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-11/result-vscode.png" alt="x" title="Visual Studio Code Result" /></p> <p>Now start the ASP.NET Core app and go to <code class="language-plaintext highlighter-rouge">/app</code> and it should look like this:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-11/result-vs.png" alt="x" title="Visual Studio Result" /></p> <p>Ok - this looks broken, right? Well - this is a more or less a <a href="https://github.com/vitejs/vite/issues/7358">“known” problem</a>, but can be easily avoided. If we import the logo from the assets it works as expected and shouldn’t be a general problem:</p> <p><img src="https://blog.codeinside.eu/assets/md-images/2023-02-11/result-fix.png" alt="x" title="Fix" /></p> <h1 id="code">Code</h1> <p>The sample code can be found <a href="https://github.com/Code-Inside/Samples/tree/master/2023/reactvideovite/reactvideovite">here</a>.</p> <h1 id="video">Video</h1> <p>I made a video about this topic (in German, sorry :-/) as well - feel free to subscribe ;)</p> <iframe width="560" height="315" src="https://www.youtube.com/embed/-2iiXpBcmDY" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen=""></iframe> <p>Hope this helps!</p> https://blog.codeinside.eu/2023/02/11/aspnet-core-react-with-vitejs/ https://blog.codeinside.eu/2023/02/11/aspnet-core-react-with-vitejs Sat, 11 Feb 2023 01:15:00 +0000