<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://shazwazza.com/rss/xslt"?>
<rss xmlns:a10="http://www.w3.org/2005/Atom" version="2.0">
  <channel>
    <title>Shazwazza</title>
    <link>https://shazwazza.com/</link>
    <description>My blog which is pretty much just all about coding</description>
    <generator>Articulate, blogging built on Umbraco</generator>
    <image>
      <url>/media/0libq25y/frog.png?rmode=max&amp;v=1da0e911f4e6890</url>
      <title>Shazwazza</title>
      <link>https://shazwazza.com/</link>
    </image>
    <item>
      <guid isPermaLink="false">1296</guid>
      <link>https://shazwazza.com/post/auto-upgrade-your-nuget-packages-with-azure-pipelines-or-github-actions/</link>
      <category>ASP.Net</category>
      <category>Umbraco</category>
      <title>Auto upgrade your Nuget packages with Azure Pipelines or GitHub Actions</title>
      <description>&lt;p&gt;Before we start I just want to preface this with some  &lt;strong&gt;warnings &lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This works for me, it might not work for you&lt;/li&gt;
&lt;li&gt;To get this working for you, you may need to tweak some of the code referenced&lt;/li&gt;
&lt;li&gt;This is not under any support or warranty by anyone&lt;/li&gt;
&lt;li&gt;Running Nuget.exe update command outside of Visual Studio will overwrite your files so there is a manual review process (more info below)&lt;/li&gt;
&lt;li&gt;This is only for ASP.NET Framework using &lt;em&gt;packages.config&lt;/em&gt; – Yes I know that is super old and I should get with the times, but this has been an ongoing behind the scenes project of mine for a long time. When I need this for Package Reference projects, ASP.NET Core/5, I’ll update it but there’s nothing stopping you from tweaking this to work for you&lt;/li&gt;
&lt;li&gt;This only works for a specified csproj, not an entire sln – it could work for that but I’ve not tested, there would be a few tweaks to make that work&lt;/li&gt;
&lt;li&gt;&lt;span style="text-decoration: line-through;"&gt;This does not yet work for GitHub actions but the concepts are all here and could probably very easily be converted&lt;/span&gt; &lt;strong&gt;UPDATE:&lt;/strong&gt; This works now!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that’s out of the way …&lt;/p&gt;
&lt;h2&gt;How do I do it?&lt;/h2&gt;
&lt;p&gt;With a lot of PowerShell :) This also uses a few methods from the &lt;a rel="noopener" href="https://github.com/microsoft/PowerShellForGitHub" target="_blank"&gt;PowerShellForGitHub&lt;/a&gt; project.&lt;/p&gt;
&lt;p&gt;The process is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run a pipeline/action on a schedule (i.e. each day)&lt;/li&gt;
&lt;li&gt;This checks against your source code for the installed version for a particular package&lt;/li&gt;
&lt;li&gt;Then it checks with Nuget (using your Nuget.config file) to see what the latest stable version is&lt;/li&gt;
&lt;li&gt;If there’s a newer version:&lt;/li&gt;
&lt;li&gt;Create a new branch&lt;/li&gt;
&lt;li&gt;Run a Nuget update against your project&lt;/li&gt;
&lt;li&gt;Build the project&lt;/li&gt;
&lt;li&gt;Commit the changes&lt;/li&gt;
&lt;li&gt;Push the changes&lt;/li&gt;
&lt;li&gt;Create a PR for review&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Azure Pipelines/GitHub Actions YAML&lt;/h2&gt;
&lt;p&gt;The only part of the YAML that needs editing is the variables, here's what they mean:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ProjectFile = The relative path to your csproj that you want to upgrade&lt;/li&gt;
&lt;li&gt;PackageFile = The relative path to your packages.config file for this project&lt;/li&gt;
&lt;li&gt;PackageName = The Nuget package name you want upgraded&lt;/li&gt;
&lt;li&gt;GitBotUser = The name used for the Git commits&lt;/li&gt;
&lt;li&gt;GitBotEmail = The email used for the Git commits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For Azure Pipelines, these are also required:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GitHubOwner = The repository owner (i.e. &lt;a href="https://github.com/Shazwazza/Articulate" title="https://github.com/Shazwazza/Articulate"&gt;https://github.com/&lt;strong&gt;Shazwazza&lt;/strong&gt;/Articulate&lt;/a&gt; )&lt;/li&gt;
&lt;li&gt;GitHubRepository = The repository name (i.e. &lt;a href="https://github.com/Shazwazza/Articulate" title="https://github.com/Shazwazza/Articulate"&gt;https://github.com/Shazwazza/&lt;strong&gt;Articulate&lt;/strong&gt;&lt;/a&gt;&lt;strong&gt; &lt;/strong&gt;)&lt;/li&gt;
&lt;li&gt;There is one Secret setting you need to create in Azure Pipelines: &lt;em&gt;GitHubAccessToken &lt;/em&gt;which is a GitHub PAT that you need to create that has access to this repository.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then there are some variables to assist with testing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;DisableUpgradeStep = If true will just check if there’s an upgrade available and exit&lt;/li&gt;
&lt;li&gt;DisableCommit = If true will run the upgrade and will exit after that (no commit, push or PR)&lt;/li&gt;
&lt;li&gt;DisablePush = If true will run the upgrade + commit and will exit after that (no push or PR)&lt;/li&gt;
&lt;li&gt;DisablePullRequest = If true will run the upgrade + commit + push and will exit after that (no PR)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Each step in the yaml build more or less either calls Git commands or PowerShell functions. The PowerShell functions are loaded as part of a PowerShell Module which is committed to the repository. This module’s functions are auto-loaded by PowerShell because the first step configures the PowerShell environment variable &lt;em&gt;PSModulePath&lt;/em&gt; to include the custom path. Once that is in place, all functions exposed by the module are auto-loaded.&lt;/p&gt;
&lt;p&gt;In these examples you’ll see that I’m referencing Umbraco Cloud names and that’s because I’m using this on Umbraco Cloud for my own website and the examples are for the &lt;em&gt;UmbracoCms&lt;/em&gt; package. But this should in theory work for all packages!&lt;/p&gt;
&lt;h2&gt;Show me the code&lt;/h2&gt;
&lt;p&gt;&lt;a rel="noopener" href="https://github.com/Shazwazza/NugetAutoUpgrade/tree/main/Examples/NET_Framework/WebApplication" target="_blank"&gt;The code for all of this is here&lt;/a&gt; in a new GitHub repo and here’s how you use it:&lt;/p&gt;
&lt;p&gt;You can copy the folder structure in the repository as-is. Here's an example of what my site's repository folder structure is to make this work (everything except the src folder is in the GitHub repo above):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;[root]
&lt;ul&gt;
&lt;li&gt;auto-upgrader.devops.yml &lt;em&gt;(If you are using Azure Pipelines)&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;.github
&lt;ul&gt;
&lt;li&gt;workflows
&lt;ul&gt;
&lt;li&gt;auto-upgrader.gh.yml &lt;em&gt;(If you are using GitHub Actions)&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;build
&lt;ul&gt;
&lt;li&gt;PowershellModules
&lt;ul&gt;
&lt;li&gt;AutoUpgradeFunctions.psd1&lt;/li&gt;
&lt;li&gt;AutoUpgradeFunctions.psm1&lt;/li&gt;
&lt;li&gt;AutoUpgradeFunctions&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;src
&lt;ul&gt;
&lt;li&gt;Shazwazza.Web
&lt;ul&gt;
&lt;li&gt;Shazwazza.Web.csproj&lt;/li&gt;
&lt;li&gt;packages.config&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of the steps have descriptive display names and it should be reasonably self documenting.&lt;/p&gt;
&lt;p&gt;The end result is a PR, here’s one that was generated by this process:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://shazwazza.com/media/8d8d9550b2c26c6/image.png?width=600&amp;amp;height=353&amp;amp;mode=max" alt=""&gt;&lt;/p&gt;
&lt;h2&gt;Nuget overwrites&lt;/h2&gt;
&lt;p&gt;Nuget.exe works differently than Nuget within Visual Studio’s Package Manager Console. All of those special commands like Install-Package, Update-Package, etc… are all PowerShell module commands built into Visual Studio and they are able to work with the context of Visual Studio. This allows those commands to try to be a little smarter when running Nuget updates and also allows the legacy Nuget features like running PowerShell scripts on install/update to run. This script just uses Nuget.exe and it’s less smart especially for these legacy .NET Framework projects. As such, it will just overwrite all files in most cases (it does detect file changes it seems but isn’t always accurate).&lt;/p&gt;
&lt;p&gt;With that  &lt;strong&gt;warning &lt;/strong&gt;it is very important to make sure you review the changed files in the PR and revert or adjust any changes you need before applying the PR.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You’ll see a note in the PowerShell script about Nuget overwrites. There are other options that can be used like "Ignore" and "IgnoreAll" but all my tests have showed that for some reason this setting will end up deleting a whole bunch of files so the default overwrite setting is used.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Next steps&lt;/h2&gt;
&lt;p&gt;Get out there and try it! Would love some feedback on this if/when you get a change to test it.&lt;/p&gt;
&lt;div class="post"&gt;
&lt;div class="body"&gt;
&lt;div id="4866d04c-80a7-43ab-a84e-d2ee7756afb6" class="postBody"&gt;
&lt;p&gt;&lt;em&gt;PackageReference&lt;/em&gt; support with .NET Framework projects could also be done (but IMO this is low priority) along with being able to upgrade the entire SLN instead of just the csproj.&lt;/p&gt;
&lt;p&gt;Then perhaps some attempts at getting a NET Core/5 version of this running. In theory that will be easier since it will mostly just be &lt;em&gt;dotnet&lt;/em&gt; commands.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:10:22 Z</pubDate>
      <a10:updated>2023-03-23T15:10:22Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1200</guid>
      <link>https://shazwazza.com/post/how-to-execute-one-controller-action-from-another-in-aspnet-5/</link>
      <category>ASP.Net</category>
      <category>Umbraco</category>
      <title>How to execute one Controller Action from another in ASP.NET 5</title>
      <description>&lt;p&gt;This will generally be a rare thing to do but if you have your reasons to do it, then this is how…&lt;/p&gt;
&lt;p&gt;In Umbraco one valid reason to do this is due to how HTTP POSTs are handled for forms. Traditionally an HTML form will POST to a specific endpoint, that endpoint will handle the validation (etc), and if all is successful it will redirect to another URL, else it will return a validation result on the current URL (i.e. PRG POST/REDIRECT/GET). In the CMS world this may end up a little bit weird because URLs are dynamic. POSTs in theory should just POST to the current URL so that if there is a validation result, this is still shown on the current URL and not a custom controller endpoint URL. This means that there can be multiple controllers handling the same URL, one for GET, another for POST and that’s exactly what Umbraco has been doing since MVC was enabled in it many years ago. For this to work, a controller is selected during the dynamic route to handle the POST (a &lt;em&gt;SurfaceController&lt;/em&gt; in Umbraco) and if successful, typically the developer will use: &lt;em&gt;return&lt;/em&gt; &lt;em&gt;RedirectToCurrentUmbracoPage&lt;/em&gt; (of type &lt;em&gt;RedirectToUmbracoPageResult&lt;/em&gt;) or if not successful will use: &lt;em&gt;return&lt;/em&gt; &lt;em&gt;CurrentUmbracoPage&lt;/em&gt; (of type &lt;em&gt;UmbracoPageResult&lt;/em&gt;). The &lt;em&gt;RedirectToUmbracoPageResult&lt;/em&gt; is easy to handle since this is just a redirect but the &lt;em&gt;UmbracoPageResult&lt;/em&gt; is a little tricky because one controller has just handled the POST request but now it wants to return a page result for the current Umbraco page which is handled by a different controller.&lt;/p&gt;
&lt;h2&gt;IActionInvoker&lt;/h2&gt;
&lt;p&gt;The concept is actually pretty simple and the &lt;em&gt;IActionInvoker&lt;/em&gt; does all of the work. You can create an &lt;em&gt;IActionInvoker&lt;/em&gt; from the &lt;em&gt;IActionInvokerFactory&lt;/em&gt; which needs an &lt;em&gt;ActionContext&lt;/em&gt;. Here’s what the &lt;em&gt;ExecuteResultAsync&lt;/em&gt; method of a custom &lt;em&gt;IActionResult&lt;/em&gt; could look like to do this:&lt;/p&gt;
&lt;pre&gt;public async Task ExecuteResultAsync(ActionContext context)
{
    // Change the route values to match the action to be executed
    context.RouteData.Values["controller"] = "Page";
    context.RouteData.Values["action"] = "Index";

    // Create a new context and excute the controller/action
    // Copy the action context - this also copies the ModelState
    var renderActionContext = new ActionContext(context)
    {
        // Normally this would be looked up via the EndpointDataSource
        // or using the IActionSelector
        ActionDescriptor = new ControllerActionDescriptor
        {
            ActionName = "Index",
            ControllerName = "Page",
            ControllerTypeInfo = typeof(PageController).GetTypeInfo(),
            DisplayName = "PageController.Index"
        }
    };

    // Get the factory
    IActionInvokerFactory actionInvokerFactory = context.HttpContext
                .RequestServices
                .GetRequiredService&amp;lt;IActionInvokerFactory&amp;gt;();

    // Create the invoker
    IActionInvoker actionInvoker = actionInvokerFactory.CreateInvoker(renderActionContext);

    // Execute!
    await actionInvoker.InvokeAsync();
}&lt;/pre&gt;
&lt;p&gt;That’s pretty must the gist of it. The note about the &lt;em&gt;ControllerActionDescriptor&lt;/em&gt; is important though, it’s probably best to not manually create these since they are already created with all of your routing. They can be queried and resolved in a few different ways such as interrogating the &lt;em&gt;EndpointDataSource&lt;/em&gt; or using the &lt;em&gt;IActionSelector&lt;/em&gt;. This execution will execute the entire pipeline for the other controller including all of it’s filters, etc…&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:10:18 Z</pubDate>
      <a10:updated>2023-03-23T15:10:18Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1279</guid>
      <link>https://shazwazza.com/post/allowing-dynamic-supportedcultures-in-requestlocalizationoptions/</link>
      <category>ASP.Net</category>
      <title>Allowing dynamic SupportedCultures in RequestLocalizationOptions</title>
      <description>&lt;p&gt;The documented usage of &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.requestlocalizationoptions?view=aspnetcore-5.0" target="_blank"&gt;&lt;em&gt;RequestLocalizationOptions&lt;/em&gt;&lt;/a&gt; in ASP.NET 5/Core is to assign a static list of &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.requestlocalizationoptions.supportedcultures?view=aspnetcore-5.0#Microsoft_AspNetCore_Builder_RequestLocalizationOptions_SupportedCultures" target="_blank"&gt;&lt;em&gt;SupportedCultures&lt;/em&gt;&lt;/a&gt; since ASP.NET is assuming you’ll know up-front what cultures your app is supporting. But what if you are creating a CMS or another web app that allows users to include cultures dynamically?&lt;/p&gt;
&lt;p&gt;This isn’t documented anywhere but it’s certainly possible. &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.requestlocalizationoptions.supportedcultures?view=aspnetcore-5.0#Microsoft_AspNetCore_Builder_RequestLocalizationOptions_SupportedCultures" target="_blank"&gt;&lt;em&gt;RequestLocalizationOptions.SupportedCultures&lt;/em&gt;&lt;/a&gt; is a mutable &lt;em&gt;IList&lt;/em&gt; which means that values can be added/removed at runtime if you really want.&lt;/p&gt;
&lt;h2&gt;Create a custom RequestCultureProvider&lt;/h2&gt;
&lt;p&gt;First thing you need is a custom &lt;em&gt;RequestCultureProvider&lt;/em&gt;. The trick is to pass in the &lt;em&gt;RequestLocalizationOptions&lt;/em&gt; into it’s ctor so you can dynamically modify the &lt;em&gt;SupportedCultures&lt;/em&gt; when required.&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;public class MyCultureProvider : RequestCultureProvider
{
    private readonly RequestLocalizationOptions _localizationOptions;
    private readonly object _locker = new object();

    // ctor with reference to the RequestLocalizationOptions
    public MyCultureProvider(RequestLocalizationOptions localizationOptions)
        =&amp;gt; _localizationOptions = localizationOptions;

    public override Task&amp;lt;ProviderCultureResult&amp;gt; DetermineProviderCultureResult(HttpContext httpContext)
    {
        // TODO: Implement GetCulture() to get a culture for the current request
        CultureInfo culture = GetCulture(); 

        if (culture is null)
        {
            return NullProviderCultureResult;
        }

        lock (_locker)
        {
            // check if this culture is already supported
            var cultureExists = _localizationOptions.SupportedCultures.Contains(culture);

            if (!cultureExists)
            {
                // If not, add this as a supporting culture
                _localizationOptions.SupportedCultures.Add(culture);
                _localizationOptions.SupportedUICultures.Add(culture);
            } 
        }

        return Task.FromResult(new ProviderCultureResult(culture.Name));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Add your custom culture provider&lt;/h2&gt;
&lt;p&gt;You can configure &lt;em&gt;RequestLocalizationOptions&lt;/em&gt; in a few different ways, this example registers a custom implementation of &lt;em&gt;IConfigureOptions&amp;lt;RequestLocalizationOptions&amp;gt;&lt;/em&gt; into DI&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;public class MyRequestLocalizationOptions : IConfigureOptions&amp;lt;RequestLocalizationOptions&amp;gt;
{
    public void Configure(RequestLocalizationOptions options)
    {
        // TODO: Configure other options parameters

        // Add the custom provider,
        // in many cases you'll want this to execute before the defaults
        options.RequestCultureProviders.Insert(0, new MyCultureProvider(options));
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then just register these options: &lt;em&gt;Services.ConfigureOptions&amp;lt;MyRequestLocalizationOptions&amp;gt;();&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That’s it, now you can have dynamic &lt;em&gt;SupportedCultures&lt;/em&gt; in your app!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:10:14 Z</pubDate>
      <a10:updated>2023-03-23T15:10:14Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1223</guid>
      <link>https://shazwazza.com/post/how-to-change-httprequestissecureconnection/</link>
      <category>ASP.Net</category>
      <title>How to change HttpRequest.IsSecureConnection</title>
      <description>&lt;p&gt;&lt;em&gt;This post is for ASP.NET Framework, not ASP.NET Core&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is an old problem that is solved in dozens of different ways…&lt;/p&gt;
&lt;p&gt;Typically in an ASP.NET Framework site when you need to check if the request is running in HTTPS you would do something like HttpContext.Request.IsSecureConnection. But this value won’t return the anticipated value if your site is running behind a proxy or load balancer which isn’t forwarding HTTPS traffic and instead is forwarding HTTP traffic. This is pretty common and the way people deal with it is to check some special headers, which will vary depending on the load balancer you are using. The primary one is &lt;a rel="noopener" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto" target="_blank"&gt;HTTP_X_FORWARDED_PROTO&lt;/a&gt; but there are others too like: X-Forwarded-Protocol, X-Forwarded-Ssl, X-Url-Scheme , and the expected values for each are slightly different too.&lt;/p&gt;
&lt;p&gt;So if you can’t rely on HttpContext.Request.IsSecureConnection then you’ll probably make an extension method, or better yet an abstraction to deal with checking if the request is HTTPS. That’s totally fine but unfortunately you can’t rely on all of the dependencies your website uses to deal with this scenario. You’d also need to be able to configure them all to possibly handle some weird header scheme that your proxy/load balancer uses.&lt;/p&gt;
&lt;h2&gt;Aha! HttpRequestBase is abstract&lt;/h2&gt;
&lt;p&gt;If you are using MVC you’ll probably know that the HttpContext.Request within a controller is HttpRequestBase which is an abstract class where it’s possible to re-implement IsSecureConnection. Great, that sounds like a winner! Unfortunately this will only get you as far as being able to replace that value within your own controllers, this will still not help you with the dependencies your website uses.&lt;/p&gt;
&lt;p&gt;And controllers aren’t the only thing you might need to worry about. You might have some super old ASP.NET Webforms or other code lying around using HttpContext.Current.Request.IsSecureConnection which is based on the old HttpRequest object which cannot be overridden.&lt;/p&gt;
&lt;h2&gt;So how does the default HttpContext.Current get this value?&lt;/h2&gt;
&lt;p&gt;The HttpContextBase is based on HttpContextWrapper which simply wraps HttpContext.Current. This is what is passed to your MVC controllers. As for HttpContext.Current, this is the source of all of this data and with a bit (a LOT) of hacking you can actually change this value.&lt;/p&gt;
&lt;p&gt;The HttpContext.Current is actually a set-able singleton value. The constructor of HttpContext has 2x overloads, one that takes in a request/response object and another that accepts something called HttpWorkerRequest. So it is possible (sort of) to construct a new HttpContext instance that wraps the old one … so can we change this value? Yes!&lt;/p&gt;
&lt;p&gt;HttpWorkerRequest is an abstract class and all methods are overridable so if we can access the underlying default HttpWorkerRequest (which is &lt;a rel="noopener" href="https://referencesource.microsoft.com/#system.web/Hosting/IIS7WorkerRequest.cs" target="_blank"&gt;IIS7WorkerRequest&lt;/a&gt;) from the current context, we could wrap it and return anything we want for IsSecureConnection. This is not a pretty endeavor but it can be done.&lt;/p&gt;
&lt;h2&gt;Wrapping the HttpContext&lt;/h2&gt;
&lt;p&gt;I created a gist to show this. The usage is easy, just create an IHttpModule and replace the HttpContext by using a custom HttpWorkerRequest instance that accepts a delegate to return whatever you want for IsSecureConnection:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now to create the wrapper, there’s a ton of methods and properties to override:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;So what about OWIN?&lt;/h2&gt;
&lt;p&gt;Owin is easy to take care of, it’s OwinContext.Request.IsSecure is purely based on whether or not the scheme is https and the .Scheme property is settable:&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h2&gt;Does this all actually work?&lt;/h2&gt;
&lt;p&gt;This was an experiment to see how possible this is and based on my rudimentary tests, yes it works. I have no idea if this will have some strange side affects but in theory its all just wrapping what normally executes. There will be a small performance penalty because this is going to create a couple of new objects each request and use a reflection call but I think that will be very trivial.&lt;/p&gt;
&lt;p&gt;Let me know if it works for you!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:10:10 Z</pubDate>
      <a10:updated>2023-03-23T15:10:10Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1309</guid>
      <link>https://shazwazza.com/post/controller-scoped-model-binding-in-aspnet-core/</link>
      <category>ASP.Net</category>
      <title>Controller Scoped Model Binding in ASP.NET Core</title>
      <description>&lt;p&gt;Want to avoid &lt;em&gt;[FromBody]&lt;/em&gt; attributes everywhere? Don’t want to use &lt;em&gt;[ApiController]&lt;/em&gt; strict conventions? Don’t want to apply &lt;em&gt;IInputFormatter&lt;/em&gt;’s globally?&lt;/p&gt;
&lt;p&gt;ASP.NET Core MVC is super flexible but it very much caters towards configuring everything at a global level. Perhaps you are building a framework or library or a CMS in .NET Core? In which case you generally want to be as unobtrusive as possible so mucking around with global MVC configuration isn’t really acceptable. The traditional way of dealing with this is by applying configuration directly to controllers which generally means using controller base classes and attributes. This isn’t super pretty but it works in almost all cases from applying authorization/resource/action/exception/result filters to api conventions. However this doesn’t work for model binding.&lt;/p&gt;
&lt;h2&gt;Model binding vs formatters&lt;/h2&gt;
&lt;p&gt;Model binding comes in 2 flavors: formatters for deserializing the request body (like JSON) into models  and value providers for getting data from other places like form body, query string, headers, etc… Both of these things internally in MVC use model binders though typically the language used for binding the request body are called formatters. The problem with formatters (which are of type &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.formatters.iinputformatter?view=aspnetcore-3.1" target="_blank"&gt;IInputFormatter&lt;/a&gt;) is that they are only applied at the global level as part of &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.mvcoptions.inputformatters?view=aspnetcore-3.1#Microsoft_AspNetCore_Mvc_MvcOptions_InputFormatters" target="_blank"&gt;MvcOptions&lt;/a&gt; which are in turn passed along to a special model binder called &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.modelbinding.binders.bodymodelbinder?view=aspnetcore-3.1" target="_blank"&gt;BodyModelBinder&lt;/a&gt;. Working with &lt;em&gt;IInputFormatter&lt;/em&gt; at the controller level is almost impossible.&lt;/p&gt;
&lt;p&gt;There seems to be a couple options that look like you might be able to apply a custom &lt;em&gt;IInputFormatter&lt;/em&gt; to a specific controller:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a custom &lt;em&gt;IModelBinderProvider&lt;/em&gt; – this unfortunately will not work because the &lt;em&gt;ModelBinderProviderContext&lt;/em&gt; doesn’t provide the &lt;em&gt;ControllerActionDescriptor&lt;/em&gt; executing so you cannot apply this provider to certain controllers/actions (&lt;a rel="noopener" href="https://github.com/dotnet/aspnetcore/issues/21724" target="_blank"&gt;though this should be possible&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Assign a custom &lt;em&gt;IModelBinderFactory&lt;/em&gt; to the controller explicitly by assigning &lt;em&gt;ControllerBase.ModelBinderFactory &lt;/em&gt;in the controllers constructor – this unfortunately doesn’t work because the &lt;em&gt;ControllerBase.ModelBinderFactory &lt;/em&gt;&lt;a rel="noopener" href="https://github.com/dotnet/aspnetcore/issues/21724" target="_blank"&gt;isn’t used for body model binding&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;So how does [ApiController] attribute work?&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;[ApiController]&lt;/em&gt; attribute does quite a lot of things and &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/aspnet/core/web-api/?view=aspnetcore-3.1#apicontroller-attribute" target="_blank"&gt;configures your controller in a very opinionated way&lt;/a&gt;. It almost does what I want and it somehow magically does this&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;[FromBody] is inferred for complex type parameters&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;That’s great! It’s what I want to do but I don’t want to use the &lt;em&gt;[ApiController]&lt;/em&gt; attribute since it applies too many conventions and the only way to toggle these …. is again at the global level :/ This also still doesn’t solve the problem of applying a specific &lt;em&gt;IInputFormatter&lt;/em&gt; to be used for the model binding but it’s a step in the right direction.&lt;/p&gt;
&lt;p&gt;The way that the &lt;em&gt;[ApiController]&lt;/em&gt; attribute works is by using MVC’s &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/application-model?view=aspnetcore-3.1" target="_blank"&gt;“application model”&lt;/a&gt; which is done by implementing &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/application-model?view=aspnetcore-3.1#iapplicationmodelprovider" target="_blank"&gt;IApplicationModelProvider&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;A custom IApplicationModelProvider&lt;/h2&gt;
&lt;p&gt;Taking some inspiration from the way [ApiController] attribute works we can have a look at the source of the application model that makes this happen: &lt;a rel="noopener" href="https://github.com/dotnet/aspnetcore/blob/master/src/Mvc/Mvc.Core/src/ApplicationModels/ApiBehaviorApplicationModelProvider.cs" target="_blank"&gt;ApiBehaviorApplicationModelProvider&lt;/a&gt;. This basically assigns a bunch of &lt;a rel="noopener" href="https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.applicationmodels.iactionmodelconvention?view=aspnetcore-3.1" target="_blank"&gt;IActionModelConvention&lt;/a&gt;’s: &lt;em&gt;ApiVisibilityConvention&lt;/em&gt;, &lt;em&gt;ClientErrorResultFilterConvention&lt;/em&gt;, &lt;em&gt;InvalidModelStateFilterConvention&lt;/em&gt;, &lt;em&gt;ConsumesConstraintForFormFileParameterConvention&lt;/em&gt;, &lt;em&gt;ApiConventionApplicationModelConvention&lt;/em&gt;, and &lt;em&gt;InferParameterBindingInfoConvention&lt;/em&gt;. The last one &lt;strong&gt;InferParameterBindingInfoConvention &lt;/strong&gt;is the important one that magically makes complex type parameters bind from the request body like JSON like good old WebApi used to do.&lt;/p&gt;
&lt;p&gt;So we can make our own application model to target our own controllers and use a custom &lt;em&gt;IActionModelConvention&lt;/em&gt; to apply a custom body model binder:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;
public class MyApplicationModelProvider : IApplicationModelProvider
{
    public MyApplicationModelProvider(IModelMetadataProvider modelMetadataProvider)
    {
        ActionModelConventions = new List&amp;lt;IActionModelConvention&amp;gt;()
        {
            // Ensure complex models are bound from request body
            new InferParameterBindingInfoConvention(modelMetadataProvider),
            // Apply custom IInputFormatter to the request body
            new MyModelBinderConvention()
        };
    }

    public List&amp;lt;IActionModelConvention&amp;gt; ActionModelConventions { get; }

    public int Order =&amp;gt; 0;

    public void OnProvidersExecuted(ApplicationModelProviderContext context)
    {
    }

    public void OnProvidersExecuting(ApplicationModelProviderContext context)
    {
        foreach (var controller in context.Result.Controllers)
        {
            // apply conventions to all actions if attributed with [MyController]
            if (IsMyController(controller))
                foreach (var action in controller.Actions)
                    foreach (var convention in ActionModelConventions)
                        convention.Apply(action);
        }
    }

    // returns true if the controller is attributed with [MyController]
    private bool IsMyController(ControllerModel controller)
        =&amp;gt; controller.Attributes.OfType&amp;lt;MyControllerAttribute&amp;gt;().Any();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And the custom convention:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;
public class MyModelBinderConvention : IActionModelConvention
{
    public void Apply(ActionModel action)
    {
        foreach (var p in action.Parameters
            // the InferParameterBindingInfoConvention must execute first,
            // which assigns this BindingSource, so if that is assigned
            // we can then assign a custom BinderType to be used.
            .Where(p =&amp;gt; p.BindingInfo?.BindingSource == BindingSource.Body))
        {
            p.BindingInfo.BinderType = typeof(MyModelBinder);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Based on the above application model conventions, any controller attributed with our custom &lt;em&gt;[MyController]&lt;/em&gt; attribute will have these conventions applied to all of it’s actions. With the above, any complex model that will be bound from the request body will use the &lt;em&gt;IModelBinder&lt;/em&gt; type: &lt;em&gt;MyModelBinder, &lt;/em&gt;so here’s how that implementation could look:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;
// inherit from BodyModelBinder - it does a bunch of magic like caching
// that we don't want to miss out on
public class MyModelBinder : BodyModelBinder
{
    // TODO: You can inject other dependencies to pass to GetInputFormatter
    public MyModelBinder(IHttpRequestStreamReaderFactory readerFactory)
        : base(GetInputFormatter(), readerFactory)
    {
    }

    private static IInputFormatter[] GetInputFormatter()
    {  
        return new IInputFormatter[]
        {
            // TODO: Return any IInputFormatter you want
            new MyInputFormatter()
        };
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The last thing to do is wire it up in DI:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;
services.TryAddSingleton&amp;lt;MyModelBinder&amp;gt;();            
services.TryAddEnumerable(
    ServiceDescriptor.Transient&amp;lt;IApplicationModelProvider,
    MyApplicationModelProvider&amp;gt;());
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That’s a reasonable amount of plumbing!&lt;/p&gt;
&lt;p&gt;It could certainly be simpler to configure a body model binder at the controller level but at least there’s actually a way to do it. For a single controller this is quite a lot of work but for a lot of controllers the MVC “application mode” is quite brilliant! … it just took a lot of source code reading to figure that out :)&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:09:49 Z</pubDate>
      <a10:updated>2023-03-23T15:09:49Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1222</guid>
      <link>https://shazwazza.com/post/how-to-register-mvc-controllers-shipped-with-a-class-library-in-aspnet-core/</link>
      <category>ASP.Net</category>
      <title>How to register MVC controllers shipped with a class library in ASP.NET Core</title>
      <description>&lt;p&gt;In many cases you’ll want to ship MVC controllers, possibly views or taghelpers, etc… as part of your class library. To do this correctly you’ll want to add your assembly to ASP.NET’s “Application Parts” on startup. Its quite simple to do but you might want to make sure you are not enabling all sorts of services that the user of your library doesn’t need.&lt;/p&gt;
&lt;p&gt;The common way to do this on startup is to have your own extension method to “Add” your class library to the services. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;public static class MyLibStartup
{
    public static IServiceCollection AddMyLib(this IServiceCollection services)
    {
        //TODO: Add your own custom services to DI

        //Add your assembly to the ASP.NET application parts
        var builder = services.AddMvc();
        builder.AddApplicationPart(typeof(MyLibStartup).Assembly);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will work, but the call to &lt;a rel="noopener" href="https://github.com/aspnet/Mvc/blob/master/src/Microsoft.AspNetCore.Mvc/MvcServiceCollectionExtensions.cs#L26" target="_blank"&gt;AddMvc() is doing a lot more than you might think&lt;/a&gt; &lt;em&gt;(also note in &lt;/em&gt;&lt;a rel="noopener" href="https://github.com/aspnet/AspNetCore/blob/master/src/Mvc/Mvc/src/MvcServiceCollectionExtensions.cs#L27" target="_blank"&gt;&lt;em&gt;ASP.NET Core 3, it’s doing a similar amount&lt;/em&gt;&lt;/a&gt;&lt;em&gt; of work). &lt;/em&gt;This call is adding all of the services to the application required for: authorization, controllers, views, taghelpers, razor, api explorer, CORS, and more… This might be fine if your library requires all of these things but otherwise unless the user of your library also wants all of these things, in my opinion it’s probably better to only automatically add the services that you know your library needs.&lt;/p&gt;
&lt;p&gt;In order to add your assembly application part you need a reference to &lt;em&gt;IMvcBuilder&lt;/em&gt; which you can resolve by calling any number of the extension methods to add the services you need. Depending on what your application requires will depend on what services you’ll want to add. It’s probably best to start with the lowest common feature-set which is a call to AddMvcCore(), the updated code might look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;//Add your assembly to the ASP.NET application parts
var builder = services.AddMvcCore();
builder.AddApplicationPart(typeof(MyLibStartup).Assembly);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;From there you can add the other bits you need, for example, maybe you also need CORS:&lt;/p&gt;
&lt;pre&gt;&lt;code class="lang-csharp"&gt;//Add your assembly to the ASP.NET application parts
var builder = services.AddMvcCore().AddCors();
builder.AddApplicationPart(typeof(MyLibStartup).Assembly);&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:09:29 Z</pubDate>
      <a10:updated>2023-03-23T15:09:29Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1231</guid>
      <link>https://shazwazza.com/post/benchmarking-performance-of-your-code-between-release-versions/</link>
      <category>ASP.Net</category>
      <title>Benchmarking performance of your code between release versions</title>
      <description>&lt;p&gt;A while ago in 2016 I posted a &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet/issues/290" target="_blank"&gt;question&lt;/a&gt; on the &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet" target="_blank"&gt;BenchmarkDotNet&lt;/a&gt; repository about an official way to run benchmarks between Nuget releases. In 2018 I managed to find some time and with the with the help of &lt;a rel="noopener" href="https://github.com/adamsitnik" target="_blank"&gt;Adam Sitnik&lt;/a&gt; (one of the project’s maintainers), was able to &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet/pull/922" target="_blank"&gt;make that work&lt;/a&gt;!&lt;/p&gt;
&lt;p&gt;I won’t go into detail about what BenchmarkDotNet is, but it’s a brilliant way to accurately run benchmarks against your code to see how it performs, how much memory is being used, etc…&lt;/p&gt;
&lt;p&gt;With this new feature you can now easily see how your code changes effect performance between your releases.&lt;/p&gt;
&lt;h2&gt;Show me the code&lt;/h2&gt;
&lt;p&gt;Making this work is quite easy and there’s a &lt;a rel="noopener" href="https://github.com/dotnet/BenchmarkDotNet/blob/master/samples/BenchmarkDotNet.Samples/IntroNuGet.cs" target="_blank"&gt;quick start code snippet&lt;/a&gt; in the repo already. For the example below I’ll use &lt;a rel="noopener" href="https://sixlabors.com/projects/imagesharp/" target="_blank"&gt;ImageSharp&lt;/a&gt; as the library to be tested and we’ll see how well &lt;a rel="noopener" href="https://twitter.com/James_M_South" target="_blank"&gt;James&lt;/a&gt; and his team is doing with regards to improving it’s JPEG decoding performance.&lt;/p&gt;
&lt;pre class="lang-csharp"&gt;&lt;code&gt;
[Config(typeof(Config))]
public class ImageTests
{
    private static readonly string _filePath = @"C:\temp\test.jpg";

    private class Config : ManualConfig
    {
        public Config()
        {
            var baseJob = Job.MediumRun.With(CsProjCoreToolchain.Current.Value);
            Add(baseJob.WithNuGet("SixLabors.ImageSharp", "1.0.0-beta0006").WithId("1.0.0-beta0006"));
            Add(baseJob.WithNuGet("SixLabors.ImageSharp", "1.0.0-beta0005").WithId("1.0.0-beta0005"));
            Add(baseJob.WithNuGet("SixLabors.ImageSharp", "1.0.0-beta0004").WithId("1.0.0-beta0004"));
        }
    }

    [Benchmark]
    public Size LoadJpg()
    {
        using (var img = Image.Load(_filePath))
        {
            var size = img.Size();
            return size;
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The code above should seem pretty straightforward. It’s just setting up 3 BenchmarkDotNet jobs, each using a different version of the SixLabors.ImageSharp Nuget package. Then the actual benchmark test is loading in a JPEG extracting it’s size and returning it.&lt;/p&gt;
&lt;p&gt;Running the benchmark is like running any other BenchmarkDotNet test, for example in a console app:&lt;/p&gt;
&lt;pre class="lang-csharp"&gt;&lt;code&gt;
class Program
{
    static void Main(string[] args)
    {   
        var summary = BenchmarkRunner.Run();
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;The results&lt;/h2&gt;
&lt;table border="0"&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Method&lt;/th&gt;
&lt;th&gt;Job&lt;/th&gt;
&lt;th&gt;NuGetReferences&lt;/th&gt;
&lt;th&gt;Mean&lt;/th&gt;
&lt;th&gt;Error&lt;/th&gt;
&lt;th&gt;StdDev&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;LoadJpg&lt;/td&gt;
&lt;td&gt;1.0.0-beta0004&lt;/td&gt;
&lt;td&gt;SixLabors.ImageSharp 1.0.0-beta0004&lt;/td&gt;
&lt;td&gt;297.5 ms&lt;/td&gt;
&lt;td&gt;142.8 ms&lt;/td&gt;
&lt;td&gt;7.827 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoadJpg&lt;/td&gt;
&lt;td&gt;1.0.0-beta0005&lt;/td&gt;
&lt;td&gt;SixLabors.ImageSharp 1.0.0-beta0005&lt;/td&gt;
&lt;td&gt;202.9 ms&lt;/td&gt;
&lt;td&gt;466.6 ms&lt;/td&gt;
&lt;td&gt;25.577 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LoadJpg&lt;/td&gt;
&lt;td&gt;1.0.0-beta0006&lt;/td&gt;
&lt;td&gt;SixLabors.ImageSharp 1.0.0-beta0006&lt;/td&gt;
&lt;td&gt;148.8 ms&lt;/td&gt;
&lt;td&gt;107.8 ms&lt;/td&gt;
&lt;td&gt;5.910 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Looks good! from the beta0004 release to the beta0006 release there’s almost twice the performance boost.&lt;/p&gt;
&lt;h2&gt;API Surface Area&lt;/h2&gt;
&lt;p&gt;There is one caveat though… In order to run these tests between versions of your library, the same API surface area will need to exist otherwise you’ll get exceptions when running the benchmarks. This is the reason why versions beta0001 –&amp;gt; beta0003 are not included in the jobs listed above. Its because in the older versions either the APIs were different or the namespaces were different.&lt;/p&gt;
&lt;p&gt;It is possible to work around this but you’d need to use some ugly reflection to do it and then you need to be careful that you are not testing the reflection performance hit either.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Now you should have a pretty easy way to know how the performance of your library is changing between versions. Happy coding!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:09:17 Z</pubDate>
      <a10:updated>2023-03-23T15:09:17Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1213</guid>
      <link>https://shazwazza.com/post/configuring-azure-active-directory-login-with-umbraco-members/</link>
      <category>ASP.Net</category>
      <category>Web Development</category>
      <category>Umbraco</category>
      <title>Configuring Azure Active Directory login with Umbraco Members</title>
      <description>&lt;p&gt;This post is about configuring Azure Active Directory with Umbraco &lt;u&gt;Members&lt;/u&gt; (not &lt;em&gt;Users&lt;/em&gt;), meaning this is for your front-end website, not the Umbraco back office. I did write up a post about Azure AD with back office users though, so if that is what you are looking for then &lt;a href="https://shazwazza.com/post/configuring-azure-active-directory-login-with-umbraco/" target="_blank"&gt;this is the link&lt;/a&gt;. &lt;/p&gt;&lt;h2&gt;Install the Nuget packages&lt;/h2&gt;&lt;p&gt;First thing to do is get the &lt;a href="https://www.nuget.org/packages/UmbracoIdentity" target="_blank"&gt;UmbracoIdentity&lt;/a&gt; package installed. &lt;/p&gt;

&lt;div style="width: 100%;"&gt;
&lt;div style="padding: 10px; color: rgb(255, 255, 255); line-height: 1.5; font-family: consolas, menlo, monaco,&amp;quot;Courier New&amp;quot;, monospace; background-color: rgb(0, 36, 64);"&gt;PM &amp;gt; Install-Package UmbracoIdentity&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(This will also install the UmbracoIdentity.Core base package)&lt;/em&gt;&lt;/p&gt;&lt;p&gt;This package installs some code snippets and updates your web.config to enable ASP.Net Identity for Umbraco members. Umbraco ships with the old and deprecated ASP.Net Membership Providers for members and not ASP.Net Identity so this package extends the Umbraco CMS and the Umbraco members implementation to use ASP.Net Identity APIs to interact with the built in members data store. Installing this package will remove the (deprecated) FormsAuthentication module from your web.config and it will no longer be used to authenticate members, so the typical members snippets built into Umbraco macros will not work. Instead use the supplied snippets shipped with this package.&lt;/p&gt;&lt;p&gt;To read more about this package see the &lt;a href="https://github.com/Shazwazza/UmbracoIdentity" target="_blank"&gt;GitHub repo here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Next, the OpenIdConnect package needs to be installed&lt;/p&gt;

&lt;div style="width: 100%;"&gt;
&lt;div style="padding: 10px; color: rgb(255, 255, 255); line-height: 1.5; font-family: consolas, menlo, monaco,&amp;quot;Courier New&amp;quot;, monospace; background-color: rgb(0, 36, 64);"&gt;PM &amp;gt; Install-Package Microsoft.Owin.Security.OpenIdConnect&lt;/div&gt;
&lt;/div&gt;

&lt;h2&gt;Configure Azure Active Directory&lt;/h2&gt;&lt;p&gt;Head over to the &lt;em&gt;Azure Active Directory &lt;/em&gt;section on the Azure portal, choose &lt;em&gt;App Registrations &lt;/em&gt;(I’m using the Preview functionality for this) and create a &lt;em&gt;New registration&lt;/em&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_4.png"&gt;&lt;img width="802" height="362" title="image" style="display: inline; background-image: none;" alt="image" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_thumb_1.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;h3&gt;Next fill out the app details&lt;/h3&gt;&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_22.png"&gt;&lt;img width="802" height="805" title="image" style="display: inline; background-image: none;" alt="image" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_thumb_10.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;You may also need to enter other redirect URLs depending on how many different environments you have. All of these URLs can be added in the Authentication section of your app in the Azure portal.&lt;/p&gt;&lt;p&gt;For AAD configuration for front-end members, the redirect Urls are just your website’s root URL and it is advised to keep the trailing slash. &lt;/p&gt;&lt;h3&gt;Next you will need to enable Id Tokens&lt;/h3&gt;&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_12.png"&gt;&lt;img width="802" height="559" title="image" style="display: inline; background-image: none;" alt="image" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_thumb_5.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;h2&gt;Configure OpenIdConnect&lt;/h2&gt;&lt;p&gt;The UmbracoIdentity package will have installed an OWIN startup class in &lt;em&gt;~/App_Start/UmbracoIdentityStartup.cs &lt;/em&gt;(or it could be in App_Code if you are using a website project)&lt;em&gt;. &lt;/em&gt;This is how ASP.Net Identity is configured for front-end members and where you can specify the configuration for different OAuth providers. There’s a few things you’ll need to do:&lt;/p&gt;&lt;h3&gt;Allow external sign in cookies&lt;/h3&gt;&lt;p&gt;If you scroll down to the &lt;em&gt;ConfigureMiddleware &lt;/em&gt;method, there will be a link of code to uncomment: &lt;em&gt;app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie); &lt;/em&gt;this is required for any OAuth providers to work.&lt;/p&gt;&lt;h3&gt;Enable OpenIdConnect OAuth for AAD&lt;/h3&gt;&lt;p&gt;You’ll need to add this extension method class to your code which is some boiler plate code to configure OpenIdConnect with AAD:&lt;/p&gt;

&lt;pre class="lang-csharp"&gt;&lt;code&gt;public static class UmbracoADAuthExtensions
{
    public static void ConfigureAzureActiveDirectoryAuth(this IAppBuilder app,
        string tenant, string clientId, string postLoginRedirectUri, Guid issuerId,
        string caption = "Active Directory")
    {
        var authority = string.Format(
            System.Globalization.CultureInfo.InvariantCulture,
            "https://login.windows.net/{0}",
            tenant);

        var adOptions = new OpenIdConnectAuthenticationOptions
        {
            ClientId = clientId,
            Authority = authority,
            RedirectUri = postLoginRedirectUri
        };

        adOptions.Caption = caption;
        //Need to set the auth type as the issuer path
        adOptions.AuthenticationType = string.Format(
            System.Globalization.CultureInfo.InvariantCulture,
            "https://sts.windows.net/{0}/",
            issuerId);
        app.UseOpenIdConnectAuthentication(adOptions);
    }
}&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Next you’ll need to call this code, add the following line underneath the &lt;em&gt;app.UseExternalSignInCookie&lt;/em&gt; method call: &lt;/p&gt;

&lt;pre class="lang-csharp"&gt;&lt;code&gt;app.ConfigureAzureActiveDirectoryAuth(
    ConfigurationManager.AppSettings["azureAd:tenantId"],
    ConfigurationManager.AppSettings["azureAd:clientId"],
    //The value of this will need to change depending on your current environment
    postLoginRedirectUri: ConfigurationManager.AppSettings["azureAd:redirectUrl"],
    //This is the same as the TenantId
    issuerId: new Guid(ConfigurationManager.AppSettings["azureAd:tenantId"]));&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then you’ll need to add a few appSettings to your web.config (based on your AAD info):&lt;/p&gt;

&lt;pre class="lang-csharp"&gt;&lt;code&gt;&amp;lt;add key="azureAd:tenantId" value="YOUR-TENANT-ID-GUID" /&amp;gt;
&amp;lt;add key="azureAd:clientId" value="YOUR-CLIENT-ID-GUID" /&amp;gt;
&amp;lt;add key="azureAd:redirectUrl" value="http://my-test-website/" /&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Configure your Umbraco data&lt;/h2&gt;&lt;p&gt;The UmbracoIdentity repository has the &lt;a href="https://github.com/Shazwazza/UmbracoIdentity#installation" target="_blank"&gt;installation documentation&lt;/a&gt; and you must follow these 2 instructions, and they are very simple:&lt;/p&gt;&lt;ol&gt;&lt;li&gt;&lt;a href="https://github.com/Shazwazza/UmbracoIdentity/wiki#2-member-type-updates" target="_blank"&gt;You need to update your member type with the securityStamp property&lt;/a&gt;&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/Shazwazza/UmbracoIdentity/wiki#3-creating-the-account-page" target="_blank"&gt;Create the Account document type&lt;/a&gt;&lt;/li&gt;&lt;/ol&gt;&lt;p&gt;Once that is done you will have an Member account management page which is based off of the installed views and snippets of the UmbracoIdentity package. This account page will look like this:&lt;/p&gt;&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_8.png"&gt;&lt;img width="802" height="305" title="image" style="display: inline; background-image: none;" alt="image" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_thumb_3.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;As you can see the button text under the “Use another service to log in” is the login provider name which is a bit ugly. The good news is that this is easy to change since this is just a partial view that was installed with the UmbracoIdentity package. You can edit the file: &lt;em&gt;~/Views/UmbracoIdentityAccount/ExternalLoginsList.cshtml&lt;/em&gt;, the code to render that button text is using &lt;em&gt;@p.Authentication&lt;/em&gt; provider but we can easily change this to &lt;em&gt;@p.Caption&lt;/em&gt; which is actually the same caption text used in the extension method we created. So the whole button code can look like this instead:&lt;/p&gt;
&lt;pre class="lang-html"&gt;&lt;code&gt;
&amp;lt;button type="submit" class="btn btn-default"
        id="@p.AuthenticationType"
        name="provider"
        value="@p.AuthenticationType"
        title="Log in using your @p.Caption account"&amp;gt;
    @p.Caption
&amp;lt;/button&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This is a bit nicer, now the button looks like:&lt;/p&gt;&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_10.png"&gt;&lt;img width="802" height="192" title="image" style="display: inline; background-image: none;" alt="image" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_thumb_4.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;The purpose of all of these snippets and views installed with UmbracoIdentity is for you to customize how the whole flow looks and works so you’ll most likely end up customizing a number of views found in this folder to suit your needs.&lt;/p&gt;&lt;h2&gt;That’s it!&lt;/h2&gt;&lt;p&gt;Once that’s all configured, if you click on the Active Directory button to log in as a member, you’ll be brought to the standard AAD permission screen:&lt;/p&gt;&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_18.png"&gt;&lt;img width="402" height="434" title="image" style="display: inline; background-image: none;" alt="image" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_thumb_8.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Once you accept you’ll be redirect back to your Account page:&lt;/p&gt;&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_20.png"&gt;&lt;img width="802" height="930" title="image" style="display: inline; background-image: none;" alt="image" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-active-directory-login_c313-image_thumb_9.png" border="0"&gt;&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Any customizations is then up to you. You can modify how the flow works, whether or not you accepting auto-linking accounts (like in the above example), or if you require a member to exist locally before being able to link an OAuth account, etc… All of the views and controller code in UmbracoIdentity is there for you to manipulate. The main files are:&lt;/p&gt;&lt;ul&gt;&lt;li&gt;~/Views/Account.cshtml&lt;/li&gt;&lt;li&gt;~/Views/UmbracoIdentityAccount/*&lt;/li&gt;&lt;li&gt;~/Controllers/UmbracoIdentityAccountController.cs&lt;/li&gt;&lt;li&gt;~/App_Start/UmbracoIdentityStartup.cs&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;&lt;br&gt;&lt;/p&gt;&lt;p&gt;Happy coding!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:09:08 Z</pubDate>
      <a10:updated>2023-03-23T15:09:08Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1302</guid>
      <link>https://shazwazza.com/post/configuring-azure-active-directory-login-with-umbraco/</link>
      <category>ASP.Net</category>
      <category>Umbraco</category>
      <title>Configuring Azure Active Directory login with Umbraco</title>
      <description>&lt;p&gt;It’s been a while since I first set this up and back then not all of these settings were in the new Azure portal, but now that they are getting this all configured is quite easy so here’s the basic steps!&lt;/p&gt;
&lt;h2&gt;Install the Nuget package&lt;/h2&gt;
&lt;p&gt;First thing to do is get the &lt;a rel="noopener" href="https://www.nuget.org/packages/UmbracoCms.IdentityExtensions.AzureActiveDirectory" target="_blank"&gt;UmbracoCms.IdentityExtensions.AzureActiveDirectory&lt;/a&gt; package installed&lt;/p&gt;
&lt;div style="width: 100%;"&gt;
&lt;div style="padding: 10px; color: #ffffff; line-height: 1.5; font-family: consolas, menlo, monaco,'Courier New', monospace; background-color: #002440;"&gt;PM &amp;gt; Install-Package UmbracoCms.IdentityExtensions.AzureActiveDirectory&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;em&gt;(This will also install the UmbracoCms.IdentityExtensions base package)&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Configure Azure Active Directory&lt;/h2&gt;
&lt;p&gt;Head over to the &lt;em&gt;Azure Active Directory &lt;/em&gt;section on the Azure portal, choose &lt;em&gt;App Registrations &lt;/em&gt;(I’m using the Preview functionality for this) and create a &lt;em&gt;New registration&lt;/em&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_4.png"&gt;&lt;img style="border: 0px currentcolor; display: inline; background-image: none;" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_thumb_1.png" border="0" alt="image" title="image" width="802" height="362" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Next fill out the app details&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_6.png"&gt;&lt;img style="border: 0px currentcolor; display: inline; background-image: none;" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_thumb_2.png" border="0" alt="image" title="image" width="802" height="805" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Add your redirect URLs for any additional environments&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_10.png"&gt;&lt;img style="border: 0px currentcolor; display: inline; background-image: none;" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_thumb_4.png" border="0" alt="image" title="image" width="802" height="382" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;If you have local, dev, staging, live, etc… sites, you’ll need to configure those URLs here, always make sure it’s the Umbraco path with a trailing slash.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h3&gt;Make note of some settings&lt;/h3&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_8.png"&gt;&lt;img style="border: 0px currentcolor; display: inline; background-image: none;" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_thumb_3.png" border="0" alt="image" title="image" width="802" height="262" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;The settings you’ll need to copy are the Application/Client ID and the Tenant ID along with the redirect URLs.&lt;/p&gt;
&lt;h2&gt;Configure you application&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;Add the Client Id, Tenant Id and redirect URL to AppSettings. I’ve used the keys: azureAd:tenantId, azureAd:clientId, azureAd:redirectUrl but you can choose whatever you like.&lt;/li&gt;
&lt;li&gt;Open the &lt;em&gt;App_Start/UmbracoStandardOwinStartup.cs&lt;/em&gt; file that was installed with the IdentityExtensions pakage&lt;/li&gt;
&lt;li&gt;Underneath the call to &lt;em&gt;base.Configuration(app); &lt;/em&gt;add the block of code that was shown in the readme shown after you installed the Nuget package which looks like this:
&lt;pre&gt;&lt;code class="lang-csharp"&gt;app.ConfigureBackOfficeAzureActiveDirectoryAuth(
    //The Tenant can also be "YOURDIRECTORYNAME.onmicrosoft.com"
    tenant: ConfigurationManager.AppSettings["azureAd:tenantId"],
    clientId: ConfigurationManager.AppSettings["azureAd:clientId"],
    //The value of this will need to change depending on your current environment
    postLoginRedirectUri: ConfigurationManager.AppSettings["azureAd:redirectUrl"],
    //This is the same as the TenantId
    issuerId: new Guid(ConfigurationManager.AppSettings["azureAd:tenantId"]));
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;Ensure that this OWIN startup class is defined in your web.config: &lt;em&gt;&amp;lt;add key="owin:appStartup" value="UmbracoStandardOwinStartup" /&amp;gt;  &lt;/em&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;That's it!&lt;/h2&gt;
&lt;p&gt;Once you’ve got this configured, and you login to the back office normally you can then link your AD account:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_12.png"&gt;&lt;img style="border: 0px currentcolor; display: inline; background-image: none;" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_thumb_5.png" border="0" alt="image" title="image" width="802" height="409" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Once linked, you can login with this provider:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_14.png"&gt;&lt;img style="border: 0px currentcolor; display: inline; background-image: none;" src="https://shazwazza.com/media/articulate/open-live-writer-configuring-azure-ad-oauth-login-with-um_bc18-image_thumb_6.png" border="0" alt="image" title="image" width="802" height="495" /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Auto linking?&lt;/h2&gt;
&lt;p&gt;If you configured your AD App to only authenticate “only accounts in this organization”, you might want to auto-link Umbraco back office accounts. Auto-linking will automatically ensure that a local Umbraco user account exists for any user that logs in via the AD provider. This is handy if you want to do all of your user administration via Azure AD. Auto-linking can be configured as part of your OWIN startup class.&lt;/p&gt;
&lt;p&gt;I won’t cover auto-linking in this post but there are some &lt;a rel="noopener" href="https://our.umbraco.com/documentation/Reference/Security/#auto-linking-accounts-for-custom-oauth-providers" target="_blank"&gt;docs&lt;/a&gt; available for that.&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:09:04 Z</pubDate>
      <a10:updated>2023-03-23T15:09:04Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1281</guid>
      <link>https://shazwazza.com/post/getting-umbraco-to-work-with-azure-easy-auth/</link>
      <category>ASP.Net</category>
      <category>Umbraco</category>
      <title>Getting Umbraco to work with Azure Easy Auth</title>
      <description>&lt;p&gt;There’s a nifty feature in your Azure App Service that allows you to very quickly add authentication and authorization to your Azure website. You’ll see most folks calling this “Easy Auth” and there’s quite a few articles on the subject such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://medium.com/tech-feed/azure-active-directorys-hidden-feature-easy-auth-315e34d92249" title="https://medium.com/tech-feed/azure-active-directorys-hidden-feature-easy-auth-315e34d92249"&gt;https://medium.com/tech-feed/azure-active-directorys-hidden-feature-easy-auth-315e34d92249&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://azure.microsoft.com/en-us/resources/videos/azure-websites-easy-authentication-and-authorization-with-chris-gillum/" title="https://azure.microsoft.com/en-us/resources/videos/azure-websites-easy-authentication-and-authorization-with-chris-gillum/"&gt;https://azure.microsoft.com/en-us/resources/videos/azure-websites-easy-authentication-and-authorization-with-chris-gillum/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.microsoft.com/en-us/azure/app-service/app-service-authentication-overview" title="https://docs.microsoft.com/en-us/azure/app-service/app-service-authentication-overview"&gt;https://docs.microsoft.com/en-us/azure/app-service/app-service-authentication-overview&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The good news is this all works the way you’d expect with an Umbraco website for front-end requests but unfortunately this doesn’t play nicely with the Umbraco back office … but it’s easy to configure Umbraco to work!&lt;/p&gt;
&lt;h2&gt;The problem&lt;/h2&gt;
&lt;p&gt;The problem is that if you turn on Easy Auth and try to log in to your Umbraco back office, the login will succeed but you’ll get 401 responses for other back office requests and essentially you’ll see a blank screen. The reason this happens is due to the way that Easy Auth works:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;It activates an HttpModule in your site called &lt;strong&gt;EasyAuthAspNetThreadPrincipalModule&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;During the &lt;em&gt;HttpModule.AuthenticateRequest&lt;/em&gt; stage it replaces the &lt;em&gt;Thread.CurrentPrincipal&lt;/em&gt; with it’s own &lt;em&gt;ClaimsPrincipal&lt;/em&gt;/&lt;em&gt;ClaimsIdentity&lt;/em&gt; instance&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Umbraco also sets the &lt;em&gt;Thread.CurrentPrincipal.Identity &lt;/em&gt;during this phase but at the OWIN level which executes before the &lt;em&gt;EasyAuthAspNetThreadPrincipalModule. &lt;/em&gt;Because the Easy Auth module replaces the principal/identity, it wipes out the one created by Umbraco. What it should do instead is check if the current principal is a &lt;em&gt;ClaimsPrincipal &lt;/em&gt;and then add it’s identity to the identity collection instead of wiping out anything that is already there. If that were the case, everything would ‘just work’ but since it is not we have to work around this issue.&lt;/p&gt;
&lt;h2&gt;The solution&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;UPDATE!&lt;/strong&gt; &lt;em&gt;(19/04/18) - &lt;a rel="noopener" href="https://twitter.com/cgillum" target="_blank" title="Chris Gillum"&gt;Chris Gillum&lt;/a&gt; who created Easy Auth got in touch with me on Twitter to share some &lt;a href="https://github.com/cgillum/easyauth/wiki"&gt;handy (and fairly hidden) documentation&lt;/a&gt; for Easy Auth. Looks like another work around is to use the &lt;a href="https://github.com/cgillum/easyauth/wiki/Advanced-Application-Settings"&gt;WEBSITE_AUTH_DISABLE_IDENTITY_FLOW&lt;/a&gt; appSetting which will prevent Easy Auth from setting the thread identity at all.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;To work around this problem we need to tell Umbraco to perform it’s authentication procedure &lt;strong&gt;after&lt;/strong&gt; the Easy Auth module runs which is actually pretty easy to do.&lt;/p&gt;
&lt;p&gt;Create a new OWIN startup class:&lt;/p&gt;
&lt;pre class="lang-csharp"&gt;&lt;code&gt;
[assembly: OwinStartup("MyOwinStartup", typeof(MyOwinStartup))]
namespace MyProject
{
    public class MyOwinStartup : Umbraco.Web.UmbracoDefaultOwinStartup
    {
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Update an appSetting in your web.config to tell OWIN to use your class:&lt;/p&gt;
&lt;pre class="lang-xml"&gt;&lt;code&gt;
&amp;lt;add key="owin:appStartup" value="MyOwinStartup" /&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Override the method that configures Umbraco's authentication procedure and tell it to execute after the default Authentication stage, notice this code block is using PipelineStage.PostAuthenticate:&lt;/p&gt;
&lt;pre class="lang-csharp"&gt;&lt;code&gt;
public class MyOwinStartup : Umbraco.Web.UmbracoDefaultOwinStartup
{
    protected override void ConfigureUmbracoAuthentication(IAppBuilder app)
    {
        app
            .UseUmbracoBackOfficeCookieAuthentication(ApplicationContext, PipelineStage.PostAuthenticate)
            .UseUmbracoBackOfficeExternalCookieAuthentication(ApplicationContext, PipelineStage.PostAuthenticate)
            .UseUmbracoPreviewAuthentication(ApplicationContext, PipelineStage.Authorize);
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That's it! Now the Umbraco back office will authenticate correctly with Azure Easy Auth turned on.&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:56 Z</pubDate>
      <a10:updated>2023-03-23T15:08:56Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1236</guid>
      <link>https://shazwazza.com/post/using-iexceptionlogger-with-per-controller-icontrollerconfiguration-in-webapi/</link>
      <category>ASP.Net</category>
      <title>Using IExceptionLogger with per-controller IControllerConfiguration in WebApi</title>
      <description>&lt;p&gt;There’s plenty of examples online about implementing a custom &lt;a href="https://docs.microsoft.com/en-us/aspnet/web-api/overview/error-handling/web-api-global-error-handling"&gt;IExceptionLogger globally in WebApi&lt;/a&gt; and I’m sure they all work as expected but what if you don’t want to register it globally? In that case you’d use an instance of &lt;em&gt;IControllerConfiguration&lt;/em&gt; to do a &lt;a href="https://blogs.msdn.microsoft.com/jmstall/2012/05/11/per-controller-configuration-in-webapi/"&gt;“per-controller”&lt;/a&gt; configuration and in theory you could just use this syntax:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;
public class MyExceptionLoggerConfigurationAttribute : Attribute, IControllerConfiguration
{
	public virtual void Initialize(
		HttpControllerSettings controllerSettings, 
		HttpControllerDescriptor controllerDescriptor)
	{
		controllerSettings.Services.Add(
			typeof(IExceptionLogger), 
			new UnhandledExceptionLogger());
	}	
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That seems pretty simple, and then you attribute whatever controller you want to use this new &lt;em&gt;IExceptionLogger&lt;/em&gt; … &lt;strong&gt;nope&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;As it turns out, the custom &lt;em&gt;UnhandledExceptionLogger&lt;/em&gt; instance will never get executed unless there is also an &lt;em&gt;ExceptionFilter&lt;/em&gt; applied to the controller (even if it doesn’t do anything)! I can’t find documentation on this anywhere but it’s definitely the case. So to make the above work, we can just replace &lt;em&gt;Attribute&lt;/em&gt; with &lt;em&gt;ExceptionFilterAttribute&lt;/em&gt; like:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;
public class MyExceptionLoggerConfigurationAttribute : ExceptionFilterAttribute, IControllerConfiguration
{
	public virtual void Initialize(
		HttpControllerSettings controllerSettings, 
		HttpControllerDescriptor controllerDescriptor)
	{
		controllerSettings.Services.Add(
			typeof(IExceptionLogger), 
			new UnhandledExceptionLogger());
	}	
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And voila! this works.&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:35 Z</pubDate>
      <a10:updated>2023-03-23T15:08:35Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1280</guid>
      <link>https://shazwazza.com/post/umbraco-passwords-and-aspnet-machine-keys/</link>
      <category>ASP.Net</category>
      <category>Umbraco</category>
      <title>Umbraco passwords and ASP.NET Machine Keys</title>
      <description>&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update!&lt;/strong&gt; I’ve updated a few points below in bold and have corrected a few things too&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This blog post is the result of a thread on Twitter which starts here: &lt;a href="https://twitter.com/crumpled_jeavon/status/880522105795870720" title="https://twitter.com/crumpled_jeavon/status/880522105795870720"&gt;https://twitter.com/crumpled_jeavon/status/880522105795870720&lt;/a&gt; and works its way into confusion. Suffice to say I can’t answer these questions in 140 chars so here’s re-cap in the form of Q and A about Machine Keys and Umbraco. Please note that I am not an expert in hashing algorithms, some of these answers are based on my own research. Hope this clears things up!&lt;/p&gt;
&lt;h3&gt;How is the password hashed?&lt;/h3&gt;
&lt;p&gt;It is &lt;a rel="noopener noreferrer" href="https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Core/Security/MembershipProviderBase.cs#L671" target="_blank"&gt;hashed in the same way&lt;/a&gt; that the ASP.NET Universal membership provider (&lt;a rel="noopener noreferrer" href="https://www.nuget.org/packages/Microsoft.AspNet.Providers.Core/" target="_blank"&gt;DefaultMembershipProvider&lt;/a&gt;) and &lt;a rel="noopener noreferrer" href="https://referencesource.microsoft.com/#System.Web/Security/SQLMembershipProvider.cs,f37d42faca2b921e" target="_blank"&gt;SqlMembershipProvider&lt;/a&gt; hashes passwords which by default uses the HMACSHA256 algorithm.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://twitter.com/jschoemaker1984?lang=en" target="_blank"&gt;Jeffrey Schoemaker&lt;/a&gt; has been discussing updating Umbraco’s default password hashing to use an even stronger hash algorithm and I’ve recently &lt;a rel="noopener noreferrer" href="http://issues.umbraco.org/issue/U4-10089" target="_blank"&gt;updated a new task on the issue tracker&lt;/a&gt; to research this but it really comes down to the fact that Microsoft does not offer the best stronger hashing method in it’s standard .NET Framework so we’ll see where we end up.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update &lt;/strong&gt;– we will be shipping umbraco with stronger password hashing, possibly in a 7.7.x release &lt;/em&gt;&lt;a href="http://issues.umbraco.org/issue/U4-10089" title="http://issues.umbraco.org/issue/U4-10089"&gt;&lt;em&gt;http://issues.umbraco.org/issue/U4-10089&lt;/em&gt;&lt;/a&gt;&lt;em&gt; and it will use HMACSHA1 + PBKDF2 which is what ASP.NET Identity uses by default.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Is the Machine Key used for password hashing?&lt;/h3&gt;
&lt;p&gt;Yes, In 7.6.0+ it is by default because &lt;a rel="noopener noreferrer" href="https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web.UI/web.Template.config#L252" target="_blank"&gt;useLegacyEncoding&lt;/a&gt; is false by default in this release. Previous to 7.6.0 the &lt;a rel="noopener noreferrer" href="https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web.UI/web.Template.config#L252" target="_blank"&gt;useLegacyEncoding&lt;/a&gt; value was true by default purely to preserve some backwards compatibility settings for other products but you’ve been able to set it to true from 7.0.0 (IIRC). Since those products support the more secure password formats, this is now false by default and should be kept as false for new installs. By default the hashing algorithm is HMACSHA256 which &lt;span style="text-decoration: line-through;"&gt;uses&lt;/span&gt; comes from the ASP.NET Machine Key &lt;span style="text-decoration: line-through;"&gt;to perform part of it’s hashing function&lt;/span&gt; ‘validation’ algorithm type. This ‘validation’ algorithm type is configurable via the Machine Key or it is &lt;a rel="noopener noreferrer" href="https://msdn.microsoft.com/en-us/library/system.web.security.membership.hashalgorithmtype(v=vs.110).aspx" target="_blank"&gt;configurable&lt;/a&gt; at the membership provider level which would override the algorithm specified in the Machine Key, but you really shouldn’t change this to be a lesser strength hashing algorithm.&lt;/p&gt;
&lt;p&gt;The &lt;a rel="noopener noreferrer" href="https://msdn.microsoft.com/en-us/library/system.security.cryptography.hmac(v=vs.110).aspx" target="_blank"&gt;HMAC&lt;/a&gt; part of this algorithm means it’s derived from a &lt;a rel="noopener noreferrer" href="https://msdn.microsoft.com/en-us/library/system.security.cryptography.keyedhashalgorithm(v=vs.110).aspx" target="_blank"&gt;keyed algorithm&lt;/a&gt; and uses a key to generate the hash &lt;span style="text-decoration: line-through;"&gt;and the machine key is used to create this key by default. There doesn’t seem to be any documentation or reference to this online that I can find but trying to look through the crypto source code (which isn’t nice to look at) it seems that the default key gets set based on some logic in the &lt;/span&gt;&lt;a rel="noopener noreferrer" href="https://msdn.microsoft.com/en-us/library/system.security.cryptography.rsacryptoserviceprovider(v=vs.110).aspx" target="_blank"&gt;&lt;span style="text-decoration: line-through;"&gt;RSACryptoServiceProvider&lt;/span&gt;&lt;/a&gt;&lt;span style="text-decoration: line-through;"&gt; class which reads some info from the machine key.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update &lt;/strong&gt;– the key used to hash the passwords is the generated salt we produce it is not the key part of the Machine Key. This logic is exactly the same as the logic used in the (&lt;/em&gt;&lt;a rel="noopener noreferrer" href="https://www.nuget.org/packages/Microsoft.AspNet.Providers.Core/" target="_blank"&gt;&lt;em&gt;DefaultMembershipProvider&lt;/em&gt;&lt;/a&gt;&lt;em&gt;) and &lt;/em&gt;&lt;a rel="noopener noreferrer" href="https://referencesource.microsoft.com/#System.Web/Security/SQLMembershipProvider.cs,f37d42faca2b921e" target="_blank"&gt;&lt;em&gt;SqlMembershipProvider&lt;/em&gt;&lt;/a&gt;&lt;em&gt; and if the hashing algorithm key length doesn’t equal the generated salt key length then it is padded/trimmed to the correct length, see source &lt;/em&gt;&lt;a href="http://bit.ly/2uEXeUo"&gt;&lt;em&gt;here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. The part of the Machine Key that is used to hash the passwords is specifically the &lt;u&gt;algorithm type&lt;/u&gt;. As you can see on &lt;a href="http://www.a2zmenu.com/utility/Machine-Key-Generator.aspx"&gt;this machine key generator&lt;/a&gt;, there can be a handful of different algorithm types used for the ‘validation’ part of a machine key and the default of this value changes based on the ASP.NET version being used. In ASP.NET 4.5 the default is HMACSHA256. Also note that in ASP.NET 4.5 the following algorithms are &lt;a href="https://blogs.msdn.microsoft.com/webdev/2012/10/23/cryptographic-improvements-in-asp-net-4-5-pt-2/"&gt;no longer allowed&lt;/a&gt; in the Machine Key config: &lt;em&gt;AES&lt;/em&gt;, &lt;em&gt;3DES&lt;/em&gt;, and &lt;em&gt;MD5&lt;/em&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Do machine keys change between environments?&lt;/h3&gt;
&lt;p&gt;If you explicitly generate and set your own machine key in your web.config then the answer is &lt;strong&gt;No.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you don’t explicitly generate and set your own machine key than you will get an auto-generated machine key. The simple answer for this is: &lt;strong&gt;In most cases No&lt;/strong&gt;, an auto-generated machine key will not change between environments.&lt;/p&gt;
&lt;p&gt;To understand when it will change between environments is a little more complicated and comes down to a combination of IIS user, IIS website virtual path (i.e. if you are running a site in a virtual directory), and a combination of a few settings set at the machine config level: “IsolateApps” and “IsolateByAppId”. Unless a server administrator specifically changes these settings than chances are you won’t be affected by different auto-generated machine keys for your site. If you are really keen, here’s a series all about this topic and other cryptographic changes in .NET 4.5:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a rel="noopener noreferrer" href="https://blogs.msdn.microsoft.com/webdev/2012/10/22/cryptographic-improvements-in-asp-net-4-5-pt-1/" target="_blank"&gt;Part 1&lt;/a&gt; – see the “A brief digression: auto-generated machine keys” for info on auto-generating keys&lt;/li&gt;
&lt;li&gt;&lt;a rel="noopener noreferrer" href="https://blogs.msdn.microsoft.com/webdev/2012/10/23/cryptographic-improvements-in-asp-net-4-5-pt-2/" target="_blank"&gt;Part 2&lt;/a&gt; – in-depth info about the machine key and hashing changes&lt;/li&gt;
&lt;li&gt;&lt;a rel="noopener noreferrer" href="https://blogs.msdn.microsoft.com/webdev/2012/10/24/cryptographic-improvements-in-asp-net-4-5-pt-3/" target="_blank"&gt;Part 3&lt;/a&gt; – interesting info especially with regards to PBKDF2 in .NET Framework&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update &lt;/strong&gt;– another reason a machine key may change between environments is based on which version of ASP.NET is running and what it’s default ‘validation’ algorithm type is&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Can I change my machine key?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="text-decoration: line-through;"&gt;No.&lt;/span&gt; YES&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style="text-decoration: line-through;"&gt;However,&lt;/span&gt; I realize In some cases you might need to change it or move from an auto-generated machine key to an explicit machine key. If that is the case there &lt;span style="text-decoration: line-through;"&gt;will&lt;/span&gt; may be &lt;span style="text-decoration: line-through;"&gt;a lot of&lt;/span&gt; some manual work you’ll need to do. If you simply just change the machine key or add an explicit one when you previously didn’t have one than your members/users &lt;span style="text-decoration: line-through;"&gt;will&lt;/span&gt; might not be able to log in! This really comes down to what hashing algorithm was used originally to hash the passwords and what hash algorithm is configured in your Machine Key. If you install or change a machine key to a different algorithm that was used to first hash your passwords, then your members/users will not be able to log in.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update&lt;/strong&gt; – Previously I was under the impression that the key in the hashing algorithm was directly affected by the key in the machine key but after some more investigation it is not actually the case. As mentioned in the above updates, the part of the Machine Key that is used in the password hashing is the algorithm type specified (if you haven’t overridden this algorithm type by specifying it directly on the membership provider). I’ve also detailed some of this investigation in this ticket: &lt;a href="http://issues.umbraco.org/issue/U4-10222" title="http://issues.umbraco.org/issue/U4-10222"&gt;http://issues.umbraco.org/issue/U4-10222&lt;/a&gt; &lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Can I change from useLegacyEncoding ‘true’ to ‘false’?&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Not easily.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This will require a bit of extra work just like the above question but it’s not quite as tricky as changing a Machine Key. When you have useLegacyEncoding=’true’ , the machine key validation algorithm is not used, so you could do something like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create a new password column in the database which will store the newly hashed password based on the new machine key validation algorithm&lt;/li&gt;
&lt;li&gt;When a user logs in you can check if they have the new password format or not.&lt;/li&gt;
&lt;ul&gt;
&lt;li&gt;If not, then you can validate the password based on the old format then re-hash with the new format and store it and delete the old stored hash password.&lt;/li&gt;
&lt;li&gt;If so, then you can validate the password based on the new format&lt;/li&gt;
&lt;/ul&gt;
&lt;li&gt;To do this would probably require inheriting from the current Umbraco membership provider and implementing this logic yourself&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Do I need to generate and store a custom Machine Key if I am planning on Load Balancing?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Yes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is also mentioned in the &lt;a rel="noopener noreferrer" href="https://our.umbraco.org/documentation/Getting-Started/Setup/Server-Setup/load-balancing/#asp-net-configuration" target="_blank"&gt;Umbraco docs&lt;/a&gt; for load balancing&lt;/p&gt;
&lt;h3&gt;Do I need to generate and install a Machine Key before I run the Umbraco installer?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Yes.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This is because during the Umbraco installation it will hash and store the password for the admin account and if you then add a Machine Key after the fact, you will no longer be able to log in.&lt;/p&gt;
&lt;h3&gt;Can Umbraco generate a custom Machine Key on install for me?&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Yes&lt;/em&gt;!&lt;/p&gt;
&lt;p&gt;but it doesn’t do that right now. I created that &lt;a rel="noopener noreferrer" href="https://github.com/umbraco/Umbraco-CMS/pull/783" target="_blank"&gt;functionality in a PR&lt;/a&gt; but we decided to remove the machine key generation part when it was accepted. We have decided to bring it back though so that will be part of an upcoming Umbraco release, whether that is the 7.6.x series or 7.7 series is still being decided.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&lt;strong&gt;Update &lt;/strong&gt;– this is shipping with 7.7 and new installs will have a Machine Key generated and installed for you. You can of course opt out of this in the advanced installer options if you like.&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;Do Machine Key’s exist in ASP.NET Core?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;No.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Well sort of but not really. I haven’t been able to research too much into this but when speaking to a couple MS Dev’s about this a couple years ago the answer was that the way machine key’s work will be different. If keys need to be shared between apps in ASP.NET Core the data protection APIs need to be used and these keys would then be stored in the registry or the Cloud (i.e. Azure Key Vault), here’s a &lt;a rel="noopener noreferrer" href="https://stackoverflow.com/a/42117903/694494" target="_blank"&gt;SO article on this&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Clear as mud?! ;)&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:31 Z</pubDate>
      <a10:updated>2023-03-23T15:08:31Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1330</guid>
      <link>https://shazwazza.com/post/owin-cookie-authentication-with-variable-cookie-paths/</link>
      <category>ASP.Net</category>
      <title>OWIN Cookie Authentication with variable cookie paths</title>
      <description>&lt;p&gt;By default OWIN Cookie Authentication let’s you specify a single configurable cookie path that does not change for the lifetime of the application, for example&lt;/p&gt;
&lt;pre class="csharpcode"&gt;app.UseCookieAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; CookieAuthenticationOptions
{                
    CookiePath = &lt;span class="str"&gt;"/Client1"&lt;/span&gt;,
    CookieSecure = CookieSecureOption.SameAsRequest,
    CookieHttpOnly = &lt;span class="kwrd"&gt;true&lt;/span&gt;
});&lt;/pre&gt;
&lt;p&gt;This is going to only allow cookie authentication to occur when the request is for  any path under &lt;em&gt;/Client1. &lt;/em&gt;But what if you wanted this same cookie and cookie authentication provider to work for other variable paths, what if we wanted it to execute for multiple configured paths like: /Client1, /Client2/Secured, /Client3/Private ? Or what if we wanted wanted this Cookie Authentication Provider to execute dynamically based on the request object?&lt;/p&gt;
&lt;h2&gt;ICookieManager to the rescue&lt;/h2&gt;
&lt;p&gt;The &lt;em&gt;CookieAuthenticationOptions&lt;/em&gt; has a property: &lt;em&gt;CookieManager&lt;/em&gt; which you can set to any instance of &lt;em&gt;ICookieManager&lt;/em&gt;. &lt;em&gt;ICookieManager&lt;/em&gt; contains these methods: &lt;em&gt;GetRequestCookie&lt;/em&gt;, &lt;em&gt;AppendResponseCookie&lt;/em&gt;, &lt;em&gt;DeleteCookie&lt;/em&gt; but all we really need to worry about &lt;em&gt;GetRequestCookie&lt;/em&gt;. It turns out that the &lt;em&gt;CookieAuthenticationHandler&lt;/em&gt; will detect if this method returns null and if so it will just not continue trying to authenticate the request. To make things easy we’ll just inherit from the default OWIN &lt;em&gt;ICookieManager&lt;/em&gt; which is &lt;em&gt;ChunkingCookieManager&lt;/em&gt;, although it’s methods are not marked as virtual we can still override them by explicitly implementing the &lt;em&gt;ICookieManager.GetRequestCookie&lt;/em&gt; method (Pro Tip! You can always override a non virtual method if you explicitly implement an interfaces method).&lt;/p&gt;
&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//explicit implementation&lt;/span&gt;
&lt;span class="kwrd"&gt;string&lt;/span&gt; ICookieManager.GetRequestCookie(IOwinContext context, &lt;span class="kwrd"&gt;string&lt;/span&gt; key)
{
    &lt;span class="rem"&gt;//TODO: Given what is in the context, we can check pretty much anything, if we don't want&lt;/span&gt;
    &lt;span class="rem"&gt;//this request to continue to be authenticated, just return null. Example:&lt;/span&gt;
    var toMatch = &lt;span class="kwrd"&gt;new&lt;/span&gt;[] {&lt;span class="str"&gt;"/Client1"&lt;/span&gt;, &lt;span class="str"&gt;"/Client2/Secured"&lt;/span&gt;, &lt;span class="str"&gt;"/Client3/Private"&lt;/span&gt;};
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (!toMatch.Any(m =&amp;gt; context.Request.Uri.AbsolutePath.StartsWith(m, StringComparison.OrdinalIgnoreCase)))
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    }

    &lt;span class="rem"&gt;//if we don't want to ignore it then continue as normal:&lt;/span&gt;
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;base&lt;/span&gt;.GetRequestCookie(context, key);            
}&lt;/pre&gt;
&lt;p&gt;The last step is to not worry about the &lt;em&gt;CookiePath&lt;/em&gt; since the custom &lt;em&gt;ICookieManager.GetRequestCookie&lt;/em&gt; is going to deal with whether the middleware receives a cookie value or not so in that case, the &lt;em&gt;CookiePath&lt;/em&gt; for the &lt;em&gt;CookieAuthenticationOptions&lt;/em&gt; will remain the default of &lt;em&gt;“/”&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We’ve been doing this in Umbraco CMS core for quite some time, I meant to blog about this then but just didn’t find the time. In Umbraco we have a few custom request paths that we need authenticated with our custom back office cookie, for reference the &lt;em&gt;BackOfficeCookieManager&lt;/em&gt; source is found here: &lt;a href="https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs" title="https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs"&gt;https://github.com/umbraco/Umbraco-CMS/blob/dev-v7/src/Umbraco.Web/Security/Identity/BackOfficeCookieManager.cs&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:23 Z</pubDate>
      <a10:updated>2023-03-23T15:08:23Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1262</guid>
      <link>https://shazwazza.com/post/umbraco-cli-running-on-aspnet-core/</link>
      <category>ASP.Net</category>
      <category>Umbraco</category>
      <title>Umbraco CLI running on ASP.NET Core</title>
      <description>&lt;h4&gt;TL;DR I’ve got Umbraco (the Core part) running on .NET Core (not just a .NET Core CLI wrapping a non .NET Core Umbraco). See below for a quick video of it working on Ubuntu and simple instructions on how to get it running yourself.&lt;/h4&gt;
&lt;p&gt;Over the past couple of years I’ve slowly been working on getting Umbraco to run on ASP.NET Core. Unlike many other ASP.NET frameworks and products that have rewritten their apps in ASP.NET Core, I’ve gone a different path and have updated Umbraco’s existing code to compile against both .Net Framework and .Net Core. This is a necessary transition for the Umbraco codebase, we don’t plan on rewriting Umbraco, just updating it to play nicely with both .Net Framework and .Net Core.&lt;/p&gt;
&lt;p&gt;During &lt;a rel="noopener" href="https://vimeo.com/channels/codegarden16/183478500" target="_blank"&gt;my talk at CodeGarden this year&lt;/a&gt; I spoke about the Future of Umbraco Core. An important aspect of that talk was the fact that we need to build &amp;amp; release Umbraco version 8 before we can consider looking in to upgrading all of Umbraco to work with ASP.NET Core. A primary reason for this is because we need to remove all of the legacy code from Umbraco (including plenty of old Webforms views) and updated plenty of other things such as old libraries that are simply not going to work with ASP.NET Core.&lt;/p&gt;
&lt;p&gt;I have been doing all of the work on updating Umbraco to work with ASP.NET Core on a &lt;a rel="noopener" href="https://github.com/shazwazza/Umbraco-Cms/tree/dev-v9" target="_blank"&gt;fork on GitHub&lt;/a&gt;. It’s been a very tedious process made even more tedious due to the constant changes of ASP.NET Core over the last 2 years. I started this whole process by modifying the VS sln file to exclude all of the projects and only including the Umbraco.Core project, then starting with the most fundamental classes to include. I’d include one class at a time using the &lt;a rel="noopener" href="https://github.com/Shazwazza/Umbraco-CMS/blob/dev-v9/src/Umbraco.Core/project.json" target="_blank"&gt;project.json file&lt;/a&gt;, compile, make changes if required until it built, include the next class, rinse/repeat.  I did this up until the point where I could compile the Umbraco.Core project to include Umbraco’s &lt;em&gt;ApplicationContext&lt;/em&gt; object and &lt;em&gt;CoreBootManager&lt;/em&gt;. This basically meant I had everything I needed in order to bootstrap Umbraco and perform the business logic operations for Umbraco on ASP.NET Core :)&lt;/p&gt;
&lt;p&gt;I did start looking at updating the Umbraco.Web project but this is going to be a much more involved process due to the way that MVC and WebApi have changed with regards to ASP.NET Core. &lt;em&gt;It is worth noting that I do have the routing working, even things like hijacked routes, SurfaceController’s, etc… ! &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;But before I continued down that road I wanted to see if I could get the core part of Umbraco running cross platform, so I tinkered around with making an Umbraco .NET Core CLI&lt;/p&gt;
&lt;p&gt;… And it just works :)&lt;/p&gt;
&lt;p&gt;&lt;em&gt;On a side note, the Git branch that this live in is a fork of Umbraco’s current source code and the branch that it exists in is a branch from v8 so it is fully merge-able. This means that as we continue developing on v7 and v8 all of these fixes/changes will merge up into this branch.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Umbraco Interactive CLI&lt;/h2&gt;
&lt;p&gt;I didn’t want to reinvent the wheel with a CLI argument parser so a quick Googling on what was available on .Net Core pointed me to a &lt;a rel="noopener" href="https://www.nuget.org/packages/Microsoft.Extensions.CommandLineUtils/" target="_blank"&gt;great framework that Microsoft had already built&lt;/a&gt;. What I wanted to make was an interactive CLI so I could either execute a single command line statement to perform an operation, or I could start the CLI and be prompted to work with Umbraco data until I exited. This Microsoft framework didn’t quite support that OOTB but &lt;a rel="noopener" href="https://github.com/Shazwazza/Umbraco-CMS/blob/dev-v9/src/Umbraco.Test.Console/CommandLineApplicationExtensions.cs" target="_blank"&gt;it wasn’t difficult to make it work&lt;/a&gt; the way I wanted without modifying it’s source. From there I wrote the code to boot Umbraco and started implementing some commands. Here’s the commands and sub-commands so far &lt;em&gt;(each command has a help option: –h)&lt;/em&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;db – Used to configure the database
&lt;ul&gt;
&lt;li&gt;install – used to install a new Umbraco db, schema and default data&lt;/li&gt;
&lt;li&gt;connect – used to connect to an existing Umbraco db&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;schema – Used for manipulating schema elements
&lt;ul&gt;
&lt;li&gt;doctype – Used for Document type operations
&lt;ul&gt;
&lt;li&gt;create, del, list&lt;/li&gt;
&lt;li&gt;groups – Used for property group operations (create + list)&lt;/li&gt;
&lt;li&gt;props – Used for property type operations (create + list)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;medtype– Used for Media type operations
&lt;ul&gt;&lt;!--StartFragment--&gt;
&lt;li&gt;create, del , list&lt;/li&gt;
&lt;li&gt;groups – Used for property group operations (create + list)&lt;/li&gt;
&lt;li&gt;props – Used for property type operations (create + list)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;See it in action&lt;/h3&gt;
&lt;div class="mceNonEditable embeditem" data-embed-url="https://www.youtube.com/watch?v=bNKTKsILtDI&amp;amp;feature=youtu.be" data-embed-height="384" data-embed-width="800" data-embed-constrain="true"&gt;&lt;iframe width="512" height="384" src="https://www.youtube.com/embed/bNKTKsILtDI?feature=oembed" frameborder="0" allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture" allowfullscreen=""&gt;&lt;/iframe&gt;&lt;/div&gt;
&lt;h2&gt;Cross Platform&lt;a rel="noopener" href="https://www.ubuntu.com/" target="_blank"&gt;&lt;img style="background-image: none; float: right; padding-top: 0px; padding-left: 0px; margin: 0px 0px 25px 25px; display: inline; padding-right: 0px; border-width: 0px;" src="http://design.ubuntu.com/wp-content/uploads/ubuntu-logo32.png" border="0" alt="" width="150" height="150" align="right" /&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;I was very interested to see if this would work on Linux so I got Ubuntu up and running and put MySql on there and created a new db to use. Then I &lt;a rel="noopener" href="http://www.hanselman.com/blog/SelfcontainedNETCoreApplications.aspx" target="_blank"&gt;updated the solution to build a standalone .NET Core app&lt;/a&gt;, published that using&lt;/p&gt;
&lt;pre class="csharpcode"&gt;dotnet publish -c release -r ubuntu.14.04-x64 &lt;/pre&gt;
&lt;p&gt;and unzipped that on my Ubuntu installation. Then I tried it by running&lt;/p&gt;
&lt;pre class="csharpcode"&gt;./Umbraco.Test.Console&lt;/pre&gt;
&lt;p&gt;and …. It worked !! There’s something quite magical about the whole thing, it really was very easy to get this to run on a non-windows environment. Very impressive :)&lt;/p&gt;
&lt;h2&gt;Try it out!&lt;/h2&gt;
&lt;p&gt;You should be able to get this working pretty easily – hopefully on any OS – here’s the steps:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;I’ve not tested any of this with OSX, so hopefully it will ‘just work’ there too &lt;/em&gt;&lt;/p&gt;
&lt;p&gt;You’ll need either an MS SQL or MySql empty database setup on your OS environment, then note the connection string since you’ll need to enter it in the CLI.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Clone the repo &lt;/strong&gt;&lt;em&gt;(It’s big, it’s the actual current Umbraco source):&lt;/em&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;git clone -b dev-v9 &lt;a href="https://github.com/Shazwazza/Umbraco-CMS.git"&gt;https://github.com/Shazwazza/Umbraco-CMS.git&lt;/a&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Go to the project folder&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;cd Umbraco-CMS
cd src
cd Umbraco.Test.Console&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Restore packages&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;dotnet restore&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Build the project, depending on your OS&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;dotnet build -r win10-x64
dotnet build -r osx.10.10-x64
dotnet build -r ubuntu.16.04-x64&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Publish it, depending on your OS&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;dotnet publish -c release -r win10-x64
dotnet publish -c release -r osx.10.10-x64
dotnet publish -c release -r ubuntu.16.04-x64&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Run it, depending on your OS&lt;/strong&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;bin\release\netcoreapp1.0\win10-x64\Umbraco.Test.Console.exe
./bin/release/netcoreapp1.0/osx.10.10-x64/Umbraco.Test.Console
./bin/release/netcoreapp1.0/ubuntu.16.04-x64/Umbraco.Test.Console&lt;/pre&gt;
&lt;p&gt;&lt;em&gt;NOTE: On Linux you’ll probably have to mark it to be executable first by doing this:&lt;/em&gt;&lt;/p&gt;
&lt;pre class="csharpcode"&gt;chmod +x ./bin/release/netcoreapp1.0/ubuntu.16.04-x64/Umbraco.Test.Console&lt;/pre&gt;
&lt;h2&gt;Next steps&lt;/h2&gt;
&lt;p&gt;I’m very excited about what has been achieved so far but there’s certainly a long way to go. As I mentioned above getting v8 completed is a requirement to getting a version of Umbraco fully working with ASP.NET Core. During that development time I do plan on continuing to tinker around with getting more stuff to work. I’d like to see some progress made with the web project, the first steps will require getting the website boot process working  (in progress) and I think a good first milestone will be getting the installer all working. From there, there’s updating the controllers and authentication/authorization mechanisms for the back office and then looking into actually getting content rendered on the front-end ( this part is actually the easiest and mostly done already ). &lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:19 Z</pubDate>
      <a10:updated>2023-03-23T15:08:19Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1242</guid>
      <link>https://shazwazza.com/post/fcn-file-change-notification-viewer-for-aspnet/</link>
      <category>ASP.Net</category>
      <title>FCN (File Change Notification) Viewer for ASP.NET</title>
      <description>&lt;style&gt;
div.nuget-badge p code {
background: none;
background-color: #202020 !important;
border: 4px solid silver !important;
border-bottom-left-radius: 5px 5px !important;
border-bottom-right-radius: 5px 5px !important;
border-top-left-radius: 5px 5px !important;
border-top-right-radius: 5px 5px !important;
color: #e2e2e2 !important;
display: block !important;
font: normal normal normal 1.5em/normal 'andale mono', 'lucida console', monospace !important;
line-height: 1.5em !important;
overflow: auto !important;
padding: 15px !important;
}
&lt;/style&gt;  &lt;p&gt;This is a follow up post about &lt;a href="http://shazwazza.com/post/all-about-aspnet-file-change-notification-fcn/" target="_blank"&gt;another article I previously wrote about FCN on ASP.NET&lt;/a&gt; and how it affects your application, performance, etc… &lt;/p&gt; &lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-fcn-file-change-notification-viewer-net_d400-image_2.png"&gt;&lt;img width="304" height="323" title="image" align="right" style="border-width: 0px; margin: 0px 0px 0px 20px; padding-top: 0px; padding-right: 0px; padding-left: 0px; float: right; display: inline; background-image: none;" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-fcn-file-change-notification-viewer-net_d400-image_thumb.png" border="0"&gt;&lt;/a&gt;Since that post, I’ve discovered a few more tidbits about FCN and application restarts and have decided to release a Nuget package that you can install to generate a report of all file/directory change monitors that ASP.NET creates.&lt;/p&gt; &lt;p&gt;The code for the FCN report generator &lt;a href="https://github.com/Shazwazza/FCNViewer" target="_blank"&gt;lives on GitHub&lt;/a&gt; and you can install it via nuget:&lt;/p&gt; &lt;div class="nuget-badge"&gt; &lt;p&gt;&lt;code&gt;PM&amp;gt; Install-Package FCNViewer&lt;/code&gt;&lt;/p&gt;&lt;/div&gt; &lt;p&gt;Once that is installed you’ll get a readme on how to enable it, basically just this in your WebApi startup/route config:&lt;/p&gt;&lt;pre class="csharpcode"&gt;config.Routes.MapFcnViewerRoute();&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;Then you can navigate to &lt;em&gt;&lt;strong&gt;/fcn&lt;/strong&gt;&lt;/em&gt; and you’ll get a nice report showing all of the files/folders being watched by ASP.NET. &lt;/p&gt;
&lt;h2&gt;FCN modes &amp;amp; app domain restarts&lt;/h2&gt;
&lt;p&gt;I won’t go into full details about all the FCN modes again (you can find those details on my &lt;a href="http://shazwazza.com/post/all-about-aspnet-file-change-notification-fcn/" target="_blank"&gt;previous post&lt;/a&gt;) but I want to provide some info about “Single” vs “NotSet” (the default). &lt;/p&gt;
&lt;p&gt;When the default (“NotSet”) is used, ASP.NET will create a directory monitor inside of every folder that the ASP.NET runtime accesses. This includes accessing a folder to return an asset request like CSS or JS, or rendering a razor file or reading from a data file. Basically it means ASP.NET has the potential to create a directory monitor for every directory you have in your site. The good part about the default mode is that each directory monitor will have it’s own buffer to manage the files it is watching so there’s less chance these buffers can overflow. The problem with the default is file system performance especially if you are hosting your site from a remote file server – the more directory monitors that are created the more strain will be put on your file server/network which could cause unwanted app domain restarts.&lt;/p&gt;
&lt;p&gt;When set to “Single”, ASP.NET will create one directory monitor and this single directory monitor will be used to monitor all folders that ASP.NET accesses. This means there is a single buffer that is used for monitoring all of the files and folders. This buffer is larger than the buffer used for each individual monitor created with the default is used, however the problem with “Single” is that it means that if you have tons of folders there’s a higher chance this buffer can overflow which could cause unwanted app domain restarts. The good part about “Single” is that its much better for performance for the file system especially when you are hosting your site from a remote file server.&lt;/p&gt;
&lt;p&gt;As you can see there’s no perfect scenario and both can cause unwanted app domain restarts. These restarts will end up in your logs with very peculiar reasons like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;Application shutdown. Details: ConfigurationChange
_shutDownMessage=Overwhelming Change Notification in 
    HostingEnvironment initiated shutdown
    CONFIG change
    Overwhelming Change Notification in D:\inetpub\test
    CONFIG change
    Change Notification for critical directories.
    Overwhelming Change Notification in bin
    Change Notification for critical directories.
    Overwhelming Change Notification in App_LocalResources
    CONFIG change
    CONFIG change
    CONFIG change
    CONFIG change&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;Or other strange “ConfigurationChange” reasons that might tell you that all sorts of files have been changed – but you definitely know that is not the cause. The cause of this is very likely FCN issues.&lt;/p&gt;
&lt;h2&gt;Files outside of the web root&lt;/h2&gt;
&lt;p&gt;An interesting bit of info is that ASP.NET wont create directory/file monitors for files that exist outside of the web root even if ASP.NET accesses them. I’d recommend where possible that you store any sort of cache files, data files, etc… that ASP.NET doesn’t need to serve up as static file requests outside of the web root. This is actually the default way of working in ASP.NET Core too. As an example, you may have heard or use &lt;a href="https://github.com/JimBobSquarePants/ImageProcessor" target="_blank"&gt;Image Processor&lt;/a&gt; which creates quite a substantial amount of cache folders for processed images. These files by default exist in /App_Data/cache and since that is in the web root, ASP.NET will create a directory watcher for each folder in there … and there can be literally thousands if you use Image Processor extensively! If you are using FCN “Single” mode and have that many folders in the Image Processor cache, there’s a good chance that you’ll have app domain restart issues - though changing it to “NotSet” could result in serious file system performance issues. The good news for Image Processor is I created a PR to allow for storing it’s cache outside of the web root: &lt;a title="https://github.com/JimBobSquarePants/ImageProcessor/pull/521" href="https://github.com/JimBobSquarePants/ImageProcessor/pull/521"&gt;https://github.com/JimBobSquarePants/ImageProcessor/pull/521&lt;/a&gt; so that functionality should be available in an upcoming release soon.&lt;/p&gt;
&lt;h2&gt;Virtual Directories&lt;/h2&gt;&lt;p&gt;&lt;em&gt;Updated 13/08/2018&lt;/em&gt;&lt;/p&gt;&lt;p&gt;As it turns out, Virtual Directories in IIS are treated differently as well! Any fcnMode that you configure has no affect on files within a Virtual Directory except for if you disable FCN. So if you are thinking of using “Single” and are using Virtual Directories, think again. The only FCN setting that affects Virtual Directories is “Disabled”. Here’s the actual code that creates directory watches for Virtual Directories: &lt;a title="https://referencesource.microsoft.com/#System.Web/FileChangesMonitor.cs,0820c837402228ef" href="https://referencesource.microsoft.com/#System.Web/FileChangesMonitor.cs,0820c837402228ef"&gt;https://referencesource.microsoft.com/#System.Web/FileChangesMonitor.cs,0820c837402228ef&lt;/a&gt; and as you can see, if it’s not disabled, it will be creating a directory watcher for every sub directory in the Virtual Directory. This problem is compounded if the Virtual Directory is pointing to a network share. &lt;/p&gt;&lt;h2&gt;FCN &amp;amp; ASP.NET CacheDependency &lt;/h2&gt;
&lt;p&gt;Another thing to be aware of is that if you use ASP.NET’s cache (i.e. &lt;em&gt;HttpRuntime.Cache&lt;/em&gt; or&lt;em&gt; HttpContext.Cache&lt;/em&gt; or &lt;em&gt;MemoryCache&lt;/em&gt;) and you create cache dependencies on specific files, this effectively goes straight to the underlying FCN engine of ASP.NET and it will create these same file/directory monitors that ASP.NET creates by default … even if these files are stored outside of the web root! So if you are creating a ton of &lt;em&gt;CacheDependency&lt;/em&gt; objects, you will be creating a ton of FCN directory/file monitors which could be directly causing FCN issues with app domain restarts.&lt;/p&gt;
&lt;p&gt;
&lt;h2&gt;The FCN Report&lt;/h2&gt;
&lt;p&gt;At least with this report viewer you can see how many files and folders are being watched. It’s important to know that these watchers are created lazily whenever ASP.NET accesses files so on first load you might not see too many but if you start browsing around your site, you’ll see the number grow. &lt;/p&gt;

&lt;p&gt;You can also modify the default route by using an overload:&lt;/p&gt;&lt;pre class="csharpcode"&gt;config.Routes.MapFcnViewerRoute(&lt;span class="str"&gt;"myfcnreport"&lt;/span&gt;);&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;This can hopefully help debug these strange restart issues, give you an idea of how much ASP.NET is actually watching and show you how the FCN Modes affect these monitors.&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:19 Z</pubDate>
      <a10:updated>2023-03-23T15:08:19Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1245</guid>
      <link>https://shazwazza.com/post/smidge-20-alpha-is-out/</link>
      <category>ASP.Net</category>
      <title>Smidge 2.0 alpha is out</title>
      <description>&lt;style&gt;
div.nuget-badge p code {
background: none;
background-color: #202020 !important;
border: 4px solid silver !important;
border-bottom-left-radius: 5px 5px !important;
border-bottom-right-radius: 5px 5px !important;
border-top-left-radius: 5px 5px !important;
border-top-right-radius: 5px 5px !important;
color: #e2e2e2 !important;
display: block !important;
font: normal normal normal 1.5em/normal 'andale mono', 'lucida console', monospace !important;
line-height: 1.5em !important;
overflow: auto !important;
padding: 15px !important;
}
&lt;/style&gt; &lt;img title="ASP.NET-Core-Logo_2colors_RGB_bitmap_MEDIUM" style="border-left-width: 0px; border-right-width: 0px; background-image: none; border-bottom-width: 0px; float: none; padding-top: 0px; padding-left: 0px; margin-left: auto; display: block; padding-right: 0px; border-top-width: 0px; margin-right: auto" border="0" alt="ASP.NET-Core-Logo_2colors_RGB_bitmap_MEDIUM" src="http://shazwazza.com/media/articulate/windows-live-writer-smidge-20-alpha-is-out_abc7-aspnet-core-logo_2colors_rgb_bitmap_medium_5.png" width="198" height="57"&gt;  &lt;p&gt;What is Smidge? Smidge is a lightweight &lt;u&gt;runtime &lt;/u&gt;bundling library (&lt;em&gt;CSS/JavaScript file minification, combination, compression&lt;/em&gt;) for ASP.NET Core. &lt;/p&gt; &lt;p&gt;&lt;img style="float: left; margin: 10px 20px 10px 0px; display: inline" src="https://raw.githubusercontent.com/Shazwazza/Smidge/master/assets/logo2.png" align="left"&gt;If you’ve come from ASP.NET 4.5 you would have been familiar with the &lt;a href="https://www.asp.net/mvc/overview/performance/bundling-and-minification" target="_blank"&gt;bundling/minification API&lt;/a&gt; and other bundling options like &lt;a href="https://github.com/shazwazza/clientdependency" target="_blank"&gt;ClientDependency&lt;/a&gt;, but that is no longer available in ASP.NET Core, instead it is advised to do all the bundling and pre-processing that you need as part of your build process …which certainly makes sense! So why create this library? A few reasons: some people just want to have a very simple bundling library and don’t want to worry about Gulp or Grunt or WebPack, in a lot of cases the overhead of runtime processing is not going to make any difference, and lastly, if you have created something like a CMS that dynamically loads in assets from 3rd party packages or plugins, you need a runtime bundler since these things don’t exist at build time.&lt;/p&gt; &lt;p&gt;Over the past few months I’ve been working on some enhancements to Smidge and have found a bit of time to get an &lt;a href="https://github.com/Shazwazza/Smidge/releases/tag/2.0.0-alpha" target="_blank"&gt;alpha released&lt;/a&gt;.&amp;nbsp; There’s loads of great new features in &lt;strong&gt;Smidge 2.0&lt;/strong&gt;! You can install via Nuget and is targets .NET Standard 1.6 and .NET Framework 4.5.2&lt;/p&gt; &lt;div class="nuget-badge"&gt; &lt;p&gt;&lt;code&gt;PM&amp;gt; Install-Package Smidge -Pre&lt;/code&gt;&lt;/p&gt;&lt;/div&gt; &lt;h2&gt;New to Smidge?&lt;/h2&gt; &lt;p&gt;It’s easy to get started with Smidge and there’s &lt;a href="https://github.com/Shazwazza/Smidge" target="_blank"&gt;lots of docs available on GitHub&lt;/a&gt; that cover installation, configuration, creating bundles and rendering&amp;nbsp; them.&lt;/p&gt; &lt;h2&gt;New Features&lt;/h2&gt; &lt;p&gt;Here’s a list of new features complete with lots of code examples&lt;/p&gt; &lt;h3&gt;Customizable Debug and Production options&lt;/h3&gt; &lt;p&gt;&lt;a title="https://github.com/Shazwazza/Smidge/issues/58" href="https://github.com/Shazwazza/Smidge/issues/58"&gt;&lt;font size="2"&gt;https://github.com/Shazwazza/Smidge/issues/58&lt;/font&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Previous to version 2.0, you could only configure aspects of the Production options and the Debug assets that were returned were just the raw static files. With 2.0, you have full control over how your assets are processed in both Debug and Production configurations. For example, if you wanted you could have your assets combined but not minified in Debug mode. This will also allow for non native web assets such as TypeScript to have pre-processors running and able to work in Debug mode. &lt;/p&gt; &lt;p&gt;Example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;services.AddSmidge(_config)
    .Configure&amp;lt;SmidgeOptions&amp;gt;(options =&amp;gt;
    {
        &lt;span class="rem"&gt;//set the default e-tag options for Debug mode&lt;/span&gt;
        options.DefaultBundleOptions.DebugOptions.CacheControlOptions.EnableETag = &lt;span class="kwrd"&gt;false&lt;/span&gt;        
    });&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;h3&gt;Fluent syntax for declaring/configuring bundles&lt;/h3&gt;
&lt;p&gt;&lt;a title="https://github.com/Shazwazza/Smidge/issues/55" href="https://github.com/Shazwazza/Smidge/issues/55"&gt;&lt;font size="2"&gt;https://github.com/Shazwazza/Smidge/issues/55&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you want to customize Debug or Production options per bundle, you can do so with a fluent syntax, for example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseSmidge(bundles =&amp;gt;
{                
    &lt;span class="rem"&gt;//For this bundle, enable composite files for Debug mode, enable the file watcher so any changes&lt;/span&gt;
    &lt;span class="rem"&gt;//to the files are automatically re-processed and cache invalidated, disable cache control headers&lt;/span&gt;
    &lt;span class="rem"&gt;//and use a custom cache buster. You could of course use the .ForProduction options too &lt;/span&gt;
    bundles.Create(&lt;span class="str"&gt;"test-bundle-2"&lt;/span&gt;, WebFileType.Js, &lt;span class="str"&gt;"~/Js/Bundle2"&lt;/span&gt;)
        .WithEnvironmentOptions(BundleEnvironmentOptions.Create()
                .ForDebug(builder =&amp;gt; builder
                    .EnableCompositeProcessing()
                    .EnableFileWatcher()
                    .SetCacheBusterType&amp;lt;AppDomainLifetimeCacheBuster&amp;gt;()
                    .CacheControlOptions(enableEtag: &lt;span class="kwrd"&gt;false&lt;/span&gt;, cacheControlMaxAge: 0))
                .Build()
        );                
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;h3&gt;Customizable Cache Buster&lt;/h3&gt;
&lt;p&gt;&lt;a title="https://github.com/Shazwazza/Smidge/issues/51" href="https://github.com/Shazwazza/Smidge/issues/51"&gt;&lt;font size="2"&gt;https://github.com/Shazwazza/Smidge/issues/51&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;In version 1.0 the only cache busting mechanism was Smidge’s version property which is set in config, in 2.0 Smidge allows you to control how cache busting is controlled at a global and bundle level. 2.0 ships with 2 &lt;em&gt;ICacheBuster&lt;/em&gt; types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;ConfigCacheBuster &lt;/em&gt;– the default and uses Smidge’s version property in config&lt;/p&gt;
&lt;li&gt;
&lt;p&gt;&lt;em&gt;AppDomainLifetimeCacheBuster &lt;/em&gt;– if enabled will mean that the server/browser cache will be invalidated on every app domain recycle&lt;/p&gt;&lt;/li&gt;&lt;/ul&gt;
&lt;p&gt;If you want a different behavior, you can define you own &lt;em&gt;ICacheBuster&lt;/em&gt; add it to the IoC container and then just use it globally or per bundle. For example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//Set a custom MyCacheBuster as the default one for Debug assets:&lt;/span&gt;
services.AddSmidge(_config)
    .Configure&amp;lt;SmidgeOptions&amp;gt;(options =&amp;gt;
    {
        options.DefaultBundleOptions.DebugOptions.SetCacheBusterType&amp;lt;MyCustomCacheBuster&amp;gt;();       
    });

&lt;span class="rem"&gt;//Set a custom MyCacheBuster as the cache buster for a particular bundle in debug mode:&lt;/span&gt;
bundles.Create(&lt;span class="str"&gt;"test-bundle-2"&lt;/span&gt;, WebFileType.Js, &lt;span class="str"&gt;"~/Js/Bundle2"&lt;/span&gt;)
    .WithEnvironmentOptions(BundleEnvironmentOptions.Create()
            .ForDebug(builder =&amp;gt; builder
                .SetCacheBusterType&amp;lt;MyCacheBuster&amp;gt;()
            .Build()
    );&lt;/pre&gt;
&lt;h3&gt;Customizable cache headers&lt;/h3&gt;
&lt;p&gt;&lt;a title="https://github.com/Shazwazza/Smidge/issues/48" href="https://github.com/Shazwazza/Smidge/issues/48"&gt;&lt;font size="2"&gt;https://github.com/Shazwazza/Smidge/issues/48&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt;&amp;nbsp;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;You can now control if you want the &lt;em&gt;ETag&lt;/em&gt; header output and you can control the value set for max-age/s-maxage/Expires header at a global or bundle level, for example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//This would set the max-age header for this bundle to expire in 5 days&lt;/span&gt;
bundles.Create(&lt;span class="str"&gt;"test-bundle-5"&lt;/span&gt;, WebFileType.Js, &lt;span class="str"&gt;"~/Js/Bundle5"&lt;/span&gt;)
    .WithEnvironmentOptions(BundleEnvironmentOptions.Create()
            .ForProduction(builder =&amp;gt; builder                                
                .CacheControlOptions(enableEtag: &lt;span class="kwrd"&gt;true&lt;/span&gt;, cacheControlMaxAge: (5 * 24)))
            .Build()
    );&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;h3&gt;Callback to customize the pre-processor pipeline per web file&lt;/h3&gt;
&lt;p&gt;&lt;a title="https://github.com/Shazwazza/Smidge/issues/59" href="https://github.com/Shazwazza/Smidge/issues/59"&gt;&lt;font size="2"&gt;https://github.com/Shazwazza/Smidge/issues/59&lt;/font&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is handy in case you want to modify the pipeline for a given web file at runtime based on some criteria, for example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;services.AddSmidge(_config)
    .Configure&amp;lt;SmidgeOptions&amp;gt;(options =&amp;gt;
    {
        &lt;span class="rem"&gt;//set the callback&lt;/span&gt;
        options.PipelineFactory.OnGetDefault = GetDefaultPipelineFactory;
    });

&lt;span class="rem"&gt;//The GetDefaultPipeline method could do something like modify the default pipeline to use Nuglify for JS processing:&lt;/span&gt;

&lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; PreProcessPipeline GetDefaultPipelineFactory(WebFileType fileType, IReadOnlyCollection&amp;lt;IPreProcessor&amp;gt; processors)
{
    &lt;span class="kwrd"&gt;switch&lt;/span&gt; (fileType)
    {
        &lt;span class="kwrd"&gt;case&lt;/span&gt; WebFileType.Js:
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; PreProcessPipeline(&lt;span class="kwrd"&gt;new&lt;/span&gt; IPreProcessor[]
            {
                processors.OfType&amp;lt;NuglifyJs&amp;gt;().Single()
            });                
    }
    &lt;span class="rem"&gt;//returning null will fallback to the logic defined in the registered PreProcessPipelineFactory&lt;/span&gt;
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
}

&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;h3&gt;File watching with automatic cache invalidation&lt;/h3&gt;
&lt;p&gt;&lt;a title="https://github.com/Shazwazza/Smidge/pull/42" href="https://github.com/Shazwazza/Smidge/pull/42"&gt;&lt;font size="2"&gt;https://github.com/Shazwazza/Smidge/pull/42&lt;/font&gt;&lt;/a&gt;&lt;font size="2"&gt;&amp;nbsp;&lt;/font&gt;&lt;/p&gt;
&lt;p&gt;During the development process it would be nice to be able to test composite files but have them auto re-process and invalidate the cache whenever one of the source files changes… in 2.0 this is possible!&amp;nbsp; You can enable file watching at the global level or per bundle. Example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//Enable file watching for all files in this bundle when in Debug mode&lt;/span&gt;
bundles.Create(&lt;span class="str"&gt;"test-bundle-7"&lt;/span&gt;,
    &lt;span class="kwrd"&gt;new&lt;/span&gt; CssFile(&lt;span class="str"&gt;"~/Js/Bundle7/a1.js"&lt;/span&gt;),
    &lt;span class="kwrd"&gt;new&lt;/span&gt; CssFile(&lt;span class="str"&gt;"~/Js/Bundle7/a2.js"&lt;/span&gt;))
    .WithEnvironmentOptions(BundleEnvironmentOptions.Create()
            .ForDebug(builder =&amp;gt; builder.EnableFileWatcher())
            .Build()
    );&lt;/pre&gt;
&lt;h2&gt;What’s next?&lt;/h2&gt;
&lt;p&gt;This is an alpha release since there’s a few things that I need to complete. Most are already done but I just need to make Nuget packages for them:&lt;/p&gt;
&lt;h4&gt;&lt;/h4&gt;
&lt;h3&gt;More pre-processors&lt;/h3&gt;
&lt;p&gt;I’ve enabled support for a &lt;a href="https://github.com/xoofx/NUglify" target="_blank"&gt;Nuglify&lt;/a&gt; pre-processor for both CSS and JS (Nuglify is a fork of the &lt;a href="http://ajaxmin.codeplex.com/"&gt;Microsoft Ajax Minifier&lt;/a&gt; for ASP.NET Core + additional features). I also enabled support for an Uglify NodeJs pre-processor which uses &lt;a href="https://github.com/aspnet/JavaScriptServices" target="_blank"&gt;Microsoft.AspNetCore.NodeServices&lt;/a&gt; to invoke Node.js from ASP.NET and run the JS version of Uglify. I just need to get these on Nuget but haven’t got around to that yet.&lt;/p&gt;
&lt;h3&gt;A quick note on minifier performance &lt;/h3&gt;
&lt;p&gt;Though Nuglify and Uglify have a better minification engine (better/smarter size reduction) than JsMin because they create an &lt;a href="https://en.wikipedia.org/wiki/Abstract_syntax_tree" target="_blank"&gt;AST (Abstract Syntax Tree)&lt;/a&gt; to perform it’s processing, they are actually much slower and consume more resources than JsMin. Since Smidge is a Runtime bundling engine, its generally important to ensure that the bundling/minification is performed quickly. Smidge has strict caching so the bundling/minification will only happen once (depending on your &lt;em&gt;ICacheBuster&lt;/em&gt; you are using) but it is still recommended to understand the performance implications of replacing JsMin with another minifier. &lt;a href="https://github.com/Shazwazza/Smidge/wiki/Custom-pre-processing#minification-benchmarks" target="_blank"&gt;I’ve put together some benchmarks&lt;/a&gt; (NOTE: a smaller Minified % is better):&lt;/p&gt;
&lt;table style="box-sizing: border-box; overflow: auto; margin-bottom: 16px; font-family: ; white-space: normal; word-spacing: 0px; margin-top: 0px; border-collapse: collapse; text-transform: none; color: ; border-spacing: 0px; orphans: 2; widows: 2; display: block; letter-spacing: normal; background-color: rgb(255,255,255); text-indent: 0px; font-variant-ligatures: normal; font-variant-caps: normal; -webkit-text-stroke-width: 0px" width="700"&gt;
&lt;thead style="box-sizing: border-box"&gt;
&lt;tr style="box-sizing: border-box; border-top: rgb(204,204,204) 1px solid; background-color: rgb(255,255,255)"&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Method&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Median&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;StdDev&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Scaled&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Scaled-SD&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Minified %&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Gen 0&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Gen 1&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Gen 2&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;
&lt;th style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Bytes Allocated/Op&lt;/font&gt;&lt;/font&gt;&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;
&lt;tbody style="box-sizing: border-box"&gt;
&lt;tr style="box-sizing: border-box; border-top: rgb(204,204,204) 1px solid; background-color: rgb(255,255,255)"&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;JsMin&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;10.2008 ms&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;0.3102 ms&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;1.00&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;0.00&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;51.75%&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;-&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;-&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;-&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;155,624.67&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="box-sizing: border-box; border-top: rgb(204,204,204) 1px solid; background-color: rgb(248,248,248)"&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;Nuglify&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;69.0778 ms&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;0.0180 ms&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;6.72&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;0.16&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;32.71%&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;53.00&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;22.00&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;15.00&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;4,837,313.07&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr style="box-sizing: border-box; border-top: rgb(204,204,204) 1px solid; background-color: rgb(255,255,255)"&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;JsServicesUglify&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;1,548.3951 ms&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;7.6388 ms&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;150.95&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;3.73&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;32.63%&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;0.97&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;-&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;-&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;
&lt;td style="box-sizing: border-box; border-top: rgb(221,221,221) 1px solid; border-right: rgb(221,221,221) 1px solid; border-bottom: rgb(221,221,221) 1px solid; padding-bottom: 6px; padding-top: 6px; padding-left: 13px; border-left: rgb(221,221,221) 1px solid; padding-right: 13px"&gt;&lt;font face="Segoe UI"&gt;&lt;font style="font-size: 12pt" color="#333333"&gt;576,056.55&lt;/font&gt;&lt;/font&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;The last benchmark may be a bit misleading because the processing is done via NodeJs which executes in a separate process so I'm unsure if the actual memory usage of that can be properly captured by &lt;a href="https://github.com/dotnet/BenchmarkDotNet"&gt;BenchmarkDotNet&lt;/a&gt; but you can see it's speed is much slower. 
&lt;h2&gt;Thanks!&lt;/h2&gt;
&lt;p&gt;Big thanks to &lt;a href="https://github.com/dazinator" target="_blank"&gt;@dazinator&lt;/a&gt; for all the help, recommendations, testing, feedback, etc… and for the rest of the community for filing bugs, questions, and comments. Much appreciated :)&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:19 Z</pubDate>
      <a10:updated>2023-03-23T15:08:19Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1232</guid>
      <link>https://shazwazza.com/post/using-aspnet5-optionsmodel/</link>
      <category>ASP.Net</category>
      <category>Web Development</category>
      <title>Using AspNet5 OptionsModel</title>
      <description>&lt;p&gt;If you’ve used AspNet5 then you’ve probably been using some MVC, in which case you’ve probably seen something like this in your Startup class:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// Add MVC services to the services container&lt;/span&gt;
services.AddMvc(configuration)
    .Configure&amp;lt;MvcOptions&amp;gt;(options =&amp;gt;
    {
        &lt;span class="rem"&gt;//Configure some MVC options like customizing the &lt;/span&gt;
        &lt;span class="rem"&gt;// view engines, etc...&lt;/span&gt;
        options.ViewEngines.Insert(0, &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(TestViewEngine));
    });&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;It turns out this syntax for specifying ‘options’ for a given service is a generic pattern that you can use in your own code. In fact the OptionsModel framework is it’s own code repository: &lt;a title="https://github.com/aspnet/Options" href="https://github.com/aspnet/Options"&gt;https://github.com/aspnet/Options&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’ve implemented custom options in my AspNet5 project called &lt;a href="https://github.com/Shazwazza/smidge" target="_blank"&gt;Smidge&lt;/a&gt; (a runtime JavaScript/CSS pre-processing engine) and wanted to share the details since as far as I’ve seen there isn’t any documentation about this.&lt;/p&gt;
&lt;h2&gt;What are options?&lt;/h2&gt;
&lt;p&gt;Probably the simplest way to describe the options framework is that: Options allow you to configure your application via code during startup.&lt;/p&gt;
&lt;p&gt;Options are just a POCO class that can contain configuration options to customize the behavior of your library. These option classes can be injected into any of your services with IoC using an interface called &lt;em&gt;&lt;a href="https://github.com/aspnet/Options/blob/dev/src/Microsoft.Framework.OptionsModel/IOptions.cs" target="_blank"&gt;Microsoft.Framework.OptionsModel.IOptions&lt;/a&gt;&lt;/em&gt;. There’s a caveat to this POCO class however: It must contain an parameter-less/empty constructor which means you cannot have services injected into the your options class via it’s constructor.&amp;nbsp; This options framework also allows for ‘named’ options. So for example, perhaps you have a single options class that you would like to have configured in 2 different ways, one for ‘staging’ and one for your ‘live’ website.&lt;/p&gt;
&lt;h2&gt;Creating options&lt;/h2&gt;
&lt;p&gt;Here’s a really simple example of a POCO options class:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomMessageOptions
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; CustomMessage()
    {
        Message = &lt;span class="str"&gt;""&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; Message { get; set; }
}&lt;/pre&gt;
&lt;p&gt;In order to use this options class you need to create an options configuration class. For example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomMessageOptionsSetup : ConfigureOptions&amp;lt;CustomMessageOptions&amp;gt;
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; CustomMessageOptionsSetup() 
    : &lt;span class="kwrd"&gt;base&lt;/span&gt;(ConfigureMessageOptions)
    {
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Set the default options&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ConfigureMessageOptions(CustomMessageOptions options)
    {
        options.Message = &lt;span class="str"&gt;"Hello world"&lt;/span&gt;;
    }
}&lt;/pre&gt;
&lt;p&gt;Then you need to add this class to your IoC container of type &lt;a href="https://github.com/aspnet/Options/blob/dev/src/Microsoft.Framework.OptionsModel/IConfigureOptions.cs" target="_blank"&gt;&lt;em&gt;Microsoft.Framework.OptionsModel.IConfigureOptions&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;&lt;pre class="csharpcode"&gt;services.AddTransient&amp;lt;IConfigureOptions&amp;lt;CustomMessageOptions&amp;gt;, CustomMessageOptionsSetup&amp;gt;();&lt;/pre&gt;
&lt;h2&gt;Using options&lt;/h2&gt;
&lt;p&gt;To configure your options during startup, you do so in the &lt;em&gt;ConfigureServices &lt;/em&gt;method like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;services.Configure&amp;lt;CustomMessageOptions&amp;gt;(options =&amp;gt;
{
    options.Message = &lt;span class="str"&gt;"Hello there!"&lt;/span&gt;;
});&lt;/pre&gt;
&lt;p&gt;Now you can have these options injected into any of your services using the &lt;em&gt;IOptions&lt;/em&gt; interface noted previously:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyCoolService 
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; MyCoolService(IOptions&amp;lt;CustomMessageOptions&amp;gt; messageOptions)
    {
        &lt;span class="rem"&gt;//IOptions exposes an 'Options' property which resolves an instance&lt;/span&gt;
        &lt;span class="rem"&gt;//of CustomMessageOptions&lt;/span&gt;
        ConfiguredMessage = messageOptions.Options.Message;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ConfiguredMessage {get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set;}
}&lt;/pre&gt;
&lt;h2&gt;Named options&lt;/h2&gt;
&lt;p&gt;As an example, lets say that you want a different message configured for your ‘staging’ and ‘live’ websites. This can be done with named options, here’s an example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;services
    .Configure&amp;lt;CustomMessageOptions&amp;gt;(options =&amp;gt;
    {
        options.Message = &lt;span class="str"&gt;"Hi! This is the staging site"&lt;/span&gt;;
    }, &lt;span class="str"&gt;"staging"&lt;/span&gt;)
    .Configure&amp;lt;CustomMessageOptions&amp;gt;(options =&amp;gt;
    {
        options.Message = &lt;span class="str"&gt;"Hi! This is the live site"&lt;/span&gt;;
    }, &lt;span class="str"&gt;"live"&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;Then in your service you can resolve the option instance by name:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyCoolService 
{
    &lt;span class="kwrd"&gt;public&lt;/span&gt; MyCoolService(IOptions&amp;lt;CustomMessageOptions&amp;gt; messageOptions)
    {
        &lt;span class="rem"&gt;//IRL This value would probably be set via some environment variable&lt;/span&gt;
        var configEnvironment = &lt;span class="str"&gt;"staging"&lt;/span&gt;;

        &lt;span class="rem"&gt;//IOptions exposes an 'GetNamedOptions' method which resolves an instance&lt;/span&gt;
        &lt;span class="rem"&gt;//of CustomMessageOptions based on a defined named configuration&lt;/span&gt;
        ConfiguredMessage = messageOptions.GetNamedOptions(configEnvironment);
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;string&lt;/span&gt; ConfiguredMessage {get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set;}
}&lt;/pre&gt;
&lt;h2&gt;Configuring options with other services&lt;/h2&gt;
&lt;p&gt;Since your options class is just a POCO object and must have a parameter-less/empty constructor, you cannot inject services into the options class. However, there is a way to use IoC services in your options classes by customizing the &lt;em&gt;ConfigureOptions&lt;/em&gt; class created above.&amp;nbsp; In many cases this won’t be necessary but this really depends on how you are using options.&amp;nbsp; As a (bad) example, lets say we wanted to expose a custom helper service called SiteHelper on the &lt;em&gt;CustomMessageOptions&lt;/em&gt; class that can be used by a developer to create the message. The end result syntax might look like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;services.Configure&amp;lt;CustomMessageOptions&amp;gt;(options =&amp;gt;
    {
        var siteId = options.SiteHelper.GetSiteId();
        options.Message = &lt;span class="str"&gt;"Hi! This is the staging site with id: "&lt;/span&gt; + siteId;
    });&lt;/pre&gt;
&lt;p&gt;In order for that to work the &lt;em&gt;options.SiteHelper&lt;/em&gt; property needs to be initialized. This is done with the &lt;em&gt;CustomMessageOptionsSetup &lt;/em&gt;class (created above) which has been added to the IoC container, this means it can have other services injected into it. The resulting class would look like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; CustomMessageOptionsSetup : ConfigureOptions&amp;lt;CustomMessageOptions&amp;gt;
{
    &lt;span class="rem"&gt;//SiteHelper gets injected via IoC&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; CustomMessageOptionsSetup(SiteHelper siteHelper) 
    : &lt;span class="kwrd"&gt;base&lt;/span&gt;(ConfigureMessageOptions)
    {
        SiteHelper = siteHelper;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; SiteHelper SiteHelper { get; &lt;span class="kwrd"&gt;private&lt;/span&gt; set; }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Set the default options&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ConfigureMessageOptions(CustomMessageOptions options)
    {
        options.Message = &lt;span class="str"&gt;"Hello world"&lt;/span&gt;;
    }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Allows for configuring the options instance before options are set&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;override&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Configure(Bundles options, &lt;span class="kwrd"&gt;string&lt;/span&gt; name = &lt;span class="str"&gt;""&lt;/span&gt;)
    {
        &lt;span class="rem"&gt;//Assign the site helper instance&lt;/span&gt;
        options.SiteHelper = SiteHelper;

        &lt;span class="kwrd"&gt;base&lt;/span&gt;.Configure(options, name);
    }
}&lt;/pre&gt;
&lt;p&gt;IRL to give you an example of why this might be useful, in my &lt;a href="https://github.com/Shazwazza/smidge" target="_blank"&gt;Smidge&lt;/a&gt; project I allow developers to create named JavaScript/CSS bundles during startup using options. In some cases a developer might want to manipulate the file processing pipeline for a given bundle and in that case they need access to a service called PreProcessPipelineFactory which needs to come from IoC. The usage might look like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;services.AddSmidge()
    .Configure&amp;lt;Bundles&amp;gt;(bundles =&amp;gt;
    {                   
        bundles.Create(&lt;span class="str"&gt;"test-bundle-3"&lt;/span&gt;, 
            bundles.PipelineFactory.GetPipeline(
                &lt;span class="rem"&gt;//add as many processor types as you want&lt;/span&gt;
                &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(DotLess), &lt;span class="kwrd"&gt;typeof&lt;/span&gt;(JsMin)), 
            WebFileType.Js, 
            &lt;span class="str"&gt;"~/Js/Bundle2"&lt;/span&gt;);
    });&lt;/pre&gt;
&lt;p&gt;In the above, the bundles.PipelineFactory is a property on the bundles (options) class which gets initialized in my own &lt;em&gt;ConfigureOptions&lt;/em&gt; class.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Hopefully this helps anyone looking to use custom options in their AspNet5 libraries!&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1253</guid>
      <link>https://shazwazza.com/post/aspnet-core-application-shutdown-events/</link>
      <category>ASP.Net</category>
      <title>ASP.NET Core application shutdown events</title>
      <description>&lt;p&gt;While porting an existing library to ASP.NET Core I had to find the equivalent functionality of &lt;a href="https://msdn.microsoft.com/en-us/library/system.web.hosting.iregisteredobject%28v=vs.110%29.aspx?f=255&amp;amp;MSPPError=-2147217396" target="_blank"&gt;&lt;em&gt;IRegisteredObject&lt;/em&gt;&lt;/a&gt; which I use for graceful shutdowns of running tasks in background threads. The newer &amp;amp; nicer approach to this in ASP.NET Core is &lt;a href="https://github.com/aspnet/Hosting/blob/dev/src/Microsoft.AspNetCore.Hosting.Abstractions/IApplicationLifetime.cs" target="_blank"&gt;&lt;em&gt;Microsoft.AspNetCore.Hosting.IApplicationLifetime&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;&lt;pre class="csharpcode"&gt;  &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
  &lt;span class="rem"&gt;/// Allows consumers to perform cleanup during a graceful shutdown.&lt;/span&gt;
  &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
  &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;interface&lt;/span&gt; IApplicationLifetime
  {
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Triggered when the application host has fully started and is about to wait&lt;/span&gt;
    &lt;span class="rem"&gt;/// for a graceful shutdown.&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    CancellationToken ApplicationStarted { get; }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Triggered when the application host is performing a graceful shutdown.&lt;/span&gt;
    &lt;span class="rem"&gt;/// Requests may still be in flight. Shutdown will block until this event completes.&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    CancellationToken ApplicationStopping { get; }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// Triggered when the application host is performing a graceful shutdown.&lt;/span&gt;
    &lt;span class="rem"&gt;/// All requests should be complete at this point. Shutdown will block&lt;/span&gt;
    &lt;span class="rem"&gt;/// until this event completes.&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    CancellationToken ApplicationStopped { get; }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;Requests termination the current application.&amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;void&lt;/span&gt; StopApplication();
  }&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/p&gt;
&lt;p&gt;Unlike the old &lt;em&gt;IRegisteredObject&lt;/em&gt; this interface is pretty clear on it’s functionality. &lt;/p&gt;
&lt;p&gt;Registering a method to be called for any of the three operations is simple:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//register the application shutdown handler&lt;/span&gt;
 applicationLifetime.ApplicationStopping.Register(DisposeResources);

&lt;span class="kwrd"&gt;protected&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; DisposeResources()
{
    &lt;span class="rem"&gt;//Cleanup stuff when the app is shutting down&lt;/span&gt;
}&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/p&gt;
&lt;p&gt;Obtaining an instance of &lt;em&gt;IApplicationLifetime&lt;/em&gt; can be done during &lt;em&gt;Startup.cs&lt;/em&gt; in the &lt;em&gt;Configure&lt;/em&gt; method&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
    &lt;span class="rem"&gt;// start your app&lt;/span&gt;
}&lt;/pre&gt;
&lt;p&gt;Happy coding!
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1269</guid>
      <link>https://shazwazza.com/post/introducing-smidge-an-aspnet-5-runtime-jscss-pre-processor/</link>
      <category>ASP.Net</category>
      <category>Web Development</category>
      <title>Introducing ‘Smidge’ – an ASP.NET 5 runtime JS/CSS pre-processor</title>
      <description>&lt;p&gt;During the past month I decided to dive deep into learning ASP.NET 5, and what better way to learn than to start a new OSS project :)&lt;/p&gt;
&lt;p&gt;I chose to make a new new simple and extensible Javascript/CSS &lt;span style="text-decoration: underline;"&gt;runtime&lt;/span&gt; pre-processor for ASP.NET 5. It does file minification, combination and compression, has a nice file caching layer and it’s all done in async operations. I ported over a few ideas and code snippets from &lt;a href="https://github.com/Shazwazza/ClientDependency/" target="_blank"&gt;CDF (client dependency framework)&lt;/a&gt; but with a more modern approach. I’ve called it ‘Smidge’ = &lt;em&gt;something really small&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/Shazwazza/Smidge" target="_blank"&gt;The project is on GitHub&lt;/a&gt;, it’s still a work in progress but its functional and there’s even some documentation! In the next few weeks I’ll get more of the code and docs updated and hopefully have a beta release out. In the meantime, you can clone the source, browse the code, build it and of course use it if you like.&lt;/p&gt;
&lt;h2&gt;Project details&lt;/h2&gt;
&lt;p&gt;It’s currently only targeting &lt;em&gt;aspnet50 &lt;/em&gt;and not the Core CLR… I didn’t start with Core CLR because there was some legacy code I had to port over and I wanted to get something up and working relatively quickly. It shouldn’t be too much work to convert to Core CLR and Mono, hopefully I’ll find time to do that soon. It’s referencing all of the beta-* libraries from the ASP.NET 5 nightly myget feeds since there’s some code I’m using that isn’t available in the current beta1 release (&lt;em&gt;like Microsoft.AspNet.WebUtilities.UriHelper&lt;/em&gt;). The target KRE version is currently &lt;em&gt;KRE-CLR-amd64 1.0.0-beta2-10760.&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;I’ve put up an Alpha 1 release on Nuget, so you can install it from there:&lt;/p&gt;
&lt;div class="nuget-badge"&gt;
&lt;p&gt;PM&amp;gt; Install-Package Smidge -Pre&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;There’s some &lt;a href="https://github.com/Shazwazza/Smidge/blob/master/README.md#install" target="_blank"&gt;installation instructions here&lt;/a&gt;, you’ll need to add the smidge.json file yourself for now, can’t figure out how to get VS 2015 (kpm pack) to package that up … more learning required!&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;There’s certainly a lot of detective work involved in learning ASP.NET 5 but with the code being open source and browse-able/searchable on GitHub, it makes finding what you need fairly easy.&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1260</guid>
      <link>https://shazwazza.com/post/aspnet-identity-for-umbraco-members/</link>
      <category>ASP.Net</category>
      <category>Umbraco</category>
      <title>ASP.Net Identity for Umbraco Members</title>
      <description>&lt;p&gt;I’ve released version 1.0 of &lt;em&gt;UmbracoIdentity&lt;/em&gt; which allows for &lt;a rel="noopener" href="http://www.asp.net/identity" target="_blank"&gt;ASP.Net Identity&lt;/a&gt; to be used with Umbraco for &lt;strong&gt;front-end&lt;/strong&gt; members. I’ve tried to write enough documentation for you to get started, all of the code and docs are here: &lt;a href="https://github.com/Shandem/UmbracoIdentity" title="https://github.com/Shandem/UmbracoIdentity"&gt;https://github.com/Shandem/UmbracoIdentity&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It’s worth noting that this is not something that ‘everyone’ should just jump in with and start using. If you are not familiar with OWIN or ASP.Net Identity than none of this will really make any sense, I’ve added a bit of a disclaimer to the docs about this here: &lt;a href="https://github.com/Shandem/UmbracoIdentity#owin-setup" title="https://github.com/Shandem/UmbracoIdentity#owin-setup"&gt;https://github.com/Shandem/UmbracoIdentity#owin-setup&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There are some &lt;a rel="noopener" href="https://github.com/Shandem/UmbracoIdentity/wiki/Known-Issues" target="_blank"&gt;known issues and limitations&lt;/a&gt; that you should be aware of, and this will also not work currently with back office users (that will come eventually too though).&lt;/p&gt;
&lt;p&gt;This package can be highly customized, it comes with many .cshtml views and c# classes that you can customize as you see fit – very similar to the Visual Studio 2013 Web Application templates that support ASP.Net Identity.&lt;/p&gt;
&lt;h2&gt;What about Asp.Net Membership with Umbraco?&lt;/h2&gt;
&lt;p&gt;The way that I’ve created this is to be 100% compatible with the current Membership structure in Umbraco. This means that this is not using EntityFramework to access data, it uses the Umbraco member services and providers using custom ASP.Net Identity user stores. This also means that the password formats are based on the current password formats of the membership provider. When the Nuget package is installed it will actually swap out the membership provider for a custom type: &lt;em&gt;UmbracoIdentity.IdentityEnabledMembersMembershipProvider. &lt;/em&gt;This is required so that the password security can still be handled by the membership provider logic.&lt;/p&gt;
&lt;p&gt;There is a &lt;a rel="noopener" href="https://github.com/Shandem/UmbracoIdentity/wiki/Known-Issues#passwords" target="_blank"&gt;note about passwords here&lt;/a&gt;, ASP.Net Identity normally will format and salt passwords different (slightly better) than how the membership providers current work, but if you need that functionality you’d have to implement your own &lt;em&gt;IPasswordHasher&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Installation&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style="text-decoration: underline;"&gt;It is absolutely essential you read &lt;/span&gt;&lt;/strong&gt;&lt;a rel="noopener" href="https://github.com/Shandem/UmbracoIdentity" target="_blank"&gt;&lt;strong&gt;the documentation&lt;/strong&gt;&lt;/a&gt; before installing. Once you’ve done that, you can use Nuget:&lt;/p&gt;
&lt;div class="nuget-badge"&gt;
&lt;p&gt;PM&amp;gt; Install-Package UmbracoIdentity&lt;/p&gt;
&lt;/div&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1278</guid>
      <link>https://shazwazza.com/post/configuring-aspnet-identity-oauth-login-providers-for-multi-tenancy/</link>
      <category>ASP.Net</category>
      <title>Configuring ASP.Net Identity OAuth login providers for multi-tenancy</title>
      <description>&lt;p&gt;Say for example you have a CMS :) You want to give full control to the developer to manage how their front-end members with authenticate, which could of course include ASP.Net Identity OAuth login providers. At the same time you want to easily allow your CMS to be configured so that ASP.Net Identity OAuth providers can be used for logging into the back office.&amp;nbsp; In this scenario, the same OAuth provider might be used for both front-end and back-office authentication but authenticated under 2 different OAuth accounts. Another example might be if you have multi-tenancy set up for your front-end site and perhaps you want to use the same OAuth login provider but have members authenticate with different OAuth accounts for different domain names. &lt;/p&gt; &lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;  &lt;h2&gt;The defaults&lt;/h2&gt; &lt;p&gt;As an example, lets assume that front-end members are configured to authenticate with the ASP.Net Identity Google OAuth2 provider. This is easily done by just following one of the many tutorials out there. Your startup code might look like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseCookieAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; CookieAuthenticationOptions ....

app.UseExternalSignInCookie();

app.UseGoogleAuthentication(
              clientId: &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
              clientSecret: &lt;span class="str"&gt;"987654321...."&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;Great, but I need 2 (or more) Google OAuth2 providers, so what now? I can’t just add 2 declarations of:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseGoogleAuthentication(
              clientId: &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
              clientSecret: &lt;span class="str"&gt;"987654321...."&lt;/span&gt;);

app.UseGoogleAuthentication(
              clientId: &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
              clientSecret: &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;);&lt;/pre&gt;
&lt;p&gt;you’ll quickly realize that doesn’t work and only one provider instance will actually be used. This is because of the default underlying settings that get used to instantiate the Google provider. Let’s have a look at what the default options are in this case. The above code is equivalent to this:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"Google"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"987654321...."&lt;/span&gt;,
    Caption = &lt;span class="str"&gt;"Google"&lt;/span&gt;,
    CallbackPath = &lt;span class="kwrd"&gt;new&lt;/span&gt; PathString(&lt;span class="str"&gt;"/signin-google"&lt;/span&gt;),
    AuthenticationMode = AuthenticationMode.Passive,
    SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType(),
    BackchannelTimeout = TimeSpan.FromSeconds(60),
    BackchannelHttpHandler = &lt;span class="kwrd"&gt;new&lt;/span&gt; System.Net.Http.WebRequestHandler(),
    BackchannelCertificateValidator = &lt;span class="kwrd"&gt;null&lt;/span&gt;,
    Provider = &lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationProvider()
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;h2&gt;The AuthenticationType&lt;/h2&gt;
&lt;p&gt;One very important aspect of the default settings is the &lt;em&gt;AuthenticationType&lt;/em&gt;. This is a &lt;strong&gt;unique &lt;/strong&gt;identifier for the provider instance and this is one of the reasons why if you have 2 x &lt;em&gt;UseGoogleAuthentication&lt;/em&gt; declarations with the defaults only one will ever be used.&lt;/p&gt;
&lt;p&gt;Knowing this, it’s clear that each declaration of &lt;em&gt;UseGoogleAuthentication&lt;/em&gt; needs to specify custom options and have the &lt;em&gt;AuthenticationType&lt;/em&gt; unique amongst them. So we might end up with something like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//keep defaults for front-end&lt;/span&gt;
app.UseGoogleAuthentication(
    clientId: &lt;span class="str"&gt;"123456789..."&lt;/span&gt;,
    clientSecret: &lt;span class="str"&gt;"987654321...."&lt;/span&gt;);

&lt;span class="rem"&gt;//custom options for back-office&lt;/span&gt;
app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"GoogleBackOffice"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;    
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;If you test this now, you’ll find out that only the first declaration is actually working even when you explicitly tell &lt;em&gt;IOwinContext.Authentication.Challenge&lt;/em&gt; to use the “GoogleBackOffice” provider.&lt;/p&gt;
&lt;h2&gt;The CallbackPath&lt;/h2&gt;
&lt;p&gt;The reason that the default (first) declaration is the one that activates is because the response from Google is sending the request to the path: “/signin-google”, which is the default. The &lt;em&gt;GoogleAuthenticationMiddleware &lt;/em&gt;will delegate to the &lt;em&gt;GoogleAuthenticationHandler &lt;/em&gt;for each request and inspect the request to see if it should execute. For this logic it checks: &lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;if&lt;/span&gt; (Options.CallbackPath.HasValue &amp;amp;&amp;amp; Options.CallbackPath == Request.Path)
{
     &lt;span class="rem"&gt;//If the path matches, auth the request...&lt;/span&gt;
}&lt;/pre&gt;
&lt;p&gt;Since the &lt;em&gt;CallbackPath&lt;/em&gt; will be the same by default on both above declarations, the first one that is registered will match and the other registered authenticators will be ignored. To fix this we’ll need to update the path that Google sends back and then update the second declaration to match that path. &lt;/p&gt;
&lt;p&gt;To tell Google to send the request back on a different path, in your Google Developers Console change the REDIRECT URIS value for the second provider:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb_2.png"&gt;&lt;img title="image_thumb" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image_thumb" src="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb_thumb.png" width="244" height="216"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then we need to update the 2nd declaration with the custom &lt;em&gt;CallbackPath&lt;/em&gt; so that it matches and activates properly:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"GoogleBackOffice"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;,
    CallbackPath = &lt;span class="kwrd"&gt;new&lt;/span&gt; PathString(&lt;span class="str"&gt;"/custom-signin-google"&lt;/span&gt;)
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;Hooray, now it should work!&lt;/p&gt;
&lt;p&gt;This concept is the same for most external login providers. For example for the Facebook one the default value is “/signin-facebook”, you’d need to configure Facebook’s “Valid OAuth redirect URIs” property with the correct callback path in Facebook’s developer portal:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb1_2.png"&gt;&lt;img title="image_thumb1" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; padding-top: 0px; padding-left: 0px; border-left: 0px; display: inline; padding-right: 0px" border="0" alt="image_thumb1" src="http://shazwazza.com/media/articulate/windows-live-writer-connet-identity-oauth-login-providers-f_a1ef-image_thumb1_thumb.png" width="184" height="244"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;What is SignInAsAuthenticationType?&lt;/h2&gt;
&lt;p&gt;The last thing to point out is that by default the &lt;em&gt;SignInAsAuthenticationType &lt;/em&gt;for each provider will resolve to: &lt;em&gt;app.GetDefaultSignInAsAuthenticationType()&lt;/em&gt;, which by default is: &lt;em&gt;DefaultAuthenticationTypes.ExternalCookie&lt;/em&gt;&amp;nbsp; = “ExternalCookie”. Each OAuth provider is linked to another middleware that is responsible for actually issuing a user’s ClaimsIdentity, so by default this will be “ExternalCookie”. In some cases you won’t want the default external cookie authentication middleware to assign the ClaimsIdentity for your OAuth provider, you might need to issue a different ClaimsIdentity or just have more granular control over what happens with the callback for each OAuth provider. In this case you’ll need to specify another custom cookie authentication declaration, for example:&lt;/p&gt;&lt;pre class="csharpcode"&gt;app.UseCookieAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; CookieAuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"CustomExternal"&lt;/span&gt;,
    AuthenticationMode = AuthenticationMode.Passive,
    CookieName = &lt;span class="str"&gt;"MyAwesomeCookie"&lt;/span&gt;,
    ExpireTimeSpan = TimeSpan.FromMinutes(5),
    &lt;span class="rem"&gt;//Additional custom cookie options....&lt;/span&gt;
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;And then you can link that up to your OAuth declaration like:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;//custom options for back-office&lt;/span&gt;
app.UseGoogleAuthentication(&lt;span class="kwrd"&gt;new&lt;/span&gt; GoogleOAuth2AuthenticationOptions
{
    AuthenticationType = &lt;span class="str"&gt;"GoogleBackOffice"&lt;/span&gt;,
    ClientId = &lt;span class="str"&gt;"abcdef..."&lt;/span&gt;,
    ClientSecret = &lt;span class="str"&gt;"zyxwv...."&lt;/span&gt;,
    SignInAsAuthenticationType = &lt;span class="str"&gt;"CustomExternal"&lt;/span&gt;
});&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1208</guid>
      <link>https://shazwazza.com/post/asmx-soap-webservices-with-abstract-models-without-using-xmlinclude/</link>
      <category>ASP.Net</category>
      <title>ASMX SOAP Webservices with abstract models without using XmlInclude</title>
      <description>&lt;p&gt;I’m hoping this post might be useful to some folks out there that might be stuck using old ASMX/SOAP webservices in ASP.Net. If you’ve tried to return an abstract or superclass from an ASMX webservice without using XmlInclude or SoapInclude, you’ll get an error like:&lt;/p&gt;&lt;pre&gt;System.InvalidOperationException: There was an error generating the XML document. ---&amp;gt; System.InvalidOperationException: The type MyAwesomeClass was not expected. Use the XmlInclude or SoapInclude attribute to specify types that are not known statically.
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write6_Item(String n, String ns, Item o, Boolean isNullable, Boolean needType)
   at Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write10_Item(Object o)
   at Microsoft.Xml.Serialization.GeneratedAssembly.ItemSerializer.Serialize(Object objectToSerialize, XmlSerializationWriter writer)
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   --- End of inner exception stack trace ---
   at System.Xml.Serialization.XmlSerializer.Serialize(XmlWriter xmlWriter, Object o, XmlSerializerNamespaces namespaces, String encodingStyle, String id)
   at System.Xml.Serialization.XmlSerializer.Serialize(TextWriter textWriter, Object o, XmlSerializerNamespaces namespaces)
   at System.Web.Services.Protocols.XmlReturnWriter.Write(HttpResponse response, Stream outputStream, Object returnValue)
   at System.Web.Services.Protocols.HttpServerProtocol.WriteReturns(Object[] returnValues, Stream outputStream)
   at System.Web.Services.Protocols.WebServiceHandler.WriteReturns(Object[] returnValues)
   at System.Web.Services.Protocols.WebServiceHandler.Invoke()&lt;/pre&gt;
&lt;p&gt;The normal way to work around this is to attribute your ASMX class with &lt;em&gt;[XmlInclude(typeof(MyAwesomeClass)] &lt;/em&gt;and repeat this for every subclass that you might be returning. This essentially tells the SOAP handler what types it should expect to serialize so it can ‘warm’ up a list of XmlSerializers. &lt;/p&gt;
&lt;p&gt;The problem with this is that you need to know about all of these types up-front, but what if you have a plugin system where other developers can define their own types? There would be no way of knowing up-front what types to register so this approach will not work.&lt;/p&gt;
&lt;h2&gt;IXmlSerializer to the rescue&lt;/h2&gt;
&lt;p&gt;To work around this problem you can define a wrapper class for your abstract/superclass.&amp;nbsp; Working with &lt;em&gt;IXmlSerializer&lt;/em&gt; is pretty annoying and I highly recommend &lt;a href="http://www.codeproject.com/Articles/43237/How-to-Implement-IXmlSerializable-Correctly" target="_blank"&gt;this great article&lt;/a&gt; if you are going to use it since one mistake can cause all sorts of problems&lt;/p&gt;
&lt;p&gt;The following class should work for any object. Also note the usage of the static dictionary to store references to created XmlSerializer instances since these are expensive to create per type.&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; SerializedObjectWrapper : IXmlSerializable
{
    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// The underlying Object reference that is being returned&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;object&lt;/span&gt; Object { get; set; }

    &lt;span class="rem"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
    &lt;span class="rem"&gt;/// This is used because creating XmlSerializers are expensive&lt;/span&gt;
    &lt;span class="rem"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
    &lt;span class="kwrd"&gt;private&lt;/span&gt; &lt;span class="kwrd"&gt;static&lt;/span&gt; &lt;span class="kwrd"&gt;readonly&lt;/span&gt; ConcurrentDictionary&amp;lt;Type, XmlSerializer&amp;gt; TypeSerializers 
        = &lt;span class="kwrd"&gt;new&lt;/span&gt; ConcurrentDictionary&amp;lt;Type, XmlSerializer&amp;gt;();

    &lt;span class="kwrd"&gt;public&lt;/span&gt; XmlSchema GetSchema()
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;null&lt;/span&gt;;
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; ReadXml(XmlReader reader)
    {
        reader.MoveToContent();

        &lt;span class="rem"&gt;//Get the Item type attribute&lt;/span&gt;
        var itemType = reader.GetAttribute(&lt;span class="str"&gt;"ItemType"&lt;/span&gt;);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (itemType == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"ItemType attribute cannot be null"&lt;/span&gt;);
            
        &lt;span class="rem"&gt;//Ensure the type is found in the app domain&lt;/span&gt;
        var itemTypeType = Type.GetType(itemType);
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (itemTypeType == &lt;span class="kwrd"&gt;null&lt;/span&gt;) &lt;span class="kwrd"&gt;throw&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; InvalidOperationException(&lt;span class="str"&gt;"Could not find the type "&lt;/span&gt; + itemType);

        var isEmptyElement = reader.IsEmptyElement;
                    
        reader.ReadStartElement();

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (isEmptyElement == &lt;span class="kwrd"&gt;false&lt;/span&gt;)
        {
            var serializer = TypeSerializers.GetOrAdd(itemTypeType, t =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(t));
            Object = serializer.Deserialize(reader);
            reader.ReadEndElement();
        }
    }

    &lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;void&lt;/span&gt; WriteXml(XmlWriter writer)
    {
        var itemType = Object.GetType();
        var serializer = TypeSerializers.GetOrAdd(itemType, t =&amp;gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; XmlSerializer(t));
            
        &lt;span class="rem"&gt;//writes the object type so we can use that to deserialize later&lt;/span&gt;
        writer.WriteAttributeString(&lt;span class="str"&gt;"ItemType"&lt;/span&gt;, 
            itemType.AssemblyQualifiedName ?? Object.GetType().ToString());

        serializer.Serialize(writer, Object);
    }
}&lt;/pre&gt;
&lt;p&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;
&lt;/p&gt;
&lt;h2&gt;Usage&lt;/h2&gt;
&lt;p&gt;Here’s an example of the usage of the &lt;em&gt;SerializedObjectWrapper&lt;/em&gt; class along with the example that would cause the above mentioned exception so you can see the difference:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;abstract&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyAbstractClass
{
}

&lt;span class="kwrd"&gt;public&lt;/span&gt; &lt;span class="kwrd"&gt;class&lt;/span&gt; MyAwesomeClass : MyAbstractClass
{
}

&lt;span class="rem"&gt;//WONT WORK&lt;/span&gt;
[WebMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; MyAbstractClass GetStuff()
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; MyAwesomeClass();
}

&lt;span class="rem"&gt;//WILL WORK&lt;/span&gt;
[WebMethod]
&lt;span class="kwrd"&gt;public&lt;/span&gt; SerializedObjectWrapper GetStuff()
{
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;new&lt;/span&gt; SerializedObjectWrapper
    {
        Object = &lt;span class="kwrd"&gt;new&lt;/span&gt; MyAwesomeClass()
    };
}&lt;/pre&gt;
&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;

&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;I know most people aren’t using AMSX web services anymore but in case your stuck on an old project or have inherited one, this might be of use :)&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1226</guid>
      <link>https://shazwazza.com/post/installing-net-core-101-on-ubuntu-1610/</link>
      <category>ASP.Net</category>
      <title>Installing .NET Core 1.01 on Ubuntu 16.10</title>
      <description>&lt;h3&gt;TL;DR&amp;nbsp; You’ll need to manually install libicu55 &lt;/h3&gt; &lt;h3&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-installing-net-core-101-on-ubuntu-110_2d9-image_2.png"&gt;&lt;img title="image" style="border-top: 0px; border-right: 0px; background-image: none; border-bottom: 0px; float: right; padding-top: 0px; padding-left: 0px; border-left: 0px; margin: 0px 0px 10px 10px; display: inline; padding-right: 0px" border="0" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-installing-net-core-101-on-ubuntu-110_2d9-image_thumb.png" width="557" align="right" height="214"&gt;&lt;/a&gt;&lt;/h3&gt; &lt;p&gt;&lt;strong&gt;Warning&lt;/strong&gt;: Linux noob content below&lt;/p&gt; &lt;p&gt;I’ve been testing out some .NET Core cross platform stuff and originally had been using Ubuntu 14.04 with .NET Core 1.0.0 and that all worked fine along with the installation instructions from &lt;a href="https://www.microsoft.com/net/core#ubuntu"&gt;https://www.microsoft.com/net/core#ubuntu&lt;/a&gt; , however some of the latest tests I’ve been doing needed a MySQL version later than 5.5. It would seem that when I installed MySQL on Ubuntu 14.04 by executing &lt;em&gt;apt-get mysql-server&lt;/em&gt; that I got 5.5 which was not compatible with what I needed. So attempting to upgrade gave me other issues for which I would require a later version of Ubuntu. Long story short, I’m a linux noob and I couldn’t get anything to upgrade, ended up executing all sorts of commands I didn’t understand and probably shouldn’t have and ultimately killed my Linux install.&lt;/p&gt; &lt;p&gt;So a clean install of Ubuntu 16.04 it was … there’s a catch though, you can choose between LTS (Long Term Support) or not. I chose not to since It’s a VM and I don’t mind newer updates, etc… Turns out that was a bad idea with .NET Core installs! It would seem that once the non LTS is installed you end up with 16.10 which has installed some newer versions of required libraries, namely something called libicu which is now on 57 instead of a required 55.&lt;/p&gt; &lt;p&gt;Trying to run the normal installation procedure from the web instructions mentioned above for 16.04 ended up telling me this:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;sudo apt-get install dotnet-dev-1.0.0-preview2-003131&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;…&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;Some packages could not be installed. This may mean that you have&lt;br&gt;requested an impossible situation or if you are using the unstable&lt;br&gt;distribution that some required packages have not yet been created&lt;br&gt;or been moved out of Incoming.&lt;br&gt;The following information may help to resolve the situation:&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;The following packages have unmet dependencies:&lt;br&gt;dotnet-dev-1.0.0-preview2-003131 : Depends: dotnet-sharedframework-microsoft.netcore.app-1.0.1 but it is not going to be installed &lt;br&gt;E: Unable to correct problems, you have held broken packages.&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;So what the heck does that mean?! So after some Googling, I tried to just install the dependency:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;sudo apt-get install dotnet-sharedframework-microsoft.netcore.app-1.0.1&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;…&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;Some packages could not be installed. This may mean that you have&lt;br&gt;requested an impossible situation or if you are using the unstable&lt;br&gt;distribution that some required packages have not yet been created&lt;br&gt;or been moved out of Incoming.&lt;br&gt;The following information may help to resolve the situation:&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;The following packages have unmet dependencies:&lt;br&gt;dotnet-sharedframework-microsoft.netcore.app-1.0.1 : Depends: libicu55 (&amp;gt;=55.1.1~) but it is not installable &lt;br&gt;E: Unable to correct problems, you have held broken packages.&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;Ok, not much further but I gather that I need libicu55 installed, so let’s try:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;sudo apt-get install libicu55&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;…&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;Package libicu55 is not available, but is referred to by another package.&lt;br&gt;This may mean that the package is missing, has been obsoleted, or&lt;br&gt;is only available from another source&lt;/font&gt;&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;font color="#666666"&gt;E: Package libicu55 has no installation candidate&lt;/font&gt;&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;h2&gt;Manual libicu55 installation&lt;/h2&gt; &lt;p&gt;I suppose normal linux users would probably just know that you need to download and install libicu55 manually. Well it took a little bit of research for me to figure that out, but here’s what to do:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;head over to &lt;a href="http://packages.ubuntu.com/en/xenial/amd64/libicu55/download"&gt;http://packages.ubuntu.com/en/xenial/amd64/libicu55/download&lt;/a&gt;  &lt;li&gt;click one of the mirror links to download the file  &lt;li&gt;in Terminal, head to the folder you downloaded it (i.e. probably ~/Downloads)  &lt;li&gt;install it using this command: &lt;em&gt;sudo dpkg –i libicu55_55.1-7_amd64.deb&lt;/em&gt;&amp;nbsp; (or whatever file name you saved it as)&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;That should install just fine, then you can run &lt;em&gt;sudo apt-get install dotnet-dev-1.0.0-preview2-003131 &lt;/em&gt;and everything will be fine again :)&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1153</guid>
      <link>https://shazwazza.com/post/all-about-aspnet-file-change-notification-fcn/</link>
      <category>ASP.Net</category>
      <title>All about ASP.Net File Change Notification (FCN)</title>
      <description>&lt;p&gt;There’s a chance you might not have heard of FCN (File Change Notification) in ASP.Net and there’s an even bigger chance you didn’t realize how much it might affect you. &lt;/p&gt; &lt;h2&gt;What is FCN in ASP.Net? &lt;/h2&gt; &lt;p&gt;As you know ASP.Net monitors a few files/folders such as the ~/web.config and ~/App_Code and will restart your app domain when it detects changes. This is part of FCN in ASP.Net but it goes much deeper than that. There are a few other files &amp;amp; folders that ASP.Net monitors which will also cause an app domain restart: bin, App_WebReferences, App_GlobalResources, App_Code, Global.asax, &lt;a href="http://shazwazza.com/post/taming-the-buildmanager-aspnet-temp-files-and-appdomain-restarts/" target="_blank"&gt;and others&lt;/a&gt;. However what you might not realize is that ASP.Net actually monitors every single folder (+ files) in your web app! &lt;/p&gt; &lt;p&gt;&lt;em&gt;&lt;u&gt;Update 29/07/2016!&lt;/u&gt; I found a &lt;/em&gt;&lt;a href="https://blogs.msdn.microsoft.com/tmarq/2007/11/01/asp-net-file-change-notifications-exactly-which-files-and-directories-are-monitored/" target="_blank"&gt;&lt;em&gt;nice MS article about FCN here&lt;/em&gt;&lt;/a&gt;&lt;em&gt;. I’ve been looking for more resources about this since a few new issues have been cropping up and I’m wondering if another MS update has caused another problem. Recently we’ve seen an increase in the error: “Overwhelming Change Notification in …” which has everything to do with FCN. I’ve also added a few links to the bottom of this post.&lt;/em&gt;&lt;/p&gt; &lt;h2&gt;Why do I care?&lt;/h2&gt; &lt;p&gt;If you have a web app that contains a lot of folders there is a good chance that the performance of your file system is affected in one way or another. To give you an example of how many file system watchers ASP.Net generates I &lt;a href="https://github.com/Shazwazza/UmbracoScripts/blob/master/src/Web/ASPNetFileMonitorList.cshtml" target="_blank"&gt;created a Razor view (.cshtml)&lt;/a&gt;&amp;nbsp; (&lt;strong&gt;which you should definitely test on your own site!&lt;/strong&gt;) to display what is actually happening behind the scenes. Here’s the output for the first run page from the Visual Studio 2015 MVC template site:&lt;/p&gt; &lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_2.png"&gt;&lt;img width="640" height="360" title="image" style="display: inline;" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_thumb.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;The table above lists all of the “&lt;em&gt;DirectoryMonitor&lt;/em&gt;” instances and the folder they are attached to along with all of the “&lt;em&gt;FileMonitor&lt;/em&gt;” instances attached to that &lt;em&gt;DirectoryMonitor&lt;/em&gt;. It’s worth nothing that these are not simply just .Net’s &lt;em&gt;FileSystemWatcher&lt;/em&gt;, but some sort of native windows IO using a delegate called &lt;em&gt;NativeFileChangeNotification&lt;/em&gt;. The above table doesn’t seem too scary but these monitors are not static either, they grow with every directory and file that is accessed in your web app.&amp;nbsp; For example, if I navigate to these pages: /Home/About, /Home/Contact, /Account/Register, /Account/Login and go back to view this table it looks like:&lt;/p&gt; &lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_4.png"&gt;&lt;img width="640" height="277" title="image" style="display: inline;" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_thumb_1.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Things start to get interesting when you have a web application that has a lot of folders. Some examples of this might be:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;You are using a dynamic image processor such as &lt;a href="http://imageresizing.net/" target="_blank"&gt;Image Resizer&lt;/a&gt; or &lt;a href="http://imageprocessor.org/" target="_blank"&gt;Image Processor&lt;/a&gt; since these will create a lot of folders based on hashes to store these dynamic images  &lt;li&gt;Maybe you have a lot of members/users on your site and you have one or more folders for each one  &lt;li&gt;Maybe you use nodejs or bower and you store these generated folders in your web root and references the assets directly in those folders … there can be &lt;strong&gt;tons&lt;/strong&gt; of folders in &lt;em&gt;bower_components&lt;/em&gt; and &lt;em&gt;node_modules&lt;/em&gt;  &lt;li&gt;You could be using a web framework or CMS like Umbraco or Orchard (I’m sure there are plenty of others) that contain quite a lot of folders by default&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Here’s the truncated result of an Orchard site after visiting the admin area, creating a page and displaying it:&lt;/p&gt; &lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_6.png"&gt;&lt;img width="640" height="243" title="image" style="display: inline;" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_thumb_2.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;Whoa! &lt;/p&gt; &lt;h2&gt;ASP.Net’s FCNMode&lt;/h2&gt; &lt;p&gt;At some stage in ASP.Net’s lifetime somebody must have complained about this to Microsoft and they released a hotfix (seen here: &lt;a title="https://support.microsoft.com/en-us/kb/911272" href="https://support.microsoft.com/en-us/kb/911272"&gt;https://support.microsoft.com/en-us/kb/911272&lt;/a&gt;). Then I can only assume that other people complained about this and with .Net 4.5 a new configuration setting appeared: &lt;a href="https://msdn.microsoft.com/en-us/library/system.web.configuration.httpruntimesection.fcnmode(v=vs.110).aspx" target="_blank"&gt;FCNMode&lt;/a&gt;. &lt;a href="https://msdn.microsoft.com/en-us/library/system.web.configuration.fcnmode(v=vs.110).aspx#" target="_blank"&gt;This documentation&lt;/a&gt; explains a little about what each option does:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Default - For each subdirectory, the application creates an object that monitors the subdirectory. This is the default behavior  &lt;li&gt;Disabled - File change notification is disabled.  &lt;li&gt;NotSet - File change notification is not set, so the application creates an object that monitors each subdirectory. This is the default behavior.  &lt;li&gt;Single - The application creates one object to monitor the main directory and uses this object to monitor each subdirectory.&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;Unfortunately these docs don’t tell us the whole story. It’s obvious that Default/NotSet are the same thing and are the default. Disabled is fairly clear but what it doesn’t mention is that if you set it to Disabled, this will disable all FCN for your web app, so if you change the contents of /bin or /App_Code, the site will not restart. However, Disabled still means that the web.config file is monitored so if you use this setting you can still bump your web.config to restart your site. &lt;/p&gt; &lt;p&gt;What exactly is “&lt;em&gt;Single&lt;/em&gt;” though?&lt;/p&gt; &lt;p&gt;The folks over at DNN seem to have quite a bit of experience with FCN and &lt;a href="http://www.dnnsoftware.com/community-blog/cid/154980/aspnet-file-change-notifications-and-dnn" target="_blank"&gt;this article&lt;/a&gt; seems to be the only place that actually explains “Single” mode correctly: &lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;“FCNMode creates a monitor object with a buffer size of 4KB for each folder. When FCNMode is set to Single, a single monitor object is created with a buffer size of 64KB. When there are file changes, the buffer is filled with file change information. If the buffer gets overwhelmed with too many file change notifications an “Overwhelming File Change Notifications” error will occur and the app domain will recycle. The likelihood of the buffer getting overwhelmed is higher in an environment where you are using separate file server because the folder paths are much larger.”&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;If I change fcnMode=”Single” in my web.config for the same Orchard site above, the results are:&lt;/p&gt; &lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_8.png"&gt;&lt;img width="640" height="203" title="image" style="display: inline;" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-all-abonet-file-change-notification-fcn_8fe4-image_thumb_3.png"&gt;&lt;/a&gt;&lt;/p&gt; &lt;p&gt;That’s quite a bit less! &lt;/p&gt; &lt;p&gt;I’m sure there are pros to using “&lt;em&gt;Default&lt;/em&gt;” instead of “&lt;em&gt;Single&lt;/em&gt;” but I’m not actually sure what they are. &lt;/p&gt; &lt;h2&gt;Real world problem&lt;/h2&gt; &lt;p&gt;The circumstance where “&lt;em&gt;Default&lt;/em&gt;” FCN mode becomes a real problem is when you have a website that is running off of a remote file share.&amp;nbsp; As noted in Shawn Walker’s DNN article mentioned above:&lt;/p&gt; &lt;blockquote&gt; &lt;p&gt;&lt;em&gt;“The likelihood of the buffer getting overwhelmed is higher in an environment where you are using separate file server because the folder paths are much larger.”&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt; &lt;p&gt;I can’t actually see a performance difference between &lt;em&gt;Default&lt;/em&gt; or &lt;em&gt;Single&lt;/em&gt; when running locally with an SSD HD, but I have seen some big issues running with &lt;em&gt;Default&lt;/em&gt; when hosting on a remote file server:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;Constant app domain restarts – I’ve seen constant app domain restarts even when a site is just serving requests without any IO activity apart from just reading. And by ‘Constant’ … I mean every few seconds all day long.  &lt;li&gt;File server performance suffers severely – When multiple sites are active and are being hosted on a remote file server with &lt;em&gt;Default &lt;/em&gt;FCNMode, the writing performance of the file server is drastically degraded even though when monitoring &lt;a href="https://en.wikipedia.org/wiki/IOPS" target="_blank"&gt;IOPS&lt;/a&gt; there doesn’t appear to be any issues&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;To solve this issue we changed fcnMode=”Single” in the machine.config so that all sites would effectively use “Single”… and the result was instant: No more constant app restarts, file server performance was instantly back to normal. And as far as I can tell, there has been no downside to running FCNMode in &lt;em&gt;Single.&lt;/em&gt;&lt;/p&gt; &lt;p&gt;&lt;strong&gt;So I really wonder what the up-side of Default is when it seems that running in Single mode is perfectly stable running on any hosting environment… ?&lt;/strong&gt;&lt;/p&gt; &lt;p&gt;&lt;em&gt;FCN doesn’t appear to be a thing with aspnetcore!&lt;/em&gt;&lt;/p&gt; &lt;h2&gt;More info?&lt;/h2&gt; &lt;p&gt;&lt;em&gt;Updated 13/08/2018 – &lt;/em&gt;I wrote an FCN Viewer tool and wrote some more in-depth info about FCN and more of it’s quirks here: &lt;a title="https://shazwazza.com/post/fcn-file-change-notification-viewer-for-aspnet/" href="https://shazwazza.com/post/fcn-file-change-notification-viewer-for-aspnet/"&gt;https://shazwazza.com/post/fcn-file-change-notification-viewer-for-aspnet/&lt;/a&gt;&lt;/p&gt;&lt;p&gt;Here’s a list of helpful links about FCN in ASP.Net:&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a title="http://imageresizing.net/docs/fcnmode" href="http://imageresizing.net/docs/fcnmode"&gt;http://imageresizing.net/docs/fcnmode&lt;/a&gt;  &lt;li&gt;&lt;a title="https://support.microsoft.com/en-us/kb/911272" href="https://support.microsoft.com/en-us/kb/911272"&gt;https://support.microsoft.com/en-us/kb/911272&lt;/a&gt;  &lt;li&gt;&lt;a title="http://stackoverflow.com/questions/17615193/azure-websites-appdomain-many-restarts" href="http://stackoverflow.com/questions/17615193/azure-websites-appdomain-many-restarts"&gt;http://stackoverflow.com/questions/17615193/azure-websites-appdomain-many-restarts&lt;/a&gt;  &lt;li&gt;&lt;a title="http://blogs.msdn.com/b/toddca/archive/2005/12/01/499144.aspx" href="http://blogs.msdn.com/b/toddca/archive/2005/12/01/499144.aspx"&gt;http://blogs.msdn.com/b/toddca/archive/2005/12/01/499144.aspx&lt;/a&gt;  &lt;li&gt;&lt;a title="http://www.dnnsoftware.com/community-blog/cid/154980/aspnet-file-change-notifications-and-dnn" href="http://www.dnnsoftware.com/community-blog/cid/154980/aspnet-file-change-notifications-and-dnn"&gt;http://www.dnnsoftware.com/community-blog/cid/154980/aspnet-file-change-notifications-and-dnn&lt;/a&gt;  &lt;li&gt;&lt;a title="https://msdn.microsoft.com/en-us/library/system.web.configuration.fcnmode(v=vs.110).aspx" href="https://msdn.microsoft.com/en-us/library/system.web.configuration.fcnmode(v=vs.110).aspx"&gt;https://msdn.microsoft.com/en-us/library/system.web.configuration.fcnmode(v=vs.110).aspx&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt; &lt;p&gt;&lt;em&gt;Updated 29/07/2016&lt;/em&gt;! – More links I’ve discovered. Turns out this has been an issue for IIS + ASP.Net for quite some time with various older hotfixes, some of these new links might shed some light on the particular problem you might be having.&lt;/p&gt; &lt;ul&gt; &lt;li&gt;&lt;a title="https://blogs.msdn.microsoft.com/tess/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles/" href="https://blogs.msdn.microsoft.com/tess/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles/"&gt;https://blogs.msdn.microsoft.com/tess/2006/08/02/asp-net-case-study-lost-session-variables-and-appdomain-recycles/&lt;/a&gt; &lt;li&gt;&lt;a title="https://blogs.msdn.microsoft.com/tmarq/2007/11/01/asp-net-file-change-notifications-exactly-which-files-and-directories-are-monitored/" href="https://blogs.msdn.microsoft.com/tmarq/2007/11/01/asp-net-file-change-notifications-exactly-which-files-and-directories-are-monitored/"&gt;https://blogs.msdn.microsoft.com/tmarq/2007/11/01/asp-net-file-change-notifications-exactly-which-files-and-directories-are-monitored/&lt;/a&gt; &lt;li&gt;&lt;a title="https://support.microsoft.com/en-us/kb/3052480" href="https://support.microsoft.com/en-us/kb/3052480"&gt;https://support.microsoft.com/en-us/kb/3052480&lt;/a&gt; &lt;li&gt;&lt;a title="https://support.microsoft.com/en-us/kb/913297" href="https://support.microsoft.com/en-us/kb/913297"&gt;https://support.microsoft.com/en-us/kb/913297&lt;/a&gt; &lt;li&gt;&lt;a title="https://support.microsoft.com/en-us/kb/920970" href="https://support.microsoft.com/en-us/kb/920970"&gt;https://support.microsoft.com/en-us/kb/920970&lt;/a&gt; &lt;li&gt;&lt;a title="https://multitiered.wordpress.com/2010/08/11/sitecore-oms-error-overwhelming-change-notification/" href="https://multitiered.wordpress.com/2010/08/11/sitecore-oms-error-overwhelming-change-notification/"&gt;https://multitiered.wordpress.com/2010/08/11/sitecore-oms-error-overwhelming-change-notification/&lt;/a&gt;&lt;/li&gt;&lt;/ul&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
    <item>
      <guid isPermaLink="false">1171</guid>
      <link>https://shazwazza.com/post/appveyor-and-aspnet-core-previously-aspnet-5/</link>
      <category>ASP.Net</category>
      <title>AppVeyor and ASP.Net Core (Previously ASP.Net 5)</title>
      <description>&lt;p&gt;Last year I created a runtime Js/Css pre-processor for ASP.Net Core (Previously ASP.Net 5) called “&lt;a href="https://github.com/Shazwazza/Smidge" target="_blank"&gt;Smidge&lt;/a&gt;” and have been meaning to blog about how I integrated this with AppVeyor – to run my tests, build the project and output the Nuget files I need, so here it goes…&lt;/p&gt; &lt;h2&gt;The build script&lt;/h2&gt; &lt;p&gt;I use Powershell for my build scripts for my projects since it’s reasonably easy to read and the same script format has worked quite well for ASP.Net Core projects too. You can see the whole build file &lt;a href="https://github.com/Shazwazza/Smidge/blob/master/build.ps1" target="_blank"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;. Here’s the important things to note:&lt;/p&gt; &lt;p&gt;With AppVeyor (and probably other build servers), you need to ensure that it actually has the dnx version you need: &lt;/p&gt;&lt;pre class="csharpcode"&gt;# ensure the correct version
&amp;amp; $DNVM install 1.0.0-rc1-update1&lt;/pre&gt;
&lt;p&gt;Next you need to make sure that the current process is using the version you need to build:&lt;/p&gt;&lt;pre class="csharpcode"&gt;# use the correct version
&amp;amp; $DNVM use 1.0.0-rc1-update1&lt;/pre&gt;
&lt;p&gt;Then we need to use DNU to make sure that your project has everything it needs to build:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&amp;amp; $DNU restore &lt;span class="str"&gt;"$ProjectJsonPath"&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;Lastly it’s just building and packaging the project:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&amp;amp; $DNU build &lt;span class="str"&gt;"$ProjectJsonPath"&lt;/span&gt;
&amp;amp; $DNU pack &lt;span class="str"&gt;"$ProjectJsonPath"&lt;/span&gt; --configuration Release --&lt;span class="kwrd"&gt;out&lt;/span&gt; &lt;span class="str"&gt;"$ReleaseFolder"&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;The rest of the build file is normal Powershell bits. &lt;/p&gt;
&lt;h2&gt;The test script&lt;/h2&gt;
&lt;p&gt;I’m using xunit for unit tests in this project and similarly to the build script I’m using a simple Powershell script to execute the tests on the build server, the test runner file is &lt;a href="https://github.com/Shazwazza/Smidge/blob/master/tests.ps1" target="_blank"&gt;&lt;strong&gt;here&lt;/strong&gt;&lt;/a&gt;. The important parts are just like the above: Ensure the correct version is installed and being used by the current process and making sure that the project has everything it needs to build and finally to build it. The last missing piece is to actually run the tests:&lt;/p&gt;&lt;pre class="csharpcode"&gt;&amp;amp; $DNX -p &lt;span class="str"&gt;"$TestsFolder"&lt;/span&gt; test&lt;/pre&gt;
&lt;p&gt;Where ‘&lt;em&gt;test’&lt;/em&gt; is a command defined in my &lt;a href="https://github.com/Shazwazza/Smidge/blob/master/tests/Smidge.Tests/project.json#L10" target="_blank"&gt;project.json as part of my unit test project&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;AppVeyor configuration&lt;/h2&gt;
&lt;p&gt;The good news is that there’s really not a lot to setup, it’s super easy. In your AppVeyor settings just go to the ‘Build’ section and tell it to execute the Powershell script with its build version information:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_2.png"&gt;&lt;img title="image" style="display: inline" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_thumb.png" width="600" height="208"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Then for the unit tests is basically the same, click on the ‘Tests’ section and tell it to execute the Powershell test script:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_4.png"&gt;&lt;img title="image" style="display: inline" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_thumb_1.png" width="600" height="222"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And that’s pretty much it! The only other part I’ve had to setup is the paths to my Artifacts (Nuget files) based on the current build number.&lt;/p&gt;
&lt;p&gt;Now whenever I commit, AppVeyor will execute the build script and test script and we can see the output:&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_6.png"&gt;&lt;img title="image" style="display: inline" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_thumb_2.png" width="600" height="238"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And it’s smart enough to know that the test runner executed is for unit tests, so all the unit test output shows up in the ‘Tests’ tab of the build&lt;/p&gt;
&lt;p&gt;&lt;a href="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_8.png"&gt;&lt;img title="image" style="display: inline" alt="image" src="http://shazwazza.com/media/articulate/windows-live-writer-smidge-rc3-released_eb4d-image_thumb_3.png" width="600" height="152"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now that that’s all setup, AppVeyor even gives you a handy Nuget feed that you can use to test your packages based on each build, this can be configured on the ‘NuGet’ settings section, for example here’s the Smidge feed: &lt;a title="https://ci.appveyor.com/nuget/smidge" href="https://ci.appveyor.com/nuget/smidge"&gt;https://ci.appveyor.com/nuget/smidge&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Smidge 1.0.0-RC3&lt;/h2&gt;
&lt;p&gt;It’s worth noting that I’ve also released a new version of Smidge since I finally had some time to work on it. Couple of bugs fixed in this release and also a handy new feature too! You can see the release notes here: &lt;a title="https://github.com/Shazwazza/Smidge/releases/tag/1.0.0-rc3" href="https://github.com/Shazwazza/Smidge/releases/tag/1.0.0-rc3"&gt;https://github.com/Shazwazza/Smidge/releases/tag/1.0.0-rc3&lt;/a&gt;.&amp;nbsp; I’ve also updated a lot of the documentation, the main readme file was getting quite long so I’ve moved all of the docs over to the project’s Wiki on GitHub and condensed the readme for the most important bits. Have a look here: &lt;a title="https://github.com/Shazwazza/Smidge/releases/tag/1.0.0-rc3" href="https://github.com/Shazwazza/Smidge/releases/tag/1.0.0-rc3"&gt;https://github.com/Shazwazza/Smidge&lt;/a&gt;&lt;/p&gt;</description>
      <pubDate>Thu, 23 Mar 2023 15:08:15 Z</pubDate>
      <a10:updated>2023-03-23T15:08:15Z</a10:updated>
    </item>
  </channel>
</rss>