<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Sebastian Nilsson | Tech Leadership Advisor · AI Strategist · Fractional CTO · Renaissance Engineer - Blog</title>
    <link>https://sebnilsson.com</link>
    <description>Tech leadership advisor and AI strategist helping organizations make technology and AI decisions that survive production. Speaker, instructor, and hands-on engineer since 2002.</description>
    <language>en</language>
    <lastBuildDate>Mon, 06 Jul 2026 08:08:00 GMT</lastBuildDate>
    <atom:link href="https://sebnilsson.com/feed.xml" rel="self" type="application/rss+xml"/>
    
    <item>
      <title>Layers of Instructions for AI Coding Agents</title>
      <link>https://sebnilsson.com/blog/layers-of-instructions-for-ai-coding-agents</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/layers-of-instructions-for-ai-coding-agents</guid>
      <description>AI coding agents receive their instructions through several different layers. Each layer loads at a different time, with a different trigger and a different cost.</description>
      <content:encoded><![CDATA[<p>When you give instructions to an AI coding agent, it can look like one single thing: you write a prompt, maybe add a project instructions file, and the agent goes to work. In practice, the instructions arrive through several different layers, and <strong>the layers behave completely differently from each other</strong>. Some load automatically on every single message, some only load when the agent decides to go looking, and some are never loaded as files at all, but fetched live at the exact moment they're needed.</p>
<p>You want to get the right piece of knowledge into the AI coding agent at the right time. If done incorrectly, you could bring in too many tokens of data for every message, for the rest of the session. Or the agent doesn't see it until it has already gone down the wrong path. Both kinds of mistakes lead to the same results: worse outcomes, higher costs, and more iterations of corrections.</p>
<p>In this article, we'll go through the four layers of instructions, what triggers each of them to load, and how to pick the right layer for the right kind of knowledge. The layers exist in Codex, Claude Code, Cursor, Gemini CLI, GitHub Copilot, and most similar tools, even if the file names differ between them.</p>
<h1>Understanding the Different Layers</h1>
<p>It helps to stop thinking of context as one big bucket, and instead think of it as separate delivery mechanisms:</p>






























<table><thead><tr><th>Layer</th><th>When it loads</th><th>Examples</th></tr></thead><tbody><tr><td>Always-loaded</td><td>At the start of every session, automatically</td><td><code>AGENTS.md</code>, <code>CLAUDE.md</code></td></tr><tr><td>On-demand</td><td>When the agent decides to read it</td><td><code>README.md</code>, source code, tests</td></tr><tr><td>Progressive disclosure</td><td>A short index always, the full details on use</td><td>Skills, plugins, deferred MCP tools</td></tr><tr><td>Live lookups</td><td>Nothing is preloaded, a lookup goes out when needed</td><td>CLI commands, docs lookups, web fetches</td></tr></tbody></table>
<p>Every mechanism you'll recognize from these tools falls into one of these buckets. Once you can place a piece of knowledge in the right bucket, deciding where it belongs stops being guesswork.</p>
<p><img src="https://files.sebnilsson.com/web/images/layers-of-instructions-for-ai-coding-agents/four-layers.png" alt="The four layers of instructions"></p>
<h1>Always-Loaded Instructions</h1>
<p>This is the layer most people already know: <a href="https://agents.md/"><code>AGENTS.md</code></a>, the open format used by Codex, GitHub Copilot, and many other tools, <code>CLAUDE.md</code> in Claude Code, and <a href="https://geminicli.com/docs/cli/gemini-md/"><code>GEMINI.md</code></a> in Gemini CLI. These files are read automatically at the start of every session, before the agent does anything else.</p>
<p><em>If your repository already has an <code>AGENTS.md</code>, the <code>CLAUDE.md</code> file can simply contain the text <code>@AGENTS.md</code> to <a href="https://code.claude.com/docs/en/memory#import-additional-files">automatically import it</a>, so you don't have to maintain two copies.</em></p>
<p>The automatic loading is exactly what makes this layer expensive. A ten-line instruction file costs you ten lines, once. <strong>A three-hundred-line instruction file costs you three hundred lines on every single message of the session</strong>, even when the current task needs none of it. There is no opt-out and no "only when relevant" for this layer.</p>
<p>This is why keeping this layer short matters so much. Put the things here that the agent genuinely can't figure out on its own: the exact test command, the package manager, the files it must never touch, and the safety rules that apply every time. Almost everything else can live in one of the cheaper layers below.</p>
<p>This is also a good layer to keep instructions on where the agent can look for more information when needed, for on-demand reads or progressive disclosure. For example, stating the path where documentation files are located, where to read previous ADRs, code style guidelines or similar, so the agent doesn't have to scan multiple directories for it and waste context.</p>
<h1>On-Demand Reads</h1>
<p><code>README.md</code>, type definitions, existing tests, the component you tell the agent to "follow the pattern of". None of this loads automatically. The agent has to decide to read the file, spend a tool call doing it, and the content then stays in the context for the rest of the session (or until it gets compacted away).</p>
<p>When used well, this is a good deal. You don't pay for anything that isn't relevant to the current task, and the files can carry far more detail than you would ever want in an always-loaded file. The trade-off is that <strong>the agent has to make the right call about what to read</strong>.</p>
<p>Point the agent to the right file, and you get one cheap, targeted read. Leave it vague, and the agent might read five files to find the one that mattered, or miss it completely.</p>
<p>It's worth noting that some tools can scope instructions to a part of the repository, like <a href="https://code.claude.com/docs/en/memory#path-specific-rules"><code>.claude/rules/</code>-files with <code>paths:</code> in their frontmatter</a>, <a href="https://code.visualstudio.com/docs/copilot/customization/custom-instructions">Copilot's <code>.instructions.md</code> files with <code>applyTo</code> globs</a>, or nested <code>AGENTS.md</code> files deeper down in the folder structure. These sit right between always-loaded and on-demand: they don't load for every session, but they load automatically as soon as the agent touches a matching file. This is a useful middle ground for conventions that only matter in one part of a codebase, for example, in a monorepo.</p>
<h1>Progressive Disclosure</h1>
<p>This is the layer that's easiest to underestimate, and the one that makes the other layers scale.</p>
<p>Skills and plugins are the clearest example. The agent doesn't load the full instructions of every skill up front, since that would defeat the whole point. What it always loads is a short index: a name and a one-line description for each available skill. The full content is only pulled into the context when a skill is actually invoked. <strong>The agent knows that the capability exists, without having paid for reading all of it</strong>, until it's actually needed.</p>
<p>Anthropic's post about <a href="https://www.anthropic.com/engineering/equipping-agents-for-the-real-world-with-agent-skills">Agent Skills</a> calls this principle <em>progressive disclosure</em>, and it's a good name for the whole layer.</p>
<p>MCP tools show why this layer matters, because they traditionally haven't used it. <strong>When you connect an MCP server, the client typically loads every tool's name, description, and full parameter schema up front</strong>, straight into the always-loaded layer. This is why adding too many MCP servers is a well-known problem: <a href="https://www.anthropic.com/engineering/advanced-tool-use">Anthropic measured</a> a typical five MCP-server setup at around 55,000 tokens of tool definitions, <strong>before the agent has even done any work</strong>.</p>
<p>The fix is moving the definitions into this layer. With deferred tool definitions, supported by both <a href="https://platform.claude.com/docs/en/agents-and-tools/tool-use/tool-search-tool">Anthropic's</a> and <a href="https://developers.openai.com/api/docs/guides/tools-tool-search">OpenAI's</a> platforms, only an index of names stays loaded, and a full schema only arrives when that specific tool is searched for or used. <a href="https://code.claude.com/docs/en/mcp#scale-with-mcp-tool-search">Claude Code</a> and <a href="https://github.com/openai/codex/releases/tag/rust-v0.142.2">Codex</a> both made this the default in mid-2026, but with fallbacks to up-front loading for older models and providers, so it's still worth checking how your tool of choice handles it.</p>
<p>You can build the same pattern yourself, with nothing more than Markdown files. Keep a short index in an always-loaded file, like <code>AGENTS.md</code>, where each line describes a subject and points to the file holding the details. The pointer instructions mentioned in the always-loaded layer are exactly this: the index costs one line per subject on every message, while a linked file only enters the context when a task actually needs it. These file pointers can be used recursively through folders and files.</p>
<p><a href="https://code.claude.com/docs/en/memory#auto-memory">Claude Code's auto memory</a> is a built-in example of the pattern. The agent writes down its own learnings in topic files and maintains a <code>MEMORY.md</code> file as a concise index of what's stored where. The index is loaded at the start of every session, while the topic files are only read on demand, when something in the index matches the task at hand.</p>
<p>Anything that is occasionally useful, expensive to load, and possible to identify with a short label is a candidate for this layer. This is the argument for moving long, situational workflows out of <code>AGENTS.md</code> and into skills: a one-line pointer costs almost nothing, and the full content only loads when it's actually relevant.</p>
<h1>Live Lookups</h1>
<p>The last layer isn't really context in the usual sense. It's a request-response cycle in the middle of a task: nothing is preloaded, a lookup goes out when it's needed, and only the answer comes back. Anthropic's article about <a href="https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents">context engineering</a> calls this strategy <em>just-in-time</em> context: the agent holds lightweight references, like file paths and URLs, and fetches the actual data at runtime.</p>
<p>The most common form isn't MCP servers or web fetches, it's plain CLI commands. <code>git log</code> and <code>git diff</code> answer history questions without a single file being read into the context. The <a href="https://cli.github.com/"><code>gh</code> CLI</a> turns pull requests, issues, and CI runs into one-line lookups. A <a href="https://jqlang.org/"><code>jq</code></a> filter returns the one field the agent asked about, instead of the whole JSON file. <strong>The shape of the command decides the shape, and the size, of the answer</strong>, which is what makes the terminal such a strong context tool for agents.</p>
<p>The same mechanism covers MCP calls to a database, documentation lookups, and web fetches. The context is not filled up until the moment of use, and the answer is current, even when the underlying data has changed since yesterday. Asking a documentation tool for the signature of one specific function costs a fraction of pasting in an entire API reference. The catch is that <strong>live lookups only work well when they're specific</strong>. A vague query returns a vague and bloated answer, and you're back to the same problem as pasting in a whole file.</p>
<h1>A Concrete Example</h1>
<p>Let's take one concrete instruction, straight from the <code>AGENTS.md</code> of this website: "run <code>pnpm run format</code> after code changes". Where it belongs depends completely on how often it's needed:</p>
<ul>
<li>If it applies to <strong>every change in the repository</strong>, it belongs in <code>AGENTS.md</code>/<code>CLAUDE.md</code>. It's short, it's universal, and the always-loaded cost is worth it.</li>
<li>If it only applies to <strong>one part of the repository</strong>, with its own formatting rules, it belongs in a path-scoped rule or a nested instruction file, not in the root file.</li>
<li>If it's one step of <strong>a larger, occasional workflow</strong>, like a release checklist, it belongs in a skill that only loads when that workflow runs.</li>
<li>If the right command <strong>depends on what was changed</strong>, it's not really a standing instruction at all. It's something the agent should look up in <code>package.json</code> on demand, instead of something you hardcode anywhere.</li>
</ul>
<p>The same fact, four possible homes, and four very different costs depending on which one you pick.</p>
<p><img src="https://files.sebnilsson.com/web/images/layers-of-instructions-for-ai-coding-agents/pick-the-right-layer.png" alt="How to pick the right layer"></p>
<h1>Picking the Right Layer</h1>
<p>There is no right or wrong when it comes to picking a layer, but asking three questions will settle most cases:</p>
<ul>
<li><strong>How often is it needed?</strong> Knowledge that's needed on every message belongs in the always-loaded layer, if you can keep it short. Knowledge that's needed occasionally belongs in a layer that only loads when it's relevant.</li>
<li><strong>Is it durable, or about the current task?</strong> Durable conventions belong in files. Current-task specifics belong in the prompt, or in a scratch file the agent reads once.</li>
<li><strong>Would a lookup be cheaper than a preload?</strong> If the agent can find the answer itself with one targeted read or one query, that's usually cheaper than a standing instruction, and it stays correct when the underlying thing changes.</li>
</ul>
<p>These questions won't give a universally right answer, but they're a good check of your instincts before you add one more paragraph to a file that will reload on every message for the rest of the project's life.</p>
<h1>More Than a Cost Problem</h1>
<p>It's tempting to treat all of this purely as cost optimization, but the quality effect is at least as important.</p>
<p>A short, focused always-loaded layer keeps the agent's attention on the few rules that apply every time, which makes it follow them more reliably. This effect is real enough that Claude Code's documentation <a href="https://code.claude.com/docs/en/memory#write-effective-instructions">recommends keeping instruction files under 200 lines</a>, since longer files reduce how reliably the instructions get followed.</p>
<p>The other layers contribute in the same direction. Well-placed pointers and indexes let the agent start from the right assumptions and go straight to the relevant files, so its effort goes into the actual task. The first attempt is more often the right one, and the follow-up corrections become fewer. Overloading or starving the layers produces the reverse, in both quality and cost.</p>
<p><strong>Getting the layering right improves quality and cost at the same time</strong>, because both depend on the same thing: the right information arriving at the right time, in the right shape.</p>
<p><img src="https://files.sebnilsson.com/web/images/layers-of-instructions-for-ai-coding-agents/why-layering-matters.png" alt="Why layering matters"></p>
<h1>Summary</h1>
<p>Instructions to an AI coding agent don't travel through one single pipe. They arrive as always-loaded files, on-demand reads, progressively disclosed indexes, and live lookups, where each layer has a different trigger and a different cost.</p>
<p><strong>The skill worth building is not writing a longer <code>AGENTS.md</code>. It's recognizing which layer a piece of knowledge actually belongs in</strong>, and trusting the other layers to do their job. Keep the root file short, move the occasional workflows into skills, and let the agent look up the rest.</p>]]></content:encoded>
      <pubDate>Mon, 06 Jul 2026 08:08:00 GMT</pubDate>
      <category>AI</category>
      <category>AI Coding Agents</category>
      <category>Claude</category>
      <category>Codex</category>
      <category>Copilot</category>
      <category>Gemini</category>
      <category>Productivity</category>
    </item>
    <item>
      <title>Nullable GUID Route Constraints in ASP.NET Core</title>
      <link>https://sebnilsson.com/blog/nullable-guid-route-constraints-in-asp-net-core</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/nullable-guid-route-constraints-in-asp-net-core</guid>
      <description>Handle optional and nullable GUID route parameters with built-in ASP.NET Core route constraints.</description>
      <content:encoded><![CDATA[<callout icon="info">
<p><em>This is the ASP.NET Core companion to my original post on <a href="/blog/nullableguidconstraint-for-asp-net-mvc-webapi">NullableGuidConstraint for ASP.NET MVC &#x26; WebApi</a>.</em></p>
</callout>
<p>The original article implements one constraint for both traditional ASP.NET MVC and Web API. ASP.NET Core unified those programming models and includes a built-in <a href="https://learn.microsoft.com/aspnet/core/fundamentals/routing#route-constraints"><code>guid</code> route constraint</a>, so the custom compatibility constraint is no longer needed in modern applications.</p>
<h1>Optional nullable GUID parameters</h1>
<p>Combine the built-in <code>guid</code> constraint with the <a href="https://learn.microsoft.com/aspnet/core/fundamentals/routing#route-template-reference">optional-route marker</a>:</p>
<pre><code class="language-csharp">[HttpGet("customers/{id:guid?}")]
public IActionResult Get(Guid? id)
{
    return id is null
        ? Ok("Return all customers")
        : Ok($"Return customer {id}");
}
</code></pre>
<p>This route matches both:</p>
<pre><code class="language-text">/customers
/customers/0f8fad5b-d9cb-469f-a165-70867728950e
</code></pre>
<p>It does not match a non-GUID value such as:</p>
<pre><code class="language-text">/customers/not-a-guid
</code></pre>
<h1>Required GUID parameters</h1>
<p>Remove <code>?</code> when the route requires a GUID:</p>
<pre><code class="language-csharp">[HttpGet("customers/{id:guid}")]
public IActionResult Get(Guid id)
{
    return Ok($"Return customer {id}");
}
</code></pre>
<h1>Minimal APIs</h1>
<p>The same constraint syntax works with <a href="https://learn.microsoft.com/aspnet/core/fundamentals/minimal-apis/route-handlers">minimal API route handlers</a>:</p>
<pre><code class="language-csharp">app.MapGet("/customers/{id:guid?}", (Guid? id) =>
{
    return id is null
        ? Results.Ok("Return all customers")
        : Results.Ok($"Return customer {id}");
});
</code></pre>
<h1>Constraint versus validation</h1>
<p>Route constraints help endpoint selection. They are not a replacement for validating business rules.</p>
<p>Use <code>{id:guid}</code> when a non-GUID path should not select the endpoint. Validate rules such as whether the GUID exists, is allowed, or must not be <code>Guid.Empty</code> inside the endpoint or application layer.</p>
<p>For traditional ASP.NET MVC and Web API, including the shared custom <code>NullableGuidConstraint</code>, see the <a href="/blog/nullableguidconstraint-for-asp-net-mvc-webapi">original article</a>.</p>]]></content:encoded>
      <pubDate>Tue, 30 Jun 2026 06:54:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>ASP.NET Core Request Paths Reference</title>
      <link>https://sebnilsson.com/blog/asp-net-core-request-paths-reference</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-core-request-paths-reference</guid>
      <description>Compare request URL, path, query string, host, scheme, and base-path values in ASP.NET Core.</description>
      <content:encoded><![CDATA[<callout icon="info">
<p><em>This is the modern ASP.NET Core update of my original <a href="/blog/asp-net-request-paths-reference">ASP.NET Request Paths Reference</a>.</em></p>
</callout>
<p>That older reference remains useful for applications built on traditional ASP.NET and <code>System.Web</code>. A separate article is needed because ASP.NET Core replaced those request APIs, separates URL components differently, and commonly runs behind reverse proxies or under a configured base path.</p>
<p>Consider this request:</p>
<pre><code class="language-text">https://www.example.com/MyApplication/MyFolder/MyPage?key=value
</code></pre>
<p>In this example, <code>/MyApplication</code> is the application's configured base path. ASP.NET Core exposes that prefix as <code>Request.PathBase</code>, and exposes the remaining path inside the application as <code>Request.Path</code>.</p>
<p><code>PathBase</code> is not automatically the first URL segment. It is a configured or forwarded path prefix for the application. It is often empty when the app runs at the domain root, such as <code>https://www.example.com/</code>. It can also contain one or more segments, such as <code>/MyApplication</code> or <code>/apps/customers</code>, when the app runs under that URL prefix.</p>
<h1>Request path properties</h1>
<p>In a controller, Razor Page, middleware, or endpoint, use properties from <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest"><code>HttpRequest</code></a>:</p>





































<table><thead><tr><th>Property</th><th>Example value</th></tr></thead><tbody><tr><td><a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest.scheme"><code>Request.Scheme</code></a></td><td><code>https</code></td></tr><tr><td><a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest.host"><code>Request.Host</code></a></td><td><code>www.example.com</code></td></tr><tr><td><a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest.pathbase"><code>Request.PathBase</code></a></td><td><code>/MyApplication</code></td></tr><tr><td><a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest.path"><code>Request.Path</code></a></td><td><code>/MyFolder/MyPage</code></td></tr><tr><td><a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest.querystring"><code>Request.QueryString</code></a></td><td><code>?key=value</code></td></tr><tr><td><a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest.query"><code>Request.Query</code></a></td><td><code>Request.Query["key"]</code> is <code>value</code></td></tr><tr><td><a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.httprequest.protocol"><code>Request.Protocol</code></a></td><td><code>HTTP/2</code> or the active protocol</td></tr></tbody></table>
<p><code>PathBase</code> contains the path prefix that has been separated from the request path. <code>Path</code> contains the remaining request path used by routing inside the application.</p>
<p>For example, if the incoming URL path is <code>/MyApplication/MyFolder/MyPage</code>:</p>

























<table><thead><tr><th>Configuration</th><th><code>Request.PathBase</code></th><th><code>Request.Path</code></th></tr></thead><tbody><tr><td>No base path</td><td>empty</td><td><code>/MyApplication/MyFolder/MyPage</code></td></tr><tr><td>Base path is <code>/MyApplication</code></td><td><code>/MyApplication</code></td><td><code>/MyFolder/MyPage</code></td></tr><tr><td>Base path is <code>/MyApplication/MyFolder</code></td><td><code>/MyApplication/MyFolder</code></td><td><code>/MyPage</code></td></tr></tbody></table>
<p>The split can come from middleware such as <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.builder.usepathbaseextensions.usepathbase"><code>UsePathBase</code></a>, hosting under a sub-application, or forwarded proxy configuration such as <code>X-Forwarded-Prefix</code>.</p>
<pre><code class="language-csharp">var request = HttpContext.Request;

var pathWithinApplication = request.Path;
var fullPath = request.PathBase + request.Path + request.QueryString;
</code></pre>
<p>For the example request:</p>
<pre><code class="language-text">pathWithinApplication = /MyFolder/MyPage
fullPath              = /MyApplication/MyFolder/MyPage?key=value
</code></pre>
<h1>Build the absolute request URL</h1>
<p>ASP.NET Core deliberately keeps URL components separate. To create the absolute display URL, use <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.http.extensions.urihelper.getdisplayurl"><code>GetDisplayUrl()</code></a> from <code>Microsoft.AspNetCore.Http.Extensions</code>:</p>
<pre><code class="language-csharp">using Microsoft.AspNetCore.Http.Extensions;

var absoluteUrl = Request.GetDisplayUrl();
// https://www.example.com/MyApplication/MyFolder/MyPage?key=value
</code></pre>
<p>When the application runs behind a reverse proxy, <a href="https://learn.microsoft.com/aspnet/core/host-and-deploy/proxy-load-balancer">configure forwarded headers</a> so <code>Scheme</code>, <code>Host</code>, and the generated absolute URL reflect the original client request.</p>
<h1>Generate application links</h1>
<p>Do not manually concatenate paths when generating links to endpoints. Use ASP.NET Core link generation with <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.mvc.iurlhelper.action"><code>Url.Action</code></a>:</p>
<pre><code class="language-csharp">var path = Url.Action("Details", "Customers", new { id = 42 });
var absolute = Url.Action(
    "Details",
    "Customers",
    new { id = 42 },
    protocol: Request.Scheme);
</code></pre>
<p>For endpoint routing outside a controller, inject <a href="https://learn.microsoft.com/dotnet/api/microsoft.aspnetcore.routing.linkgenerator"><code>LinkGenerator</code></a>.</p>
<h1>Which property should you use?</h1>
<ul>
<li>Use <code>Request.Path</code> to inspect the route path inside the application.</li>
<li>Use <code>Request.PathBase + Request.Path</code> when the mounted base path matters.</li>
<li>Use <code>Request.Query</code> to read parsed query-string values.</li>
<li>Use <code>GetDisplayUrl()</code> when you need the complete incoming URL for diagnostics or display.</li>
<li>Use <code>Url</code>, <code>LinkGenerator</code>, or endpoint names when generating application links.</li>
</ul>
<p>For traditional ASP.NET APIs such as <code>Request.RawUrl</code>, <code>Request.ApplicationPath</code>, and <code>Request.Url</code>, see the <a href="/blog/asp-net-request-paths-reference">original ASP.NET Request Paths Reference</a>.</p>]]></content:encoded>
      <pubDate>Fri, 26 Jun 2026 06:47:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>AI Driven Migration of New Website</title>
      <link>https://sebnilsson.com/blog/ai-driven-migration-of-new-website</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/ai-driven-migration-of-new-website</guid>
      <description>Experiences from migrating sebnilsson.com from ASP.NET to Next.js using AI coding agents.</description>
      <content:encoded><![CDATA[<p>My personal website has existed in different forms since 2012. The previous version was built with the original <a href="https://dotnet.microsoft.com/apps/aspnet/mvc">ASP.NET MVC</a> and later upgraded to <a href="https://docs.microsoft.com/aspnet/core/">ASP.NET Core</a>. Over the years, it accumulated controllers, Razor views, view components, custom routing, URL rewrite rules, RavenDB integrations, Gulp scripts, SCSS styles, frontend build scripts, and several supporting libraries.</p>
<p>It worked, but maintaining it had become unnecessarily complicated for what the website needed to be. For example, setting up the frontend pipeline for a small tweak, sometimes several years and major npm package versions later, was an unbelievable waste of time.</p>
<p>Most of the website consists of content: blog posts, conference talks, articles, podcast appearances, and information about me. It did not need a database-backed application with over-complicated architecture and exaggerated technical solutions. I wanted a modern website that was easier to change, faster to experiment with, and better suited for working on together with AI coding agents.</p>
<h1>Why Next.js</h1>
<p>It's quite clear that <a href="https://2025.stateofjs.com/en-US/libraries/front-end-frameworks">React has sort of won the frontend race</a>. I used to think the React model was too simple and stupid, but after using it for a while, I realized that this was actually the strength of the framework. It ensured a data flow which was easy to follow and troubleshoot.</p>
<p>Also, I wanted a website which was rendered on the server, for SEO and predictability, but still allowed the full frontend expressiveness of TypeScript/JavaScript. React has, by far, the largest ecosystem for components and functionality out there. AI coding agents are extremely competent in React and very good at Next.js. Personally, I'm also quite comfortable in Next.js, all the way from Next.js 13 and forward. All that put together made the decision easy for me.</p>
<h1>AI-Powered Migration</h1>
<p>The migration was done in mid-2026, so it was of course done in collaboration with AI-powered tools, such as AI coding agents.</p>
<p>Deleting the source code for the previous ASP.NET solution in the repository deleted more than 9 000 lines of code across 118 files. That included various code, templates, scripts, libraries, configuration, and more, accumulated during more than a decade.</p>
<p>Deleting the application was the easy part. The important part was preserving the content. I had some foresight here, and all my blog posts were already in <a href="https://daringfireball.net/projects/markdown/">Markdown-formatted</a> files.</p>
<h2>Migrating to Next.js</h2>
<p>I then used <a href="https://v0.dev/">Vercel's v0</a> tool to create the first Next.js version of the website. It provided a useful visual starting point with an App Router application, pages, components, <a href="https://tailwindcss.com/">Tailwind CSS</a>, and <a href="https://ui.shadcn.com/">shadcn/ui</a>. It produced an impressive result quickly, but it was still just a starting point.</p>
<p>The initial version contained more than one hundred new files, including dozens of UI components the website did not use. Some parts looked finished while the underlying structure still needed work. The application could render pages, but it was not yet the website I had envisioned.</p>
<h2>Choosing an AI Coding Agent</h2>
<callout icon="warning">
<p><strong>Warning:</strong> This section is subjective, partly based on my own tooling habits, and likely to age quickly. It could be outdated days after the post is published.</p>
</callout>
<p>From this point, I needed a strong AI coding agent to work with, to build the technical solution I wanted, in the way and with the structure I wanted. The main agents I used were <a href="https://code.claude.com/">Claude Code</a> CLI, <a href="https://developers.openai.com/codex/cli">Codex CLI</a>, and <a href="https://developers.openai.com/codex/app">Codex App</a>.</p>
<p>The <a href="https://martinfowler.com/articles/harness-engineering.html">harnesses</a> and the <a href="https://openrouter.ai/models">AI models</a> are changing constantly, with us being in the midst of a fierce race to the top between the frontier models. Despite benchmarks, published features, and measured differences, <strong>people easily base their preferences on feelings</strong> and how well a coding agent vibes with them (pun intended). I know that I did.</p>
<p>My experience with Claude vs. Codex was roughly this: Codex reads between the lines of <strong>my prompts</strong> extremely well and gets very close to what I intended to ask for. I've also found a good flow working with it. Claude produces great results, but burns tokens fast, sometimes does work I did not request, and bombards me with approval prompts for every little change.</p>
<p>At the time of writing this article, I found specifically that the <a href="https://developers.openai.com/codex/app">Codex App</a> had the UX that worked best for me personally. So, that was my primary tool, while complementing it with Claude Code for second opinions or when I ran out of token usage.</p>
<h2>Token Optimization</h2>
<p>I intentionally used the lowest tier subscriptions for both Codex and Claude, to see how far it could take me. This meant that I really needed to mind my token burn. This drove me to adopt some key patterns, to get <strong>the most output and best results for the least amount of tokens</strong>. I shortly considered installing the <a href="https://www.skills.sh/juliusbrussee/caveman/caveman">Caveman-skill</a> to really minimize token usage but chose not to, as I wanted a realistic experience and to optimize in more conventional ways.</p>
<p>Another early task was updating the shadcn/ui setup and removing all components not used. That change alone removed thousands of lines from the repository. A <strong>key to saving tokens</strong> here was to tell the agent to use the <a href="https://ui.shadcn.com/docs/cli">shadcn CLI</a> instead of reading and writing large source files directly from GitHub (which I once had to stop an agent from doing, mid-token apocalypse).</p>
<h2>Better AI Agent Instructions</h2>
<p>First, I ensured the project had a solid <code>AGENTS.md</code> to give the AI coding agent basic information about the project. The key here was to <strong>avoid including information which easily starts to drift</strong> with changes to the website.</p>
<p>Another important instruction was to tell the agent to read the latest Next.js documentation, included in the installed npm package, before making relevant changes. Instructions on formatting, linting, and building were also included.</p>
<p>I also added specialized agent skills for areas such as Next.js best practices, React best practices, shadcn/ui, and SEO. To ensure access across both Codex and Claude, I used <a href="https://skills.sh/">Vercel's skills.sh</a>.</p>
<h2>AI Agent Iterative Development</h2>
<p>The work was not a single conversion prompt followed by a finished website. It was an iterative development process where I remained responsible for the direction, while Codex handled most of the implementation.</p>
<p>First, I took the opportunity, <strong>while the codebase was still relatively small</strong>, to do larger sweeping operations with agents and set codebase-wide baselines. I installed <a href="https://www.skills.sh/vercel/nextjs-skills/next-best-practices">Vercel's own skills for Next.js best practices</a> and asked the agent to improve everything according to the best practices. It improved the codebase to better match Next.js conventions, reorganized code, improved SEO, implemented server actions, and simplified where possible.</p>
<p>The <strong>key workflow</strong> I used to ensure the <strong>best outcome and surprising effectiveness in token usage</strong> was the following points:</p>
<ul>
<li>Point out the exact entry point file for the change.
<ul>
<li>If changing the functionality or look of a page on the site, I pointed to the specific <code>page.tsx</code> file.</li>
<li>If the change was pure functionality, I pointed to the relevant file or files.</li>
</ul>
</li>
<li>I described the expected outcome of the functionality I wanted added.
<ul>
<li>If I knew of specific functional or technical limitations, I explicitly mentioned these.</li>
</ul>
</li>
<li>Default to medium effort on models. Use low or medium effort for very straight forward tweaks.</li>
<li>For tweaks to implementations which could be improved, I pointed to the exact file and named function and variable names to focus on.</li>
<li>Keep conversation threads short. Only stay in the same thread of changes as long as most of the context is relevant.</li>
</ul>
<p>Explicitly pointing out where to look seemed to keep token usage down significantly. I very rarely hit the limits on the lowest tier subscriptions to Codex and Claude. That makes sense, since the AI probably doesn't have to scan as much of the file, or multiple files, to figure out where to start and where to make the changes.</p>
<p><em>It's important to note that this was highly efficient at the time of posting this blog. The harnesses and/or models might change/improve significantly over time.</em></p>
<h1>Stabilize and Improve Content</h1>
<p>The blog was one of the most important parts of the migration. Some posts have existed for more than fifteen years, and their URLs still receive traffic. Preserving those posts and their URLs mattered more than reproducing every detail of the old application.</p>
<p>The first Next.js version loaded the Markdown files using custom code. With Codex, I later introduced Velite to provide a clearer content model and build process.</p>
<p>After deliberating with both Codex and Claude, we decided to use <a href="https://velite.js.org/">Velite</a> to structure the existing blog post content in Markdown format. This means each blog post now has validated frontmatter containing fields such as its title, publication date, summary, tags, image, series, and draft status. Velite processes the Markdown and produces structured data for Next.js.</p>
<p>This made several later improvements easier:</p>
<ul>
<li>Posts can be grouped into a series</li>
<li>Tags can be sorted and filtered consistently</li>
<li>Blog search can operate on structured content</li>
<li>Draft posts are supported outside production</li>
<li>RSS feeds and sitemaps can use the same content source</li>
<li>Syntax highlighting can be applied during content processing</li>
</ul>
<p>Codex helped implement these features incrementally. Blog search, for example, was added as a focused feature rather than as part of the original migration. The same was true for series navigation, improved code highlighting, responsive images, and fallback images.</p>
<p>Each change was small enough to understand and review, but together they preserved the previous blog experience and, in many ways, improved on it.</p>
<h1>Moving Beyond a Direct Replacement</h1>
<p>At first, the goal was to replace the old ASP.NET website. Once the new foundation was stable, the work became more interesting: I could start improving what the website actually communicated.</p>
<p>The old site had grown around sections created at different times. During the migration, I reconsidered whether those sections still represented me and my work. The start page was redesigned several times and my portfolio content was restructured quite a lot. Articles I've written and podcast appearances are now shown on the website. Conference talks and speaking information became more prominent.</p>
<p>Some of these changes began as broad requests such as improving the start page. Others were extremely specific, such as adjusting the behavior of a navigation button or changing the layout of a single conference talk.</p>
<h1>Using Codex as a Reviewer</h1>
<p>Codex was also useful when I did not have a specific implementation in mind.</p>
<p>I could ask it to review the website for unnecessary complexity, Next.js issues, SEO opportunities, or performance problems. It would inspect the current repository, identify concrete improvements, and implement the ones that made sense.</p>
<p>The important part was still reviewing the result. Codex can inspect a large amount of code quickly, but it does not own the product decisions. Some technically valid suggestions did not match the website I wanted. Others needed another iteration after I saw them in the browser.</p>
<p>The best results came from treating Codex as an engineering collaborator rather than as an automatic code generator.</p>
<h1>Summary</h1>
<p><strong>This migration couldn't have been done without using modern AI coding agents.</strong> At least not within any reasonable time.</p>
<p>The AI agents played an important role, but not by performing one automatic conversion. Their role was closer to that of engineering collaborators: inspecting the existing work, implementing focused improvements, cleaning up generated code, following project-specific instructions, and helping me improve the process continuously.</p>
<p>The website moved from a server-side ASP.NET application with more than a decade of accumulated architecture to a content-focused Next.js application built around Markdown and reusable React components.</p>
<p><strong>.NET, C#, and ASP.NET are still my main tools of choice</strong> when building high-performant, robust, testable, and long-lived solutions for serious organizations. ASP.NET for building APIs is still unmatched and C# is by far my favorite language. That said, Next.js and React are my favorites for server-side and client-side hybrid solutions for stable, dynamic, and expressive websites and web applications.</p>
<p>The migration gave me a modern website. More importantly, it <strong>solidified a collaboration process with AI coding agents</strong> which lets me make improvements, add features, or just do small tweaks extremely quickly and get them out to production within minutes. We really live in amazing times, and hopefully it'll only get better.</p>]]></content:encoded>
      <pubDate>Mon, 22 Jun 2026 07:33:00 GMT</pubDate>
      <category>AI</category>
      <category>AI Coding Agents</category>
      <category>Claude</category>
      <category>Codex</category>
      <category>Next.js</category>
      <category>Productivity</category>
      <category>Projects</category>
      <category>TypeScript</category>
    </item>
    <item>
      <title>dotnet cleanup v2: Quickly Clean Up bin, obj &amp; node_modules Folders</title>
      <link>https://sebnilsson.com/blog/dotnet-cleanup-v2-quickly-clean-up-bin-obj-node-modules-folders</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/dotnet-cleanup-v2-quickly-clean-up-bin-obj-node-modules-folders</guid>
      <description>Use the rebuilt dotnet-cleanup .NET tool to quickly remove generated directories, using glob patterns.</description>
      <content:encoded><![CDATA[<callout icon="info">
<p><em>This blog post is about version 2 of my .NET Tool <code>dotnet-cleanup</code>. You can read the post about version 1 here: <a href="/blog/dotnet-cleanup-clean-up-solution-project-folder"><code>dotnet-cleanup</code>: Clean Up Solution, Project &#x26; Folder</a>.</em></p>
</callout>
<p>The v2 of the tool has been rebuilt around directory-tree cleanup and glob patterns. Compared with the original solution-and-project-oriented version, the current version can be used on any directory with sub-directories including .NET projects, web-applications, or any combination of these. It can also be used on other types of directories by specifying which folders and files, with glob patterns, to clean up.</p>
<p>The tool command name remains <a href="https://www.nuget.org/packages/DotnetCleanup"><code>dotnet-cleanup</code></a>, with a hyphen.</p>
<p>Like with the previous version, one big USP (unique selling point) for this tool is that it removes the cleanup folders extremely fast, by first moving them to a temporary folder, before actually deleting them off disk.</p>
<h1>Install the tool</h1>
<p>Install <a href="https://www.nuget.org/packages/DotnetCleanup"><code>dotnet-cleanup</code></a> as a global .NET tool:</p>
<pre><code class="language-shell">dotnet tool install --global dotnet-cleanup
</code></pre>
<p>Update an existing installation:</p>
<pre><code class="language-shell">dotnet tool update --global dotnet-cleanup
</code></pre>
<h1>Include and exclude directories</h1>
<p>Add include patterns with <code>--path</code> or <code>-p</code> and exclude patterns with <code>--exclude</code> or <code>-x</code>:</p>
<pre><code class="language-shell">dotnet-cleanup \
  -p "**/bin" \
  -p "**/obj" \
  -p "**/node_modules" \
  -x "**/samples/**"
</code></pre>
<p>This glob-based model is the biggest change from the original tool. It can clean generated directories across mixed .NET and web repositories without first resolving a solution or project file.</p>
<p>By default, the tool includes the following paths:</p>
<pre><code class="language-text">**/bin
**/obj
**/node_modules
</code></pre>
<h1>Cleanup preview</h1>
<p>The tool will first give you a list of matching files and directories, which will be deleted. You'll then have to actively confirm.</p>
<pre><code class="language-shell">dotnet-cleanup
</code></pre>
<p>If you want to be totally sure that no files will actually be cleaned, add the <code>--noop</code> option:</p>
<pre><code class="language-shell">dotnet-cleanup --noop
</code></pre>
<p><code>--noop</code> lists matching directories without moving or deleting them. Use it before every new automated cleanup configuration.</p>
<h1>CI/CD scenario: Auto confirm</h1>
<p>To skip the confirmation prompt, for example when used inside a CI/CD solution, add <code>--yes</code> to automatically confirm the deletions:</p>
<pre><code class="language-shell">dotnet-cleanup --yes
</code></pre>
<h1>Customization</h1>
<p>Matched directories are moved to a temporary directory before deletion by default. There are options provided for controlling that process, if needed:</p>
<pre><code class="language-shell">dotnet-cleanup --no-move
dotnet-cleanup --no-delete
dotnet-cleanup --temp-path "D:\cleanup-temp"
</code></pre>
<p>Use <code>--no-delete</code> when you want the moved directories to remain available for inspection. Use <code>--no-move</code> only when direct deletion is acceptable.</p>
<h1>Review the current options</h1>
<p>The README and command-line help are the source of truth for current behavior:</p>
<pre><code class="language-shell">dotnet-cleanup --help
</code></pre>
<p>Cleanup is destructive. Commit or stash work, run <code>--noop</code>, and review include and exclude patterns before confirming.</p>
<p>See the <a href="https://github.com/sebnilsson/DotnetCleanup">DotnetCleanup repository</a> for the current README and source.</p>
<p>The <a href="/blog/dotnet-cleanup-clean-up-solution-project-folder">original article</a> documents the earlier solution-and-project-oriented implementation.</p>]]></content:encoded>
      <pubDate>Wed, 17 Jun 2026 06:46:00 GMT</pubDate>
      <category>.NET</category>
      <category>.NET Tools</category>
      <category>Developer Tools</category>
      <category>Productivity</category>
      <category>Projects</category>
    </item>
    <item>
      <title>dotnet-ping: Ping URLs in the Terminal</title>
      <link>https://sebnilsson.com/blog/dotnet-ping-ping-urls-in-the-terminal</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/dotnet-ping-ping-urls-in-the-terminal</guid>
      <description>When working with the web development at a rapid pace, you need to constantly ensure that key parts of your website always work</description>
      <content:encoded><![CDATA[<p>When working with the web development at a rapid pace, you need to constantly ensure that key parts of your website always work.
There are tools out there that offers advanced monitoring,
but what about when you just want to fire off quick ensuring tests on your local machine?</p>
<p>This is the background to why I built <code>dotnet-ping</code>,
which is easily installed as a <a href="https://learn.microsoft.com/dotnet/core/tools/global-tools">.NET Global Tool</a>
and makes pinging URLs via the terminal really easy.</p>
<h1>Installation</h1>
<p>Download <a href="https://dotnet.microsoft.com/download">the latest version of .NET</a>. Then install the <a href="https://www.nuget.org/packages/dotnet-ping"><code>dotnet-ping</code></a> .NET Tool, using the terminal:</p>
<pre><code class="language-sh">dotnet tool install -g dotnet-ping
</code></pre>
<p>Once installed, you can verify the tool is available by running <code>dotnet tool list -g</code>.</p>
<h1>Basic scenarios</h1>
<p>To ping a single URL just supply the URL as the command argument:</p>
<pre><code class="language-sh">dotnet ping https://example.com/section/page
</code></pre>
<p>If you want to ping multiple URLs, you can supply multiple command arguments.</p>
<pre><code class="language-sh">dotnet ping example.com/page other.com/other-page
</code></pre>
<p>If a URL is missing the protocol (e.g., <code>http://</code> or <code>https://</code>), the tool will automatically assume <code>https://</code>.</p>
<p>You can use the <code>-s</code> option to set the sleep time between requests
and the <code>-t</code> option to set the timeout limit for a response from the pinged URL.</p>
<p>If you want to ping multiple pages on the same website, you can supply a base-URL, using the <code>-b</code> option:</p>
<pre><code class="language-sh">dotnet ping -b example.com /home /about /contact-us /products
</code></pre>
<p>Pings expect, by default, a <code>200</code> response as HTTP status. This can be modified with the <code>-e</code> option.
The full list of documentation can be found by calling the tool with the <code>-h</code> option or looking at the <code>README</code> on
<a href="https://github.com/sebnilsson/DotnetPing">GitHub</a> or on <a href="https://www.nuget.org/packages/dotnet-ping/">NuGet.org</a>.</p>
<h1>Advanced scenarios</h1>
<p>For more advanced scenarios, where you want to have a better overview and more complex configuration for multiple URLs,
the tool supports configuration via a <code>.json</code> file. If there is a <code>ping.json</code> file in the directory that the tool is executed from,
and no URL is passed as a command argument, this file will be used.</p>
<p>The basic structure of the file allows an array of URLs (<code>urls</code>) and their configuration,
as well as an array of configuration group (<code>groups</code>), which are applied to one or multiple URLs.</p>
<pre><code class="language-json">{
    // Single URLs, with Single configurations
    "urls": [
        {
            "url": "test.com", // Required
            "method": "GET", // Default: GET
            "timeout": 15000, // Default: 5000ms
            "sleep": 100, // Default: 500ms
            "expect": [ 200, 201, 403 ] // Default: 200
        },
        {
            "url": "http://test2.com",
            "method": "DELETE",
            "timeout": 10000,
            "sleep": 200,
            "expect": [ 201, 202, 204 ]
        }
    ],
    // Groups of configurations, with single or multiple URLs
    "groups": [
        {
            "timeout": 20000,
            "sleep": 250,
            "expect": [ 301, 302 ],
            "urls": [ "test3.com/redirect", "test4.com/redirect" ]
        },
        {
            "timeout": 5000,
            "sleep": 550,
            "baseUrl": "https://test5.com/",
            "expect": [ 200, 201 ],
            "urls": [ "/", "/about", "/contact", "products" ]
        }
    ]
}
</code></pre>
<h1>Usage Documentation</h1>
<p>See the usage documentation of the tool by running <code>dotnet ping -h</code>:</p>
<pre><code class="language-sh">USAGE:
    dotnet-ping [urls] [OPTIONS]

EXAMPLES:
    dotnet-ping https://example.com
    dotnet-ping https://example.com other.com -s 1000
    dotnet-ping https://example.com other.com -s 1000 -s 2000 -t 5000
    dotnet-ping /about /contact -b https://example.com
    dotnet-ping -c ping.json

ARGUMENTS:
    [urls]    The URLs to ping. If not specified, the URLs are read from the JSON config file

OPTIONS:
    -h, --help        Prints help information
    -b, --base-url    Sets the base-URL to use for requests
    -c, --config      The path to the JSON config file
    -d, --debug       Use debug console messaging
    -e, --expect      Sets the expected status code of requests. Default: 200
    -X, --request     Sets the request method. Default: GET
    -m, --minimal     Use minimal console messaging
    -s, --sleep       Sets the sleep wait time between requests in milliseconds. Default: 500ms
    -t, --timeout     Sets the timeout for requests in milliseconds. Default: 5000ms. If two values are provided, a
                      random number between the two numbers will be generated for each request
</code></pre>
<h1>Outro</h1>
<p>Take it for a spin and feel free to give feedback on the tool.
If you find bugs or have suggestions,
feel free to <a href="https://github.com/sebnilsson/DotnetPing">open an issue on GitHub or submit a pull request</a>.</p>
<p>You can find the <a href="https://github.com/sebnilsson/DotnetPing">source-code on GitHub</a>
and the <a href="https://www.nuget.org/packages/dotnet-ping/">package on Nuget</a>.</p>]]></content:encoded>
      <pubDate>Mon, 14 Oct 2024 06:44:00 GMT</pubDate>
      <category>.NET</category>
      <category>.NET Tools</category>
      <category>Developer Tools</category>
      <category>Productivity</category>
      <category>Projects</category>
    </item>
    <item>
      <title>How to Understand Log Levels</title>
      <link>https://sebnilsson.com/blog/how-to-understand-log-levels</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/how-to-understand-log-levels</guid>
      <description>Log levels are more than just black or red rows in your logging system</description>
      <content:encoded><![CDATA[<p><em><strong>Originally written and published for <a href="https://lightrun.com/best-practices/how-to-understand-log-levels/">Lightrun's best practices</a></strong></em></p>
<hr>
<p>More than once, I've heard experienced software developers say that there are only two reasons to log: either you log <code>Information</code> or you log an <code>Error</code>. The implication here is that either you want to <strong>record something that happened</strong> or you want to be able to <strong>react to something that went wrong</strong>.</p>
<p>In this article, we'll take a closer look at logging and explore the fact that <strong>log levels are more than just black or red rows</strong> in your main logging system. When used correctly, they let you filter certain types of data to be logged to different destinations, have different retention times, and can be searched more easily in different structures of the data.</p>
<h1>Why Logging?</h1>
<p>While developing software, hopefully you write unit tests to validate isolated functionality in your code, add some integration tests, and maybe do some manual testing on top of that. But when your code is running in production, you need a way to get information about what code is being executed inside your software and have that accessible from the outside.</p>
<p>The most common way to do this is to add logging to your code. Usually, this code will then write to a destination, which can be a local file, a database, or a centrally controlled more advanced log solution. You can then access this information to get technical insights into what's going on in the running code.</p>
<p>Log entries, depending on configuration, usually contain a time stamp, a severity level, a message entered in the code, sometimes which class/file is doing the logging, sometimes a stack trace from an error in the code, and other metadata about the execution context. When done right, this can help developers follow the flow of logic through the software.</p>
<p>Many use logging to log key events in the system, like orders completed, users registered, reviews written, and so on. <strong>With correctly structured data, you can pipe this data into different analysis tools to get more business insights.</strong> For example, usually, you turn to your logs when something goes wrong in the software. If logging is set up correctly, you'll be able to figure out where the problem comes from and from which line of code.</p>
<p>If there's not enough information in your logs, you might want to ensure that a lower level of logging is written to your logs, so you can get more details about what's going on in your software. You can usually achieve this by using different log levels.</p>
<h1>Understanding The Different Log Levels</h1>
<p><strong>Log levels convey the intention of the specific content of what's being logged. This can help you filter different levels of log data into different destinations, enabling you to focus on the log level relevant to the current issue you're facing.</strong> Logging to different destinations also allows you to have different retention levels for different logged content.</p>
<p>These are the most common log levels for logging libraries:</p>
<ul>
<li><code>Critical</code><em>*</em></li>
<li><code>Error</code></li>
<li><code>Warn</code></li>
<li><code>Info</code></li>
<li><code>Debug</code></li>
<li><code>Trace</code></li>
</ul>
<p><em>* Sometimes under other names, such as <strong>Fatal</strong> or <strong>Fault</strong>.</em></p>
<p>Different languages and platforms, and their most popular logging libraries, actually support different log levels, even if the core functionality is there across them all.</p>




































































<table><thead><tr><th></th><th><code>Trace</code></th><th><code>Debug</code></th><th><code>Info</code></th><th><code>Warn</code></th><th><code>Error</code></th><th><code>Critical</code></th></tr></thead><tbody><tr><td><a href="https://docs.microsoft.com/dotnet/api/microsoft.extensions.logging.loglevel">C#/.NET</a></td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td></tr><tr><td><a href="https://logging.apache.org/log4j/2.x/manual/customloglevels.html">Java</a></td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️ (as <code>Fatal</code>)</td></tr><tr><td><a href="https://docs.python.org/3/library/logging.html#levels">Python</a></td><td></td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td></tr><tr><td><a href="https://docs.rs/log/0.4.14/log/">Rust</a></td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td></td></tr><tr><td><a href="https://developer.apple.com/documentation/os/oslogtype">Swift</a></td><td></td><td>✔️</td><td>✔️</td><td></td><td>✔️</td><td>✔️ (as <code>Fault</code>)</td></tr><tr><td><a href="https://github.com/MicroUtils/kotlin-logging/blob/master/src/jvmMain/kotlin/mu/KLogger.kt">Kotlin</a></td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td>✔️</td><td></td></tr></tbody></table>
<p>Many logging libraries allow you to also handle an <code>All</code> scenario, where all the levels are written to the configured destinations. The <code>None</code> scenario, then, turns off all the logging. Some libraries also support a <code>Custom</code> scenario, where you can specify exactly which log levels to include.</p>
<h1>Picking the Right Log Level</h1>
<p><strong>There is no right or wrong when it comes to picking a level of logging, but it's important to set the same expectations throughout a project and maybe throughout an entire organization.</strong></p>
<p>Here are a few best-practice suggestions as a starting point that any team should be able to build upon:</p>
<ul>
<li><code>Critical</code>: Used when your application is in an unrecoverable state. It crashes during startup configuration, or a framework-level component is not working as expected.<br>
<em>Example: Your app cannot start up correctly or your DI setup fails.</em></li>
<li><code>Error</code>: Used for errors that stop the flow of the execution. Usually used for unknown and unexpected errors in a central catch-all scenario for an application.<br>
<em>Example: Routing in your web app fails, or code in an MVC controller throws an exception.</em></li>
<li><code>Warn</code>: Used for errors that don't stop the flow of execution. Usually, these errors are somewhat expected, since the logging code is added manually to these points in the code.<br>
<em>Example: Calling an external service, which you know can fail and you can silently recover from.</em></li>
<li><code>Info</code>: Used to log events in the normal flow of the code. Can be used for only system key events, to keep the volume of log data down.<br>
<em>Example: User clicked a call-to-action button or new user registered.</em></li>
<li><code>Debug</code>: Used for scenarios where the information in higher levels is not enough to <a href="https://lightrun.com/debugging/debugging-microservices-the-ultimate-guide/">debug a problem</a>. Should record the flow through the system.<br>
<em>Example: Method X was called in class/object Y, to track different flows.</em></li>
<li><code>Trace</code>: Used to get as much detail as possible, tracking the flow of data through the system. Can contain sensitive data. Should probably never be activated in production.<br>
<em>Example: Method X was called with parameter values Y and Z.</em></li>
</ul>
<p>Usually, <code>Critical</code>, <code>Error</code>, and sometimes <code>Warn</code> levels contain a <strong>full stack trace</strong> for full analysis of the technical context of the problem.</p>
<p>You will probably want different configurations for your logging between your local development environment, your testing environment, and your production environment. It's worth noting that, with most logging libraries, configuring for one level includes the levels above it. For example, if you configure for the <code>Info</code> level, it'll include all levels above it, too, in the logging. So you'll also get <code>Info</code>, <code>Warn</code> (where available), <code>Error</code>, and <code>Critical</code>.</p>
<p>Some libraries allow you to set an upper limit as well, but this is for very specific scenarios, since you would rarely want to see <code>Error</code> logs but not <code>Critical</code> logs, for example.</p>
<p>However, all solutions have different needs, and these needs can change depending on what problem occurs when. Let's glance through some examples of various setups.</p>
<h2>Local Development Environment</h2>
<p><strong>In a development environment on your local machine, you probably want to start off with the <code>Debug</code> level of logging.</strong> You can lower it to <code>Trace</code> if more detailed issues need diagnosed, or increase it to <code>Info</code> if it gets too noisy.</p>
<p>You'll probably always want to write to local files on your file system for quick access, and avoid writing to any central logging destination, unless you're explicitly testing the integration itself. This is because it can generate a lot of data over time, even with a small team, which usually increases cost quite a lot.</p>
<h2>Testing Environment</h2>
<p><strong>In a testing environment, which is not on your local machine, you probably want to set the logging level to <code>Info</code> and then temporarily turn the level down to <code>Debug</code> and <code>Trace</code> as needed for the moment.</strong> If you're not interested in the normal flow of the app and only want to catch errors, you can actually set the logging level to <code>Error</code>.</p>
<p>As it's a test environment, you should only have test data logging here, so lower logging levels should not be logging sensitive production data. You don't have to worry about that aspect here, even if you should always be vigilant of it.</p>
<p>Since this is not a local machine, you probably don't have (and maybe shouldn't have) easy access to the machine's local disk. This is a good opportunity to use a central logging solution (there are plenty of those on the market at the moment at various pricing levels).</p>
<h2>Production Environment</h2>
<p><strong>In a production environment, you could start out by configuring your logging to write <code>Info</code> and higher to a centralized logging service, such as a SaaS solution in the cloud. You should consider writing the <code>Error</code> level and higher to local disk files, in case the SaaS has any technical issues.</strong> Remember to manage the retention of these local logs to avoid being incompliant with data privacy rules and to keep costs down.</p>
<p>For the very complicated and hard-to-solve bugs, you need to be able to activate <code>Debug</code> and <code>Trace</code> level logging. To comply with data privacy rules without too much hassle, consider writing only these two low levels to local files, which can easily be deleted, and set a very short retention time for them. <strong>Always consider using a <em>staging environment</em> first, when using the <code>Trace</code> level</strong> and only use the production environment as the last way out.</p>
<p>You can also consider forwarding just the <code>Info</code> entries to an analysis tool of choice, to analyze key business events being triggered in your system. Some logging libraries support sending additional data in their entries, which can make this scenario more powerful.</p>
<p>If needed, you can also configure <code>Error</code> and <code>Critical</code> to log to another external system, maybe another SaaS, that sends out alerts for these log entries. Many existing SaaSes for logging have this functionality built-in, so there's usually not a need for this configuration, but it's good to know it's an option.</p>
<p>This would then mean that you're double-logging between two systems, but since you hopefully won't have a large volume of this kind of log entry, you don't have to worry too much about cost and you're only using the right tool for the right job.</p>
<h1>The Caveats of Logging</h1>
<p>Logging a lot of data might be the only way to solve some of the craziest bugs created out there, but there are some downsides of logging too much.</p>
<p><strong>Depending on the solution you choose for logging data, too much data could make it very hard to easily search through your logs.</strong> If the logging is split into different files for different days (or hours), it's hard to analyze a trend over time.</p>
<p>Normally, no matter what solution you have in place for logging, <strong>the more data you log, the higher the cost will be</strong>. Even if you're logging to the local disk of the server, space can get used up quickly over time.</p>
<p>There is also a major security risk of leaking sensitive data if you store too much data, with too detailed information, for too long. <a href="https://en.wikipedia.org/wiki/Internet_privacy#Global_privacy_policies">With all the new privacy rules out there</a>, you also risk being noncompliant for things like <a href="https://en.wikipedia.org/wiki/General_Data_Protection_Regulation">GDPR</a>, if you store personal information too long, even in local files.</p>
<h1>Conclusion</h1>
<p><strong>Logging is something you should include in your workflow right from the beginning when writing your software. Setting it up, and with the right strategy, will enable you to produce well-running software, <a href="https://lightrun.com/debugging/complete-agility-extend-your-ci-cd-pipelines-with-continuous-debugging-and-continuous-observability/">monitor it in a robust way</a>, and quickly access details about any problems that occur. Just keep the potential pitfalls in mind, such as cost, searchability, and security.</strong></p>
<p>Having a solid strategy for which log level to use for what scenario is crucial for a long-term path growth path for your software. This will allow you to extend your logging in the future, making use of more refined and mature logging tools, as your software grows and the need inevitably shows itself.</p>]]></content:encoded>
      <pubDate>Sun, 05 Sep 2021 12:27:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>Best 20 C# &amp; .NET Blogs</title>
      <link>https://sebnilsson.com/blog/best-csharp-dotnet-blogs</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/best-csharp-dotnet-blogs</guid>
      <description>Whether you&apos;re getting into C# with the launch of .NET 5 or if you&apos;re a long-time C# developer, there are a lot of great blogs out there</description>
      <content:encoded><![CDATA[<p><em><strong>Originally written for and published on <a href="https://draft.dev/learn/technical-blogs/c-sharp-blogs">the Draft.dev blog</a></strong></em></p>
<hr>
<p>C# is a language loved by its users for being versatile, productive, and keeping up with
the current problems programmers need to solve. For example, maintainers have added
functional programming concepts to the primarily imperative C# language, adding the powerful
query-functionality in LINQ, and smoother handling of asynchronous programming with the <code>async</code> / <code>await</code>-syntax.</p>
<p>The unification of all versions of .NET into .NET 5 has given C# and .NET future-safety,
no matter which platform you use to develop or which platform you develop for: desktop, web, cloud, mobile, or other.</p>
<p>Whether you're getting into C# with the launch of .NET 5 or if you're a long-time C# developer,
there are a lot of great blogs out there. Based on writing quality, consistency, longevity,
technical depth, and usefulness, I've put together <strong>this comprehensive list of the 20 best C# blogs publishing today</strong>.</p>
<h1><a href="https://devblogs.microsoft.com/dotnet/">.NET Blog</a></h1>
<p><img src="https://files.sebnilsson.com/web/images/top-csharp-blogs/dotnet-blog.jpg" alt="Screenshot of the .NET Blog"></p>
<p>Maybe a bit obvious, but the .NET blog from Microsoft should probably your first place to check
for new updates on C# and .NET. They consistently publish updates about everything related to C# and .NET
but also dives deep into different subjects, such as functionality deep within .NET or the details
about the performance improvements being made there.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 5</li>
<li>Longevity: 5</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 5</li>
</ul>
<h1><a href="https://www.hanselman.com/blog">Scott Hanselman's Blog</a></h1>
<p><img src="https://files.sebnilsson.com/web/images/top-csharp-blogs/hanselman.jpg" alt="Screenshot of Scott Hanselman&#x27;s blog"></p>
<p>Sometimes, I'm unsure if you're allowed to use .NET if you're not reading Scott Hanselman's blog.
There might be something in EULA about that. 😉</p>
<p>Jokes aside, Hanselman has been blogging about C# and .NET from the very start and has inspired
many people with the content on his blog, his conference-talks, his podcast, his YouTube-channel, and more.
He mixes high-level articles with some technical deep-dives, and his posts seem to be driven by his passion
for learning and solving problems.</p>
<p>Hanselman has become quite a household name in the .NET-world and is often featured in Microsoft's keynotes.
This is well deserved, given his unparalleled professional approach to quality content, interesting topics,
and entertaining delivery.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 5</li>
<li>Longevity: 5</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 5</li>
</ul>
<h1><a href="https://ardalis.com/blog">Ardalis: Steve Smith's Blog</a></h1>
<p><img src="https://files.sebnilsson.com/web/images/top-csharp-blogs/ardalis.jpg" alt="Screenshot of Ardalis: Steve Smith&#x27;s Blog"></p>
<p>Steve Smith (aka Ardalis) is a strong proponent of producing content instead of consuming it,
which is quite obviously something he lives by when you look at his output. If you are a person
wanting to build your own brand, Steve is a role-model. He continually puts out qualitative information
on his blog, on Twitter, on Twitch, his newsletter, his Pluralsight-courses, and he now also is
building his own developer coaching-community.</p>
<p>Lately, Steve has been focusing on a lot of content around Domain-Driven Design (DDD) and the SOLID-principles.
Much of this can be found on his blog and on some great Pluralsight-courses.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 5</li>
<li>Longevity: 5</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://www.alvinashcraft.com/">Alvin Ashcraft's Morning Dew</a></h1>
<p><img src="https://files.sebnilsson.com/web/images/top-csharp-blogs/morning-dew.jpg" alt="Screenshot of Alvin Ashcraft&#x27;s Morning Dew"></p>
<p>Want to see basically every new article the community puts out every single day? Well, then Alvin Ashcraft's
<em>Morning Dew</em> has you covered when it comes to the subjects of C#, .NET, and the Microsoft-ecosystem.</p>
<p>Alvin Ashcraft is a longtime Microsoft MVP. From what you can tell from comments on his website,
Morning Dew is the result of Alvin reading through over 1,600 feeds daily. Any interesting articles found
are categorized and published on the blog.</p>
<ul>
<li>Writing Quality: N/A</li>
<li>Consistency: 5</li>
<li>Longevity: 5</li>
<li>Technical Depth: N/A</li>
<li>Broad Usefulness: 5</li>
</ul>
<h1><a href="https://www.troyhunt.com/">Troy Hunt</a></h1>
<p><img src="https://files.sebnilsson.com/web/images/top-csharp-blogs/troy-hunt.jpg" alt="Screenshot of Troy Hunt&#x27;s blog"></p>
<p>One of the most influential voices on the topic of security within the Microsoft-ecosystem is Troy Hunt.
He is the creator of the service <a href="https://haveibeenpwned.com/">Have I Been Pwned (HIBP)</a>, which helps users
identify if and how they've been affected by data breaches and other malicious activity on the internet.</p>
<p>Since Troy has Microsoft MVP for developer-security for a longer time, this is a subject that is often covered on his blog.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 5</li>
<li>Longevity: 5</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 3</li>
</ul>
<h1><a href="https://timheuer.com/blog">Tim Heuer</a></h1>
<p>Tim Heuer has worked at Microsoft since 2005, currently with a focus on .NET, Visual Studio, and Azure.
This gives him a lot of insight, which you can tell by the in-depth content and a great variety of technologies covered on his blog.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 4</li>
<li>Longevity: 5</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://thedatafarm.com/blog/">The Data Farm: Julie Lerman's World of Data</a></h1>
<p>Julie Lerman is the absolute authority on <a href="https://docs.microsoft.com/en-us/ef/">Entity Framework</a>, including EF Core.
No matter if you're looking for a detailed, low-level problem within EF, or if you're looking for
a solid guide to walk you through various aspects of Entity Framework, there is a real chance that you'll find
material around it produced by Julie Lerman.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 4</li>
<li>Longevity: 5</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://haacked.com/">You've Been Haacked</a></h1>
<p>Phil Haack was an integral part of helping Microsoft make many of its development-software open-source,
along with Scott Hanselman, Scott Guthrie, and Rob Connery. Since then, Phil has moved on from Microsoft
but still consistently blogs about technologies in the Microsoft-ecosystem.</p>
<p>With his experience inside Microsoft during their exciting transformation, there is usually something interesting
for developers to learn in his posts.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 4</li>
<li>Longevity: 5</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://blog.ploeh.dk/">ploeh: Mark Seemann</a></h1>
<p>If you feel completely bulletproof in your coding-skills, go check out Mark Seemann's blog and
get a glimpse of the endless things you could be doing better.</p>
<p>Writing good software is an art, so you can have endless opinions on other peoples' opinions,
but there is almost always something new to learn from Mark's deep-diving and well-thought-through posts.
Each article walks you through a complicated concept and helps you understand it and become a better developer
who writes better, more maintainable code.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 5</li>
<li>Longevity: 5</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 3</li>
</ul>
<h1><a href="https://www.cazzulino.com/">Daniel Cazzulino's Blog</a></h1>
<p>Daniel Cazzulino (aka 'kzu') is the creator of the most popular mocking framework for C# and
.NET, called <a href="https://github.com/moq/moq4">Moq</a>, which is used for testing the source-code behind .NET.</p>
<p>Kzu writes about all different kinds of technologies related to the Microsoft-ecosystem and mixes
high-level guides with technical deep dives into non-mainstream topics.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 4</li>
<li>Longevity: 4</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://devblogs.microsoft.com/visualstudio/">Visual Studio Blog</a></h1>
<p>The blog for the Visual Studio Engineering Team, of course, covers everything related to Visual Studio,
but it also includes adjacent technologies, which can contribute to great inspiration. They cover topics
like Unity, Visual Studio for Mac, GitHub-integrations, debugging with memory-dumping, and much more.</p>
<p>For anyone interested in productivity in your Visual Studio-editor, it's worth noting that
<a href="https://www.madskristensen.net/">Mads Kristensen</a> writes posts on the subject on the Visual Studio Blog.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 5</li>
<li>Longevity: 4</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://blog.maartenballiauw.be/">Maarten Balliauw</a></h1>
<p>Maarten has a focus on web and cloud-apps, but he was also the founder of <a href="https://www.myget.org/">MyGet</a> and
is a frequent speaker at conferences. He brings a unique mix of experiences and knowledge to his blog,
which covers many different technologies within the Microsoft-ecosystem.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 4</li>
<li>Longevity: 5</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://codeblog.jonskeet.uk/">Jon Skeet</a></h1>
<p>If you have ever searched for a C# question, there's a 99% chance that you have, at least once,
landed on an answer on Stack Overflow by Jon Skeet.</p>
<p>He's been <strong>the number one contributor to Stack Overflow</strong> for many years and usually with a focus
on .NET and C#. It is said that he's read the whole C# specification (maybe more than once),
and he regularly blogs about some of the deepest subjects around C#.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 4</li>
<li>Longevity: 4</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 3</li>
</ul>
<h1><a href="https://jimmybogard.com/">Jimmy Bogard</a></h1>
<p>Jimmy is the man behind some of the most productivity-boosting frameworks for C# and .NET developers:
AutoMapper and MediatR. These frameworks help you write isolated and more easily maintainable code and
his blog-posts revolve around these frameworks, but also these topics in general.</p>
<ul>
<li>Writing Quality: 4</li>
<li>Consistency: 4</li>
<li>Longevity: 4</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="https://weblog.west-wind.com/">Rick Strahl's Web Log</a></h1>
<p>If you've worked with C# and .NET since its early days, especially with a focus on ASP.NET and the web,
you will most probably have run into more than one of Rick Strahl's blog-posts.</p>
<p>In the course of working hands-on solving problems for clients, Rick has documented many solutions to
real-world problems on his blog. The topics often coincide with what other people are looking to answer,
so you can often find one of Rick's articles linked in answers on Stack Overflow.</p>
<ul>
<li>Writing Quality: 4</li>
<li>Consistency: 4</li>
<li>Longevity: 5</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 5</li>
</ul>
<h1><a href="https://blog.jetbrains.com/dotnet/">.NET Tools Blog - JetBrains</a></h1>
<p>JetBrain's blog for .NET covers very useful topics, whether you use their tools or not. They have specific posts
about the popular tools ReSharper and Rider, but also great articles about a broad range of topics related to C# and .NET.</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 5</li>
<li>Longevity: N/A</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 4</li>
</ul>
<h1><a href="http://wildermuth.com/">Shawn Wildermuth</a></h1>
<p>Shawn has been a prolific creator of content around C#, .NET, and the Microsoft-ecosystem since the
earliest days of .NET. Focusing mainly on the web-aspect of .NET, and recently, with a lot of Vue.js content,
he now describes himself as an author, teacher, and filmmaker.</p>
<ul>
<li>Writing Quality: 4</li>
<li>Consistency: 4</li>
<li>Longevity: 5</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 3</li>
</ul>
<h1><a href="https://ericlippert.com/">Fabulous Adventures in Coding - Eric Lippert's Blog</a></h1>
<p>Eric Lippert used to work on the C# language design team, which is clear based on his superhuman
rate of answering questions on Stack Overflow. On his blog, he deep-dives into language-design
with a focus on "making developers' lives better and having fun doing it".</p>
<ul>
<li>Writing Quality: 5</li>
<li>Consistency: 3</li>
<li>Longevity: 5</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 2</li>
</ul>
<h1><a href="https://www.strathweb.com/">StrathWeb - Filip W.</a></h1>
<p>When searching for various intricate technical issues related to the Microsoft-ecosystem,
it is not uncommon to end up on an in-depth article written by Filip. Recently, the topic of
quantum computing has been a big focus, to add to the long archive of articles focused on C# and .NET.</p>
<ul>
<li>Writing Quality: 4</li>
<li>Consistency: 4</li>
<li>Longevity: 4</li>
<li>Technical Depth: 5</li>
<li>Broad Usefulness: 3</li>
</ul>
<h1><a href="http://dontcodetired.com/blog">Don't Code Tired - Jason Roberts</a></h1>
<p>Jason Roberts is a former Microsoft MVP who blogs on different topics around the Microsoft-ecosystem.
Lately, he's been focused on testing with posts about approval tests, feature-flags, and optimizing various testing frameworks.</p>
<ul>
<li>Writing Quality: 4</li>
<li>Consistency: 4</li>
<li>Longevity: 5</li>
<li>Technical Depth: 4</li>
<li>Broad Usefulness: 2</li>
</ul>
<h1>Final Words</h1>
<p>While researching this post, I went through every single account I subscribe to on Twitter to pick out
the best blogs from the best people I've been following for many years - often over a decade.
I was surprised to recognize so many names I had associated with quality content and learned so much from,
but what surprised me even more was how many of these people had stopped blogging or switched focus away from C# and .NET.</p>
<p>Scott Guthrie is probably a perfect example. He used to be one of the top bloggers within our field before he
was promoted to the fancy title of <em>Executive Vice President</em> at Microsoft, where the blog no longer seemed to be a priority.
So subscribe to these blogs while you can. You never know when things will change.</p>]]></content:encoded>
      <pubDate>Mon, 21 Dec 2020 14:44:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>From C# to Rust: Code Basics</title>
      <link>https://sebnilsson.com/blog/from-csharp-to-rust-code-basics</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/from-csharp-to-rust-code-basics</guid>
      <description>Understanding Rust&apos;s code-basics could possibly be fast-tracked by reating these concepts to the equivalent in C# and .NET.</description>
      <content:encoded><![CDATA[<p>Now that we've gotten the <a href="/blog/from-csharp-to-rust-fundamentals/">fundamentals</a> out of the way, we can finally get into the basics of Rust-code.</p>
<p><a href="/blog/from-csharp-to-rust-introduction/">This series</a> is written from the perspective of getting to know Rust from knowing C#. There are already many good <em>getting-started-guides</em> out there for Rust, but <strong>this series tries to leverage your existing .NET/C#-knowledge</strong> to fast-track you into understanding Rust, by relating the concepts to what you already know.</p>
<p><em><strong>Disclaimer</strong>: This series is being written while I'm learning Rust, so I'm by no means an expert and maybe this might be reflected in some of the example code. If you find any blatant errors, feel free to add some feedback in the comments.</em></p>
<h1>Setup</h1>
<p>In the post about <a href="/blog/from-csharp-to-rust-fundamentals/">Rust fundamentals</a>, we could read about how <strong>Rust provides a complete toolchain</strong> for development, which is made available by installing <a href="https://www.rust-lang.org/tools/install">Rustup, the recommended way of installing Rust</a>.</p>
<p>Create a new project in a command-line by running: <code>cargo new example_project</code></p>
<p>The file <strong><code>src/main.rs</code> is your application's entry point</strong>, which will be run when you execute <code>cargo run</code>. So this is a good file to start with, to <strong>follow along in your code-editor</strong>. This file will only contain a function called <code>main</code>, with a simple <em>Hello World</em>, when generated by Cargo:</p>
<pre><code class="language-rust">fn main() {
    println!("Hello, world!");
}
</code></pre>
<h1>Code Basics</h1>
<p>Let's start looking at some basic example-code, to go through some basic concepts in Rust. Since Rust is a C-style language, <strong>you will probably recognize much of the syntax</strong> you see in this code-snippet, as a C#-developer.</p>
<p>You can always find the full code for this series in the <a href="https://github.com/sebnilsson/from-csharp-to-rust"><code>from-csharp-to-rust</code>-project on GitHub</a>.</p>
<h1>Variables</h1>
<p><a href="https://doc.rust-lang.org/reference/variables.html">Variables in Rust</a> are created by using the <code>let</code>-keyword, in a very similar way to the use of the <code>var</code>-keyword in C#.</p>
<pre><code class="language-rust">let title = "Ghost Buster";
let year: u16 = 1984;
</code></pre>
<p><a href="https://doc.rust-lang.org/stable/rust-by-example/types/inference.html">Types are inferred</a> in Rust, as you can see with the <code>title</code>-variable. You can also specify the type, as we do with the <code>year</code>-variable, where we want to use a smaller number-type than what is inferred by default.</p>
<p>One important difference between Rust and C# is that <strong>variables are immutable by default in Rust</strong>. If you want a variable to be mutable, you have to add <code>mut</code> to the variable declaration:</p>
<pre><code class="language-rust">let mut rating_avg = 7.8;

// Someone rated the movie
rating_avg = 7.9;
</code></pre>
<p>Variables can be created as <a href="https://doc.rust-lang.org/std/keyword.const.html">constants in Rust</a>, by using the <code>const</code>-keyword, just like in C#. These variables <strong>have to have their types specified</strong>:</p>
<pre><code class="language-rust">const GOOD_MOVIE_LIMIT: f32 = 7.5;
</code></pre>
<h2>Naming Conventions</h2>
<p>As you may have noticed, <a href="https://doc.rust-lang.org/1.0.0/style/style/naming/README.html">Rust naming conventions</a> use <a href="https://en.wikipedia.org/wiki/Snake_case"><em>Snake case</em></a> (<code>example_variable_name</code>) for its variables. Unlike C# which usually uses <a href="https://en.wikipedia.org/wiki/Camel_case">Camel case</a> (<code>exampleVariableName</code>) or Pascal case (<code>ExampleVariableName</code>) for most of its variables, fields, and properties.</p>
<p>The Rust-compiler will even warn you about using the wrong conventions for different namings.</p>
<p><em>At the moment of writing, Rust-developers also seems to prefer shorter names for variables and functions, than we usually see in C# and .NET.</em></p>
<h1>Strings</h1>
<p>In C#, we only have one string-type for all types of strings. <strong>In Rust, there are two different string-types</strong> you learn about at first. The primitive <a href="https://doc.rust-lang.org/std/str/"><code>str</code>-type</a>, which is immutable and fixed length, as well as the <a href="https://doc.rust-lang.org/std/string/struct.String.html"><code>String</code>-type</a>, which can be modified and grow in size.</p>
<pre><code class="language-rust">let mut value = String::default();
for x in 65..68 {
    value.push(x as u8 as char);
}
// value: "ABC"
</code></pre>
<p>On Stack Overflow, a question called <a href="https://stackoverflow.com/questions/24158114/what-are-the-differences-between-rusts-string-and-str/24159933#24159933"><em>What are the differences between Rust's <code>String</code> and <code>str</code>?</em></a> the most popular answer, by far, summarizes:</p>
<blockquote>
<p>Use <code>String</code> if you need owned string data (like passing strings to other threads, or building them at runtime), and use <code>str</code> if you only need a view of a string.</p>
</blockquote>
<p>Conversion between the two types is quite straight forward:</p>
<pre><code class="language-rust">let title = "Ghostbusters";
// From str to String
let title_string = String::from(title);
// From String to str
let title_str = title_string.as_str();
</code></pre>
<p>In practical use, you can see Rust's <code>String</code>-type as the equivalent of <code>StringBuilder</code> in C#, while Rust's <code>str</code> is the equivalent of <code>ReadOnlySpan&#x3C;char></code>.</p>
<h1>Collections</h1>
<p>In Rust, the two most common types used to create collections are <a href="https://doc.rust-lang.org/std/primitive.array.html"><code>array</code></a> and <a href="https://doc.rust-lang.org/std/vec/struct.Vec.html"><code>Vec</code> (vector)</a>.</p>
<p>The <code>array</code>-type is a fixed-size collection and is compared to an array of a type in C# and .NET, like <code>string[]</code>, <code>int[]</code>, <code>char[]</code>, and so on. The <code>Vec</code>-type can change in size and can be compared to <code>List&#x3C;T></code> in C# and .NET.</p>
<p><strong>Both types can be mutated</strong> if the variable has the <code>mut</code>-keyword. They can also easily be converted between each other.</p>
<pre><code class="language-rust">let mut arr = [1, 2, 3];
arr[0] = 0;

let mut vec = vec![1, 2];
vec.push(3);
vec[0] = 0;

let arr_from_vec = &#x26;vec[0.. 2];
let vec_from_arr = arr.to_vec();
</code></pre>
<p>Rust also has the <a href="https://doc.rust-lang.org/std/collections/struct.HashMap.html"><code>HashMap</code>-type</a>, which is the equivalent of <code>Dictionary&#x3C;TKey, TValue></code> in C# and .NET.</p>
<pre><code class="language-rust">let mut map = HashMap::new();
map.insert("key", 123);
</code></pre>
<h2>Generics</h2>
<p>Rust has <a href="https://doc.rust-lang.org/book/ch10-00-generics.html">support for generics</a>, just like C# does, but with a little bit more smart functionality built into the compiler. In C#, you don't always have to specify the exact generics used in some contexts, since it can be inferred. Rust has some additional functionality for this.</p>
<p>For both <code>Vec</code> and <code>HashMap</code>, <strong>you don't have to specify the type explicitly</strong> when creating the object. It will be <strong>inferred by the first items added</strong> and enforced to the following added items.</p>
<h1>Logic Flow</h1>
<p>The <code>if</code>-statements in Rust are very similar to the ones in C#, except <strong>you don't need parenthesis around the condition</strong>, but it's possible to use it if you want to.</p>
<pre><code class="language-rust">let mut info = String::from(title);

if rating_avg >= GOOD_MOVIE_LIMIT {
    info += " - You're in for a good movie";
} else if rating_avg &#x3C; GOOD_MOVIE_LIMIT &#x26;&#x26; year &#x3C;= 1995 {
    info += "- Could be a classic...";
} else {
    info += "... Do you want to look for another movie?";
}
</code></pre>
<p>The <code>if</code>-statement is in itself an expression, from which you can catch the result. This means that you can <strong>use an <code>if</code>-statement to assign a variable</strong>. You can catch the value resulting from the <code>if</code>, the <code>if else</code>, or the <code>else</code>.</p>
<p>This can be used to create a <em>shorthand if</em>. This is a good replacement for the <em>ternary conditional operator</em> (In C#: <code>var a = true ? b : c</code>), since it's not supported in Rust.</p>
<pre><code class="language-rust">let classic = year &#x3C;= 1995 &#x26;&#x26; !title.ends_with(" II");
let text = if classic { "Potential classic" } else { "We'll see..." };
</code></pre>
<h2>Pattern Matching</h2>
<p>Rust also has very appreciated <a href="https://doc.rust-lang.org/book/ch18-03-pattern-syntax.html">pattern-matching-functionality</a>. This is something that <a href="https://docs.microsoft.com/en-us/dotnet/csharp/pattern-matching">C# has implemented</a> and seems to keep on improving it with every version.</p>
<p>Pattern-matching in Rust can do a lot more than just replace simple <code>if</code>-statements. It can also, among other things, be used to assign the result to variables. More sophisticated usages will be shown as this series goes on.</p>
<pre><code class="language-rust">let info = match rating_avg {
    x if x > GOOD_MOVIE_LIMIT =>
        format!("{} - You're in for a good movie", x),
    x if x &#x3C; GOOD_MOVIE_LIMIT &#x26;&#x26; year &#x3C;= 1995 =>
        format!("{} - Could be a classic...", x),
    _ => String::from("... Do you want to look for another movie?"),
};
</code></pre>
<h1>Standard Output</h1>
<p>To write to the standard output, in the equivalent way of <code>Console.WriteLine</code> in C# and .NET, you use <a href="https://doc.rust-lang.org/std/macro.println.html">the function <code>println!</code></a> in Rust.</p>
<pre><code class="language-rust">let hello = "Hello";
let world = "World";
println!("{} {}!", hello, world);
</code></pre>
<p>In .NET, we specify the indexes inside the placeholder-curly brackes like this: <code>Console.WriteLine("{1} {0}!", world, hello)</code>. These explicit indexes can also be used in Rust like this <code>println!("{1} {0}!", world, hello)</code>.</p>
<p>If you don't specify the index In Rust and just use the empty placeholder <code>{}</code>, as in the above example, <strong>the index will be inferred</strong>.</p>
<p>Just like in C# and .NET, you can <a href="https://doc.rust-lang.org/stable/rust-by-example/hello/print/fmt.html">add formatting</a> to a parameter by adding a colon-character (<code>:</code>) after it and a specific flag. For debugging, it's very useful to use the <a href="https://doc.rust-lang.org/rust-by-example/hello/print/print_debug.html">debug-formatting</a>, which <strong>shows the whole content of the object</strong> in the console.</p>
<pre><code class="language-rust">let obj = complex_obj();
println!("Debug: {:?}", obj);
println!("Debug pretty: {:#?}", obj);
</code></pre>
<h2>Command-Line Arguments</h2>
<p><em>Standard input</em> is not as straight forward as <em>Standard output</em> and not a one-liner like in C# and .NET with <code>Console.ReadLine</code>. So we will get more into that in future articles.</p>
<p>Getting access to the <strong>command-line arguments passed to the application</strong> is a lot easier. This can be used to quickly build a CLI-type application.</p>
<pre><code class="language-rust">// Execute: cargo run "The Shawshank Redemption"

let args: Vec&#x3C;String> = env::args().collect();
let first_arg =
    if args.len() > 1 { args[1].clone() } else { String::default() };
// first_arg: "The Shawshank Redemption"
</code></pre>
<h1>Functions</h1>
<p><a href="https://doc.rust-lang.org/book/ch03-03-how-functions-work.html">Functions in Rust</a> work just like in C#, except you declare it using the <code>fn</code>-keyword. <strong>You can specify a return-type</strong>, but if you don't the function will just act like a <code>void</code> in C#.</p>
<pre><code class="language-rust">fn is_sequel(title: &#x26;str) -> bool {
    if title.is_empty() {
        return false;
    }
    let sequel_title = title.ends_with("II");

    sequel_title
}
</code></pre>
<p>Notice the <strong>lack of a trailing semicolon</strong> (<code>;</code>) behind the <code>sequel_title</code>-variable at the end of the method. This makes the statement into an "expression" and Rust will <strong>implicitly accept this as a return statement</strong>, as long as it's the <strong>final expression of the method</strong>. This is why a <code>return</code> is needed in the body of the early returning <code>if</code>-statement.</p>
<p>This is a <strong>feature that might look weird</strong> when you're coming from another C-style language, but that you will see all over the place in Rust-code.</p>
<p>Functions are then called with their names and parameters, just like in C#:</p>
<pre><code class="language-rust">fn main() {
    let sequel = is_sequel("Ghostbusters");
}
</code></pre>
<h2>Macros</h2>
<p>In this article, you've seen the use of the <code>println!</code>-function, with the unusually looking exclamation-point (<code>!</code>) at the end. This annotation makes this a <em>macro</em>. This is a too advanced of a topic to go into in this part about basic code, so I'll just point to official <a href="https://doc.rust-lang.org/book/ch19-06-macros.html">Rust Programming Language Book's section on macros</a>, which summarizes:</p>
<blockquote>
<p>Macros are a way of writing code that writes other code, which is known as <em>metaprogramming</em>.</p>
</blockquote>
<h1>Null-Values</h1>
<p>The notorious <a href="https://en.wikipedia.org/wiki/Tony_Hoare#Apologies_and_retractions"><em>Billion dollar mistake</em></a> of allowing <code>null</code>-values into programming languages seems to be a <strong>problem tackled only recently</strong>. C# got <em>Nullable reference types</em> with C# 8.0 in late 2019 and F# doesn't have nulls built-in at all (even if there are ways to get around it).</p>
<p><strong>Rust does not support null values.</strong> Instead, it uses patterns to wrap around types, to help indicate if there was a value or not. The most commonly used such type is the <a href="https://doc.rust-lang.org/std/option/"><code>Option</code>-type</a>. It will return either a <code>Some</code>, carrying the value, or a <code>None</code>, indicating there was no object.</p>
<pre><code class="language-rust">fn main() {
    let quotient = divide(123, divisor);
    match quotient {
        Some(x) if x > 10 => println!("Big division result: {}", x),
        Some(x) => println!("Division result: {}", x),
        None => println!("Division failed")
    }
}

fn divide(dividend: i32, divisor: i32) -> Option&#x3C;i32> {
    if divisor == 0 {
        return None;
    }
    Some(dividend / divisor)
}
</code></pre>
<h1>Object-Orientation</h1>
<p><a href="https://doc.rust-lang.org/book/ch17-00-oop.html">Object-orientation in Rust</a> is a point in the code-basics where <strong>things get a bit strange</strong> for the regular C#-developer. In C#, we are used to having a <code>class</code> that owns its fields, properties, and methods. The class is then a template for creating an <em>instance</em> of an object.</p>
<p>Rust uses what they call a <code>struct</code> instead of classes, which is just a "dumb" data-structure, which contains fields, but <strong>they do not (directly) contain properties or methods</strong>. Instead, Rust provides the possibility to add functions to a <code>struct</code> through the <code>impl</code>-keyword.</p>
<pre><code class="language-rust">pub struct Movie {
    pub title: String,
    release_year: u16,
}

impl Movie {
    // Constructor - Associated method
    pub fn new(title: &#x26;str, release_year: u16) -> Self {
        Self { title: String::from(title), release_year }
    }
    // Method
    pub fn display_title(&#x26;self) -> String {
        format!("{} ({})", self.title, self.release_year)
    }
    // Method with mutability
    pub fn update_release_year(&#x26;mut self, year: u16) {
        self.release_year = year;
    }
}

fn main() {
    let movie = Movie::new("Ghostbusters", 1984);
    println!("Movie: {}", movie.display_title());
}
</code></pre>
<p>First, we define the <code>struct</code> and its fields, where we add the <code>pub</code>-keyword to the <code>struct</code> itself and its field <code>title</code>. <strong>All public fields are mutable</strong> in Rust if used with the <code>mut</code>-keyword by other code. If you want to protect a field, use methods, like the <code>update_release_year</code>-function in this example.</p>
<p>In the <code>impl</code>-block, we have the <code>new</code>-function, which acts as a constructor. It's an associated method to the type, which is the equivalent of a <code>static</code> method in C#. It returns a new instance of the implementing type, which in this case is a <code>Movie</code>.</p>
<p>The function <code>display_title</code> is a <strong>method on the instance of the object</strong> and through the <code>self</code>-keyword in the first parameter, it can access fields and methods on the object, even non-public ones. It's the equivalent to the <code>this</code>-keyword in C#.</p>
<h2>Inheritance</h2>
<p><strong>Rust doesn't have inheritance</strong>. At least not in the way a C#-developer is used to it. This seems to be a very <a href="https://doc.rust-lang.org/book/ch17-01-what-is-oo.html">conscious decision</a> by the Rust-team.</p>
<p>Instead of inheritance, Rust provides the very powerful <a href="https://doc.rust-lang.org/1.9.0/book/traits.html">concept of traits</a>, which allows you to extend any type, no matter if you've created the type or not. As a C#-developer it acts like of mixture of interfaces and extension-methods. We will look closer at traits in upcoming articles in the series.</p>
<h1>Ownership &#x26; Borrowing</h1>
<p>You've seen the use of the ampersand (<code>&#x26;</code>) character in some places of the example-code. These indicate that the use of an object is done by reference. This is something you normally very rarely need to deal with in C# and .NET.</p>
<p>This relates to the unique concept in Rust of <a href="https://doc.rust-lang.org/1.8.0/book/references-and-borrowing.html">References and Borrowing</a>. This is <strong>the foundational concept which enables the language's memory-safety, performance, and "<a href="https://doc.rust-lang.org/book/ch16-00-concurrency.html">fearless concurrency</a>"</strong>.</p>
<p>This is also one of <strong>the hardest parts of Rust to master</strong>. It's usually the number one complaint about the language from newcomers and a very frequent topic on Stack Overflow and other Q&#x26;A-forums.</p>
<h1>Primitives Comparison Table</h1>
<p>Rust has a set of primitives that overlap quite well with the ones we're used to in C# and .NET. They are listed for reference:</p>

































































<table><thead><tr><th>Rust</th><th>C#</th><th>Comments</th></tr></thead><tbody><tr><td>bool</td><td>bool</td><td></td></tr><tr><td>char</td><td>char</td><td></td></tr><tr><td>i8, i16, i32, i64, i128</td><td>sbyte, short, int, long, (N/A)</td><td>Signed 128-bit integer not available in .NET</td></tr><tr><td>u8, u16, u32, u64, u128</td><td>byte, ushort, uint, ulong, (N/A)</td><td>Unsigned 128-bit integer not available in .NET</td></tr><tr><td>isize, usize</td><td>(N/A)</td><td></td></tr><tr><td>f32, f64</td><td>float, double</td><td>.NET has the 128-bit floating-point number <code>decimal</code>, which is not available in Rust out-of-the-box</td></tr><tr><td>Array</td><td>Array</td><td>Not a primitive type in .NET. Fixed size.</td></tr><tr><td>Tuple</td><td>System.ValueTuple / System.Tuple</td><td>Not a primitive type in .NET</td></tr><tr><td>Slice</td><td>Span&#x3C;T></td><td>Not a primitive type in .NET</td></tr><tr><td>str</td><td>string</td><td><code>str</code> is immutable and fixed length in Rust, but not in .NET</td></tr><tr><td>Function</td><td>Func&#x3C;T></td><td>Not a primitive type in .NET</td></tr></tbody></table>
<h1>Learn More</h1>
<p>If you want to learn more about Rust, unrelated to its equivalent functionality in C# and .NET, you can check out the <a href="https://www.rust-lang.org/learn"><em>Learn Rust</em>-section</a> of the official website, which points to multiple resources, including the <a href="https://doc.rust-lang.org/book/"><em>Rust Programming Language</em>-book</a> and the <a href="https://doc.rust-lang.org/stable/rust-by-example/"><em>Rust by Example</em>-book</a>.</p>
<p>I also found the guide <a href="https://github.com/Dhghomon/easy_rust"><em>Writing Easy Rust</em></a> very helpful, because it helps to explain the more complicated Rust-concepts in easier terms.</p>
<h1>Summary</h1>
<p>This article tried to lead you into the Rust-language by <strong>relating concepts to the ones you already know in C#</strong> and .NET.</p>
<p>Rust is very <strong>similar syntactically</strong> to other C-style languages, including C#. There are some concepts in Rust that are relatively different from what you're used to, but this can be a great way to be <strong>inspired to solve things in new ways</strong>. I've actually heard multiple people say that they've <strong>rediscovered their love for programming by learning Rust</strong>.</p>]]></content:encoded>
      <pubDate>Tue, 28 Jul 2020 13:47:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Rust</category>
    </item>
    <item>
      <title>From C# to Rust: Fundamentals</title>
      <link>https://sebnilsson.com/blog/from-csharp-to-rust-fundamentals</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/from-csharp-to-rust-fundamentals</guid>
      <description>Rust has some fundamental tools and concepts we need to understand before we get into the code.</description>
      <content:encoded><![CDATA[<p>There are some <strong>fundamental tools and concepts which we should understand</strong> before we get into actually coding Rust.</p>
<p>Since this series focuses on Rust from <strong>the perspective of a C#-developer</strong>, we will try to <strong>relate the Rust-concepts to the equivalent concepts in C#</strong> and .NET.</p>
<h1>Modern Toolchain</h1>
<p>Rust comes with a complete toolchain of <strong>everything you need to compile and run your Rust-code</strong>. All the way from the compiler, to package-management, testing, code-formatting, linting, documentation-generation, and more.</p>
<h1>The Rust Compiler</h1>
<p>The compiler for Rust <strong>can</strong> be executed by using the command <a href="https://doc.rust-lang.org/rustc/what-is-rustc.html"><code>rustc</code></a>. <strong>This is usually not done</strong> by Rust-developers, but instead, it's done through the Cargo-tool.</p>
<p><strong>.NET equivalent</strong>: <a href="https://docs.microsoft.com/visualstudio/msbuild/msbuild">MSBuild</a> / <a href="https://docs.microsoft.com/dotnet/csharp/language-reference/compiler-options/command-line-building-with-csc-exe">The C#-compiler (csc.exe)</a></p>
<h1>Cargo: Build System &#x26; Package Manager</h1>
<p><a href="https://doc.rust-lang.org/cargo/">Cargo</a> is used by Rust-developers to manage, build, test, and document their projects. This is done by using various <a href="https://doc.rust-lang.org/stable/cargo/commands/">cargo-commands</a>.</p>
<p><strong>.NET equivalent</strong>: <a href="https://docs.microsoft.com/dotnet/core/tools/">.NET CLI</a> and <a href="https://docs.microsoft.com/nuget/">NuGet</a></p>
<h2>Cargo-Commands</h2>
<p>Cargo can be used to <a href="https://doc.rust-lang.org/cargo/guide/creating-a-new-project.html">create a new project</a> by running, for example, <code>cargo new example_project</code>.</p>
<p><strong>.NET equivalent</strong>: <code>dotnet new</code></p>
<p>As mentioned above, Cargo <a href="https://doc.rust-lang.org/cargo/guide/working-on-an-existing-project.html">builds the project</a> and this is done by running the command <code>cargo build</code>.</p>
<p><strong>.NET equivalent</strong>: <code>dotnet build</code></p>
<p>Cargo is the Rust-equivalent of .NET's NuGet, so it's also used to <a href="https://doc.rust-lang.org/cargo/guide/dependencies.html">resolve and download libraries</a>, which it does automatically when you run the <code>cargo build</code>-command.</p>
<p>Now that your code has been built, you can run the code, given that it's a binary. This is done by using <code>cargo run</code>.</p>
<p><strong>.NET equivalent</strong>: <code>dotnet run</code></p>
<p>To just <a href="https://doc.rust-lang.org/edition-guide/rust-2018/cargo-and-crates-io/cargo-check-for-faster-checking.html">check that the code is valid</a> and if that it can build, but not actually do a full build, there is a more lightweight command in Rust, which is <code>cargo check</code>.</p>
<h1>Rustup: Rust Toolchain Installer</h1>
<p>To easily get access to the <a href="https://stackoverflow.com/a/62419829/2429">complete toolchain</a>, we use <a href="https://rustup.rs/"><code>rustup</code>, the Rust toolchain installer</a>, which installs <code>rustc</code>, <code>cargo</code>, the <a href="https://github.com/rust-lang/rustup"><code>rustup</code>-CLI</a>, and other Rust-tools.</p>
<p><strong>.NET equivalent</strong>: .NET Core SDK</p>
<p><a href="https://doc.rust-lang.org/edition-guide/rust-2018/rustup-for-managing-rust-versions.html">With Rustup</a>, you can change which version of Rust is used, install different platforms for cross-compiling, and installing various other components.</p>
<h2>Rust on Windows</h2>
<p><strong>For Rust and Rustup to work on Windows</strong>, you need to <a href="https://visualstudio.microsoft.com/downloads/">install Visual Studio</a>, or the <a href="https://visualstudio.microsoft.com/visual-cpp-build-tools/">C++ Build Tools</a> and the <a href="https://developer.microsoft.com/windows/downloads/windows-10-sdk">Windows 10 SDK</a> separately. Details on this can be found on <a href="https://github.com/rust-lang/rustup#working-with-rust-on-windows">Rustup's GitHub-page</a>.</p>
<h1>Package Manifest</h1>
<p>When you run <code>cargo new</code>, your new project will get a <a href="https://doc.rust-lang.org/cargo/reference/manifest.html"><code>Cargo.toml</code>-file</a>, which is the manifest that contains the meta-data about your project.</p>
<p>An example-version of the file, with the <strong>added dependency to the <em>regex</em>-package</strong>, looks like this:</p>
<pre><code class="language-toml">[package]
name = "example_project"
version = "0.1.0"
authors = ["Seb Nilsson"]
edition = "2018"

[dependencies]
regex = "1.3.9"
</code></pre>
<p><strong>.NET equivalent</strong>: The <code>.csproj</code>-file (or the formerly used <code>packages.config</code>-file).</p>
<p><strong>Node.js equivalent</strong>: The <code>package.json</code>-file.</p>
<h1>Crates</h1>
<p>In Rust, the term <a href="https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html"><em>crate</em></a> is used for a package. It can be either an executable binary or a library.</p>
<p><strong>.NET equivalent</strong>: NuGet-packages</p>
<h2>Crates.io</h2>
<p>To find useful packages/crates to include in your Rust-projects, the registry-site <a href="https://crates.io/">Crates.io</a> is used.</p>
<p><strong>.NET equivalent</strong>: <a href="http://nuget.org/">NuGet.org</a></p>
<h1>Formatting Rust-code</h1>
<p>Cargo contains a command which can automatically format all the Rust-code in your project. It's called <a href="https://github.com/rust-lang/rustfmt"><em>rustfmt</em></a> and can be executed by running <code>cargo fmt</code>.</p>
<p><a href="https://rust-lang.github.io/rustfmt/">Customizing the rules applied when formatting</a> is done by adding a <code>rustfmt.toml</code>-file to the project, which <em>rustfmt</em> then will follow.</p>
<p><strong>.NET equivalent</strong>: There is no built-in way to do this in the .NET CLI, but there is .NET Global Tool from the .NET-team called <a href="https://github.com/dotnet/format"><em>dotnet-format</em></a>, which allows you to run <code>dotnet format</code> on your project.</p>
<h1>Testing</h1>
<p><a href="https://doc.rust-lang.org/cargo/guide/tests.html">Running the tests in a project</a> is also done through Cargo, by running <code>cargo test</code>.</p>
<p><strong>.NET equivalent</strong>: <code>dotnet test</code></p>
<p><a href="https://doc.rust-lang.org/book/ch11-00-testing.html">Testing is built into Rust</a>, so you do not need to add any external testing-package.</p>
<h1>VS Code Setup</h1>
<p>First, make sure you've <a href="https://rustup.rs/">installed Rustup</a>. You can verify that you have it installed by running the command <code>rustup --version</code>, which should show you a version-number.</p>
<p>To get started developing in Rust, with features such as syntax highlighting, auto-complete, code-formatting, refactoring, debugging, and much more, you can install <a href="https://code.visualstudio.com/">Visual Studio Code</a>, with the <a href="https://marketplace.visualstudio.com/items?itemName=rust-lang.rust"><em>Rust</em></a>-extension and the <a href="https://marketplace.visualstudio.com/items?itemName=vadimcn.vscode-lldb"><em>CodeLLDB</em></a>-extension.</p>
<p>Consider evaluating the extension <a href="https://marketplace.visualstudio.com/items?itemName=matklad.rust-analyzer"><em>rust-analyzer</em></a> as an alternative to the <em>Rust</em>-extension. It's not as well <a href="https://rust-analyzer.github.io/">documented</a>, but it seems to have more features, including the showing of type inference.</p>
<p>Next, create a new Rust-project by running <code>cargo new</code>. Now, all you have to do now is press <kbd>F5</kbd> in VS Code and it will automatically create a <code>launch.json</code> for you, which allows you to debug your Rust-code.</p>
<h1>Summary</h1>
<p>By just installing <a href="https://rustup.rs/"><code>rustup</code></a>, we get access to the complete Rust-toolchain. This includes, among other things, <a href="https://doc.rust-lang.org/cargo/">Cargo</a>, which lets us <strong>work through the full development-cycle</strong> with our projects, like: <strong>create new</strong> projects, <strong>compile</strong> the code, <strong>run the code</strong>, <strong>format</strong> the code, and <strong>run the tests</strong> in our projects.</p>
<p>Add VS Code with a few Rust-extensions, and you'll have a great developer-experience to get started with.</p>]]></content:encoded>
      <pubDate>Thu, 16 Jul 2020 13:43:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Rust</category>
    </item>
    <item>
      <title>From C# to Rust: Introduction</title>
      <link>https://sebnilsson.com/blog/from-csharp-to-rust-introduction</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/from-csharp-to-rust-introduction</guid>
      <description>Rust has been the most loved programming language for the last 5 years. For a C#-developer, it could be a powerful addition to the tool-belt.</description>
      <content:encoded><![CDATA[<p><a href="https://www.rust-lang.org/">Rust</a> has been the <strong><a href="https://stackoverflow.blog/2020/01/20/what-is-rust-and-why-is-it-so-popular/">most loved programming language</a> for the last 5 years</strong>. This, and many other factors, made me interested in learning more about Rust, especially <strong>from the perspective of a C#-developer</strong>.</p>
<h1>Why Rust?</h1>
<p>In early 2019, a Microsoft engineer revealed that about <a href="https://www.zdnet.com/article/microsoft-70-percent-of-all-security-bugs-are-memory-safety-issues/">70% of all vulnerabilities in their products are due to memory safety issues</a>. Memory <strong>safety is something you get for free with C# and .NET</strong>. But sometimes, you need more tools to squeeze out every last drop of performance.</p>
<p>It's also generally very beneficial to <strong>learn new languages</strong>, which could inspire us to find <strong>new ways of solving problems</strong>. To specifically do so with a modern language, which could replace C/C++ over time and has a <strong>focus on both performance and productivity</strong>, could bring a very <strong>valuable tool</strong> to any developer's toolbox.</p>
<p>Rust has actually been the most loved language every single year, from the <a href="https://insights.stackoverflow.com/survey/2016#technology-most-loved-dreaded-and-wanted">2016 survey</a>, all the way to this year's <a href="https://insights.stackoverflow.com/survey/2020#technology-most-loved-dreaded-and-wanted-languages-loved">2020 survey</a>.</p>
<h1>Rust Overview</h1>
<p>Rust is a C-style language, similar to C# or C++, and even has <a href="https://doc.rust-lang.org/reference/influences.html">influences from C#</a> (among others), with a focus on <strong>memory safety and performance</strong>.</p>
<p>The slogan on <a href="https://www.rust-lang.org/">Rust's official website</a> is:</p>
<blockquote>
<p>A language empowering everyone to build reliable and efficient software.</p>
</blockquote>
<p>The language is <a href="https://en.wikipedia.org/wiki/Static_typing">statically typed</a> and is primarily <a href="https://en.wikipedia.org/wiki/Imperative_programming">imperative</a> but also has <a href="https://en.wikipedia.org/wiki/Functional_programming">functional</a> aspects, <strong>similar to C#</strong>. It's an open-source language <a href="https://research.mozilla.org/rust/">initially developed by Mozilla</a>.</p>
<p>Wikipedia describes the <a href="https://en.wikipedia.org/wiki/Rust_(programming_language)">Rust programming language</a> in the following way:</p>
<blockquote>
<p>Rust is a multi-paradigm programming language focused on performance and safety, especially safe concurrency. Rust is syntactically similar to C++ but provides memory safety without using garbage collection.</p>
</blockquote>
<p>As a C#-developer, you'll find the syntax familiar, with the <em>"Hello World!"</em> for Rust looking like this:</p>
<pre><code class="language-rust">fn main() {
    println!("Hello World!");
}
</code></pre>
<p>Rust was announced in 2010, with version 1.0 released in 2015. In comparison, C# was released in the year 2000, Java in 1995, C++ in 1985, and C in 1972. So it's quite a modern language, which has been <a href="https://doc.rust-lang.org/reference/influences.html">influenced by many other languages</a> and has hopefully used many lessons learned from these.</p>
<h2>Performance</h2>
<p><strong>Rust can be as fast as C and C++</strong> and in some cases, it might be even faster. The code <a href="https://rustc-dev-guide.rust-lang.org/overview.html">compiles to machine code</a>, instead of compiling to an <a href="https://docs.microsoft.com/en-us/dotnet/standard/managed-code">intermediate language (IL), like with C#</a> or being <a href="https://en.wikipedia.org/wiki/Interpreted_language">interpreted on the fly</a>, like with JavaScript or Ruby.</p>
<p>The memory management is not provided by using automated garbage collection (like in .NET/Java) or automatic reference counting (like in Swift/Objective C). The <strong>memory safety-guarantees</strong> are provided by Rust's <strong>key concept called <em><a href="https://doc.rust-lang.org/1.8.0/book/ownership.html">Ownership</a></em></strong>. By enforcing <a href="https://en.wikipedia.org/wiki/Resource_Acquisition_Is_Initialization">Resource Acquisition Is Initialization (RAII)</a>, Rust makes sure that any objects which go out of scope get deconstructed and its resources are freed up.</p>
<h1>Systems &#x26; Application Programming Language</h1>
<p><em>Systems programming languages</em> typically are more <em>close to the metal</em> and have more direct access to the physical hardware of the machine it is running on, which <strong>enables writing performant software</strong>, such as operating systems, drivers, embedded systems, game-engines, network services, and more. Assembly language, C, and C++ are examples of traditional systems programming languages.</p>
<p>C# is considered as an <em>application programming language</em>, which usually prioritizes <strong>productive ways of building software</strong> which gives functionality to end-users. They are usually <strong>not intended to compete on performance</strong> with systems programming languages.</p>
<p>Rust is a language that tries to <strong><a href="https://doc.rust-lang.org/book/foreword.html">straddle both</a> systems and application programming</strong>.</p>
<h1>Industry Adoption</h1>
<p>The 2020 <em><a href="https://insights.stackoverflow.com/survey/2020">Stack Overflow Developer Survey</a></em> shows that when it comes to <strong>the most professionally used programming language</strong>, <a href="https://insights.stackoverflow.com/survey/2020#most-popular-technologies">C# has a 32,3% popularity, while Rust only has 4,8%</a>. Comparing these numbers to JavaScript's 69,7% popularity might indicate that <strong>Rust is in an early phase of its widespread professional adoption</strong>.</p>
<p>The adoption of Rust does seem to be ramping up though, for good reasons. In a 2020 virtual talk about <a href="https://youtu.be/NQBVUjdkLAA?t=580">Rust at Microsoft</a>, one of their <em>cloud developer advocates</em> said:</p>
<blockquote>
<p>Rust is the industry's <strong>best chance</strong> at safe systems programming</p>
</blockquote>
<p>It does seem like <a href="https://thenewstack.io/microsoft-rust-is-the-industrys-best-chance-at-safe-systems-programming/">Microsoft is exploring gradually switching to Rust</a> from C and C++. These languages are not memory safe, which has <strong>caused a lot of costly errors</strong>, as mentioned before, with Microsoft's having around 70% of all their security bugs related to memory safety issues.</p>
<p>In 2019, Microsoft experimented with rewriting a <a href="https://www.zdnet.com/article/microsofts-rust-experiments-are-going-well-but-some-features-are-missing/">low-level component in Windows with Rust</a>, with a reported generally positive experience.</p>
<p>It's said that Amazon Web Services (AWS) uses Rust to power the deployment of the Lambda serverless runtime and some parts of EC2.</p>
<p><a href="https://www.rust-lang.org/production/users">Many other companies are adopting Rust</a>, including big players like <a href="https://www.youtube.com/watch?v=kylqq8pEgRs">Facebook</a> (also with <a href="https://developers.libra.org/docs/community/coding-guidelines">Libra</a>), <a href="https://twitter.com/benwilliamson/status/1240113606374686721">Apple</a>, Google (with <a href="https://en.wikipedia.org/wiki/Google_Fuchsia">Fuchsia</a>), and <a href="https://blog.cloudflare.com/tag/rust/">Cloudflare</a>.</p>
<h1><em>"From C# to Rust"</em>-Series</h1>
<p>Given that I'm learning Rust as I'm going, the goals of this series might change over time. But at this time, some topics I aim to cover are:</p>
<ul>
<li><a href="/blog/from-csharp-to-rust-fundamentals/"><strong>Fundamentals</strong></a>: Tools and concepts we need to understand</li>
<li><strong>Code basics</strong>: Learning the basics of Rust-code and how the concepts relate to C#</li>
<li><strong>Advanced code</strong>: Diving deeper into more advanced code and concepts in Rust</li>
<li><strong>Rust specific functionality</strong>: Functionality and concepts which exists in Rust, but not in C#</li>
<li><strong>Rust's drawbacks</strong>: Exploring what the reasons are behind the perceived steeper learning curve of Rust</li>
</ul>
<p>There will probably be more subjects discovered along the way. Feel free to <strong>write in the comments</strong> if there are any specific subjects you're interested in, especially coming in as a C#-developer.</p>
<h1>Summary</h1>
<p>Some points that <strong>make me quite excited about Rust</strong> and motivated me to start this exploration are:</p>
<ul>
<li>Modern C-style language, like C#, should give familiarity</li>
<li>The most loved language for half a decade</li>
<li>Enables both high-level productivity and low-level performance</li>
<li>Growing industry adoption, even by many of the giants</li>
</ul>]]></content:encoded>
      <pubDate>Mon, 06 Jul 2020 13:49:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Rust</category>
    </item>
    <item>
      <title>Deno: The Official Node.js-Successor?</title>
      <link>https://sebnilsson.com/blog/deno-the-official-nodejs-successor</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/deno-the-official-nodejs-successor</guid>
      <description>Explore Deno&apos;s design, security model, TypeScript support, and potential as a modern successor to Node.js.</description>
      <content:encoded><![CDATA[<p>Why is <a href="https://deno.land/v1">the announcement of Deno 1.0</a> possibly <strong>very exciting</strong>? Are there <strong>enough upsides to warrant a switch</strong> from Node.js to <a href="https://github.com/denoland/deno">Deno</a>?</p>
<p>The announcement of 1.0 was done middle of May 2020, but the initial announcement came in a presentation named <a href="https://youtu.be/M3BM9TB-8yA"><em>10 Things I Regret About Node.js</em> by Ryan Dahl</a> in mid-2018.</p>
<p>Deno is not just a rearrangement of the first two and the last two letters of "Node". It's built on top of more than <strong>11 years of experience from Node.js</strong> running in production all over the world, <strong>by the original creator of Node.js</strong>. So this does not seem like another case of <em>"I don't like how this project is handled, <a href="https://www.infoworld.com/article/2855057/why-iojs-decided-to-fork-nodejs.html">so I'm making my own fork</a>"</em>, it's a completely new implementation.</p>
<h1>10 Regrets about Node.js</h1>
<p>The 10 things Ryan Dahl regretted about Node.js, which he acknowledges are <strong>impossible to change now</strong>, seem to be <strong>large motivators for the creation of Deno</strong>. It's worth noting that JavaScript has changed a lot during its 11 years of existence and Node has driven a lot of those changes.</p>
<p>The numbered <a href="https://youtu.be/M3BM9TB-8yA">regrets brought up in the talk</a> were:</p>
<ol>
<li><strong>Not sticking with promises</strong>: Promises allow the usage of <code>async</code>/<code>await</code> and avoids "<a href="http://callbackhell.com/">Callback Hell</a>".</li>
<li><strong>Security</strong>: Your linter shouldn't get complete access to your computer and network.</li>
<li><strong>The Build System (GYP)</strong>: Awful experience for users. It's a non-JSON, Python adaptation of JSON.</li>
<li><strong><code>package.json</code></strong>: Not a strictly necessary abstraction and doesn't exist on the web. Includes all sorts of unnecessary information.</li>
<li><strong><code>node_modules</code></strong>: Massively complicates the module resolution. Deviates greatly from browser semantics.</li>
<li><strong><code>require("module")</code> without the extension "<code>.js</code>"</strong>: Needlessly less explicit. Module loader has to query the file system at multiple locations.</li>
<li><strong><code>index.js</code></strong>: Needlessly complicated the module loading system.</li>
</ol>
<p>It was also mentioned that Deno supports the following things:</p>
<ul>
<li>Unhandled promises should die immediately</li>
<li>Support top-level <code>await</code></li>
<li>Browser compatible where functionality overlaps</li>
</ul>
<h1>Introducing Deno</h1>
<p><a href="https://deno.land/">Deno</a> is a runtime for both JavaScript and <a href="https://www.typescriptlang.org/">TypeScript</a>, built on the <a href="https://v8.dev/">V8 JavaScript engine</a> and <a href="https://www.rust-lang.org/">Rust</a>, with the asynchronous runtime <a href="https://tokio.rs/">Tokio</a>.</p>
<p>The <a href="https://deno.land/manual#feature-highlights">feature highlights</a>, as of version 1.0, are:</p>
<ul>
<li><strong>Secure by default</strong>: Access to files, network or environment must be <strong><a href="https://deno.land/manual/getting_started/permissions">explicitly enabled</a></strong></li>
<li><strong>Supports TypeScript out of the box</strong></li>
<li><strong>Ships a single executable</strong>: No separate package-manager, like <em>npm</em></li>
<li><strong>Built-in utilities</strong>: <a href="https://deno.land/manual/testing">test runner</a>, <a href="https://deno.land/manual/tools/formatter">code formatter</a>, built in <a href="https://deno.land/manual/tools/debugger">debugger</a>, dependency inspector and <a href="https://deno.land/manual/tools">more</a></li>
<li><strong>Bundling</strong>: Scripts can be <a href="https://deno.land/manual/tools/bundler">bundled</a> into a single JavaScript file</li>
<li><strong>Standard modules</strong>: Audited and <a href="https://github.com/denoland/deno/tree/master/std">guaranteed to work with Deno</a></li>
</ul>
<h1>Executing JavaScript/TypeScript</h1>
<p>Deno being a single executable file, not needing a separate package-manager or <code>package.json</code>-file, an example of a <strong>working HTTP server application</strong> looks like this:</p>
<pre><code class="language-js">import { serve } from "https://deno.land/std@0.50.0/http/server.ts";
for await (const req of serve({ port: 8000 })) {
  req.respond({ body: "Hello World\n" });
}
</code></pre>
<p>There is <strong>no need to install anything</strong> beforehand or add any configuration-files. <strong>All you need to run is</strong>:</p>
<pre><code class="language-sh">deno run example.js
</code></pre>
<p>Since the code is executed in a sandbox, which is secure by default, the <strong>explicit access must be granted</strong> for the fetching the remote dependency, by adding the flag <code>--allow-net</code> to the command-line.</p>
<p>The remote dependency is <strong>cached locally</strong> and only reloaded if the script is executed with the flag <code>--reload</code>.</p>
<h1>Limitations</h1>
<p>Deno 1.0 <a href="https://deno.land/v1#limitations">has some known limitations</a>, which include things like:</p>
<ul>
<li>No automatic compatibility with existing npm-packages</li>
<li>HTTP server performance is not as good as Node.js, even if it's not too far away</li>
<li>TypeScript performance issues</li>
</ul>
<p>Since Deno uses ECMAScript modules, which uses <code>import</code> instead of <code>require</code>, any module using <code>require</code> has to be converted.</p>
<h1>Summary</h1>
<p><strong>I'm surprised at how excited I am about the potential of Deno.</strong> For me, to have the creator of Node.js use a decade of learning to start over with a blank slate is what makes this a rare situation of high potential.</p>
<p>Some things I look forward to from Deno are:</p>
<ul>
<li>A fresh take on a JavaScript/TypeScript runtime</li>
<li>First Class TypeScript Support</li>
<li>Skipping <code>package.json</code> and <code>npm install</code> when you just want to get started fast</li>
<li>Promises as default: Avoiding callback hell and mixed concepts between different parts of the code</li>
<li>Not having to deal with the <code>node_modules</code>-folder</li>
</ul>]]></content:encoded>
      <pubDate>Mon, 18 May 2020 12:38:00 GMT</pubDate>
      <category>Deno</category>
      <category>JavaScript</category>
    </item>
    <item>
      <title>C# Nullable Reference Types: IntelliSense Confusion</title>
      <link>https://sebnilsson.com/blog/c-nullable-reference-types-intellisense-confusion</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/c-nullable-reference-types-intellisense-confusion</guid>
      <description>Understand confusing IntelliSense behavior when C# projects and libraries use different nullable reference type settings.</description>
      <content:encoded><![CDATA[<p>The feature and concept of <em><a href="https://docs.microsoft.com/en-us/dotnet/csharp/nullable-references">Nullable reference types</a></em> were introduced in C# 8.0 and it basically <strong>made all types non-nullable by default</strong> and ensured that these types could never be assigned the value <code>null</code>. This is one of my favorite features in C# recently, but there are scenarios where <strong>a mixed nullable environment could cause confusion</strong>.</p>
<p><img src="https://files.sebnilsson.com/web/images/nullable-confusion/confusion2.jpg" alt="Confusion"></p>
<p>To enable the assignment of the value <code>null</code> to a type, <strong>you have to explicitly mark that type</strong>. This uses the same concept of nullable as introduced in C# 2.0, where you, for example, make an <code>int</code> nullable by adding a question mark after it: <code>int?</code>.</p>
<p>When we look at a regular example service-class, we can see which benefits can be had from <em>Nullable reference types</em>:</p>
<pre><code class="language-csharp">public class ProductService
{
    // This method accepts a non-null string for 'productId'
    // and always returns a string
    public string FormatProductId(string productId)
    {
        // ...
    }

    // This method accepts a nullable 'formattedProductId'
    // and returns a string or null
    public string? TryGetProductName(string? formattedProductId)
    {
        // ...
    }
}
</code></pre>
<p>This makes things all fine and clear. We know that the method <code>FormatProductId</code> never returns <code>null</code> and that it doesn't accept <code>null</code> in its parameter. We also know that the method <code>TryGetProductName</code> returns a <code>string</code> which could be <code>null</code> and that the parameter accepts a <code>string</code> which could be <code>null</code>.</p>
<p>This is great, this means that <strong>we don't have to perform a <code>null</code>-check</strong> on <code>productId</code>-parameter of the <code>FormatProductId</code>-method, right? <strong>Well, not exactly</strong>...</p>
<h1>Confusion: Mixed nullable environments</h1>
<p>In an environment where all your code has <em>Nullable reference types</em> enabled, you can trust the output of a method and the input to its parameters. <strong>In a mixed nullable environment, things are not as straight forward</strong>, especially when you look at how IntelliSense in Visual Studio signals <strong>what to expect from the code</strong>.</p>
<h2>Scenario 1: Modern app &#x26; legacy library</h2>
<p>Imagine that your new modern app has <em>Nullable reference types</em> enabled, but you're using an external library that is legacy and does not have this enabled. This external library can be your own old library or something you've included from NuGet.</p>
<p>The problem now becomes that the external library is signaling, for example, that it has a method that returns a <code>string</code> and not a <code>string?</code>, so you should be able to trust that it is not <code>null</code>, right? <strong>Unfortunately not</strong>. Even with a local non-nullable project, <strong>IntelliSense tells me that the returned <code>string</code> is not <code>null</code>, even when it is</strong>.</p>
<p><img src="https://files.sebnilsson.com/web/images/nullable-confusion/value-is-not-null.png" alt="Value is not null"></p>
<h2>Scenario 2: Legacy app &#x26; modern library</h2>
<p>Imagine that you have just put together a nice library that you want others to use, either in your project, organization or publicly through NuGet. One of the best parts about using <em>Nullable reference types</em> is that <strong>the compiler will warn you if you try to send in a <code>null</code> value as a parameter</strong> to a method that explicitly states that it doesn't support <code>null</code>.</p>
<p>Nice, now you can clean out all those noisy <code>null</code>-checks at the top of all the methods, right? <strong>Unfortunately not</strong>. Your code might be used by another assembly (or an older version of Visual Studio), which <strong>doesn't detect the non-nullability</strong>.</p>
<p>In a way, this means you have to reverse the way you do <code>null</code>-checks in your code.</p>
<pre><code class="language-csharp">public class ProductService
{
    // This method does not accept a null-value
    // and if it does, it should throw an exception
    public string FormatProductId(string productId)
    {
        if (productId == null)
            throw new ArgumentNullException(productId);
        // ...
    }

    // This method accepts null-values
    // and should adjust its logic accordingly
    public string? TryGetProductName(string? formattedProductId)
    {
        return
            formattedProductId != null
            ? GetProductName(formattedProductId)
            : null;
    }
}
</code></pre>
<h1>Key takeaways</h1>
<p>My own take-aways from exploring this aspect of <em>Nullable reference types</em> are:</p>
<ul>
<li>When building a library, always check for <code>null</code> in incoming method-arguments, even when <em>Nullable reference types</em> is enabled</li>
<li>When consuming an external legacy library, don't trust the return-type to not be <code>null</code> (even if it says it's not)</li>
<li>In a mixed nullable environment, the feature to guard us against <code>NullReferenceException</code>s is likely to mistakenly cause some more of them</li>
<li>When this feature is fully adopted, there will be a reduction in a lot of the overhead in <code>null</code>-handling code</li>
</ul>
<h1>Thoughts</h1>
<p>Hopefully, in .NET 5, this feature is enabled by default and these kinds of confusions, and described associated errors can be avoided.</p>
<p>One idea for an improvement to the IntelliSense-behavior around assemblies that are not known to have <em>Nullable reference types</em> enabled could be to <strong>show all these types as nullable</strong>. Both because it makes things super-clear, but also because of the fact that they actually are nullable.</p>
<p>This change would make <strong>everything in the whole .NET Core CLR light up as nullable</strong>, but as of .NET Core 3.1, it all is nullable, by definition.</p>]]></content:encoded>
      <pubDate>Thu, 13 Feb 2020 16:49:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <title>PowerShell LINQ with Short Aliases</title>
      <link>https://sebnilsson.com/blog/powershell-linq-with-short-aliases</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/powershell-linq-with-short-aliases</guid>
      <description>Create short PowerShell aliases for common LINQ methods to make complex filtering, ordering, and projection pipelines easier to write.</description>
      <content:encoded><![CDATA[<p>Most modern applications or code today deal with some kind of filtering or querying. In C# and .NET, we have <a href="/blog/tags/linq">Language Integrated Query (LINQ)</a>, which we also have access to in PowerShell, because it's built on .NET.</p>
<p>To list the top 10 largest files in the Windows temporary folder, which is larger than 1 Mb and starts with the letter W, skipping the first 5, ordering by size, the C#-code with LINQ would look somewhat like this:</p>
<pre><code class="language-csharp">new System.IO.DirectoryInfo(@"C:\Windows\Temp")
    .GetFiles()
    .Where(x => x.Length > 1024 &#x26;&#x26; x.Name.StartsWith("W"))
    .OrderByDescending(x => x.Length)
    .Select(x => new { x.Name, x.Length })
    .Skip(5)
    .Take(10)
    .ToList()
    .ForEach(x => Console.WriteLine($"{x.Name} ({x.Length})"));
</code></pre>
<p>The equivalent logic in PowerShell has a bit of a more daunting syntax, especially if you're not used to it:</p>
<pre><code class="language-powershell">Get-ChildItem "C:\Windows\Temp" `
| Where-Object {$_.Length -gt 1024 -and $_.Name.StartsWith("W")} `
| Sort-Object {$_.Length} -Descending `
| Select-Object -Property Name, Length -First 10 -Skip 5 `
| ForEach-Object {Write-Host "$($_.Name) ($($_.Length))"}
</code></pre>
<p>That's <strong>a bit explicit and verbose</strong>, but if you use the command <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/get-alias"><code>Get-Alias</code></a> in PowerShell, you will see a lot of useful aliases, which make the syntax a bit terser and easier to get an overview of:</p>
<pre><code class="language-powershell">gci "C:\Windows\Temp" `
| ?{$_.Length -gt 1024 -and $_.Name.StartsWith("W")} `
| sort{$_.Length} -Descending `
| select Name, Length -First 10 -Skip 5 `
| %{write "$($_.Name) ($($_.Length))"}
</code></pre>
<p>In a real scenario, you probably wouldn't write each result to the console, but let PowerShell present the result in its default grid format.</p>]]></content:encoded>
      <pubDate>Mon, 15 Jul 2019 17:04:00 GMT</pubDate>
      <category>.NET</category>
      <category>LINQ</category>
      <category>PowerShell</category>
    </item>
    <item>
      <title>HTML Encode TagHelper in ASP.NET Core</title>
      <link>https://sebnilsson.com/blog/html-encode-taghelper-in-asp-net-core</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/html-encode-taghelper-in-asp-net-core</guid>
      <description>Build an ASP.NET Core Tag Helper that renders nested HTML, Razor expressions, and Tag Helpers as encoded source code.</description>
      <content:encoded><![CDATA[<p>For a specific scenario recently, I wanted to display the HTML-encoded output of a <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro">TagHelper</a> in ASP.NET Core. So I wanted to use the TagHelper, but not output its actual result, but see the <strong>raw HTML</strong> which would have been included in my template.</p>
<p><img src="https://files.sebnilsson.com/web/images/html-encode-aspnet-core/html.jpg" alt="HTML"></p>
<p>So I created another TagHelper, which allows me to <strong>wrap any HTML, inline code in ASP.NET Core and other TagHelpers</strong>, and get all the content inside the TagHelper's tag to be HTML-encoded, like this:</p>
<pre><code class="language-html">&#x3C;html-encode>
    &#x3C;a href="@Url.Action("Index")">Read More&#x3C;/a>
    @Html.TextBox("No_Longer_Recommended-TagHelpers_Preferred")
    &#x3C;my-other-tag-helper />
&#x3C;/html-encode>
</code></pre>
<p>From this, I will get the raw HTML of the link with an UrlHelper-result, the result of the HTML-helper and the result of my other TagHelper.</p>
<p>The source-code for the <code>html-encode</code>-TagHelper is as follows:</p>
<pre><code class="language-csharp">[HtmlTargetElement("html-encode", TagStructure = TagStructure.NormalOrSelfClosing)]
public class HtmlEncodeTagHelper : TagHelper
{
    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        var childContent = output.Content.IsModified
            ? output.Content.GetContent()
            : (await output.GetChildContentAsync()).GetContent();

        string encodedChildContent = WebUtility.HtmlEncode(childContent ?? string.Empty);

        output.TagName = null;
        output.Content.SetHtmlContent(encodedChildContent);
    }
}
</code></pre>]]></content:encoded>
      <pubDate>Thu, 27 Jun 2019 14:31:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Razor</category>
    </item>
    <item>
      <title>API Rate Limit HTTP Handler with HttpClientFactory</title>
      <link>https://sebnilsson.com/blog/api-rate-limit-http-handler-with-httpclientfactory</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/api-rate-limit-http-handler-with-httpclientfactory</guid>
      <description>Centralize per-second API rate limiting in .NET with a delegating HTTP handler configured through HttpClientFactory.</description>
      <content:encoded><![CDATA[<p>Most APIs have a <strong>Rate Limit</strong> of some sort. For example, <a href="https://developer.github.com/v3/#rate-limiting">GitHub has a limit</a> of 5000 requests per hour. This can be handled, as a consumer of the API, by limiting your use by timing your requests to the API or through caching of the results.</p>
<p>What about when an API <strong>limits your requests per second</strong>? This is probably something you would want to <strong>handle somewhere central in your code</strong> and not spread out everywhere where you make an HTTP call to the API.</p>
<p><img src="https://files.sebnilsson.com/web/images/ratelimithttpmessagehandler/water-funnel.jpg" alt="Funnel"></p>
<p>For me, the solution was to add a <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-2.2#outgoing-request-middleware">Outgoing request middleware</a> to the setup of the <a href="https://docs.microsoft.com/en-us/dotnet/standard/microservices-architecture/implement-resilient-applications/use-httpclientfactory-to-implement-resilient-http-requests"><code>HttpClientFactory</code></a>.</p>
<p>With this, I can just configure the startup services to use this <code>RateLimitHttpMessageHandler</code>-class with the <code>HttpClientFactory</code>:</p>
<pre><code class="language-csharp">services
    .AddHttpClient&#x3C;IApi, Api>()
    .AddHttpMessageHandler(() =>
        new RateLimitHttpMessageHandler(
            limitCount: 5,
            limitTime: TimeSpan.FromSeconds(1)))
    .SetHandlerLifetime(Timeout.InfiniteTimeSpan);
</code></pre>
<p>This ensures that wherever I use the class <code>IApi</code>, through dependency injection, it will limit the calls to the API to only 5 calls per second.</p>
<p>The simplified version of code for the <code>RateLimitHttpMessageHandler</code>:</p>
<pre><code class="language-csharp">public class RateLimitHttpMessageHandler : DelegatingHandler
{
    private readonly List&#x3C;DateTimeOffset> _callLog =
        new List&#x3C;DateTimeOffset>();
    private readonly TimeSpan _limitTime;
    private readonly int _limitCount;

    public RateLimitHttpMessageHandler(int limitCount, TimeSpan limitTime)
    {
        _limitCount = limitCount;
        _limitTime = limitTime;
    }

    protected override async Task&#x3C;HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        var now = DateTimeOffset.UtcNow;

        lock (_callLog)
        {
            _callLog.Add(now);

            while (_callLog.Count > _limitCount)
                _callLog.RemoveAt(0);
        }

        await LimitDelay(now);

        return await base.SendAsync(request, cancellationToken);
    }

    private async Task LimitDelay(DateTimeOffset now)
    {
        if (_callLog.Count &#x3C; _limitCount)
            return;

        var limit = now.Add(-_limitTime);

        var lastCall = DateTimeOffset.MinValue;
        var shouldLock = false;

        lock (_callLog)
        {
            lastCall = _callLog.FirstOrDefault();
            shouldLock = _callLog.Count(x => x >= limit) >= _limitCount;
        }

        var delayTime = shouldLock &#x26;&#x26; (lastCall > DateTimeOffset.MinValue)
            ? (limit - lastCall)
            : TimeSpan.Zero;

        if (delayTime > TimeSpan.Zero)
            await Task.Delay(delayTime);
    }
}
</code></pre>]]></content:encoded>
      <pubDate>Mon, 18 Feb 2019 16:01:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>Azure Storage Easy Web File-Hosting</title>
      <link>https://sebnilsson.com/blog/azure-storage-easy-web-file-hosting</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/azure-storage-easy-web-file-hosting</guid>
      <description>Set up Azure Blob Storage as affordable web file hosting with public access, a custom domain, and Azure CDN.</description>
      <content:encoded><![CDATA[<p>In an ambition to improve my blog a little bit, I wanted to include more images in the posts but felt a <strong>lack of a good solution for web file-hosting</strong>. To find the best fit, I put down a check-list of features and criteria. The solution I was looking for should or must check the following:</p>
<ul>
<li><strong>Ownership of the files:</strong> If the solution used disappears tomorrow, you can still access my files.</li>
<li><strong>Predictable URLs:</strong> The URL to the resources should never change. You don't want to have to update all your blog-posts or other external links floating around the internet.</li>
<li><strong>Good tooling:</strong> Avoiding slow web-upload, when uploading multiple and/or large files, but also easily getting an overview of your files.</li>
<li><strong><em>(Bonus)</em> Pretty URLs:</strong> "Pretty" looking URLs are easier to check for copy-paste errors, but could also potentially benefit <a href="https://en.wikipedia.org/wiki/Search_engine_optimization">SEO</a>.</li>
<li><strong><em>(Bonus)</em> Low or no cost:</strong> Since there are free services out there, paying for file-hosting must be worth it.</li>
</ul>
<p><img src="https://files.sebnilsson.com/web/images/azure-storage-file-hosting/lead.jpg" alt="Images &#x26; Tech"></p>
<h1>Non-fitting Alternatives</h1>
<p>When I started evaluating alternatives, a while back, <strong>Flickr</strong> was still a thing. The problem was that I couldn't predictable directly link to an image I've uploaded. After feeling all the obstacles, which indicated that using Flickr for image-hosting was being actively blocked, I understood it was too much of a hack.</p>
<p>Historically, I've been using <strong>Google's image hosting through Blogger</strong>, which is where this blog started out. The problem was that this also felt like I hack and I was always worried that the URLs would change and I'd have to go through every single blog-posts I've ever made and update all images.</p>
<p>Services like <strong>Dropbox</strong> and <strong>Google Drive</strong> seem to actively try to block the use of their services for this, even if they are accessible through the web.</p>
<h1>Azure Storage for easy web file-hosting</h1>
<p>Enter <a href="https://azure.microsoft.com/services/storage/">Azure Storage</a>, with its widespread adoption, familiar interface and <a href="https://azure.microsoft.com/en-us/pricing/details/storage/blobs/">extremely affordably priced Blob Storage</a>. It checks off all my points in the checklist and more. Giving it's backing, it's fair to assume more functionality will be added ongoingly.</p>
<p><a href="https://azure.microsoft.com/services/storage/blobs/">Azure Blob Storage</a> can be used to store data-blobs of almost any size in the Azure-cloud. By providing a path/key, you can read or write to that "file" at that "path". The overall <a href="https://docs.microsoft.com/en-us/azure/storage/common/storage-scalability-targets">performance of Azure Storage</a> is great and also an important feature of the service, but the simple mechanisms of Azure Blob Storage make it very fast.</p>
<h2>Expose blob-content to the internet</h2>
<p>So you could build a web-app which accesses your files on Azure Blob Storage and expose them through URLs in your API, but you can also <strong>let Azure handle that for you</strong>, by activating <a href="https://docs.microsoft.com/azure/storage/blobs/storage-manage-access-to-resources">anonymous read access to your blobs</a>.</p>
<p>You can do this on blob-level, so <strong>you can have a dedicated blob for public files</strong>, separately from your other blobs in the same Storage-account. These files will be read-only when you use the option <code>Blob (anonymous read access for blobs only)</code>, found under the <em>Access policy</em>-section of the selected blob.</p>
<h2>Upload files</h2>
<p>Then you can use the Azure Portal, programmatically use the <a href="https://docs.microsoft.com/azure/storage/">Azure Blob Storage API</a> to upload files, or you can use application <a href="https://azure.microsoft.com/features/storage-explorer/">Azure Storage Explorer</a>, for a friendly GUI-experience to get started.</p>
<p><img src="https://files.sebnilsson.com/web/images/azure-storage-file-hosting/storage-explorer.png" alt="Azure Storage Explorer"></p>
<p>Now you can share your files anywhere you want, via the provided URL from Azure or through a more pretty URL, using a custom domain.</p>
<h2>Add a custom domain</h2>
<p>To fulfill the criteria of pretty URLs, you can <a href="https://docs.microsoft.com/en-us/azure/storage/blobs/storage-custom-domain-name">set your own custom domain for an Azure Storage-account</a>. If you do not do this, the default URL for Azure Blob storage is <code>https://{storage-account-name}.blob.core.windows.net/{file-path}</code>.</p>
<h2>Activate Azure CDN</h2>
<p>This is a great start for your small project to start out with, but you can in the future easily transition into using the full power of <a href="https://azure.microsoft.com/services/cdn/">Azure Content Delivery Network (Azure CDN)</a> on your existing Azure Storage-account, simply by <a href="https://docs.microsoft.com/azure/cdn/cdn-overview">activating it from the <em>Azure CDN</em>-section</a> in your Storage-account.</p>]]></content:encoded>
      <pubDate>Thu, 10 Jan 2019 15:10:00 GMT</pubDate>
      <category>Azure</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>dotnet-guid: Generate GUIDs/UUIDs with the Command Line</title>
      <link>https://sebnilsson.com/blog/dotnet-guid-generate-guids-uuids-with-the-command-line</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/dotnet-guid-generate-guids-uuids-with-the-command-line</guid>
      <description>Install and use the dotnet-guid global tool to generate one or more GUIDs and UUIDs from the command line.</description>
      <content:encoded><![CDATA[<p>There have been a few projects, although not many, which I've been involved in, where generating <a href="https://en.wikipedia.org/wiki/Universally_unique_identifier">GUIDs/UUIDs</a> has been important. For that, I used to use online-tools like <a href="https://guidgenerator.com">https://guidgenerator.com</a>, but when I switched machine, the autocomplete in my browser lost that link.</p>
<p>Minimally for this reason, and mostly for fun, I decided to write a <a href="https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools">.NET Core Global Tool</a> which quickly generates one or multiple GUIDs/UUIDs, in whatever format could be needed.</p>
<h1>Installation</h1>
<p>Download the <a href="https://aka.ms/DotNetCore21">.NET Core SDK 2.1</a> or later. Then install the <a href="https://www.nuget.org/packages/dotnet-guid"><code>dotnet-guid</code></a> .NET Global Tool, using the command-line:</p>
<pre><code class="language-sh">dotnet tool install -g dotnet-guid
</code></pre>
<h1>Usage</h1>
<pre><code class="language-sh">Usage: guid [arguments] [options]

Arguments:
  Count         Defines how may GUIDs/UUIDs to generate. Defaults to 1.

Options:
  -?|-h|--help  Show help information
  -n            Formatted as 32 digits:
                00000000000000000000000000000000
  -d            Formatted as 32 digits separated by hyphens:
                00000000-0000-0000-0000-000000000000
  -b            Formatted as 32 digits separated by hyphens, enclosed in braces:
                {00000000-0000-0000-0000-000000000000}
  -p            Formatted as 32 digits separated by hyphens, enclosed in parentheses:
                (00000000-0000-0000-0000-000000000000)
  -x            Formatted as four hexadecimal values enclosed in braces,
                where the fourth value is a subset of eight hexadecimal values that is also enclosed in braces:
                {0x00000000,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}}
  -e            Defines if the GUIDs/UUIDs should be empty, using zero-values only.
  -u            Defines if the GUIDs/UUIDs generated should be upper-cased letters.
</code></pre>
<h1>Examples</h1>
<p>To get a single GUID/UUID, simply type:</p>
<pre><code class="language-sh">guid
</code></pre>
<p>To get 3 random GUIDs/UUIDs, with letters in upper-case, formatted with brackets:</p>
<pre><code class="language-sh">guid 3 -b -u
</code></pre>
<p>You can find the <a href="https://github.com/sebnilsson/DotnetGuid">source-code on GitHub</a> and the <a href="https://www.nuget.org/packages/dotnet-guid/">package on Nuget</a>.</p>
<p>You can find <a href="https://github.com/natemcmaster/dotnet-tools">a great list of more .NET Core Global Tools on GitHub</a>, maintained by Nate McMaster.</p>]]></content:encoded>
      <pubDate>Sat, 29 Dec 2018 10:58:00 GMT</pubDate>
      <category>.NET</category>
      <category>.NET Tools</category>
      <category>Developer Tools</category>
      <category>Projects</category>
    </item>
    <item>
      <title>dotnet-cleanup: Clean Up Solution, Project &amp; Folder</title>
      <link>https://sebnilsson.com/blog/dotnet-cleanup-clean-up-solution-project-folder</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/dotnet-cleanup-clean-up-solution-project-folder</guid>
      <description>Use the dotnet-cleanup global tool to remove generated files and folders from .NET solutions, projects, and directories.</description>
      <content:encoded><![CDATA[<publishedat date="2026-06-17T06:46:00Z">
<callout>
<p>For the rebuilt tool and its glob-based cleanup, see <a href="/blog/dotnet-cleanup-v2-quickly-clean-up-bin-obj-node-modules-folders">dotnet cleanup 2.0: Quickly Clean Up bin, obj &#x26; node_modules Folders</a>.</p>
</callout>
</publishedat>
<p>We developers like to think of developing software as an exact science, but <strong>sometimes, you just need to wipe your source-files</strong> to solve some kinds of problems.</p>
<p>For .NET-developers, there are many issues on Stackoverflow which are solved by just deleting your <code>bin</code> and <code>obj</code>-folders. For people using Node.js, probably just as many answers contains the step of removing your <code>node_modules</code>-folder.</p>
<p>Those are some of the reasons why I created <code>dotnet-cleanup</code>, which is a <a href="https://docs.microsoft.com/en-us/dotnet/core/tools/global-tools">.NET Core Global Tool</a> for cleaning up solution, project or folder. This was made easy by following Nate McMaster's post on <a href="https://natemcmaster.com/blog/2018/05/12/dotnet-global-tools/">getting started with creating a .NET Core global tool package</a>.</p>
<p>Deleted files and folders are first moved to a temporary folder before deletion, so <strong>you can continue working with your projects</strong>, while the tool keeps cleaning up in background.</p>
<h1>Installation</h1>
<p>Download the <a href="https://aka.ms/DotNetCore21">.NET Core SDK 2.1</a> or later. Then install the <a href="https://www.nuget.org/packages/dotnet-cleanup"><code>dotnet-cleanup</code></a> .NET Global Tool, using the command-line:</p>
<pre><code class="language-sh">dotnet tool install -g dotnet-cleanup
</code></pre>
<h1>Usage</h1>
<pre><code class="language-sh">Usage: cleanup [arguments] [options]

Arguments:
  PATH                  Path to the solution-file, project-file or folder to clean. Defaults to current working directory.

Options:
  -p|--paths            Defines the paths to clean. Defaults to 'bin', 'obj' and 'node_modules'.
  -y|--confirm-cleanup  Confirm prompt for file cleanup automatically.
  -nd|--no-delete       Defines if files should be deleted, after confirmation.
  -nm|--no-move         Defines if files should be moved before deletion, after confirmation.
  -t|--temp-path        Directory in which the deleted items should be moved to before being cleaned up. Defaults to system Temp-folder.
  -v|--verbosity        Sets the verbosity level of the command. Allowed levels are Minimal, Normal, Detailed and Debug.
  -?|-h|--help          Show help information
</code></pre>
<p>The argument <code>PATH</code> can point to a specific <code>.sln</code>-file or a project-file (<code>.csproj</code>, <code>.fsharp</code>, <code>.vbproj</code>). If a <code>.sln</code>-file is specified, all its projects will be cleaned.</p>
<p>If it points to a folder, the folder will be scanned for a single solution-file and then for a single project-file. If multiple files are detected an error will be shown and you need to specify the file.</p>
<p>If not solution or project is found, the folder will be cleaned as a project.</p>
<h1>Example</h1>
<p>To cleanup a typical web-project, you can specify the paths to be cleaned in the projects like this:</p>
<pre><code class="language-sh">cleanup -p "bin" -p "obj"  -p "artifacts" -p "npm_modules"
</code></pre>
<p>You can find the <a href="https://github.com/sebnilsson/DotnetCleanup">source-code on GitHub</a> and the <a href="https://www.nuget.org/packages/dotnet-cleanup/">package on Nuget</a>.</p>
<p>You can find <a href="https://github.com/natemcmaster/dotnet-tools">a great list of more .NET Core Global Tools on GitHub</a>, maintained by Nate McMaster.</p>]]></content:encoded>
      <pubDate>Wed, 17 Oct 2018 15:57:00 GMT</pubDate>
      <category>.NET</category>
      <category>.NET Tools</category>
      <category>Developer Tools</category>
      <category>Productivity</category>
      <category>Projects</category>
    </item>
    <item>
      <title>LINQ Distinct-Method using Lambda Expression</title>
      <link>https://sebnilsson.com/blog/linq-distinct-method-using-lambda-expression</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/linq-distinct-method-using-lambda-expression</guid>
      <description>Add LINQ extension methods that select distinct objects by a property expressed with a convenient lambda.</description>
      <content:encoded><![CDATA[<p>If you've ever wanted to filter a collection for a distinct result you probably know about the extension-method <code>.Distinct</code> in LINQ. It can be useful on simple data structures containing easily comparable objects, like I collection of <code>strings</code> or <code>ints</code>, but for more complex scenarios you need to pass in a <code>IEqualityComparer</code>. This is not very convenient.</p>
<p>More convenient would be to able to pass in a Lambda-expression, specifying what field you want to do the distinction by, like this:</p>
<pre><code class="language-csharp">var distinctItems = items.Distinct(x => x.Id);
</code></pre>
<p>To do this, you can <strong>add the following extension-methods to your projects</strong>:</p>
<pre><code class="language-csharp">public static IQueryable&#x3C;TSource> Distinct&#x3C;TSource>(
    this IQueryable&#x3C;TSource> source, Expression&#x3C;Func&#x3C;TSource, object>> predicate)
{
    // TODO: Null-check arguments
    return from item in source.GroupBy(predicate) select item.First();
}

public static IEnumerable&#x3C;TSource> Distinct&#x3C;TSource>(
    this IEnumerable&#x3C;TSource> source, Func&#x3C;TSource, object> predicate)
{
    // TODO: Null-check arguments
    return from item in source.GroupBy(predicate) select item.First();
}
</code></pre>
<p>The extension-method using <code>IQueryable&#x3C;T></code> works with ORMs like Entity Framework, while <code>IEnumerable&#x3C;T></code> works with all types of collections, in-memory or otherwise, depending on implementation.</p>
<p><em><strong>Warning</strong>: <strong>Avoid using this with EF Core version 1.x or 2.0</strong>, since the <code>.GroupBy</code>-execution is always made in-memory. So you might get the whole content of your database loaded into memory. <a href="https://blogs.msdn.microsoft.com/dotnet/2018/05/30/announcing-entity-framework-core-2-1/">Only use it with EF Core 2.1 and above</a> in production-scenarios.</em></p>]]></content:encoded>
      <pubDate>Tue, 21 Aug 2018 05:33:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>LINQ</category>
    </item>
    <item>
      <title>API-Versioning in ASP.NET</title>
      <link>https://sebnilsson.com/blog/api-versioning-in-asp-net</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/api-versioning-in-asp-net</guid>
      <description>Support URL, query string, header, and content-type API versioning in ASP.NET with route version attributes.</description>
      <content:encoded><![CDATA[<p>The <a href="https://www.nuget.org/packages/AspNetRouteVersions/">ASP.NET Route Versions-library</a> was created after I was inspired by a discussion with a colleague and reading the great article <a href="https://www.troyhunt.com/your-api-versioning-is-wrong-which-is/"><strong>Your API versioning is wrong</strong> by Troy Hunt</a>, where he concludes that <strong>you don't need a war of preferences between different ways of versioning your API</strong>, you can actually support multiple ways in the same API.</p>
<p>In his article, Troy lists 3 ways (to do it wrong), which I have implemented for ASP.NET Core, and <strong>added support for one more way</strong>, which is URL versioning. This library supports the following ways to version your API:</p>
<ul>
<li>URL versioning</li>
<li>Query string versioning</li>
<li>Custom request header</li>
<li>Content type</li>
</ul>
<p><strong>URL versioning</strong>:</p>
<pre><code class="language-http">HTTP GET:
https://my-web-app.com/api/v2/customers
</code></pre>
<p><strong>Query string versioning</strong>:</p>
<pre><code class="language-http">HTTP GET:
https://my-web-app.com/api/customers?api-version=2
</code></pre>
<p><strong>Custom request header</strong>:</p>
<pre><code class="language-http">HTTP GET:
https://my-web-app.com/api/customers
api-version: 2
</code></pre>
<p><strong>Content type</strong>:</p>
<pre><code class="language-http">HTTP GET:
https://my-web-app.com/api/customers
Accept: application/vnd.api-version.v2+json
</code></pre>
<h1><code>[RouteVersion]</code>-attribute</h1>
<p>All you need to do is use the <code>[RouteVersion]</code>-attribute on the Controller-Actions you want to version and provide the route-version as an argument:</p>
<pre><code class="language-csharp">[Route("api/v{api-version}/[controller]")]
[Route("api/[controller]")]
[ApiController]
public class CustomersController : ControllerBase
{
    [HttpGet]
    [RouteVersion(1)]
    public ActionResult&#x3C;string> GetV1()
    {
        return "Get Customers Version 1";
    }

    [HttpGet]
    [RouteVersion(2)]
    public ActionResult&#x3C;string> GetV2()
    {
        return "Get Customers Version 2";
    }

    [HttpPost]
    [RouteVersion(1)]
    public ActionResult&#x3C;string> PostV1()
    {
        return "Post Customers Version 1";
    }

    [HttpPost]
    [RouteVersion(2)]
    public ActionResult&#x3C;string> PostV2()
    {
        return "Post Customers Version 2";
    }
}
</code></pre>
<p>The attribute will only resolve versioning between Controller-Actions, <strong>everything else is handled by the regular ASP.NET Core routing</strong>, and behave as you're used to.</p>
<h1>Configuration</h1>
<p>In your <code>Startup.cs</code> you can configure what ways of API-versioning you want to support (all activated by default). You can also change the keys of the routing, query string, custom header and content type.</p>
<pre><code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
    services.ConfigureRouteVersions(options =>
    {        
        options.UseRoute = true;
        options.UseQuery = true;
        options.UseCustomHeader = true;
        options.UseAcceptHeader = true;

        // Set route-name in template used. For example: "api/v{version}/[controller]"
        // Default: "api-version"
        options.RouteKey = "version";

        // Set query string-key used. For example: "/api/customers?v=1"
        // Default: "api-version"
        options.QueryKey = "v"; // To use: '/api/customers?v=1'

        // Set custom version header used. For example: "my-app-api-version"
        // Default: "api-version"
        options.CustomHeaderKey = "my-app-api-version";

        // Set Accept-header vendor used. For example: "application/vnd.my-custom-api-header.v1+json"
        // Default: "application/vnd.api-version.v1+json"
        options.SetAcceptHeader("my-custom-api-header");

        // Set Accept-header regex-pattern. For example: "application/pre.my-custom-vendor-api.v1+json"
        options.AcceptRegexPattern = @"application\/pre\.my-custom-vendor-api\.v([\d]+)\+json";
    });

    services.AddMvc();
}
</code></pre>
<h1>Default version</h1>
<p>If you know that <strong>your new version of an API-endpoint is compatible with previous version</strong>, and if you want to support it, you can use the <code>IsDefault</code>-parameter with the <code>[RouteVersion]</code>-attribute. For example, if you've just added new fields to the next version and you find that is compatible enough to be the default version of the API-endpoint:</p>
<pre><code class="language-csharp">[Route("api/[controller]")]
[ApiController]
public class CustomersController : ControllerBase
{
    [HttpGet]
    [RouteVersion(1)]
    public ActionResult&#x3C;string> GetV1()
    {
        return "Get Customers Version 1";
    }

    [HttpGet]
    [RouteVersion(2, IsDefault = true)]
    public ActionResult&#x3C;string> GetV2()
    {
        return "Get Customers Version 2";
    }
}
</code></pre>
<p>Then you can make a call to the URL for the API-endpoint <strong>without specifying the version</strong> and get the default version, which in this example is v2:</p>
<pre><code>HTTP GET:
https://my-web-app.com/api/customers/
> "Get Customers Version 2"
</code></pre>
<h1>Contributing</h1>
<p>You can find the <a href="https://github.com/sebnilsson/AspNetRouteVersions/">source code on GitHub</a>, the <a href="https://www.myget.org/feed/sebnilsson/package/nuget/AspNetRouteVersions">newest unstable build on MyGet</a> and the <a href="https://www.nuget.org/packages/AspNetRouteVersions/">latest version of the library on NuGet</a></p>]]></content:encoded>
      <pubDate>Fri, 10 Aug 2018 13:02:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Projects</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>Azure Deployment of Mono-Repos in GitHub</title>
      <link>https://sebnilsson.com/blog/azure-deployment-of-mono-repos-in-github</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/azure-deployment-of-mono-repos-in-github</guid>
      <description>Deploy different projects from a GitHub monorepo to separate Azure App Services by configuring Kudu&apos;s PROJECT setting.</description>
      <content:encoded><![CDATA[<p>With the increasing adoption of <a href="https://en.wikipedia.org/wiki/Microservices">Microservices</a>, one of the <a href="https://www.quora.com/What-companies-use-a-monorepo-but-deploy-as-microservices">questions</a> sometimes <a href="https://hackernoon.com/one-vs-many-why-we-moved-from-multiple-git-repos-to-a-monorepo-and-how-we-set-it-up-f4abb0cfe469">discussed</a> is <a href="http://blog.shippable.com/our-journey-to-microservices-and-a-mono-repository"><em>mono-repo</em> vs. <em>multi-repo</em></a>, which tries to answer if you structure your code to have <strong>one large, single repository</strong> for all/multiple microservices or <strong>individual, small repositories</strong> for each microservice.</p>
<p>If you're in the scenario of using a <em>mono-repo</em>, where you have multiple projects in a single repo, and you want to <strong>deploy this single code-base to multiple applications and services in Azure</strong>, there is a simple way to do this.</p>
<p><a href="https://github.com/projectkudu/kudu">Kudu</a>, the engine behind git-deployments in Azure App Service, has <a href="https://github.com/projectkudu/kudu/wiki">documentation</a> on how to <a href="https://github.com/projectkudu/kudu/wiki/Customizing-deployments">customize deployments</a>, but <strong>only one of these ways works well with the <em>mono-repo</em>-scenario</strong>. The approach of using a <code>.deployment</code>-file unfortunately locks the configuration of the specified project into your source-code, so <strong>it won't work</strong> for <em>mono-repos</em>.</p>
<p>Instead, <a href="https://github.com/projectkudu/kudu/wiki/Customizing-deployments#using-app-settings-instead-of-a-deployment-file">using the <em>Application settings</em></a> available in all <a href="https://docs.microsoft.com/en-us/azure/app-service/web-sites-configure">Azure App Services</a>, you use the key <code>PROJECT</code> to <strong>set the value for the path of the project</strong> you want to be deployed to your different Azure App Services. So this solution works for Function Apps, Web Apps, API Apps and much more.</p>
<h1>Example</h1>
<p>If you have the following code-structure in your single repository:</p>
<ul>
<li><code>/src/ExampleProject/ExampleProject.csproj</code></li>
<li><code>/src/ExampleProject.FunctionsApp/ExampleProject.FunctionsApp.csproj</code></li>
<li><code>/src/ExampleProject.WebApiApp/ExampleProject.WebApiApp.csproj</code></li>
<li><code>/src/ExampleProject.WebApp/ExampleProject.WebApp.csproj</code></li>
<li><code>/test/ExampleProject.Tests/ExampleProject.Tests.csproj</code></li>
</ul>
<p>Then you'd set up your <code>PROJECT</code>-path in <em>Application settings</em> for your different Application Services like this:</p>
<ul>
<li><strong>Function App</strong>: <code>"src/ExampleProject.FunctionsApp"</code></li>
<li><strong>Web App</strong>: <code>"src/ExampleProject.WebApp"</code></li>
<li><strong>API App</strong>: <code>"src/ExampleProject.WebApiApp"</code></li>
</ul>
<p>With the <strong>paths relative to the Git-repository's root-path</strong>. You can also point directly to the <code>.csproj</code>-file, if there is any risk of ambiguity in the same file-folder.</p>
<p>When this is done you can <a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-continuous-deployment">configure your Azure App Services for Continuous Deployment</a> <strong>using the same repository</strong>, in GitHub, Bitbucket, local Git or any other source supported in Azure.</p>]]></content:encoded>
      <pubDate>Thu, 22 Feb 2018 15:16:00 GMT</pubDate>
      <category>Azure</category>
      <category>Deployment</category>
    </item>
    <item>
      <title>Convert C# Anonymous (or Any) Types Into Dynamic ExpandoObject</title>
      <link>https://sebnilsson.com/blog/convert-c-anonymous-or-any-types-into-dynamic-expandoobject</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/convert-c-anonymous-or-any-types-into-dynamic-expandoobject</guid>
      <description>Convert anonymous types or other C# objects into dynamic ExpandoObject instances by copying their properties.</description>
      <content:encoded><![CDATA[<publishedat date="2026-09-01T06:38:00Z">
<callout>
<p>For modern alternatives and guidance on choosing between dynamic objects and JSON, see <a href="/blog/modern-csharp-object-conversion-expandoobject-reflection-json">Modern C# Object Conversion: ExpandoObject, Reflection &#x26; JSON</a>.</p>
</callout>
</publishedat>
<p>There are scenarios when you need to convert an <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/classes-and-structs/anonymous-types">anonymous type</a> in C#, or any other type, into <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/dynamic">a <code>dynamic</code></a>, or more specifically to the underlying <a href="https://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx"><code>ExpandoObject</code>-type</a>.</p>
<p>My specific need was to be able to move the data from an anonymous type from the current assembly into a dynamically executed external assembly. So I created an extension-method for this, which <strong>moves all the properties from any object</strong> into a new <code>ExpandoObject</code>.</p>
<pre><code class="language-csharp">public static ExpandoObject ToExpandoObject(this object obj)
{
    // Null-check

    IDictionary expando = new ExpandoObject();

    foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(obj.GetType()))
    {
        expando.Add(property.Name, property.GetValue(obj));
    }

    return (ExpandoObject) expando;
}
</code></pre>
<p><strong>You can use the extension-method on any type of object</strong> and choose to reference the resulting type by it's actual type <code>ExpandoObject</code> or as a <code>dynamic</code>.</p>
<pre><code class="language-csharp">var anonymous = new {Id = 123, Text = "Abc123", Test = true};

dynamic dynamicObject = anonymous.ToExpandoObject();
ExpandoObject expandoObject = anonymous.ToExpandoObject();
</code></pre>
<p>Since the code uses the type <code>System.ComponentModel.TypeDescriptor</code>, <strong>if you use .NET Core or .NET Standard, you might need to reference</strong> <a href="https://www.nuget.org/packages/System.ComponentModel.TypeConverter">the Nuget-package named <code>System.ComponentModel.TypeConverter</code></a>.</p>]]></content:encoded>
      <pubDate>Wed, 06 Dec 2017 08:14:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>KeyLocks: Lock .NET/C#-code on Specific Values</title>
      <link>https://sebnilsson.com/blog/keylocks-lock-net-c-code-on-specific-values</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/keylocks-lock-net-c-code-on-specific-values</guid>
      <description>Use KeyLocks to synchronize .NET code by a specific value or ID without blocking unrelated operations.</description>
      <content:encoded><![CDATA[<p>If you've ever needed to <strong>ensure that multiple threads are not running the same code</strong>, you've probably used <a href="https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/lock-statement">a <code>lock</code>-statement</a> in your .NET/C#-code.</p>
<p>Sometimes a regular <code>lock</code> can be <strong>too aggressive and lock too much running code for too long</strong>. You can solve this by cleverly locking on unique objects, but <a href="https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/threading/thread-synchronization">that handling is complex, error-prone and can become tedious</a>.</p>
<p>Many times you know that you have <strong>a specific value or ID which is the key</strong> you want to lock on. For instance, you might want your code to not write to the database from multiple actions performed in parallel on your web-application. Using the Nuget-package <a href="https://www.nuget.org/packages/KeyLocks/">KeyLocks</a> will give you easy to write syntax to handle this:</p>
<pre><code class="language-csharp">private static KeyLock&#x3C;string> _keyLock = new KeyLock&#x3C;string>();

public void Main()
{
    Parallel.Invoke(
        () => { UpdateData("entity-123", "First new value"); },
        () => { UpdateData("entity-123", "Second new value"); }, // This will await line above
        () => { UpdateData("another-entity-456", "Another new value"); },        
        () => { UpdateData("yet-another-entity-789", "Yet another new value"); });
}

private void UpdateData(string id, string value)
{
    _keyLock.RunWithLock(id, () =>
    {
        // Execute locked code
    });
}
</code></pre>
<p>Make sure the instance of <code>KeyLock&#x3C;T></code> is shared between threads executing the code you want to lock on. In this case, I solved it by making the instance <code>static</code> and therefore shared across all instances of the code using it.</p>
<p>The package also contains the type <code>NameLock</code> is a short-hand term for <code>KeyLock&#x3C;string></code>. It defaults to being case-sensitive, but that can be changed by passing the correct <code>IEqualityComparer&#x3C;T></code> as a constructor-argument like this:</p>
<pre><code class="language-csharp">var nameLock = new NameLock(StringComparer.InvariantCultureIgnoreCase)
</code></pre>
<p><a href="https://github.com/sebnilsson/KeyLocks">See the README-file on GitHub</a> for the latest detailed information about KeyLocks. Or try it out through Nuget by running <code>Install-Package KeyLocks</code> in your project. You can even follow the <a href="https://www.myget.org/feed/sebnilsson/package/nuget/KeyLocks">absolutely latest build on MyGet</a>.</p>]]></content:encoded>
      <pubDate>Thu, 30 Nov 2017 16:07:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Projects</category>
    </item>
    <item>
      <title>C# DateTime to RFC3339/ISO 8601</title>
      <link>https://sebnilsson.com/blog/c-datetime-to-rfc3339-iso-8601</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/c-datetime-to-rfc3339-iso-8601</guid>
      <description>Format C# DateTime values as RFC 3339 and ISO 8601 strings for standards-compliant API requests.</description>
      <content:encoded><![CDATA[<publishedat date="2026-08-25T07:11:00Z">
<callout>
For a modern .NET implementation focused on `DateTimeOffset`, see [C# DateTimeOffset to RFC 3339 &#x26; ISO 8601](/blog/csharp-datetimeoffset-to-rfc-3339-iso-8601).
</callout>
</publishedat>
<p>According to Wikipedia <a href="https://en.wikipedia.org/wiki/ISO_8601">the date and time-format RFC3339/ISO 8601</a> usages includes:</p>
<blockquote>
<p>On the Internet, <a href="https://www.w3.org/TR/NOTE-datetime">the World Wide Web Consortium (W3C)</a> uses ISO 8601 in defining a profile of the standard that restricts the supported date and time formats to reduce the chance of error and the complexity of software.</p>
</blockquote>
<p>My specific need to format a <code>System.DateTime</code>-value in a RFC3339-format came when I used one of Google's REST APIs and they required a parameter in the RFC3339-format. Here is the code is the extension-method which provides the functionality of formatting a <code>DateTime</code> as a <code>string</code> in RFC3339-format:</p>
<pre><code class="language-csharp">public static string ToRfc3339String(this DateTime dateTime)
{
    return dateTime.ToString("yyyy-MM-dd'T'HH:mm:ss.fffzzz", DateTimeFormatInfo.InvariantInfo);
}
</code></pre>]]></content:encoded>
      <pubDate>Tue, 28 Nov 2017 08:02:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>Convert C# URI/URL to Absolute or Relative</title>
      <link>https://sebnilsson.com/blog/convert-c-uri-url-to-absolute-or-relative</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/convert-c-uri-url-to-absolute-or-relative</guid>
      <description>Convert URLs between absolute and relative forms in C# with reusable System.Uri extension methods.</description>
      <content:encoded><![CDATA[<publishedat date="2026-08-18T07:27:00Z">
<callout>
<p>For modern URL validation and handling of queries and fragments, see <a href="/blog/modern-csharp-uri-handling-absolute-relative-query-fragment-urls">Modern C# URI Handling: Absolute, Relative, Query &#x26; Fragment URLs</a>.</p>
</callout>
</publishedat>
<p>There are many situations when you handle <a href="https://en.wikipedia.org/wiki/URL">URLs</a> or <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier">URIs</a> in applications today, no matter if it's a web-application or not. Often you need to handle absolute URLs, like <code>https://testsite.com/section/page</code>, and relative URLs, like <code>/section/page.html</code>.</p>
<p>To easily convert URLs between absolute and relative, or just ensure these two formats, I created extension-methods for <a href="https://msdn.microsoft.com/en-us/library/system.uri.aspx">the type <code>System.Uri</code></a>, which allows you to write code like this:</p>
<pre><code class="language-csharp">var absoluteToRelative = new Uri("https://www.test-relative.com/customers/details.html").ToRelative();
// Outputs: "/customers/details.html"

var relativeToAbsolute = new Uri("/orders/id-123/", UriKind.Relative).ToAbsolute("https://www.test-absolute.com");
// Outputs: "https://www.test-absolute.com/orders/id-123/"
</code></pre>
<p>The extension-methods which makes this possible are the following:</p>
<pre><code class="language-csharp">public static string ToRelative(this Uri uri)
{
    // TODO: Null-checks

    return uri.IsAbsoluteUri ? uri.PathAndQuery : uri.OriginalString;
}

public static string ToAbsolute(this Uri uri, string baseUrl)
{
    // TODO: Null-checks

    var baseUri = new Uri(baseUrl);

    return uri.ToAbsolute(baseUri);
}

public static string ToAbsolute(this Uri uri, Uri baseUri)
{
    // TODO: Null-checks

    var relative = uri.ToRelative();

    if (Uri.TryCreate(baseUri, relative, out var absolute))
    {
        return absolute.ToString();
    }

    return uri.IsAbsoluteUri ? uri.ToString() : null;
}
</code></pre>]]></content:encoded>
      <pubDate>Fri, 24 Nov 2017 07:56:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>Registering Autofac &amp; AutoMapper Circularly</title>
      <link>https://sebnilsson.com/blog/registering-autofac-automapper-circularly</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/registering-autofac-automapper-circularly</guid>
      <description>Configure Autofac and AutoMapper together so mapping operations can resolve registered dependencies through the Autofac container.</description>
      <content:encoded><![CDATA[<p>Have you ever wanted to register <a href="https://autofac.org/">Autofac</a> and <a href="http://automapper.org/">AutoMapper</a> circularly? By this I mean to do <strong>the inception of these two things, at the same time, in the same application</strong>:</p>
<ul>
<li>Register <strong>AutoMapper</strong>'s mappings through <strong>Autofac</strong>'s component-registration for dependency-injection</li>
<li>Use registered components in <strong>Autofac</strong> for dependency-injection into <strong>AutoMapper</strong>'s mapped objects</li>
</ul>
<p><strong>This is actually possible!</strong> It's done by providing AutoMapper with Autofac's <code>IComponentContext</code>-object, which is not dependent on if you've registered everything you need in the Autofac component-registrations, before configuring AutoMapper. <strong>So you can register more components after registering your AutoMapper-configuration and still access all these in your AutoMapper context</strong> when they get resolved later in your code.</p>
<p>We'll start with <strong>the code for registering the Autofac-components</strong> and follow it with some explaining:</p>
<pre><code class="language-csharp">public IContainer RegisterComponents()
{
    var builder = new ContainerBuilder();

    builder.RegisterType&#x3C;PreMapperComponent>().As&#x3C;IPreMapperComponent>();

    builder.Register(ConfigureMapper).SingleInstance();

    builder.RegisterType&#x3C;PostMapperComponent>().As&#x3C;IPostMapperComponent>();

    return builder.Build();
}

private IMapper ConfigureMapper(IComponentContext context)
{
    var configuration = new MapperConfiguration(config =>
    {
        var ctx = context.Resolve&#x3C;IComponentContext>();

        config.CreateMap&#x3C;EntityType, DtoType>()
            .ConstructUsing(_ =>
                new DtoType(ctx.Resolve&#x3C;IPreMapperComponent>(), ctx.Resolve&#x3C;IPostMapperComponent>()));
    });

    return configuration.CreateMapper();
}
</code></pre>
<p>The method <code>RegisterComponents</code> is included to show a somewhat realistic scenario, and for this case specifically showing that <strong>you can register components in Autofac both before and after configuring AutoMapper</strong>.</p>
<p>The code <code>var ctx = context.Resolve&#x3C;IComponentContext>()</code> <strong>might look strange, but is crucial</strong> for this solution to work. Why not use the <code>context</code>-argument directly in the <code>ConfigureMapper</code>-method? Because it will throw an exception starting with <code>This resolve operation has already ended</code>, and <strong>instructs you to resolve <code>IComponentContext</code> again</strong>, which is what we're doing here.</p>
<h1>Running the AutoMapper-code</h1>
<p>Then we run the code using AutoMapper and the mapping of types needing dependency-injection of constructor-parameters:</p>
<pre><code class="language-csharp">public static void Run(IContainer container)
{
    var mapper = container.Resolve&#x3C;IMapper>();

    var source = new EntityType(123, "Test-text", "Test-description");

    var dto = mapper.Map&#x3C;DtoType>(source);

    dto.RunComponents();
}
</code></pre>
<p>The code <code>dto.RunComponents()</code> is the one that executes the injected implementations of the interfaces <code>IPreMapperComponent</code> and <code>IPostMapperComponent</code> used in the type <code>DtoType</code>.</p>
<p>You can find all the code-files involved in this example <a href="https://gist.github.com/sebnilsson/f9ed88934206fbab1decbe62491a2570">in this Gist</a>.</p>
<p>This can all also be done through the recommended approach of <a href="https://autofaccn.readthedocs.io/en/latest/configuration/modules.html">Modules in Autofac</a> and <a href="https://github.com/AutoMapper/AutoMapper/wiki/Configuration#profile-instances">Profiles in AutoMapper</a>.</p>]]></content:encoded>
      <pubDate>Mon, 20 Nov 2017 08:08:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>C# Clamp: Limit IComparable Between Two Values</title>
      <link>https://sebnilsson.com/blog/c-clamp-limit-icomparable-between-two-values</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/c-clamp-limit-icomparable-between-two-values</guid>
      <description>Clamp any comparable C# value between minimum and maximum bounds with a reusable generic extension method.</description>
      <content:encoded><![CDATA[<p>If you've ever needed to limit a value between two known limits of values, then you have been looking for <a href="https://en.wikipedia.org/wiki/Clamping_(graphics)">Clamping</a>.</p>
<p>Sometimes when you do calculations on values you know that the result should not fall outside two specific values. For example, if your calculating a percentage-value as an <code>int</code>-value, then you know the result should be between <code>0</code> and <code>100</code>.</p>
<pre><code class="language-csharp">public int GetPercentage(int val1, int val2)
{
    var calculation = val1 / val2;
    var ensuredPercentage = calculation.Clamp(0, 100);
    return ensuredPercentage;
}
</code></pre>
<p>This functionality can easily be extended to all classes which <a href="https://msdn.microsoft.com/en-us/library/4d7sx9hd.aspx">inherits from <code>System.IComparable&#x3C;T></code></a>, which are for example all types of numbers like <code>int</code>, <code>double</code>, <code>long</code> and so on, but also <code>DateTime</code> and more.</p>
<p>The following extension-method adds the <code>Clamp</code>-method to all objects of types inheriting from <code>IComparable&#x3C;T></code>:</p>
<pre><code class="language-csharp">public static T Clamp&#x3C;T>(this T value, T min, T max)
    where T : IComparable&#x3C;T>
{
    var comparer = Comparer&#x3C;T>.Default;

    if (comparer == null)
        throw new ArgumentException($"Failed to get default comparer for type '{typeof(T).FullName}'.");

    var isMinGreaterThanMax = comparer.Compare(min, max) > 0;

    if (isMinGreaterThanMax)
    {
        throw new ArgumentOutOfRangeException(
            nameof(min),
            "Minimum value cannot be larger than maximum value.");
    }

    var isValueLessThanMin = comparer.Compare(value, min) &#x3C; 0;
    var isValueGreaterThanMax = !isValueLessThanMin &#x26;&#x26; comparer.Compare(value, max) > 0;

    return isValueLessThanMin ? min : (isValueGreaterThanMax ? max : value);
}
</code></pre>]]></content:encoded>
      <pubDate>Wed, 15 Nov 2017 08:41:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>ASP.NET Core MVC SEO-Framework</title>
      <link>https://sebnilsson.com/blog/asp-net-core-mvc-seo-framework</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-core-mvc-seo-framework</guid>
      <description>Manage SEO metadata in ASP.NET Core MVC using dependency injection, action attributes, and Tag Helpers.</description>
      <content:encoded><![CDATA[<p>Following my last post on my <a href="/blog/asp-net-mvc-seo-framework/">ASP.NET MVC SEO-Framework</a> I started looking at adding support also for <strong>ASP.NET Core MVC</strong>, with its superior <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection">Dependency Injection</a> and <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/">Tag Helpers</a>.</p>
<p><a href="/blog/asp-net-mvc-seo-framework/">The previous post</a> shows examples on how to use attributes to set SEO-specific values for Controller-Actions and in Views, which is also used in ASP.NET Core MVC. What is new to Core MVC is how you <a href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection#registering-your-own-services">register the SEO-helper as a Service for Dependency Injection</a> and <a href="https://docs.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/intro#tag-helpers-compared-to-html-helpers">use Tag Helpers instead of HTML Helpers</a>.</p>
<p>To register the SEO-helper as a service for Dependency Injection you just need to <strong>use the framework's provided extension-method</strong> in the <code>ConfigureServices</code>-method inside <code>Startup.cs</code>:</p>
<pre><code class="language-csharp">public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMvc();

        services.AddSeoHelper();
    }
}
</code></pre>
<p>These SEO-values can easily be accessed and rendered as HTML-tags inside <code>Views</code> through provided <code>Tag Helpers</code>:</p>
<pre><code class="language-html">&#x3C;head>
    &#x3C;seo-title />

    &#x3C;seo-link-canonical />
    &#x3C;seo-meta-description />
    &#x3C;seo-meta-keywords />
    &#x3C;seo-meta-robots-index />
&#x3C;/head>
</code></pre>
<p>To access these <code>Tag Helpers</code> <strong>you need to reference them</strong> in you <code>_ViewImports.cshtml</code>:</p>
<pre><code class="language-csharp">@addTagHelper *, AspNetSeo.CoreMvc
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
</code></pre>
<p><a href="https://github.com/sebnilsson/AspNetSeo">See the <code>README</code>-file on GitHub</a> for the latest detailed information about this ASP.NET SEO-framework. Or try it out through Nuget by running <code>Install-Package AspNetSeo.CoreMvc</code> or <code>Install-Package AspNetSeo.Mvc</code> in your project. You can even follow the <a href="https://www.myget.org/feed/sebnilsson/package/nuget/AspNetSeo.CoreMvc">absolutely latest build on MyGet</a>.</p>]]></content:encoded>
      <pubDate>Thu, 18 May 2017 17:18:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Projects</category>
      <category>SEO</category>
    </item>
    <item>
      <title>ASP.NET MVC SEO-Framework</title>
      <link>https://sebnilsson.com/blog/asp-net-mvc-seo-framework</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-mvc-seo-framework</guid>
      <description>Implement consistent page titles, meta descriptions, canonical URLs, and other SEO metadata in ASP.NET MVC.</description>
      <content:encoded><![CDATA[<p><em><strong>See also the <a href="/blog/asp-net-core-mvc-seo-framework/">ASP.NET Core-implementation</a> of this project.</strong></em></p>
<hr>
<p>For any serious web-application you should always <strong>implement a solid <a href="https://en.wikipedia.org/wiki/Search_engine_optimization">Search engine optimization</a>-strategy</strong>, but there is no standardized way to handle this in ASP.NET MVC, out of the box.</p>
<p>You could easily use the <code>ViewBag</code>-object to send <code>dynamic</code> values from <code>Controller</code>-<code>Actions</code> into <code>Views</code>, like this, for example:</p>
<pre><code class="language-csharp">public ActionResult Index()
{
    this.ViewBag.PageTitle = "This is the page title";

    return this.View();
}
</code></pre>
<p>Then you'd have to make sure you <strong>correctly spell or copy-paste</strong> <code>ViewBag.PageTitle</code> correctly into your <code>View</code>:</p>
<pre><code class="language-html">&#x3C;head>
    &#x3C;title>@ViewBag.PageTitle&#x3C;/title>
    &#x3C;!-- More head-values -->
&#x3C;/head>
</code></pre>
<p>One problem is that <strong>if you refactor</strong> the naming for <code>ViewBag.PageTitle</code> into, for example <code>ViewBag.Title</code>, this <strong>will break the functionality, potentially website-wide</strong>, because you won't get any tooling-help from Visual Studio for that rename.</p>
<p>This is why I created <strong>a framework for ASP.NET MVC SEO</strong>, to get <strong>structured and reusable functionality around the SEO-data</strong> for a web-application. The framework is <a href="https://www.nuget.org/packages/AspNetSeo.Mvc/">available on Nuget</a>, with the <a href="https://github.com/sebnilsson/AspNetSeo">source-code on GitHub</a>.</p>
<h1>Setting SEO-values</h1>
<p>You can set SEO-values using the properties on a <code>SeoHelper</code>-object in <code>Controller</code>-<code>Actions</code> and <code>Views</code>, or you can use <code>ActionFilter</code>-<code>attributes</code> in <code>Controllers</code>, to set SEO-related data like:</p>
<ul>
<li>Meta-Description</li>
<li>Meta-Keywords</li>
<li>Title, split on page-title and base-title (website-title)</li>
<li>Canonical Link</li>
<li>Meta No-index for robots</li>
</ul>
<p>This can be done inside <code>Controllers</code> and <code>Controller</code>-<code>Actions</code>:</p>
<pre><code class="language-csharp">[SeoBaseTitle("Website name")]
public class InfoController : SeoController
{
    [SeoTitle("Listing items")]
    [SeoMetaDescription("List of the company's product-items")]
    public ActionResult List()
    {
        var list = this.GetList();

        if (list.Any())
        {
            this.Seo.Title += $" (Total: {list.Count})";
            this.Seo.LinkCanonical = "~/pages/list.html";
        }
        else
        {
            this.Seo.MetaRobotsNoIndex = true;
        }

        return this.View(model);
    }
}
</code></pre>
<p>If you don't want to inherit from <code>SeoController</code> to get access to the <code>this.Seo</code>-property, you can use the extension-method <code>GetSeoHelper</code>:</p>
<pre><code class="language-csharp">public class InfoController : Controller
{
    public ActionResult List()
    {
        var seo = this.GetSeoHelper();

        seo.Title = "Page title";

        return this.View(model);
    }
}
</code></pre>
<p>You can even set SEO-values inside <code>Views</code>:</p>
<pre><code class="language-csharp">@{
    this.Layout = null;
    this.Seo.MetaRobotsNoIndex = true; // Always block Robots from indexing this View
}
</code></pre>
<h1>Rendering SEO-values</h1>
<p>These SEO-values can easily be accessed and rendered as HTML-tags inside Views through provided <code>HtmlHelper</code>-extensions:</p>
<pre><code class="language-html">&#x3C;head>
    @Html.SeoTitle()

    @Html.SeoLinkCanonical()
    @Html.SeoMetaDescription()
    @Html.SeoMetaKeywords()
    @Html.SeoMetaRobotsIndex()
&#x3C;/head>
</code></pre>
<p><a href="https://github.com/sebnilsson/AspNetSeo">See the <code>README</code>-file on GitHub</a> for the latest detailed information about this ASP.NET MVC SEO-framework. Or try it out through Nuget by running <code>Install-Package AspNetSeo.Mvc</code> in your project. You can even follow the <a href="https://www.myget.org/feed/sebnilsson/package/nuget/AspNetSeo.Mvc">absolutely latest build on MyGet</a>.</p>]]></content:encoded>
      <pubDate>Wed, 18 Jan 2017 08:37:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Projects</category>
      <category>SEO</category>
    </item>
    <item>
      <title>Display Local DateTime with Moment.js in ASP.NET</title>
      <link>https://sebnilsson.com/blog/display-local-datetime-with-moment-js-in-asp-net</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/display-local-datetime-with-moment-js-in-asp-net</guid>
      <description>Render SEO-friendly UTC timestamps in ASP.NET and convert them to each visitor&apos;s local date and time with Moment.js.</description>
      <content:encoded><![CDATA[<p>Displaying a <code>DateTime</code> in local format in C# is <a href="https://msdn.microsoft.com/en-us/library/system.datetime.tolocaltime.aspx">relatively easy</a>, but it will only use the server's settings to tell what "local" is.</p>
<p>For example, you might want <code>2016-03-07 14:35 UTC</code> to show as <code>2016-03-07 15:35</code> for a visitor from a CET-timezone.</p>
<p>If you want to dynamically show the local date and time you can use the web-client's information through JavaScript and format it with <a href="http://momentjs.com/">Moment.js</a>, for any user, anywhere in the world.</p>
<p>To do this in a way that is fault-tolerant and also SEO-friendly I want the UTC-<code>DateTime</code> to be hard-coded in the HTML and let Moment.js format it on the fly, when the page loads. To do this I need to populate my <code>.cshtml</code>-file with the following:</p>
<pre><code class="language-html">&#x3C;span class="local-datetime"
        title="@(Model.DateUtc.ToString("yyyy-MM-dd HH:mm")) UTC"
        data-utc="@(Model.DateUtc.GetEpochTicks())">
    @(Model.DateUtc.ToString("yyyy-MM-dd HH:mm")) UTC
&#x3C;/span>
</code></pre>
<p><strong>Make sure you run <code>.ToUniversalTime()</code> on your <code>DateTime</code> first.</strong></p>
<p>Notice the <code>.GetEpochTicks()</code>-extension method. It makes sure the format of the <code>DateTime</code> is passed in a format that Moment.js can handle easily. The implementation looks like this:</p>
<pre><code class="language-csharp">private static readonly DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

public static double GetEpochTicks(this DateTime dateTime)
{
    return dateTime.Subtract(Epoch).TotalMilliseconds;
}
</code></pre>
<p>The last step is to tell Moment.js to format our <code>DateTime</code> to a local format:</p>
<pre><code class="language-javascript">$('.local-datetime').each(function() {
    var $this = $(this), utcDate = parseInt($this.attr('data-utc'), 10) || 0;

    if (!utcDate) {
        return;
    }

    var local = moment.utc(utcDate).local();
    var formattedDate = local.format('YYYY-MM-DD HH:mm');
    $this.text(formattedDate);
});
</code></pre>
<p>If this (or other, unrelated) JavaScript-code would fail for any reason the UTC-<code>DateTime</code> is the actually HTML-content and will still be displayed.</p>]]></content:encoded>
      <pubDate>Tue, 08 Mar 2016 07:21:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>JavaScript</category>
    </item>
    <item>
      <title>NullableGuidConstraint for ASP.NET MVC &amp; WebApi</title>
      <link>https://sebnilsson.com/blog/nullableguidconstraint-for-asp-net-mvc-webapi</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/nullableguidconstraint-for-asp-net-mvc-webapi</guid>
      <description>Create a reusable nullable GUID route constraint that works with both ASP.NET MVC and Web API.</description>
      <content:encoded><![CDATA[<publishedat date="2026-06-30T06:54:00Z">
<callout>
<p>For the built-in modern routing APIs, see <a href="/blog/nullable-guid-route-constraints-in-asp-net-core">Nullable GUID Route Constraints in ASP.NET Core</a>.</p>
</callout>
</publishedat>
<p>Have you ever written a very usable Route-constraint in ASP.NET MVC or in WebAPI than you wanted to share between them both? For example a constraint that supports nullable Guids (<code>Guid?</code>) as route-parameter.</p>
<p>This can be done by implementing both <a href="https://msdn.microsoft.com/en-us/library/system.web.routing.irouteconstraint.aspx"><code>System.Web.Routing.IRouteConstraint</code></a> and <a href="https://msdn.microsoft.com/en-us/library/system.web.http.routing.ihttprouteconstraint.aspx"><code>System.Web.Http.Routing.IHttpRouteConstraint</code></a>.</p>
<p>Hopefully this article will be <a href="https://www.asp.net/vnext/overview/aspnet-vnext/aspnet-5-overview#unify">obsolete with the release of ASP.NET 5</a>, but until then, here's how you solve this problem:</p>
<pre><code class="language-csharp">public class NullableGuidConstraint : IRouteConstraint, IHttpRouteConstraint
{
    // ASP.NET MVC-signature
    public bool Match(
        HttpContextBase httpContext,
        Route route,
        string parameterName,
        RouteValueDictionary values,
        RouteDirection routeDirection)
    {
        return MatchInternal(parameterName, values);
    }

    // WebAPI-signature
    public bool Match(
        HttpRequestMessage request,
        IHttpRoute route,
        string parameterName,
        IDictionary values,
        HttpRouteDirection routeDirection)
    {
        return MatchInternal(parameterName, values);
    }

    private static bool MatchInternal(string parameterName, IDictionary values)
    {
        object value;
        if (!values.TryGetValue(parameterName, out value))
        {
            return false;
        }

        if (value is Guid)
        {
            return true;
        }

        string stringValue = Convert.ToString(value, CultureInfo.InvariantCulture);

        Guid guid;
        bool isMatch = string.IsNullOrWhiteSpace(stringValue) || Guid.TryParse(stringValue, out guid);
        return isMatch;
    }
}
</code></pre>
<p>Then you register this constraint through, for example, <code>DefaultInlineConstraintResolver</code> in <code>System.Web.Mvc.Routing</code> for ASP.NET MVC and <code>System.Web.Http.Routing</code> for WebAPI.</p>
<pre><code class="language-csharp">var constraintResolver = new DefaultInlineConstraintResolver();
constraintResolver.ConstraintMap.Add("guid?", typeof(NullableGuidConstraint));

// ASP.NET MVC
routes.MapMvcAttributeRoutes(constraintResolver);

// WebAPI
routes.MapHttpAttributeRoutes(constraintResolver);
</code></pre>
<p>Now you can write attribute-routes like this:</p>
<pre><code class="language-csharp">[Route("{controller}/{action}/{id=guid?}")]
</code></pre>]]></content:encoded>
      <pubDate>Wed, 25 Mar 2015 07:22:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>PowerShell Profile with Permanent Aliases</title>
      <link>https://sebnilsson.com/blog/powershell-profile-with-permanent-aliases</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/powershell-profile-with-permanent-aliases</guid>
      <description>Use a PowerShell profile to load permanent aliases and reusable scripts every time the console opens.</description>
      <content:encoded><![CDATA[<p>If you're a PowerShell-user who <strong>manually runs scripts</strong> or <strong>binds an alias</strong> every time you open PowerShell, then <strong>there is a file you really should know about</strong>. It's the <strong>PowerShell profile-file</strong> (or actually, the <a href="http://blogs.technet.com/b/heyscriptingguy/archive/2012/05/21/understanding-the-six-powershell-profiles.aspx">six profile-files</a>).</p>
<p>I use the profile-file for <strong>Current User in the console</strong> located here:</p>
<pre><code class="language-powershell">%UserProfile%\Documents\WindowsPowerShell\Microsoft.PowerShell_profile.ps1
</code></pre>
<p>When you've ensured that this file is created you can enter <strong>PowerShell-scripts that will run every time you open your PowerShell-console</strong>. Ensure that your <a href="https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.security/set-executionpolicy">execution policy is configured to support this</a>:</p>
<pre><code class="language-powershell">Set-ExecutionPolicy -ExecutionPolicy Unrestricted
</code></pre>
<p>For example you can create a PowerShell-<code>alias</code> for the <code>git</code>-command to work with just using <code>g</code> instead:</p>
<pre><code class="language-powershell">set-alias g git
</code></pre>
<p>Now I can just type <code>g status</code> and save many, many seconds and key-strokes during a long week of Git-usage.</p>]]></content:encoded>
      <pubDate>Wed, 17 Sep 2014 07:52:00 GMT</pubDate>
      <category>PowerShell</category>
      <category>Productivity</category>
    </item>
    <item>
      <title>Render .ascx-Files in ASP.NET MVC Using Only RazorViewEngine</title>
      <link>https://sebnilsson.com/blog/render-ascx-files-in-asp-net-mvc-using-only-razorviewengine</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/render-ascx-files-in-asp-net-mvc-using-only-razorviewengine</guid>
      <description>Render legacy ASP.NET WebForms .ascx controls inside MVC Razor views while retaining the RazorViewEngine.</description>
      <content:encoded><![CDATA[<p>If you're stuck in an environment where you're migrating from <a href="https://www.asp.net/mvc">ASP.NET MVC</a> to <a href="https://www.asp.net/web-forms">ASP.NET WebForms</a> it's good to know that you can actually <strong>render your existing WebForms-Controls in you MVC-views</strong>. This might sound like a crazy thing to do <em>(and it is in the long run!)</em> but it <strong>might be useful if you're stuck between sprints and have perfectly working WebForms-Controls</strong> (<code>.ascx</code>-files) that you don't have time to migrate right now. All you have to do is use the <a href="https://msdn.microsoft.com/en-us/library/system.web.mvc.htmlhelper.aspx"><code>HtmlHelper</code></a>'s helper-method <a href="https://msdn.microsoft.com/en-us/library/system.web.mvc.html.renderpartialextensions.renderpartial.aspx"><code>.RenderPartial(string partialViewName)</code></a> and pass it the path to the WebForms-Control.</p>
<pre><code class="language-csharp">// Write the content of a control inside a view:
Html.RenderPartial("~/Controls/ControlVirtualPath.ascx");

// Or to get the content of a control as a MvcHtmlString, for further manipulation:
Html.Partial("~/Controls/CustomControl.ascx")
</code></pre>
<p><strong>It's important that your controls inherits from <a href="https://msdn.microsoft.com/en-us/library/system.web.mvc.viewusercontrol.aspx"><code>System.Web.Mvc.ViewUserControl</code></a></strong> and NOT the old <code>System.Web.UI.UserControl</code>.</p>
<p>One performance-tip that is often mentioned around ASP.NET MVC is to <a href="http://samsaffron.com/archive/2011/08/16/Oh+view+where+are+thou+finding+views+in+ASPNET+MVC3+">deactivate the WebForms-View Engine for MVC Razor-views</a> (which actually turns out to <a href="http://encosia.com/a-harsh-reminder-about-the-importance-of-debug-false/">maybe not make such a big difference</a> after all). <strong>This will not prevent <code>.aspx</code>, <code>.ascx</code> and other WebForms-files from working</strong>.</p>
<p><strong>But you still want your <code>.ascx</code>-files to work inline in your MVC Razor-views.</strong> This can be achieved by implementing your own <code>class</code> that inherits <a href="https://msdn.microsoft.com/en-us/library/system.web.mvc.razorviewengine.aspx">RazorViewEngine</a>, which <strong>only uses the <a href="https://msdn.microsoft.com/en-us/library/system.web.mvc.webformviewengine.aspx">WebFormViewEngine</a> when actually needed</strong>.</p>
<h1><code>Global.asax</code> (or other config-<code>class</code>)</h1>
<pre><code class="language-csharp">// Remove WebFormViewEngine (and RazorViewEngine)
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new CustomRazorViewEngine());
</code></pre>
<h1><code>CustomRazorViewEngine : System.Web.Mvc.RazorViewEngine</code></h1>
<pre><code class="language-csharp">private static readonly WebFormViewEngine WebFormsEngine = new WebFormViewEngine();

public override ViewEngineResult FindPartialView(
    ControllerContext context, string name, bool useCache)
{
    if (name.EndsWith(".ascx"))
    {
        return WebFormsEngine.FindPartialView(context, name, useCache);
    }

    return base.FindPartialView(context, name, useCache);
}
</code></pre>
<p>If you need the actual <code>class</code> of the control to do some further analysis/manipulation, you can do the following <strong>anywhere in your code</strong>:</p>
<pre><code class="language-csharp">var viewPage = new ViewPage();
var control = viewPage.LoadControl("~/Controls/ControlVirtualPath.ascx") as ControlType;
</code></pre>]]></content:encoded>
      <pubDate>Tue, 11 Mar 2014 07:48:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Razor</category>
    </item>
    <item>
      <title>Serialize HtmlString &amp; MvcHtmlString in JSON.NET</title>
      <link>https://sebnilsson.com/blog/serialize-htmlstring-mvchtmlstring-in-json-net</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/serialize-htmlstring-mvchtmlstring-in-json-net</guid>
      <description>Serialize and deserialize HtmlString and MvcHtmlString values in JSON.NET by implementing a custom JsonConverter.</description>
      <content:encoded><![CDATA[<p>The <a href="https://msdn.microsoft.com/en-us/library/system.web.htmlstring.aspx"><code>HtmlString</code></a>-class (and <a href="https://msdn.microsoft.com/en-us/library/system.web.mvc.mvchtmlstring.aspx"><code>MvcHtmlString</code></a>) that is and has been used in the ASP.NET-platform, including <a href="https://www.asp.net/web-pages">WebPages</a>, since the introduction of <a href="https://www.asp.net/mvc">ASP.NET MVC</a> is basically just a <strong>wrapped string, that doesn't gets automatically <a href="https://en.wikipedia.org/wiki/Character_encodings_in_HTML">HTML-encoded</a></strong> when used in Razor-views. Despite this fact, if you want to serialize or deserialize this object in <a href="http://james.newtonking.com/json">JSON.NET</a> it will come back as <code>null</code>.</p>
<p>To be able to <strong>serialize an object containing a property of a type inheriting from <code>IHtmlString</code></strong>, like <code>HtmlString</code> and <code>MvcHtmlString</code>, to then, for instance, cache the serialized object, you need to implement your own <a href="http://james.newtonking.com/json/help/index.html?topic=html/AllMembers_T_Newtonsoft_Json_JsonConverter.htm"><code>Newtonsoft.Json.JsonConverter</code></a> that handles the serialization and deserialization.</p>
<h1><code>HtmlStringConverter : Newtonsoft.Json.JsonConverter</code></h1>
<pre><code class="language-csharp">public override bool CanConvert(Type objectType)
{
    return typeof(IHtmlString).IsAssignableFrom(objectType);
}

public override object ReadJson(
    JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
    var value = reader.Value as string;
    // Specifically MvcHtmlString
    if (objectType == typeof(MvcHtmlString))
    {
        return new MvcHtmlString(value);
    }
    // Generally HtmlString
    if (objectType == typeof(HtmlString))
    {
        return new HtmlString(value);
    }

    // Fallback for other (future?) implementations of IHtmlString
    return Activator.CreateInstance(objectType, value);
}

public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
    var htmlString = value as HtmlString;
    if (htmlString == null)
    {
        return;
    }

    writer.WriteValue(htmlString.ToString());
}
</code></pre>
<p>You then have to register this Converter in your <a href="http://james.newtonking.com/json/help/index.html?topic=html/AllMembers_T_Newtonsoft_Json_JsonSerializerSettings.htm"><code>JsonSerializerSettings</code></a> like this:</p>
<pre><code class="language-csharp">CurrentConverter.Converters.Add(new HtmlStringConverter());
</code></pre>]]></content:encoded>
      <pubDate>Sun, 02 Mar 2014 17:44:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>Rewrite Old URLs with Regex into RouteValueDictionary</title>
      <link>https://sebnilsson.com/blog/rewrite-old-urls-with-regex-into-routevaluedictionary</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/rewrite-old-urls-with-regex-into-routevaluedictionary</guid>
      <description>Convert named Regex groups from legacy URLs into an ASP.NET RouteValueDictionary for clean redirects and rewrites.</description>
      <content:encoded><![CDATA[<p>Have you ever needed to rewrite/redirect old URLs that have very similar pattern as your new, modern URLs, but want to do it with simple, maintainable code?</p>
<p>In the following URL you very specifically can see an <code>ID</code>-value and a potential <code>Category</code>-value.</p>
<pre><code>http://test.com/products/details.aspx?id=123&#x26;category=tea-cups
</code></pre>
<p>So you probably want to use Regex and point out named groups in above URL.</p>
<pre><code>^(?:.*)\/?products\/details\.aspx\?id=(?&#x3C;id>[\d]*)(&#x26;category=(?&#x3C;category>[^&#x26;]*))?
</code></pre>
<p>Then you want to get those named values into a <code>RouteValueDictionary</code>, with above named <code>Key</code>s, like <code>&#x3C;id></code> and <code>&#x3C;category></code> with the Regex-matched <code>Value</code>s in the URL. You can then, for example, send it to a <code>UrlHelper</code>. This is what the following method does:</p>
<pre><code class="language-csharp">public static RouteValueDictionary GetRegexRouteValues(string url, string urlPattern)
{
    if (url == null)
    {
        throw new ArgumentNullException("url");
    }
    if (urlPattern == null)
    {
        throw new ArgumentNullException("urlPattern");
    }

    var regex = new Regex(urlPattern);
    var match = regex.Match(url);
    if (!match.Success)
    {
        return null;
    }

    var namedGroupNames = regex.GetGroupNames().Where(x => x != null &#x26;&#x26; !Regex.IsMatch(x, @"^[0-9]+$"));
    var groups = (from groupName in namedGroupNames
                  let groupItem = match.Groups[groupName]
                  where groupItem != null
                  select new KeyValuePair&#x3C;string, string>(groupName, groupItem.Value)).ToList();

    var routeValues = new RouteValueDictionary();
    groups.ForEach(x => routeValues.Add(x.Key, x.Value));

    return routeValues;
}
</code></pre>
<p>Now you can write code that is more easy to read and maintain to redirect specific URLs:</p>
<pre><code class="language-csharp">private static void RedirectProductDetails(string requestUrl) {
    string urlRegex = @"^(?:.*)\/?products\/details\.aspx\?id=(?&#x3C;id>[\d]*)(&#x26;category=(?&#x3C;category>[^&#x26;]*))?";
    var routeValues = GetRegexRouteValues(requestUrl, urlRegex);

    routeValues["controller"] = "Products";
    routeValues["action"] = "Details";
    return this.Url.RouteUrl(routeValues);
}
</code></pre>]]></content:encoded>
      <pubDate>Fri, 28 Feb 2014 07:53:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>ViewSource - View Source in Mobile Browsers</title>
      <link>https://sebnilsson.com/blog/viewsource-view-source-in-mobile-browsers</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/viewsource-view-source-in-mobile-browsers</guid>
      <description>Introducing ViewSource, a web app for inspecting a website&apos;s HTML, CSS, and JavaScript source from mobile browsers.</description>
      <content:encoded><![CDATA[<p>Here's another small app <a href="/blog/tags/projects">that I created</a> to play around with some code, but mostly because I felt I had a need for it.</p>
<p><a href="http://viewsource.apphb.com/">ViewSource</a> is an app for viewing the HTML-source of any website <strong>from your web-browser</strong>. Which enables you to <strong>view source from mobile browsers</strong>.</p>
<p><img src="https://lh3.googleusercontent.com/--n83Ps9TqCI/UUiLuIiCl8I/AAAAAAAAAW0/AFK_kq07J_Y/s282/viewsource-screenshot.png" alt="ViewSource Screenshot"></p>
<p>Just enter any URL and view the HTML-source. You also get <strong>a list of CSS-files and JavaScript-files</strong>, which you can view the source of, instantly in your browser.</p>
<p>You can quickly reach the app through <a href="https://bit.ly/vsource">bit.ly/vsource</a>.</p>
<h1>Fork on GitHub</h1>
<p>As always, <a href="https://github.com/sebnilsson/ViewSource">the source is available on GitHub</a> for forking.</p>]]></content:encoded>
      <pubDate>Mon, 25 Mar 2013 06:47:00 GMT</pubDate>
      <category>Projects</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>IIS URL Rewrite-Rules Skipping Files-types</title>
      <link>https://sebnilsson.com/blog/iis-url-rewrite-rules-skipping-files-types</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/iis-url-rewrite-rules-skipping-files-types</guid>
      <description>Configure IIS URL Rewrite rules to skip selected file extensions, physical files, and directories.</description>
      <content:encoded><![CDATA[<p>If you need to put in a rule for the <a href="http://www.iis.net/downloads/microsoft/url-rewrite">IIS URL Rewrite Module</a>, but need the rule to <strong>skip some file-endings</strong> and/or targets that are <strong>directories</strong> or actual <strong>files on disk</strong>, this is the post for you.</p>
<p><img src="https://lh3.googleusercontent.com/-j9iVvBhMSpc/UUiFxNJntcI/AAAAAAAAAWs/Dbr5oGozpKs/s250/iis-welcome.png" alt="IIS Welcome"></p>
<p>Following some <a href="http://www.mattcutts.com/blog/seo-advice-url-canonicalization/">SEO best-practices that tells us to use trailing slashes on our URLs</a> I used the IIS Manager and added the IIS URL Rewrite-module's built-in rule "<em>Append or remove the trailing slash symbol</em>", which creates the following rule:</p>
<pre><code class="language-xml"> &#x3C;rule name="Add trailing slash" stopProcessing="true">
  &#x3C;match url="(.*[^/])$" />
  &#x3C;conditions>
    &#x3C;add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
    &#x3C;add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
  &#x3C;/conditions>
  &#x3C;action type="Redirect" redirectType="Permanent" url="{R:1}/" />
&#x3C;/rule>
</code></pre>
<p>This rule takes into account and doesn't apply the rule to <strong>files and directories that exists on disk</strong>. But there is <strong>a big problem with this generic rule</strong>.</p>
<p>If you are dynamically serving up files with extensions, then an URL like:</p>
<pre><code>http://website.com/about.html
</code></pre>
<p>will become:</p>
<pre><code>http://website.com/about.html/
</code></pre>
<h1>Adding conditions for specific file-endings</h1>
<p>To solve this you can add conditions for certain file-endings, like <code>.html</code> and <code>.aspx</code>:</p>
<pre><code class="language-xml">&#x3C;conditions>
  &#x3C;!-- ... -->
  &#x3C;add input="{REQUEST_FILENAME}" pattern="(.*?)\.html$" negate="true" />
  &#x3C;add input="{REQUEST_FILENAME}" pattern="(.*?)\.aspx$" negate="true" />
&#x3C;/conditions>
</code></pre>
<p>Since the rules above already don't apply for files physically on disk, you don't need to add file-endings like <code>.css</code>, <code>.png</code> or <code>.js</code>.</p>
<h1>Update: Match ANY file-ending</h1>
<p>If you want to match just any file-ending at all, you use the following pattern:</p>
<pre><code class="language-xml">&#x3C;conditions>
  &#x3C;!-- ... -->
  &#x3C;add input="{URL}" pattern=".*/[^.]*\.[\d\w]+$" negate="true" />
&#x3C;/conditions>
</code></pre>]]></content:encoded>
      <pubDate>Tue, 19 Mar 2013 18:44:00 GMT</pubDate>
      <category>ASP.NET</category>
      <category>SEO</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>ASP.NET: Transform Web.config with Debug/Release on Build</title>
      <link>https://sebnilsson.com/blog/asp-net-transform-web-config-with-debug-release-on-build</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-transform-web-config-with-debug-release-on-build</guid>
      <description>Automatically transform an ASP.NET Web.config for the active Debug or Release configuration whenever the project builds.</description>
      <content:encoded><![CDATA[<p>Did you ever wish you could run your web application with the <code>Web.config</code> <strong>being transformed according to the current Solution Configuration for Debug or Release</strong> directly from Visual Studio? Well, with some <em>pre-build-magic</em> we can do this.</p>
<p><img src="https://lh3.googleusercontent.com/-1nzx25BqcmY/USTZ6QdUIuI/AAAAAAAAAVs/SRTs0kQHvUM/s249/web_config.png" alt="Web.config Transformation"></p>
<h1>Files in project</h1>
<p>Create a file named <code>Web.Base.config</code>, besides the existing <code>Web.Debug.config</code> and <code>Web.Release.config</code>. This file will be the equivalent to your old <code>Web.config</code>, as it will be the base for the tranformation. You will end up with these files:</p>
<ul>
<li><code>Web.config</code></li>
<li><code>Web.Base.config</code></li>
<li><code>Web.Debug.config</code></li>
<li><code>Web.Release.config</code></li>
</ul>
<h1>Web.config</h1>
<p>Add the following configuration to the bottom of your <code>.csproj</code>-file, just before the closing <code>&#x3C;/Project></code>-tag:</p>
<pre><code class="language-xml">&#x3C;Import Project="$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\WebApplications\Microsoft.WebApplication.targets" />
&#x3C;Target Name="BeforeBuild">
    &#x3C;TransformXml Source="Web.Base.config" Transform="Web.$(Configuration).config" Destination="Web.config" />
&#x3C;/Target>
</code></pre>
<p><strong>UPDATE:</strong> From a reminder in the comments I realized that I also have a problem with Visual Studio <strong>transforming the XML twice, when Publishing a project</strong>. The solution to this is to add a <code>Condition</code> to the <code>Target</code>-tag like this:</p>
<pre><code class="language-xml">&#x3C;Target Name="BeforeBuild" Condition="'$(PublishProfileName)' == '' And '$(WebPublishProfileFile)' == ''">
</code></pre>
<p>You can now <strong>build, run your project or publish</strong> it all depending on what <em>Solution Configuration</em> you have selected. <em>Debug</em> or <em>Release</em>. <strong>Just press your CTRL+SHIFT+B</strong> and see the <code>Web.config</code>-file be transformed.</p>
<h1>Version control</h1>
<p><strong>I recommend that you leave <code>Web.config</code> out of your Version Control</strong>. This solution for transforming the <code>Web.config</code> on the fly would mean that this specific file would constantly be modified and if one person is working with <em>Debug</em> and another person is working with <em>Release</em> the <code>Web.config</code> would probably get big changes constantly.</p>
<h1>Testing-tool</h1>
<p>The people over at <a href="https://elmah.io/">elmah.io</a> has created the <a href="https://elmah.io/tools/webconfig-transformation-tester/">Web.config Transformation Tester</a>, where you can try out what the result will be of combining a <code>Web.config</code>-file with a transformation.</p>
<p>The tool can even show you what the diff from the original file is when the transformation is applied.</p>]]></content:encoded>
      <pubDate>Wed, 20 Feb 2013 18:10:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Deployment</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <title>MVC: Get Current Action and Controller in View</title>
      <link>https://sebnilsson.com/blog/mvc-get-current-action-and-controller-in-view</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/mvc-get-current-action-and-controller-in-view</guid>
      <description>Retrieve the current controller and action names inside an ASP.NET MVC view or shared layout.</description>
      <content:encoded><![CDATA[<p>Have you ever needed to know what <code>Action</code> and/or <code>Controller</code> that is currently used in your <code>View</code>? This might be <strong>most helpful in an <code>Layout</code>-file, used by another <code>View</code></strong>.</p>
<pre><code class="language-csharp">string currentAction =
    ViewContext.Controller.ValueProvider.GetValue("action").RawValue.ToString();
string currentController =
    ViewContext.Controller.ValueProvider.GetValue("controller").RawValue).ToString();
</code></pre>
<p>Then you can do customization code like this in your <code>_Layout.cshtml</code>-file.</p>
<pre><code class="language-csharp">bool isIndexPage = currentAction.Equals("index", StringComparison.InvariantCultureIgnoreCase)
    &#x26;&#x26; currentController.Equals("blog", StringComparison.InvariantCultureIgnoreCase);
</code></pre>
<p><em><strong>Disclaimer:</strong> Of course this breaks the fundamental rules of <a href="https://en.wikipedia.org/wiki/Separation_of_concerns">separation of concerns</a> in MVC, between the <code>View</code> and the <code>Controller</code>, but sometimes you just don't want, or can, pass around sufficient data between the <code>View</code> and the <code>Controller</code>.</em></p>]]></content:encoded>
      <pubDate>Wed, 23 Jan 2013 20:31:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
    </item>
    <item>
      <title>Create Human-Readable File Size Strings in C#</title>
      <link>https://sebnilsson.com/blog/create-human-readable-file-size-strings-in-c</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/create-human-readable-file-size-strings-in-c</guid>
      <description>Format byte counts as compact, human-readable file sizes in C# with a simple cross-platform extension method.</description>
      <content:encoded><![CDATA[<p>After needing functionality in C# for getting a <strong>human-readable file-size string</strong> I posted <a href="https://stackoverflow.com/questions/128618/c-file-size-format-provider">a question about it on Stackoverflow</a>, as one does.</p>
<p><a href="https://stackoverflow.com/a/128683/2429">The accepted answer</a> had about <strong>72 lines of code</strong>. One explanation for this could be that <em>I did specify that I wanted the solution to implement <a href="https://msdn.microsoft.com/library/system.iformatprovider.aspx">IFormatProvider</a></em>. Not sure why I did that, probably seemed right at the time, in the end of 2008.</p>
<p><a href="https://stackoverflow.com/a/129110/2429">One creative solution was to use a Win32 API call</a> to <a href="https://msdn.microsoft.com/library/bb759974.aspx">StrFormatByteSizeA</a></p>
<pre><code class="language-csharp">[DllImport("Shlwapi.dll", CharSet = CharSet.Auto)]
    public static extern long StrFormatByteSize(long fileSize, [MarshalAs(UnmanagedType.LPTStr)] StringBuilder buffer, int bufferSize);
</code></pre>
<h1>Compact, clean, cross-platform solution</h1>
<p>For the sake of simplicity, readability and <em>the bonus of cross-platform</em> I re-implemented an earlier solution I found, that was written in JavaScript. But <strong>the solution was easily translateble into C#</strong>.</p>
<pre><code class="language-csharp">public static class FileSizeHelper
{
    private static readonly string[] Units = { "B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" };

    private static string GetReadableFileSize(long size) // Size in bytes
    {
        int unitIndex = 0;
        while (size >= 1024)
        {
            size /= 1024;
            ++unitIndex;
        }

        string unit = Units[unitIndex];
        return string.Format("{0:0.#} {1}", size, unit);
    }
}
</code></pre>]]></content:encoded>
      <pubDate>Wed, 16 Jan 2013 18:23:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>FTP Upload File Using Only .NET Framework</title>
      <link>https://sebnilsson.com/blog/ftp-upload-file-using-only-net-framework</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/ftp-upload-file-using-only-net-framework</guid>
      <description>Upload a file to an FTP server using only the .NET Framework&apos;s built-in FtpWebRequest class.</description>
      <content:encoded><![CDATA[<p>Here an example of how to upload a file to a FTP-server, using the class <a href="https://msdn.microsoft.com/library/system.net.ftpwebrequest.aspx"><code>FtpWebRequest</code></a>, <strong>which is included in the .NET Framework</strong>.</p>
<pre><code class="language-csharp">string ftpPath = string.Format("ftp://{0}/{1}", urlOrIpNumber, filePath);
FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpPath);
request.Method = WebRequestMethods.Ftp.UploadFile;
request.Credentials = new NetworkCredential (userName, password);

byte[] fileContents = GetFileContent();
request.ContentLength = fileContents.Length;

using(var requestStream = request.GetRequestStream())
{
    requestStream.Write(fileContents, 0, fileContents.Length);
    requestStream.Close();
}
</code></pre>
<p>All you need to do is reference the <code>System.Net</code> namespace.</p>
<h1>Update: Shorter code version</h1>
<p>This code comes from <a href="http://madskristensen.net/post/Simple-FTP-file-upload-in-C-20.aspx">Mads Kristensen</a>, <strong>written in the middle of 2006</strong>.</p>
<pre><code class="language-csharp">private static void Upload(string ftpServer, string userName, string password, string filename)
{
   using (var client = new WebClient())
   {
      client.Credentials = new NetworkCredential(userName, password);
      client.UploadFile(ftpServer + "/" + new FileInfo(filename).Name, "STOR", filename);
   }
}
</code></pre>
<p>I'm not sure if there are <strong>any scenarios that this code doesn't work with</strong>.</p>]]></content:encoded>
      <pubDate>Thu, 10 Jan 2013 19:18:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>Squishify - Minify JavaScript &amp; CSS Online</title>
      <link>https://sebnilsson.com/blog/squishify-minify-javascript-css-online</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/squishify-minify-javascript-css-online</guid>
      <description>An introduction to Squishify, an ASP.NET MVC web app for quickly minifying JavaScript and CSS online with SquishIt.</description>
      <content:encoded><![CDATA[<p><a href="http://squishify.apphb.com/">Squishify</a> was created out of the need of a <a href="https://en.wikipedia.org/wiki/Minification_(programming)#Web_development">minifier</a> for JavaScript. I quickly put together a web-app on <a href="https://www.appharbor.com">AppHarbor</a> to make minification always available quickly. The code is <a href="https://github.com/sebnilsson/Squishify">hosted on GitHub</a>.</p>
<p><img src="https://lh3.googleusercontent.com/-iASSd0ZSfVM/UH67cjIiouI/AAAAAAAAASI/JGPnKlag7G8/s576/squishify_screenshot.png" alt="Squishify Screenshot"></p>
<p>The application is an ASP.NET MVC-app, using <a href="http://www.codethinked.com/squishit-the-friendly-aspnet-javascript-and-css-squisher">Justin Etheredge's framework</a> for minification called <a href="https://github.com/jetheredge/SquishIt">SquishIt</a>. The app also uses <a href="https://www.asp.net/web-api">ASP.NET Web API</a> together with some simple <a href="https://jquery.com/">jQuery</a> to display the results of the minifications without any page-reloads.</p>
<p>The SquishIt-framework is a very easy to use and provides multiple minifiers for both JavaScript and CSS.</p>
<p>JavaScript minifiers:</p>
<ul>
<li><a href="https://developers.google.com/closure/">Google Closure</a>*</li>
<li><a href="http://www.crockford.com/javascript/jsmin.html">Douglas Crockford's JsMin</a></li>
<li><a href="https://ajaxmin.codeplex.com/">Microsoft Ajax Minifier</a></li>
<li><a href="https://developer.yahoo.com/yui/compressor/">Yahoo's YUI Compressor</a></li>
</ul>
<p><em>* At the moment of writing this post, Google Closure is not working as expected.</em></p>
<p>CSS minifiers:</p>
<ul>
<li><a href="https://ajaxmin.codeplex.com/">Microsoft Ajax Minifier</a></li>
<li><a href="https://developer.yahoo.com/yui/compressor/">Yahoo's YUI Compressor</a></li>
</ul>
<p>Enjoy it at <a href="http://squishify.apphb.com/">squishify.apphb.com</a> and <a href="https://github.com/sebnilsson/Squishify">fork it on GitHub</a>.</p>]]></content:encoded>
      <pubDate>Thu, 30 Aug 2012 18:08:00 GMT</pubDate>
      <category>JavaScript</category>
      <category>Projects</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>ASP.NET MVC 4 Razor v2 - New Features</title>
      <link>https://sebnilsson.com/blog/asp-net-mvc-4-razor-v2-new-features</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-mvc-4-razor-v2-new-features</guid>
      <description>Learn the key Razor v2 improvements in ASP.NET MVC 4, including app-relative URLs, conditional attributes, and unclosed HTML tags.</description>
      <content:encoded><![CDATA[<p>With the imminent release of ASP.NET MVC 4 my previous post <a href="http://www.sebnilsson.com/blog/2012/3/21/aspnet-mvc-3-razor-the-ultimate-quick-reference.html">ASP.NET MVC 3 Razor - The Ultimate Quick Reference</a> needed a follow-up on <strong>what's new in the view-engine Razor v2</strong>, that comes with MVC 4.</p>
<p><img src="https://lh3.googleusercontent.com/-40bwv8UgY70/UH67b-z1GSI/AAAAAAAAARw/KqKTXg1rp9M/s200/reference_dictionary_bw.png" alt="Reference"></p>
<h1>App-relative URLs automatically resolved</h1>
<p>In Razor v1 your views would be littered with code like this:</p>
<pre><code class="language-html">&#x3C;script src\="@Url.Content("~/content/scripts.js")"\>&#x3C;/script>
</code></pre>
<p>But in Razor v2 you can shorten it with a <em>tilde</em> in front of the URL, which was used a lot in WebForms:</p>
<pre><code class="language-html">&#x3C;script src\="~/content/scripts.js"\>&#x3C;/script>
</code></pre>
<p>This will work for <strong>any HTML-attribute</strong> that <strong>starts with</strong> the <em>title</em>-sign.</p>
<h1>Conditional attributes hides null-valued attributes</h1>
<p>Razor v1 treated null-valued attributes as empty string, writing out attributes empty values. Razor v2 will instead skip even writing out the attribute that has a null value:</p>
<pre><code class="language-csharp">@{ string itemId \= string.Empty; string itemClass \= "class-of-item"; string itemValue \= null; } &#x3C;div id\="@itemId" class\="@itemClass @itemValue" rel\="@itemValue"\>&#x3C;/div\>
</code></pre>
<p>Will result in this HTML:</p>
<pre><code class="language-html">&#x3C;div id\="" class\="class-of-item"\>&#x3C;/div>
</code></pre>
<p>Note that <code>string.Empty</code> still makes Razor v2 to write out the attribute. Any <code>data-</code>attribute will <strong>ignore this rule and always write out the attribute</strong>.</p>
<h1>Support for unclosed HTML-tags</h1>
<p>The HTML5-specs clearly states that unclosed HTML-tags are supported, but Razor v1 didn't have an advanced enough parser to support this. Razor v2 now supports this with the elements listed in <a href="https://dev.w3.org/html5/markup/syntax.html#syntax-elements">W3C's spec</a>.</p>
<h1>What else?</h1>
<p>There has been some major improvements on how the syntax-trees are structured and other deep functionality in the language. The focus was <a href="http://vibrantcode.com/blog/2012/4/13/what-else-is-new-in-razor-v2.html/">internal clean-up and future-proofing</a>.</p>]]></content:encoded>
      <pubDate>Mon, 21 May 2012 17:55:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Razor</category>
    </item>
    <item>
      <title>DevSum Scheduler - Plan Your Attendance</title>
      <link>https://sebnilsson.com/blog/devsum-scheduler-plan-your-attendance</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/devsum-scheduler-plan-your-attendance</guid>
      <description>Introducing DevSum Scheduler, a mobile-friendly web app for selecting conference talks and saving an attendance plan locally.</description>
      <content:encoded><![CDATA[<p>Since I'm attending <a href="http://devsum.se/">DevSum 2012</a> at the end of this month, I felt I needed to keep track of which talks to attend... but also the need to play around with some web-technologies.</p>
<p><a href="http://devsum.se/"><img src="https://lh3.googleusercontent.com/-Nt4-_V8N9mQ/UH67U1wt8ZI/AAAAAAAAAPY/-q_FOj6-sMw/s183/devsum2012.png" alt="DevSum 2012"></a></p>
<p>From those needs I took some evening hours to build <a href="http://devsumscheduler.apphb.com/about">DevSum Scheduler</a>. It's a web-app that allows you to <strong>highlight which talks you're going to attend</strong>.</p>
<p>The app uses <a href="https://htmlagilitypack.codeplex.com/">HTML Agility Pack</a> to get the data from DevSum's own website and then <a href="https://www.asp.net/mvc">ASP.NET MVC Razor</a> to display the content properly. To store this I've used <a href="https://www.w3.org/TR/webstorage/">HTML 5 LocalStorage</a> to persist the choices made.</p>
<p>There are many other technologies used, which are listed on the <a href="http://devsumscheduler.apphb.com/about">about-page</a>. Since <strong>the website is suppose to help the attendees by being available on their smart-phones</strong>, I've used CSS Media Queries for mobile layout and Modernizr for feature-detection in the web-browser.</p>
<p>Check out the full <a href="https://github.com/sebnilsson/DevSumScheduler">source-code on GitHub</a>. Again, the outstanding <a href="http://devsumscheduler.apphb.com/">AppHarbour</a> has been used to quickly get the app on the Internet (through a GitHub-service hook of course).</p>]]></content:encoded>
      <pubDate>Mon, 14 May 2012 21:39:00 GMT</pubDate>
      <category>Projects</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>Making MVC 3 Razor IntelliSense work after installing MVC 4 Beta</title>
      <link>https://sebnilsson.com/blog/making-mvc-3-razor-intellisense-work-after-installing-mvc-4-beta</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/making-mvc-3-razor-intellisense-work-after-installing-mvc-4-beta</guid>
      <description>Restore Razor IntelliSense in ASP.NET MVC 3 projects after installing the MVC 4 Beta by explicitly setting assembly versions.</description>
      <content:encoded><![CDATA[<p>After installing the MVC 4 Beta the IntelliSense breaks for Razor-views in MVC 3-applications in Visual Studio 2010. <a href="https://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253815">This is stated in the release-notes</a>, but nobody usually reads those.</p>
<p><img src="https://lh4.googleusercontent.com/-4sVNXbSXtTk/UH67Wh7DZwI/AAAAAAAAAP8/5KLL7Ei04Iw/s108/aspnet_logo.png" alt="ASP.NET"></p>
<p>This time the solution to the problem are actually listed in those release-notes. You need to the <strong>explicitly state the version-numbers</strong> of the references in your <em>web.config</em>.</p>
<p>Add a new <code>appSettings</code>-entry for explicitly stating the version of WebPages to use:</p>
<pre><code class="language-xml">&#x3C;appSettings> &#x3C;add key\="webpages:Version" value\="1.0.0.0"/> &#x3C;!-- ... --> &#x3C;/appSettings>
</code></pre>
<p>Then you have to edit your <em>.csproj</em>-file, where you need to find your references to <code>System.Web.WebPages</code> and <code>System.Web.Helpers</code> and makes sure they have the explicit version-numbers like this:</p>
<pre><code class="language-xml">&#x3C;Reference Include\="System.Web.WebPages, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL"/> &#x3C;Reference Include\="System.Web.Helpers, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35, processorArchitecture=MSIL" />
</code></pre>
<p>Hopefully this will be resolved in the final version of MVC 4 or maybe the case is that <strong>the references to versions in Razor v1 were just too loose in MVC 3-projects</strong>.</p>]]></content:encoded>
      <pubDate>Wed, 18 Apr 2012 08:05:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Razor</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <title>HtmlEncoder - Testing out MVC 4 on AppHarbor &amp; GitHub</title>
      <link>https://sebnilsson.com/blog/htmlencoder-testing-out-mvc-4-on-appharbor-github</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/htmlencoder-testing-out-mvc-4-on-appharbor-github</guid>
      <description>A look at building and deploying HtmlEncoder as an ASP.NET MVC 4 and Web API app using GitHub and AppHarbor.</description>
      <content:encoded><![CDATA[<p><a href="http://htmlencoder.apphb.com">HtmlEncoder</a> is a web-application built on <a href="https://www.asp.net/mvc/mvc4">ASP.NET MVC 4</a>, source-controlled on <a href="https://github.com/sebnilsson/HtmlEncoder">GitHub</a>, deployed on <a href="http://htmlencoder.apphb.com">AppHarbor</a>.</p>
<p><img src="https://lh3.googleusercontent.com/-G08CpgVymWQ/UH67UOEYHQI/AAAAAAAAAPU/tzH8qKWuPfc/s130/aspnet_apphb_github.png" alt="ASP.NET, AppHarbor, GitHub"></p>
<p><a href="https://github.com/blog/961-deploy-to-appharbor-from-github">GitHub allows you to directly deploy to AppHarbor</a> on checkin/push to the Git-repository, which is a very powerful and useful feature, to quickly get your ASP.NET web-apps online in the cloud.</p>
<p>It started out with a need to encode strings for HTML and developed into a quick test of how <a href="https://weblogs.asp.net/jgalloway/archive/2012/02/16/asp-net-4-beta-released.aspx">Web API on MVC 4</a> works in an AJAX-enabled web-app.</p>
<p>Try it out at <a href="http://htmlencoder.apphb.com">http://htmlencoder.apphb.com</a> and <a href="https://github.com/sebnilsson/HtmlEncoder">fork it on GitHub</a>.</p>]]></content:encoded>
      <pubDate>Fri, 23 Mar 2012 10:36:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Projects</category>
    </item>
    <item>
      <title>ASP.NET MVC 3 Razor - The Ultimate Quick Reference</title>
      <link>https://sebnilsson.com/blog/asp-net-mvc-3-razor-the-ultimate-quick-reference</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-mvc-3-razor-the-ultimate-quick-reference</guid>
      <description>A comprehensive ASP.NET MVC 3 Razor syntax reference covering layouts, sections, models, inline code, helpers, and namespaces.</description>
      <content:encoded><![CDATA[<p>With the transition to the <a href="https://www.asp.net/mvc/mvc3">Razor view-engine in ASP.NET MVC 3</a> a need occurred for a quick-reference.</p>
<p><img src="https://lh6.googleusercontent.com/-Id7MlNJoFuI/UH67b-UAywI/AAAAAAAAAR0/clSFjw4NBPQ/s200/reference_dictionary.png" alt="Reference"></p>
<h1>Sections - Replacement for <code>asp:ContentPlaceHolder</code> and <code>asp:Content</code></h1>
<p>Where you the old WebForms view-engine used to use the controls and to <strong>dynamically switch out parts of the content on a page</strong>, <a href="https://weblogs.asp.net/scottgu/archive/2010/12/30/asp-net-mvc-3-layouts-and-sections-with-razor.aspx">the Razor view-engine uses sections</a>.</p>
<p><code>_Layout.cshtml</code> (Equivalent to a <code>.master</code>-page):</p>
<pre><code class="language-html">&#x3C;div>Template content&#x3C;/div>
@RenderBody()
&#x3C;div>More template content&#x3C;/div>
@RenderSection("OtherContent", required: false)
</code></pre>
<p><code>Page.cshtml</code>:</p>
<pre><code class="language-html">@section OtherContent {
    &#x3C;span>Other content goes here&#x3C;/span>
}
&#x3C;div>Main page-content&#x3C;/div>
</code></pre>
<p>In above code the <code>RenderSection</code>-method in the <code>_Layout.cshtml</code> renders the content within the matching <code>@section</code> in the <code>Page.cshtml</code>. The <code>required</code>-parameter indicates if the section is required and should throw an exception if the section doesn't exist. The <code>RenderBody</code>-method renders the rest of the content in the <code>Page.cshtml</code>, which is not inside any section.</p>
<h1>Declaring the ViewModel</h1>
<p>In the old WebForms view-engine your declaration of the view-model would look like something like this:</p>
<pre><code>&#x3C;%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
    Inherits="System.Web.Mvc.ViewPage&#x3C;MyViewModel>" %>
</code></pre>
<p>While <a href="https://weblogs.asp.net/scottgu/archive/2010/10/19/asp-net-mvc-3-new-model-directive-support-in-razor.aspx">in the Razor view-engine declaring your view-model is as easy as this</a>:</p>
<pre><code>@model MyViewModel
</code></pre>
<h1>Inline C#-code in the HTML</h1>
<p>If you wanted to loop over a collection in your view-model in WebForms view-engine your code would look something like this:</p>
<pre><code>&#x3C;% foreach(var item in Model.Items) { %>
    &#x3C;% if(item.IsValid()) { %>
        &#x3C;div class="&#x3C;%: item.ClassName %>">&#x26;;lt;%: item.Title %>&#x3C;/div>
    &#x3C;% } %>
&#x3C;% } %>
</code></pre>
<p>The percent-tags make it a bit hard to quickly get an overview of what is HTML and what is code. This is one of the largest upsides to the Razor view-engine, where the same code would be written much more readable like this:</p>
<pre><code>@foreach(var item in Model.Items) {
    if(item.IsValid())
    {
        &#x3C;div class="@item.ClassName">@item.Title&#x3C;/div>
    }
}
</code></pre>
<p>If you make a <a href="https://www.asp.net/mvc/mvc3">proper installation of MVC 3</a> you will get <strong>syntax-highlighting in Visual Studio for separating C#-code and HTML-tags</strong>.</p>
<h1>Advanced inline C#-code</h1>
<p>Razor is <a href="https://weblogs.asp.net/scottgu/archive/2010/12/16/asp-net-mvc-3-implicit-and-explicit-code-nuggets-with-razor.aspx">extremely intelligent when it comes to determining when code starts and ends</a> behind the @-signs, which is very well visualized by the IntelliSense in Visual Studio.</p>
<pre><code class="language-html">&#x3C;div>This is @Model.Name's page&#x3C;/div>
</code></pre>
<p>Since the apostrophe doesn't follow any pattern that could make it correct C#-code, Razor knows to cut the code from there.</p>
<p>If you want to be extra clear in your code, against other developers, but also against Razor, as to where the code starts and ends, you can use parentheses like this:</p>
<pre><code class="language-html">&#x3C;div>This is @(Model.Name)'s page and has the status "@(Model.Status)"!&#x3C;/div>
</code></pre>
<h1>Inline C#-code for logic</h1>
<p>You can include code on the page that is not necessarily written out on the page directly, but handles logic and page-specific functionality. For this you use the <code>@</code>-sign, followed by curly braces.</p>
<pre><code class="language-html">&#x3C;div>Other content&#x3C;/div>
@{
    string capitalizedTitle = Model.Title.ToUpper();
}
&#x3C;h1>Page about @capitalizedTitle&#x3C;/h1>
</code></pre>
<p>This is used in the templates that comes with MVC 3 to set which <code>Layout</code>-file to use. But you can use this on your own for setting the title-text in the <code>title</code>-tag.</p>
<p><code>Page.cshtml</code>:</p>
<pre><code class="language-csharp">@{  
    ViewBag.Title = "Index titel - " + Model.SubTitle;
}
</code></pre>
<p><code>\_Layout.cshtml</code>:</p>
<pre><code class="language-html">&#x3C;head>
    &#x3C;title>@ViewBag.Title&#x3C;/title>
    &#x3C;!-- ... -->
</code></pre>
<h1>Helpers - Reusing code specific to view-template</h1>
<p>With <a href="https://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx">the new @helper-syntax in Razor</a> you can easily write re-usable methods that deals with output-functionality within view-templates.</p>
<pre><code class="language-html">@helper ShowInfo(string name, bool hasContent) {
    if(hasContent) {
        &#x3C;div>This is info about @name.ToUpper()&#x3C;/div>
    }
}
</code></pre>
<h1>Namespaces</h1>
<p>Using a namespace is very easy and reminds us a lot of the old way to do it:</p>
<pre><code>@namespace System.ComponentModel.DataAnnotations
</code></pre>
<h1>Server-side comments</h1>
<p>To do <a href="https://weblogs.asp.net/scottgu/archive/2010/11/12/asp-net-mvc-3-server-side-comments-with-razor.aspx">server-side comments with Razor</a> you can click the "Comment" toolbar button or press Ctrl+K, Ctrl+C to apply a server-side comment. The commented code is place between a <code>@*</code> and a <code>*@</code> and looks like this:</p>
<pre><code class="language-html">@" This is the text of the model. MUST be HTML-encoded. "@
&#x3C;div class="special-elemet">@Model.Text&#x3C;/div>
</code></pre>
<h1>Global settings for view-templates</h1>
<p>If you place a file named <code>_ViewStart.cshtml</code> in the root of the <code>~/Views</code>-folder, the Razor-code in this code will be applied as default to all view-templates in the sub-folders. In the templates that comes with MVC 3 this is used to set the default Layout-file to be used for the view-templates.</p>
<pre><code>@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}
</code></pre>
<h1>Not HTML-encoding content</h1>
<p>In the old WebForms view-engine you could use a colon-character instead of an equals-sign to HTML-encode content like this:</p>
<pre><code>&#x3C;%= ContentToBeOutputWithoutEncoding %>  
&#x3C;%: ContentToBeEncoded %>
</code></pre>
<p>The Razor view-engine automatically HTML-encodes whatever strings you output without explicitly using <code>Html.Raw</code>-method like this:</p>
<pre><code>@Html.Raw(ContentToBeOutputWithoutEncoding)
</code></pre>
<h1>The <code>&#x3C;text></code>-tag for Razor</h1>
<p>The way Razor analyzes the code to find the start and end only makes it it possible to have one element (with multiple children of course) inside an expression. To resolve this <a href="https://weblogs.asp.net/scottgu/archive/2010/12/15/asp-net-mvc-3-razor-s-and-lt-text-gt-syntax.aspx">Razor introduces a <code>&#x3C;text></code>-tag</a>, where you can nest multiple lines of code:</p>
<pre><code class="language-html">&#x3C;text>
    &#x3C;div>One nested item&#x3C;/div>
    &#x3C;span>Another nested item&#x3C;/span>
&#x3C;/text>
</code></pre>]]></content:encoded>
      <pubDate>Wed, 21 Mar 2012 09:03:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Razor</category>
    </item>
    <item>
      <title>jMapMarker - jQuery-Plugin to Easily Add Google Maps with Markers to Your Website</title>
      <link>https://sebnilsson.com/blog/jmapmarker-jquery-plugin-to-easily-add-google-maps-with-markers-to-your-website</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/jmapmarker-jquery-plugin-to-easily-add-google-maps-with-markers-to-your-website</guid>
      <description>Use the jMapMarkers jQuery plugin to add configurable Google Maps, markers, and info windows to a website.</description>
      <content:encoded><![CDATA[<p>I just uploaded my new project called <a href="https://github.com/sebnilsson/jMapMarkers">jMapMarkers</a> to GitHub.</p>
<p><img src="https://lh3.googleusercontent.com/-17ANANJKqkI/UH67aZj_b4I/AAAAAAAAARM/vK9gf98KCCA/s242/jquery_logo.png" alt="jQuery"></p>
<p>It's a jQuery-plugin that easily allows the user to add one or more <strong>Google Maps-maps with markers</strong> and info-windows to the website.</p>
<p>It uses a simple <strong>object-literal as an argument for configuration</strong> when calling. To add a map to a <code>div</code>-tag with and ID, simple use the following code:</p>
<pre><code class="language-javascript">$('#map-placeholder').jMapMarkers({
    mapOptions: { // Straight Google Maps API-configuration
        zoom: 1,
        mapTypeId: google.maps.MapTypeId.ROADMAP,
        mapTypeControl: false
    },
    markers: [
        { lat: '59.329444', long: '18.068611', title: 'Stockholm', desc: 'Capital of Sweden' },
        { lat: '59.949444', long: '10.756389', title: 'Oslo', desc: 'Capital of Norway' }
    ]
});
</code></pre>
<p>You can even add on more markers after the initial map has been added. Just leave out the <code>mapOptions</code>-argument in the configurations-arguments, like this:</p>
<pre><code class="language-javascript">$('#map-placeholder').jMapMarkers({
    markers: [
        { lat: 52.500556, long: 13.398889, title: 'Berlin', desc: 'Capital of Germany' },
        { lat: 48.8567, long: 2.3508, title: 'Paris', desc: 'Capital of France' },
        { lat: 51.507222, long: -0.1275, title: 'London', desc: 'Capital of England' }
    ]
});
</code></pre>
<p>You can find examples in the <a href="https://github.com/sebnilsson/jMapMarkers/blob/master/demo.html">demo.html</a>-file in the GitHub-project.</p>
<p>A big bonus-feature is that if you don't state otherwise the plugin will <strong>automatically zoom and move the map so that all markers are visible</strong>, after markers are added to the map.</p>
<p>As it say in the GitHub-README: please feel free to fork and/or give feedback.</p>]]></content:encoded>
      <pubDate>Sun, 12 Feb 2012 20:05:00 GMT</pubDate>
      <category>Google Maps</category>
      <category>JavaScript</category>
      <category>Projects</category>
    </item>
    <item>
      <title>Microsoft Word Macro: Convert Word-files to PDF-files</title>
      <link>https://sebnilsson.com/blog/microsoft-word-macro-convert-word-files-to-pdf-files</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/microsoft-word-macro-convert-word-files-to-pdf-files</guid>
      <description>Use a Microsoft Word macro to batch-convert every Word document in a folder into a PDF file.</description>
      <content:encoded><![CDATA[<p>This post comes out of me helping a colleague with a quick macro, for Microsoft Office Word, that he needed to speed up service towards a customer.</p>
<p><img src="https://lh4.googleusercontent.com/-lPOKoW9y7XA/UH7F1-FSsPI/AAAAAAAAATM/imkHPiykXMQ/s66/word_macros.png" alt="Microsoft Word Macro"></p>
<p>I simply recorded a macro while converting one Word-file into a PDF-file and then Googled for some code to access files on disc and put it all together in a loop.</p>
<pre><code class="language-vb">Sub ConvertWordsToPdfs()

    Dim directory As String    
    directory = "C:\Wordup"
  
    Dim fso, newFile, folder, files
    Set fso = CreateObject("Scripting.FileSystemObject")
    
    Set folder = fso.GetFolder(directory)
    Set files = folder.files
    
    For Each file In files

        Dim newName As String
        newName = Replace(file.Path, ".doc", ".pdf")
                
        Documents.Open FileName:=file.Path, _
            ConfirmConversions:=False, ReadOnly:=False, AddToRecentFiles:=False, _
            PasswordDocument:="", PasswordTemplate:="", Revert:=False, _
            WritePasswordDocument:="", WritePasswordTemplate:="", Format:= _
            wdOpenFormatAuto, XMLTransform:=""
            
        ActiveDocument.ExportAsFixedFormat OutputFileName:=newName, _
            ExportFormat:=wdExportFormatPDF, OpenAfterExport:=False, OptimizeFor:= _
            wdExportOptimizeForPrint, Range:=wdExportAllDocument, From:=1, To:=1, _
            Item:=wdExportDocumentContent, IncludeDocProps:=True, KeepIRM:=True, _
            CreateBookmarks:=wdExportCreateNoBookmarks, DocStructureTags:=True, _
            BitmapMissingFonts:=True, UseISO19005_1:=False
        
        ActiveDocument.Close
      
    Next

End Sub
</code></pre>
<p>I guess I won't update or tune this macro a lot, but <a href="https://gist.github.com/1014112">you can find this macro as a Github Gist</a> as well.</p>]]></content:encoded>
      <pubDate>Tue, 27 Sep 2011 19:33:00 GMT</pubDate>
      <category>Productivity</category>
    </item>
    <item>
      <title>Language Localization with Google Maps API</title>
      <link>https://sebnilsson.com/blog/language-localization-with-google-maps-api</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/language-localization-with-google-maps-api</guid>
      <description>Control the language and regional localization used by the Google Maps JavaScript API on your website.</description>
      <content:encoded><![CDATA[<publishedat date="2026-09-08T07:42:00Z">
<callout>
<p>For the current Google Maps JavaScript API, see <a href="/blog/language-region-localization-with-google-maps-api">Language &#x26; Region Localization with Google Maps API</a>.</p>
</callout>
</publishedat>
<p>When you include a Google Maps to your website via the Google Maps JavaScript API uses <a href="https://code.google.com/apis/maps/documentation/javascript/basics.html#Localization">the browser's set preferred language to display the texts</a>. Sometimes this doesn't turned out as planned and you want to be able to override this with your own choice.</p>
<p><img src="https://lh6.googleusercontent.com/-82RElfQtQNQ/UH67VZKyV6I/AAAAAAAAAPc/0ni1HLJEuCA/s175/google_maps_logo.gif" alt="Google Maps"></p>
<p>Changing language is done with an additional argument when referencing the script-file. The argument used is <code>language</code>.</p>
<pre><code class="language-html">&#x3C;script type="text/javascript"
    src="http://maps.google.com/maps/api/js?sensor=false&#x26;language=ja">
</code></pre>
<p>There is of course a <a href="https://spreadsheets.google.com/pub?key=p9pdwsai2hDMsLkXsoM05KQ&#x26;gid=1">reference to the supported languages and their language codes</a>.</p>
<h1>Region Localization</h1>
<p>To set the language of the names of the countries, cities and other places, you can use the <a href="https://code.google.com/apis/maps/documentation/javascript/basics.html#Region">Region Localization</a>.</p>]]></content:encoded>
      <pubDate>Wed, 27 Apr 2011 16:17:00 GMT</pubDate>
      <category>Google Maps</category>
      <category>JavaScript</category>
    </item>
    <item>
      <title>Javascript: Timeout on a Textbox using jQuery</title>
      <link>https://sebnilsson.com/blog/javascript-timeout-on-a-textbox-using-jquery</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/javascript-timeout-on-a-textbox-using-jquery</guid>
      <description>Debounce textbox input with jQuery so an action runs after typing stops while Enter key presses are handled immediately.</description>
      <content:encoded><![CDATA[<p>Here is a quick post about how to use a JavaScript-timer to only execute a textbox's functionality after <em>a certain amount of time</em>.</p>
<p><img src="https://lh3.googleusercontent.com/-17ANANJKqkI/UH67aZj_b4I/AAAAAAAAARM/vK9gf98KCCA/s242/jquery_logo.png" alt="jQuery"></p>
<p>Worth noticing in the code is that we handle a key-press on the Enter-button instantly, while otherwise we only execute the functionality after the user left the keyboard alone for 0,5 seconds.</p>
<pre><code class="language-javascript">var filterTimeoutId = 0;

var textboxFunction = function() {
   // The function the textbox should perform
};

$('input#TextBox').keypress(function (e) {
    if (e.which === 13) { // Enter-key
        e.preventDefault(); // Prevent page postback
        clearTimeout(filterTimeoutId);

        textboxFunction();
        return;
    }

    clearTimeout(filterTimeoutId);
    var timeout = 500; // Timeout in milliseconds
    filterTimeoutId = setTimeout(textboxFunction, timeout);
});

</code></pre>]]></content:encoded>
      <pubDate>Mon, 18 Apr 2011 17:28:00 GMT</pubDate>
      <category>JavaScript</category>
    </item>
    <item>
      <title>Visual Studio 2010: Dropped Assembly References Workaround</title>
      <link>https://sebnilsson.com/blog/visual-studio-2010-dropped-assembly-references-workaround</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/visual-studio-2010-dropped-assembly-references-workaround</guid>
      <description>Work around Visual Studio 2010 unexpectedly dropping external assembly references from projects.</description>
      <content:encoded><![CDATA[<p>After adding some references to external assemblies like to <a href="http://nlog-project.org/">NLog</a> or <a href="https://munq.codeplex.com/">Munq</a> I found out that on some projects Visual Studio 2010 had a tendency to drop the reference to some of these assemblies.</p>
<p>After the usual searching of <a href="https://www.google.com/">Google</a> and <a href="https://stackoverflow.com/">Stackoverflow</a> I've put together a combination of different solutions that seems to solve this issue.</p>
<ul>
<li>Step 1: Expand your references and bring up the properties-window. Set <strong>Specific Version</strong> to <em>True</em>:<br>
<img src="https://lh4.googleusercontent.com/-xVHK62v4Byw/UH67asQHiAI/AAAAAAAAARU/jpm7_oLQ1vg/s362/reference_1.png" alt="Reference properties in Visual Studio with Specific Version set to True"></li>
<li>Step 2: Right click on the project and click <strong>Untload Project</strong>:<br>
<img src="https://lh4.googleusercontent.com/-ejUlJVod8mk/UH67bEahScI/AAAAAAAAARc/GR_LnYKk4pA/s434/reference_4.png" alt="Solution Explorer context menu with Unload Project selected"></li>
<li>Step 3: Right click again on the project and click <strong>Edit ...csproject</strong>.</li>
<li>Step 4: Add an XML-element with the name <strong>SpecificVersion</strong> with the value <em>True</em> beneath the reference in question:<br>
<img src="https://lh4.googleusercontent.com/-5cKhTjV8lew/UH67bDUd3mI/AAAAAAAAARs/MuYgcmtmRxY/s320/reference_3.png" alt=".csproj XML with a SpecificVersion element set to True under the reference"></li>
<li>Step 5: Right click on the project and click <strong>Reload Project</strong>.</li>
</ul>
<p>This works for me so far.</p>]]></content:encoded>
      <pubDate>Wed, 08 Sep 2010 10:29:00 GMT</pubDate>
      <category>.NET</category>
      <category>Developer Tools</category>
      <category>Visual Studio</category>
    </item>
    <item>
      <title>Conditional Scrolling Banner with YUI</title>
      <link>https://sebnilsson.com/blog/conditional-scrolling-banner-with-yui</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/conditional-scrolling-banner-with-yui</guid>
      <description>Build a YUI-powered banner that becomes fixed and follows the viewport only after the user scrolls past its original position.</description>
      <content:encoded><![CDATA[<p>I was in need of <strong>a banner that would scroll along on the page, even when the user had scrolled passed it</strong>. After Googling with Bing for any pre-done JavaScript to achieve this, I still only found plug-ins for different PHP-based CMS:es.</p>
<p>After spending almost as much time searching for something already built as it would have taken to build it, I did just that, I took matters into my own hands.</p>
<p>In my case I solved it with Yahoo's <a href="https://developer.yahoo.com/yui/2/">YUI 2</a>, but you can do it just as well in any other Javascript-library, like <a href="https://jquery.com/">jQuery</a>.</p>
<pre><code class="language-html">&#x3C;!-- Static banners above conditional scrolling one -->
&#x3C;div id="scrollBanner" class="scrollBanner">
&#x3C;!-- Image and/or flash-banners -->
&#x3C;img src="Banner.gif" alt="Banner" />
&#x3C;/div>
</code></pre>
<p>What we need to do is to find the element to scroll in the DOM and find it's initial Y-position. Then we add a listener to the <code>scroll</code>-event and just flip the CSS-class of the element, depending if we've scrolled past it or not.</p>
<pre><code class="language-javascript">var scrollBanner = document.getElementById("scrollBanner");
// Initial banner Y-position
var bannerYPos = YAHOO.util.Dom.getY(scrollBanner);

YAHOO.util.Event.addListener(window, 'scroll',
    function() {
        var isBannerAboveScrollTop = (YAHOO.util.Dom.getDocumentScrollTop() > bannerYPos);
        var oldClassName = isBannerAboveScrollTop ? "scrollBanner" : "scrollBanner_fixed";
        var newClassName = isBannerAboveScrollTop ? "scrollBanner_fixed" : "scrollBanner";
        YAHOO.util.Dom.replaceClass(scrollBanner, oldClassName, newClassName);
    }
);
</code></pre>
<p>Just style your <code>scrollingBanner_fixed</code>-class with a fixed position and the <code>width</code> you want it to have. Adjust the <code>top</code>-setting to set how high up on the screen the scrolling banner should be. You could also use <code>padding</code> to make the scrolling-experience more smooth.</p>
<pre><code class="language-javascript">.scrollingBanner_fixed {
    position: fixed;
    top: 0px;
    width: 100px;
}
</code></pre>
<p>This code could of course also be used for good, to have some kind of toolbar that would scroll along on a page.</p>]]></content:encoded>
      <pubDate>Wed, 01 Sep 2010 13:15:00 GMT</pubDate>
      <category>JavaScript</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>Guidelines for URI Design</title>
      <link>https://sebnilsson.com/blog/guidelines-for-uri-design</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/guidelines-for-uri-design</guid>
      <description>Explore practical principles for designing clean, readable, consistent, and search-friendly URIs for websites.</description>
      <content:encoded><![CDATA[<p><a href="http://jacobwg.com/">Jacob Gillespie</a> has worked on a post concerning <a href="http://forrst.com/posts/URL_Guidelines-m0F">URL Guidelines</a>, that underwent much revision and was posted as a guest post on CSS-Tricks named <a href="https://css-tricks.com/guidelines-for-uri-design/">Guidelines for URI Design</a>.</p>
<blockquote>
<p>Clean URIs are one component of a clean website, and it is an important one. The majority of end-user access to the Internet involves a URI, and whether or not the user actually enters the URI, they are working with one nonetheless.</p>
</blockquote>
<p>Here is an outtake of the general principles of the article:</p>
<ul>
<li><strong>A URI must represent an object, uniquely and permanently</strong> - The URI must be unique so that it is a one-to-one match – one URI per one data object.</li>
<li><strong>Be as human-friendly as possible</strong> - URIs should be designed with the end user in mind. SEO and ease of development should come second.</li>
<li><strong>Consistency</strong> - URIs across a site must be consistent in format. Once you pick your URI structure, be consistent and follow it!</li>
<li><strong>“Hackable” URIs</strong> - Related to consistency, URIs should be structured so that they are intelligibly “hackable” or changeable.</li>
<li><strong>Keywords</strong> - The URI should be composed of keywords that are important to the content of the page. So, if the URI is for a blog post that has a long title, only the words important to the content of the page should be in the URI.</li>
</ul>
<p>When it comes to technical details, here are their concerned bullet-points:</p>
<ul>
<li><strong>No WWW</strong> - The <a href="http://www">www</a>. should be dropped from the website URI, as it is unnecessary typing and violates the rules of being as human-friendly as possible and not including unnecessary information in the URI.</li>
<li><strong>Format</strong> - Google News has some interesting requirements for webpages that want to be listed in the Google News results – Google requires at least a 3-digit unique number.</li>
<li><strong>All lowercase</strong> - All characters must be lowercase. Attempting to describe a URI to someone when mixed case is involved is next to impossible.</li>
<li><strong>URI identifiers should be made URI friendly</strong> - A URI might contain the title of a post, and that title might contain characters that are not URI-friendly. That post title must therefore be made URI friendly. [...] Spaces should be replaced with hyphens.</li>
</ul>
<p><a href="http://www.4guysfromrolla.com/ScottMitchell.shtml">Scott Mitchell</a> has written an article on 4GuysFromRolla.com about <a href="http://www.4guysfromrolla.com/articles/072810-1.aspx">Techniques for Preventing Duplicate URLs in Your Website</a>.</p>
<blockquote>
<p>A key tenet of search engine optimization is URL normalization, or URL canonicalization. URL normalization is the process of eliminating duplicate URLs in your website. This article explores four different ways to implement URL normalization in your ASP.NET website.</p>
</blockquote>
<p>The important subjects of this article are the following:</p>
<ul>
<li><strong>First Things First: Deciding on a Canonical URL Format</strong> - Before we examine techniques for normalizing URLs, and certainly before such techniques can be implemented, we must first decide on a canonical URL format.</li>
<li><strong>URL Normalization Using Permanent Redirects</strong> - [...] when a search engine spider receives a 301 status it updates its index with the new URL. Therefore, if anytime a request comes in for a non-canonical URL we immediately issue a permanent redirect to the same page but use the canonical form then a search engine spider crawling our site will only maintain the canonical form in its index.</li>
<li><strong>Issuing Permanent Redirects From ASP.NET</strong> - Every time an incoming request is handled by the ASP.NET engine, it raises the <em>BeginRequest</em> event. You can execute code in response to this event by creating an HTTP Module or by creating the <em>Application_BeginRequest</em> event handler in <em>Global.asax</em>.</li>
<li><strong>Rewriting URLs Into Canonical Form Using IIS 7's URL Rewrite Module</strong> - Shortly after releasing IIS 7, Microsoft created and released a free <a href="http://learn.iis.net/page.aspx/734/url-rewrite-module/">URL Rewrite Module</a>. The URL Rewrite Module makes it easy to define URL rewriting rules in your <em>Web.config</em> file.</li>
<li><strong>Rewriting URLs Into Canonical Form Using ISAPI_Rewrite</strong> - Microsoft's URL Rewriter Module is a great choice if you are using IIS 7, but if you are using previous version of IIS you're out of luck.</li>
<li><strong>Telling Search Engine Spiders Your Canonical Form In Markup</strong> - Consider a URL that may include querystring parameters that don't affect the content rendered on the page or only affect non-essential parts of the page.<br>
In the case of YouTube, all video pages specify a <code>&#x3C;link></code> element like so, regardless of whether the querystring includes just the <em>videoId</em> or the <em>videoId</em> and other parameters:</li>
</ul>
<pre><code class="language-html">&#x3C;link rel\="canonical" href\="/watch?v=videoId"\>
</code></pre>]]></content:encoded>
      <pubDate>Wed, 04 Aug 2010 05:10:00 GMT</pubDate>
      <category>SEO</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>ASP.NET WebForms SEO: Compressing View State</title>
      <link>https://sebnilsson.com/blog/asp-net-webforms-seo-compressing-view-state</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-webforms-seo-compressing-view-state</guid>
      <description>Reduce ASP.NET WebForms page size by compressing View State before saving it and decompressing it when the page loads.</description>
      <content:encoded><![CDATA[<p>In my previous post about <a href="https://sebnilsson.blogspot.com/2010/03/aspnet-webforms-seo-moving-view-state.html">Moving View State to Bottom of the Form</a> I touched on one way to do some <a href="https://en.wikipedia.org/wiki/Search_engine_optimization">Search Engine Optimization</a> in ASP.NET WebForms. Another thing you can do is to <strong>compress large View States</strong> on a page.</p>
<p>All the code in this article should be put in a class inheriting from <a href="https://msdn.microsoft.com/en-us/library/system.web.ui.page.aspx">System.Web.UI.Page</a>. Like a page's Code-behind file or your own PageBase-class.</p>
<p>First we need some common logic for both loading and saving a compressed View State, the name of the hidden field to use.</p>
<pre><code class="language-csharp">private const string ViewStateFieldName = "SEOVIEWSTATE";
</code></pre>
<p>We start with the loading-part, where you see the use of my implementation of the CompressionHelper-class, which simplifies compression. It also solves the issue with DeflateStream and GZipStream inflating already compressed data, <a href="https://blogs.msdn.com/bclteam/archive/2009/05/22/what-s-new-in-the-bcl-in-net-4-beta-1-justin-van-patten.aspx">which is resolved in .NET Framework 4</a>.</p>
<pre><code class="language-csharp">protected override object LoadPageStateFromPersistenceMedium() {
    return LoadCompressedPageState();
}

private object LoadCompressedPageState() {
    string viewState = Request.Form[ViewStateFieldName];
    if(string.IsNullOrEmpty(viewState)) {
        return string.Empty;
    }

    byte[] bytes = Convert.FromBase64String(viewState.Substring(1));

    bool isCompressed = Convert.ToBoolean(Convert.ToInt32(viewState.Substring(0, 1)));
    if(isCompressed) {
        bytes = CompressionHelper.Decompress(bytes);
    }

    string decompressedBase64 = Convert.ToBase64String(bytes);

    ObjectStateFormatter formatter = new ObjectStateFormatter();
    return formatter.Deserialize(decompressedBase64);
}
</code></pre>
<p>We then move on to the implementation of saving the page's state.</p>
<pre><code class="language-csharp">protected override void SavePageStateToPersistenceMedium(object state) {
    SaveCompressedPageState(state);
}

private void SaveCompressedPageState(object state) {
    byte[] viewStateBytes;
    using(MemoryStream stream = new MemoryStream()) {
        ObjectStateFormatter formatter = new ObjectStateFormatter();
        formatter.Serialize(stream, state);
        viewStateBytes = stream.ToArray();
    }

    byte[] compressed;
    bool successfulCompress = CompressionHelper.TryCompress(viewStateBytes, out compressed);
    string compressedBase64 =
        Convert.ToInt32(successfulCompress) + Convert.ToBase64String(compressed);

    ClientScript.RegisterHiddenField(ViewStateFieldName, compressedBase64);
}
</code></pre>
<p>So the summary is that this will compress the View State of an ASP.NET WebForms page, if the View State is large enough. Otherwise it will just keep it the way it is.</p>]]></content:encoded>
      <pubDate>Wed, 31 Mar 2010 12:50:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>SEO</category>
    </item>
    <item>
      <title>ASP.NET WebForms SEO: Moving View State to Bottom of the Form</title>
      <link>https://sebnilsson.com/blog/asp-net-webforms-seo-moving-view-state-to-bottom-of-the-form</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-webforms-seo-moving-view-state-to-bottom-of-the-form</guid>
      <description>Improve ASP.NET WebForms SEO by using an HTTP module to move View State markup below the page&apos;s meaningful content.</description>
      <content:encoded><![CDATA[<p>As we all know, <a href="https://en.wikipedia.org/wiki/Search_engine_optimization">SEO</a> is very important for almost all sites and some of us are still stuck with sites based on <a href="https://msdn.microsoft.com/en-us/library/ms973868.aspx">ASP.NET WebForm</a>. But there are still things you can do to optimize these sites.</p>
<p>Since <a href="http://articles.sitepoint.com/article/indexing-limits-where-bots-stop">Google and other search-engines only indexes X amount of KB of a page</a>, you don't want half of that content to be meaningless <a href="https://weblogs.asp.net/infinitiesloop/archive/2006/08/03/Truly-Understanding-Viewstate.aspx">View State (<em>which you should TRULY understand by now</em>)</a>.</p>
<p>One solution is to <a href="https://sebnilsson.blogspot.com/2010/03/aspnet-webforms-seo-compressing.html">compress the View State</a>, but in this article I will show you how to move it to the bottom of the <a href="https://www.w3schools.com/TAGS/tag_form.asp">Form-tag</a>. To achieve the latter, I will use a <a href="https://msdn.microsoft.com/en-us/library/zec9k340(VS.71).aspx">HttpModule</a>, which will intercept all requests to files served through ASP.NET in the IIS.</p>
<p>First we need to hook in to the <a href="https://msdn.microsoft.com/en-us/library/system.web.httpapplication.beginrequest.aspx">BeginRequest</a>-event to only intercept requests to <strong>.aspx</strong>-pages.</p>
<pre><code class="language-csharp">public class ViewStateSeoHttpModule : IHttpModule {
    public void Init(HttpApplication context) {
        context.BeginRequest += new EventHandler(BeginRequest);
    }

    private void BeginRequest(object sender, EventArgs e) {
        HttpApplication application = sender as HttpApplication;

        bool isAspNetPageRequest = GetIsAspNetPageRequest(application);
        if(isAspNetPageRequest) {
            application.Context.Response.Filter =
                new ViewStateSeoFilter(application.Context.Response.Filter);
        }
    }

    private bool GetIsAspNetPageRequest(HttpApplication application) {
        string requestInfo = application.Context.Request.Url.Segments.Last();
        bool isAspNetPageRequest = requestInfo.ToLowerInvariant().Contains(".aspx");
        return isAspNetPageRequest;
    }
    // [...]
</code></pre>
<p>What we do here is add a Reponse Filter which moves the View State to the bottom of the Form. I made this to an internal class called <strong>ViewStateSeoFilter</strong>.</p>
<pre><code class="language-csharp">internal class ViewStateSeoFilter : Stream {
    private string _topPageHiddenFields;
    private Stream _originalFilter;

    public ViewStateSeoFilter(Stream originalFilter) {
        _originalFilter = originalFilter;
    }

    public override bool CanRead { get { return true; } }
    public override bool CanSeek { get { return true; } }
    public override bool CanWrite { get { return true; } }
    public override long Length { get { return 0; } }
    public override long Position { get; set; }

    public override void Flush() {
        _originalFilter.Flush();
    }

    public override int Read(byte[] buffer, int offset, int count) {
        return _originalFilter.Read(buffer, offset, count);
    }

    public override long Seek(long offset, SeekOrigin origin) {
        return _originalFilter.Seek(offset, origin);
    }

    public override void SetLength(long value) {
        _originalFilter.SetLength(value);
    }
    public override void Close() {
        _originalFilter.Close();
    }

    public override void Write(byte[] buffer, int offset, int count) {
        byte[] data = new byte[count];
        Buffer.BlockCopy(buffer, offset, data, 0, count);
        string html = Encoding.Default.GetString(buffer);

        html = ExtractPageTopHiddenFields(html);
        html = InsertExtractedHiddenFields(html);

        byte[] outdata = Encoding.Default.GetBytes(html);
        _originalFilter.Write(outdata, 0, outdata.GetLength(0));
    }

    private string ExtractPageTopHiddenFields(string html) {
        int formStartIndex = html.IndexOf("&#x3C;form");
        if(formStartIndex &#x3C; 0) {
            return html;
        }

        int divStartOpenIndex = html.IndexOf("&#x3C;div", formStartIndex);
        if(divStartOpenIndex &#x3C; 0) {
            return html;
        }
        int divStartCloseIndex = html.IndexOf(">", divStartOpenIndex);
        int divStartLenght = divStartCloseIndex - divStartOpenIndex;
        int divEndOpenIndex = html.IndexOf("&#x3C;/div", divStartOpenIndex);
        int divEndCloseIndex = html.IndexOf(">", divEndOpenIndex);

        int divContentLength = divEndOpenIndex - divStartCloseIndex - 1;

        _topPageHiddenFields = html.Substring(divStartCloseIndex + 1, divContentLength);
        html = html.Remove(divStartOpenIndex, divEndCloseIndex - divStartOpenIndex + 1);
        return html;
    }

    private string InsertExtractedHiddenFields(string html) {
        if(string.IsNullOrEmpty(_topPageHiddenFields)) {
            return html;
        }

        int insertIndex = html.IndexOf("&#x3C;/form>");
        if(insertIndex > 0) {
            html = html.Insert(insertIndex, _topPageHiddenFields + Environment.NewLine);
            _topPageHiddenFields = null;
        }

        return html;
    }
}
</code></pre>
<p>One bonus is that it moves all available <a href="https://www.w3schools.com/TAGS/tag_input.asp">Hidden Input HTML-tags</a> controlled by ASP.NET to the bottom of the Form-tag. It seems to skip the Hidden Input that handles <a href="https://msdn.microsoft.com/en-us/library/system.web.ui.page.enableeventvalidation.aspx">EventValidation</a>, which is a good thing, because ASP.NET seems to want this tag early in the <a href="https://msdn.microsoft.com/en-us/library/ms178472.aspx">Page Life Cycle</a>.</p>]]></content:encoded>
      <pubDate>Tue, 30 Mar 2010 13:52:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>SEO</category>
    </item>
    <item>
      <title>ASP.NET Request Paths Reference</title>
      <link>https://sebnilsson.com/blog/asp-net-request-paths-reference</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/asp-net-request-paths-reference</guid>
      <description>A practical reference showing the values returned by ASP.NET Request and Request.Url path properties for a sample URL.</description>
      <content:encoded><![CDATA[<publishedat date="2026-06-23T06:47:00Z">
<callout>
<p>For the modern APIs that replaced these traditional ASP.NET APIs, see <a href="/blog/asp-net-core-request-paths-reference">ASP.NET Core Request Paths Reference</a>.</p>
</callout>
</publishedat>
<p>I decided to write down and document for myself the different paths provided by ASP.NET, to get a grip on the subject and a reference to turn to.</p>
<p>The path I will be requesting is:<br>
<code>http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue</code></p>
<p>This will be an ASP.NET-application named <strong>MyApplication</strong> in the IIS.</p>
<h1>Request-reference</h1>
<p>Here is the result returned by the <code>Request</code>-property of the page, which is a <a href="https://msdn.microsoft.com/en-us/library/system.web.httprequest_properties.aspx">HttpRequest</a>.</p>
<p><code>[Request.ApplicationPath](https://msdn.microsoft.com/en-us/library/system.web.httprequest.applicationpath.aspx):</code><br>
/MyApplication - <em>Gets the ASP.NET application's virtual application root path on the server.</em></p>
<p><code>[Request.AppRelativeCurrentExecutionFilePath](https://msdn.microsoft.com/en-us/library/system.web.httprequest.apprelativecurrentexecutionfilepath.aspx):</code><br>
<del>/MyFolder/MyPage.aspx _- Gets the virtual path of the application root and makes it relative by using the tilde (</del>) notation for the application root (as in "~/page.aspx")._</p>
<p><code>[Request.CurrentExecutionFilePath](https://msdn.microsoft.com/en-us/library/system.web.httprequest.currentexecutionfilepath.aspx):</code><br>
/MyApplication/MyFolder/MyPage.aspx <em>- Gets the virtual path of the current request.</em></p>
<p><code>[Request.FilePath](https://msdn.microsoft.com/en-us/library/system.web.httprequest.filepath.aspx):</code><br>
/MyApplication/MyFolder/MyPage.aspx <em>- Gets the virtual path of the current request.</em></p>
<p><code>[Request.Path](https://msdn.microsoft.com/en-us/library/system.web.httprequest.path.aspx):</code><br>
/MyApplication/MyFolder/MyPage.aspx <em>- Gets the virtual path of the current request.</em></p>
<p><code>[Request.PathInfo](https://msdn.microsoft.com/en-us/library/system.web.httprequest.pathinfo.aspx):</code><br>
<em>- Gets additional path information for a resource with a URL extension.</em></p>
<p><code>[Request.PhysicalApplicationPath](https://msdn.microsoft.com/en-us/library/system.web.httprequest.physicalapplicationpath.aspx):</code><br>
C:\Visual Studio Projects\MyApplication\ <em>- Gets the physical file system path of the currently executing server application's root directory.</em></p>
<p><code>[Request.PhysicalPath](https://msdn.microsoft.com/en-us/library/system.web.httprequest.physicalpath.aspx):</code><br>
C:\Visual Studio Projects\MyApplication\MyFolder\MyPage.aspx <em>- Gets the physical file system path corresponding to the requested URL.</em></p>
<p><code>[Request.RawUrl](https://msdn.microsoft.com/en-us/library/system.web.httprequest.rawurl.aspx):</code><br>
/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue <em>- Gets the ASP.NET application's virtual application root path on the server.</em></p>
<h1>Request.Url-reference</h1>
<p>Then there is the property <code>[Request.Url](https://msdn.microsoft.com/en-us/library/system.web.httprequest.url.aspx)</code> that returns a <code>[System.Uri](https://msdn.microsoft.com/en-us/library/system.uri_properties.aspx)</code> , with all its properties. This is an interesting thing to explore as well.</p>
<p><code>[Request.Url.AbsolutePath](https://msdn.microsoft.com/en-us/library/system.uri.absolutepath.aspx):</code><br>
/MyApplication/MyFolder/MyPage.aspx <em>- Gets the absolute path of the URI.</em></p>
<p><code>[Request.Url.AbsoluteUri](https://msdn.microsoft.com/en-us/library/system.uri.absoluteuri.aspx):</code><br>
<a href="http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue">http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue</a> <em>- Gets the absolute URI.</em></p>
<p><code>[Request.Url.DnsSafeHost](https://msdn.microsoft.com/en-us/library/system.uri.dnssafehost.aspx):</code><br>
<a href="http://www.myurl.com">www.myurl.com</a> <em>- Gets an unescaped host name that is safe to use for DNS resolution.</em></p>
<p><code>[Request.Url.Host](https://msdn.microsoft.com/en-us/library/system.uri.host.aspx):</code><br>
<a href="http://www.myurl.com">www.myurl.com</a> <em>- Gets the host component of this instance.</em></p>
<p><code>[Request.Url.LocalPath](https://msdn.microsoft.com/en-us/library/system.uri.localpath.aspx):</code><br>
/MyApplication/MyFolder/MyPage.aspx <em>- Gets a local operating-system representation of a file name.</em></p>
<p><code>[Request.Url.OriginalString](https://msdn.microsoft.com/en-us/library/system.uri.originalstring.aspx):</code><br>
<a href="http://www.myurl.com:80/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue">http://www.myurl.com:80/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue</a> <em>- Gets the original URI string that was passed to the Uri constructor.</em></p>
<p><code>[Request.Url.PathAndQuery](https://msdn.microsoft.com/en-us/library/system.uri.pathandquery.aspx):</code><br>
/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue <em>- Gets the AbsolutePath and Query properties separated by a question mark (?).</em></p>
<p><code>[Request.Url.Query](https://msdn.microsoft.com/en-us/library/system.uri.query.aspx):</code><br>
?QueryStringKey=QueryStringValue <em>- Gets any query information included in the specified URI.</em></p>
<p><code>[Request.Url.ToString()](https://msdn.microsoft.com/en-us/library/system.uri.tostring.aspx):</code><br>
<a href="http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue">http://www.myurl.com/MyApplication/MyFolder/MyPage.aspx?QueryStringKey=QueryStringValue</a> <em>- Gets a canonical string representation for the specified Uri instance.</em></p>
<p><code>Request</code> also has the property <code>[Request.UrlReferrer](https://msdn.microsoft.com/en-us/library/system.web.httprequest.urlreferrer.aspx)</code> which is of the type <code>System.Uri</code> and has the same properties as <code>Request.Url</code>. It has the following description: <em>Gets information about the URL of the client's previous request that linked to the current URL.</em></p>]]></content:encoded>
      <pubDate>Tue, 16 Feb 2010 12:03:00 GMT</pubDate>
      <category>.NET</category>
      <category>ASP.NET</category>
      <category>Web Development</category>
    </item>
    <item>
      <title>C# 4: Reflected Dynamics</title>
      <link>https://sebnilsson.com/blog/c-4-reflected-dynamics</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/c-4-reflected-dynamics</guid>
      <description>Examine how C# 4 resolves overloaded methods when reflection and the dynamic keyword are used together.</description>
      <content:encoded><![CDATA[<p>In Scott Hanselman's blog-entry titled <a href="https://www.hanselman.com/blog/BackToBasicsC4MethodOverloadingAndDynamicTypes.aspx">Back to Basics: C# 4 method overloading and dynamic types</a> , Scott talks about method-overloads in C# 4 and the <code>dynamic</code> -keyword.</p>
<pre><code class="language-csharp">class Program {
    static void f(Int32 x) { }
    static void f(dynamic x) {}
    static void f(Int32 x, dynamic y) {}
    static void f(dynamic x, Int32 y) {}
    static void f(Int32 x, dynamic y, Int32 z) {}
    static void f(dynamic x, Int32 y, dynamic z) {}
    static void Main(string[] args) {
        f(10); // Works - obvious
        f(10, 10); // Ambiguous - obvious
        f(10, 10, 10); // Ambiguous - not so obvious - since it should be possible to resolve
    }
}
</code></pre>
<p>...the behavior is totally by design:</p>
<ul>
<li><code>dynamic</code> in method signatures doesn't come into it: it behaves like System.Object does.</li>
<li>Given that, neither of the ternary signatures is better because each fits better than the other on some arguments (Int32 fits 10 better than object does)</li>
</ul>
<p>The key point here, in bold, because it's significant is: <strong>having the type dynamic means "use my runtime type for binding".</strong></p>
<p>It all becomes very clear when <a href="https://www.red-gate.com/products/reflector/">Reflector</a> is used on the code. This loosens up some thought-patterns and makes it easier to really understand the <em>dynamic</em> -keyword.</p>
<p>Another way to look at this is with Reflector. This C# code:</p>
<pre><code class="language-csharp">static void f(Int32 x, dynamic y, Int32 z) {}
</code></pre>
<p>is essentially this, from a method signature point of view:</p>
<pre><code class="language-csharp">static void f(int x, \[Dynamic\] object y, int z) {}
</code></pre>
<p>and if there was a method that returned dynamic, it'd look like this:</p>
<pre><code class="language-csharp">[return: Dynamic]
private static object GetCalculator() {}
</code></pre>]]></content:encoded>
      <pubDate>Mon, 15 Feb 2010 15:14:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
    </item>
    <item>
      <title>Visual Studio: C#-Settings &amp; StyleCop</title>
      <link>https://sebnilsson.com/blog/visual-studio-c-settings-stylecop</link>
      <guid isPermaLink="true">https://sebnilsson.com/blog/visual-studio-c-settings-stylecop</guid>
      <description>Configure Visual Studio C# formatting settings to align more closely with StyleCop and Microsoft&apos;s .NET design guidelines.</description>
      <content:encoded><![CDATA[<p><a href="https://msdn.microsoft.com/en-us/library/ms229042.aspx">Design Guidelines</a> for .NET development is something very close and dear to me. Partially for my own sake, but mostly to have consistency across a company, between friends and maybe even across blog-examples.</p>
<p><a href="https://code.msdn.microsoft.com/sourceanalysis">The tool StyleCop</a> is Microsoft's tool for enforcing these guidelines.</p>
<blockquote>
<p>StyleCop analyzes C# source code to enforce a set of style and consistency rules. It can be run from inside of Visual Studio or integrated into an MSBuild project.</p>
</blockquote>
<p>After asking a question <a href="https://stackoverflow.com/questions/325330/visual-studio-c-settings-and-stylecop-ms-source-analysis">Visual Studio C#-settings and StyleCop (MS Source Analysis)</a> on Stackoverflow I set out to try to get C# in Visual Studio to behave as compliant as possible.</p>
<p>The result after some testing around was <a href="https://docs.google.com/open?id=0B3cURG28K2dIRW1TeWRGY2VfT3c">this Visual Studio settings file</a>. You can <a href="https://msdn.microsoft.com/en-us/library/ms165479.aspx">easily import</a> these settings to your own Visual Studio.</p>
<p>It's mainly about <strong>placements of parentheses and curly-braces</strong>.</p>
<p>Yes, it can be a bit of a hassle to get used to having the curly-braces on the same line as the namespace-declaration, the class-declaration and method-declaration, but it saves some space and I got used to it quiet quickly and now have problems going back.</p>
<pre><code class="language-csharp">namespace TestApp {
    public class TestObject {
        static TestObject() {
            if(true) {
                DoSomething();
                DoSomething2();
            } else {
                DoSomethingElse()
            }
        }
    }
}
</code></pre>
<p>This is as close as I can get to the conventions. It's worth to note that StyleCop can differ a bit from the book <a href="https://www.amazon.com/gp/product/0321545613?ie=UTF8&#x26;tag=liquiddevelo-20&#x26;linkCode=as2&#x26;camp=1789&#x26;creative=390957&#x26;creativeASIN=0321545613">Framework Design Guidelines: Conventions, Idioms, and Patterns for Reusable .NET Libraries</a> .</p>]]></content:encoded>
      <pubDate>Fri, 12 Feb 2010 14:35:00 GMT</pubDate>
      <category>.NET</category>
      <category>C#</category>
      <category>Developer Tools</category>
      <category>Visual Studio</category>
    </item>
  </channel>
</rss>