<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>less | Ash Grennan</title><link>https://www.ashgrennan.com/tag/less/</link><atom:link href="https://www.ashgrennan.com/tag/less/index.xml" rel="self" type="application/rss+xml"/><description>less</description><generator>Wowchemy (https://wowchemy.com)</generator><language>en-us</language><copyright>Copyright 2021 Ash Grennan | Information provided is published and reviewed according to the latest literature and is for general information purpose only</copyright><lastBuildDate>Sun, 07 Jun 2020 00:00:00 +0000</lastBuildDate><image><url>https://www.ashgrennan.com/media/icon_hu11c635150b33d0b2d171d7f02d87fa59_7607_512x512_fill_lanczos_center_3.png</url><title>less</title><link>https://www.ashgrennan.com/tag/less/</link></image><item><title>Micro Multi Tenanted Value Resolver Library 📚</title><link>https://www.ashgrennan.com/post/asp-net-core-multitenant-resolver-library/</link><pubDate>Sun, 07 Jun 2020 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/asp-net-core-multitenant-resolver-library/</guid><description>&lt;p>I&amp;rsquo;ve been recently dealing with enabling multi tenancy in a full stack application, the back end being ASP.NET Core. When looking into various multi tenant libraries I found them to have one or more characteristics:&lt;/p>
&lt;ul>
&lt;li>The apis were quite complex, and required lots of documentation parsing&lt;/li>
&lt;li>Difficult to plug in different value resolutions&lt;/li>
&lt;li>Require lots of boilerplate code and implementation of services&lt;/li>
&lt;/ul>
&lt;p>Many of these libraries are designed to use configuration files or resolution databases in order to load credentials. I &lt;strong>don&amp;rsquo;t&lt;/strong> like this, why?&lt;/p>
&lt;p>The reason is simple, &lt;em>most&lt;/em> credentials don&amp;rsquo;t belong in files such as &lt;code>appsettings.json&lt;/code>. Instead, these should be stored in a Key Vault which has a host of benefits such as, permission management hardware level encryption and so on. Services such as &lt;a href="https://azure.microsoft.com/en-gb/services/key-vault/" target="_blank" rel="noopener">Azure Key Vault&lt;/a> have these benefits.&lt;/p>
&lt;p>&lt;escape>&lt;!-- more -->&lt;/escape>&lt;/p>
&lt;p>So, more to the point I&amp;rsquo;ve written a very, very small library which implements a &lt;code>Middleware&lt;/code> pattern to essentially push specific credentials based upon a tenant resolution pattern into the current &lt;code>HttpContext&lt;/code>. The NuGet package can be found &lt;a href="https://www.nuget.org/packages/BobNudd.MicroMultiTenant" target="_blank" rel="noopener">here&lt;/a>&lt;/p>
&lt;p>The nice thing about Azure Key Vault is all secrets (depending upon access rights) can be loaded into &lt;code>IConfiguration&lt;/code> on application build.&lt;/p>
&lt;p>More information and the source can be found on GitHub:&lt;/p>
&lt;p>&lt;a href="https://github.com/BobNudd/MicroMultiTenant" target="_blank" rel="noopener">https://github.com/BobNudd/MicroMultiTenant&lt;/a>&lt;/p></description></item><item><title>🔃 Angular Network Aware Preload Strategy</title><link>https://www.ashgrennan.com/post/angular-network-aware-preload-strategy/</link><pubDate>Sun, 22 Dec 2019 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/angular-network-aware-preload-strategy/</guid><description>&lt;h3 id="lazy-loading-routes">Lazy Loading Routes&lt;/h3>
&lt;p>As your app becomes larger, with different modules to group feature components, a common approach is to lazy load
each module in your main routing configuration. Angular recommends this from the start, since it&amp;rsquo;s a simple yet scalable
pattern to load your projects dependencies once the &lt;code>route&lt;/code> is activated.
&lt;escape>&lt;!-- more -->&lt;/escape>
You have likely seen or implemented this pattern in the &lt;code>app-routing.module.ts&lt;/code> like below:&lt;/p>
&lt;pre>&lt;code class="language-csharp">import { NgModule } from '@angular/core';
import { RouterModule, Routes }
const routes: Routes = [
{
path: 'index',
loadChildren: 'src/app/modules/home/home.module#HomeModule'
},
{
path: 'shop',
loadChildren: 'src/app/modules/shop/shop.module#ShopModule'
}
];
&lt;/code>&lt;/pre>
&lt;p>or&lt;/p>
&lt;pre>&lt;code class="language-csharp">import { NgModule } from '@angular/core';
import { RouterModule, Routes }
const routes: Routes = [
{
path: 'index',
loadChildren: () =&amp;gt; import('src/app/modules/home/home.module').then(m =&amp;gt; m.HomeModule) }
},
{
path: 'users',
loadChildren: () =&amp;gt; import('src/app/modules/user/user.module').then(m =&amp;gt; m.UserModule) }
}
];
&lt;/code>&lt;/pre>
&lt;p>Note: the second example is new as of Angular 8, and is a &lt;a href="https://caniuse.com/#feat=es6-module-dynamic-import" target="_blank" rel="noopener">widely supported&lt;/a> method of importing modules.&lt;/p>
&lt;p>The above examples allow the module to be loaded in when they&amp;rsquo;re requested via accessing the &lt;code>route&lt;/code> tied to the module.&lt;/p>
&lt;h3 id="eager-loading">Eager Loading&lt;/h3>
&lt;p>The standard method of preloading any specified modules as above is to use the &lt;code>PreloadAllModules&lt;/code> strategy. This quite simple loads all modules that have been specified in our &lt;code>routes&lt;/code> array. The advantage of this method is a better user experience since there isn&amp;rsquo;t any time lag between an end user clicking a route e.g. &lt;code>/users&lt;/code> and the module having to be downloaded.&lt;/p>
&lt;pre>&lt;code class="language-csharp">imports: [
... // omitted for brevity
RouterModule.forRoot(routes,
{ preloadingStrategy: PreloadAllModules })
]
&lt;/code>&lt;/pre></description></item><item><title>Image Mutation Pipeline - Reshaping and Overlay Images</title><link>https://www.ashgrennan.com/post/image-mutation-pipeline-reshaping-and-overlay-images/</link><pubDate>Mon, 04 Nov 2019 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/image-mutation-pipeline-reshaping-and-overlay-images/</guid><description>&lt;h3 id="overview">Overview&lt;/h3>
&lt;p>In this post, we’ll go over image manipulation via creating a pipeline, the goal of this post will be to create avatar, consisting of a user/character, then surrounding this picture with a frame as an overlay.&lt;/p>
&lt;h3 id="requirements">Requirements&lt;/h3>
&lt;p>Rather than using &lt;code>System.Drawing&lt;/code> we’ll instead using &lt;a href="https://github.com/SixLabors/ImageSharp" target="_blank" rel="noopener">ImageSharp&lt;/a> which is the most popular image processing library written using .NET Core, it’s very fast and highly optimized, despite being in beta I have used in production for a year without problems.&lt;/p>
&lt;p>Using this library, we’ll create our own pipeline of image operations to perform using &lt;code>IImageProcessingContext&lt;/code>, and take advantage of some of heavy lifting ImageSharp provides.&lt;/p>
&lt;p>For assets, we’ll be using two images, a base picture and an overlay to surround:&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/post/image-mutation-pipeline-reshaping-and-overlay-images/me_hu0c96fc038056bc68338da817d10dd4e0_43311_22d60783a2c0b6bb1e3b9f09fdb4a262.png 400w,
/post/image-mutation-pipeline-reshaping-and-overlay-images/me_hu0c96fc038056bc68338da817d10dd4e0_43311_91c189164261c65bf467cc56c4cdaea3.png 760w,
/post/image-mutation-pipeline-reshaping-and-overlay-images/me_hu0c96fc038056bc68338da817d10dd4e0_43311_1200x1200_fit_lanczos_3.png 1200w"
src="https://www.ashgrennan.com/post/image-mutation-pipeline-reshaping-and-overlay-images/me_hu0c96fc038056bc68338da817d10dd4e0_43311_22d60783a2c0b6bb1e3b9f09fdb4a262.png"
width="225"
height="199"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
Base picture (me.png)&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/post/image-mutation-pipeline-reshaping-and-overlay-images/masters-bronze_hu7229e9bc8f6f78302b6d02ef5bce2a16_20128_a81af27f9b3d4e75fad816bb0f339896.png 400w,
/post/image-mutation-pipeline-reshaping-and-overlay-images/masters-bronze_hu7229e9bc8f6f78302b6d02ef5bce2a16_20128_59e0ca1fdf1c204818e71c34fa3356cc.png 760w,
/post/image-mutation-pipeline-reshaping-and-overlay-images/masters-bronze_hu7229e9bc8f6f78302b6d02ef5bce2a16_20128_1200x1200_fit_lanczos_3.png 1200w"
src="https://www.ashgrennan.com/post/image-mutation-pipeline-reshaping-and-overlay-images/masters-bronze_hu7229e9bc8f6f78302b6d02ef5bce2a16_20128_a81af27f9b3d4e75fad816bb0f339896.png"
width="221"
height="226"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
Overlay (frame.png)&lt;/p>
&lt;h3 id="project-setup">Project Setup&lt;/h3>
&lt;ul>
&lt;li>Create a .NET Core Console App&lt;/li>
&lt;li>Add the following Package Reference to your .csproj file &lt;code>&amp;lt;PackageReference Include=&amp;quot;SixLabors.ImageSharp.Drawing&amp;quot; Version=&amp;quot;1.0.0-beta0007&amp;quot; /&amp;gt;&lt;/code> If you install through nuget, ensure that &lt;code>.Drawing&lt;/code> is included, else you won’t be able to access the &lt;code>SixLabors.Shapes&lt;/code> namespace&lt;/li>
&lt;li>Add the assets to your project, make sure you select &lt;code>Copy if newer&lt;/code> in the Properties panel &amp;gt; Copy to Output Directory&lt;/li>
&lt;/ul>
&lt;h3 id="code">Code&lt;/h3>
&lt;p>The first part of this process is to alter the shape of our user image to something the resembles a diamond.&lt;/p>
&lt;p>Below is the code for this, with heavy use of comments elaborating on the process since this is much easier than blog annotations:&lt;/p>
&lt;pre>&lt;code class="language-csharp"> static void Main(string[] args)
{
// directory to output results
System.IO.Directory.CreateDirectory(&amp;quot;output&amp;quot;);
// wrap operations in using statements to ensure that Dispose is called
using (var img = Image.Load(&amp;quot;me.png&amp;quot;))
{
// clone the original image, since we need this for future runs of the application
using (Image destRound = img.Clone(x =&amp;gt; x.AvatarShaping(new Size(225, 225), 150)))
{
destRound.Save(&amp;quot;output/result.png&amp;quot;);
}
}
}
/// &amp;lt;summary&amp;gt;
/// Here's we're implementing the IImageProcessingContext interface and extending it via an extension method,
/// This implements a full image mutating pipeline operating on IImageProcessingContext
/// &amp;lt;/summary&amp;gt;
/// &amp;lt;param name=&amp;quot;processingContext&amp;quot;&amp;gt;the processingContext&amp;lt;/param&amp;gt;
/// &amp;lt;param name=&amp;quot;size&amp;quot;&amp;gt;Size of the image&amp;lt;/param&amp;gt;
/// &amp;lt;param name=&amp;quot;cornerRadius&amp;quot;&amp;gt;corner radius desired, higher will result in a smaller fill&amp;lt;/param&amp;gt;
/// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
private static IImageProcessingContext AvatarShaping(this IImageProcessingContext processingContext, Size size, float cornerRadius)
{
return processingContext.Resize(new ResizeOptions
{
Size = size,
Mode = ResizeMode.Crop
}).ApplyRoundedCorners(cornerRadius); // the next part of our pipeline
}
// This method can be seen as an inline implementation of an `IImageProcessor`:
// (The combination of `IImageOperations.Apply()` + this could be replaced with an `IImageProcessor`)
private static IImageProcessingContext ApplyRoundedCorners(this IImageProcessingContext ctx, float cornerRadius)
{
Size size = ctx.GetCurrentSize();
IPathCollection corners = BuildCorners(size.Width, size.Height, cornerRadius);
var graphicOptions = new GraphicsOptions(true)
{
// AlphaCompositionMode = PixelAlphaCompositionMode.DestOut // enforces that any part of this shape that has color is punched out of the background
};
// mutating in here as we already have a cloned original
// use any color (not Transparent), so the corners will be clipped
return ctx.Fill(graphicOptions, Rgba32.LimeGreen, corners);
}
private static IPathCollection BuildCorners(int imageWidth, int imageHeight, float cornerRadius)
{
// first create a square
var rect = new RectangularPolygon(-0.5f, -0.5f, cornerRadius, cornerRadius);
// then cut out of the square a circle so we are left with a corner
// Changing the offsets will change how much of the shape is cut out
IPath cornerTopLeft = rect.Clip(new EllipsePolygon(cornerRadius - 0.5f, cornerRadius - 0.5f, cornerRadius));
// corner is now a corner shape positions top left
//lets make 3 more positioned correctly, we can do that by translating the original around the center of the image
float rightPos = imageWidth - cornerTopLeft.Bounds.Width + 1;
float bottomPos = imageHeight - cornerTopLeft.Bounds.Height + 1;
// move it across the width of the image - the width of the shape
// cut the remaining 3 corners
IPath cornerTopRight = cornerTopLeft.RotateDegree(90).Translate(rightPos, 0);
IPath cornerBottomLeft = cornerTopLeft.RotateDegree(-90).Translate(0, bottomPos);
IPath cornerBottomRight = cornerTopLeft.RotateDegree(180).Translate(rightPos, bottomPos);
return new PathCollection(cornerTopLeft, cornerBottomLeft, cornerTopRight, cornerBottomRight);
}
&lt;/code>&lt;/pre>
&lt;p>The above code results in the following image:&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="image-mutation-pipeline-reshaping-and-overlay-images/fb-1.png" alt="" loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>We can achieve our approximate diamond shape via increasing the &lt;code>cornerRadius&lt;/code> float value, however this will result in less of the canvas showing, below is 200:&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="image-mutation-pipeline-reshaping-and-overlay-images/fb-2.png" alt="" loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>Side note, if you wanted a circle, all that would be required is to set the &lt;code>cornerRadius&lt;/code> to 50% of the image size.&lt;/p>
&lt;p>Currently we’re filling in the areas we’ve clipped with a solid green. Great for testing, but not for our desired result. You will want to comment out the following line which will automatically remove our colour fill.&lt;/p>
&lt;p>&lt;code>AlphaCompositionMode = PixelAlphaCompositionMode.DestOut&lt;/code>&lt;/p>
&lt;p>Next, we’ll add our overlay, this is simpler than the previous code. We’ll embed another &lt;code>using&lt;/code> statement since we still want the original outputs, this makes viewing each stage of the process and making changes much easier whilst we build the pipeline.&lt;/p>
&lt;p>Add the following within the &lt;code>destRound&lt;/code> using, after &lt;code>destRound.Save(&amp;quot;output/fb.png&amp;quot;);&lt;/code>&lt;/p>
&lt;pre>&lt;code class="language-csharp">using (var overlay = Image.Load(&amp;quot;frame.png&amp;quot;))
{
using (Image overlayClone = destRound.Clone(x =&amp;gt; x.GenerateOverlay(overlay)))
{
overlayClone.Save(&amp;quot;output/complete.png&amp;quot;, new PngEncoder()
{
ColorType = PngColorType.RgbWithAlpha // needed to instruct the encoder transparency is required
});
}
}
&lt;/code>&lt;/pre>
&lt;p>&lt;code>GenerateOverlay&lt;/code> is part our pipeline for this project, add the following:&lt;/p>
&lt;pre>&lt;code class="language-csharp">private static IImageProcessingContext GenerateOverlay(this IImageProcessingContext processingContext, Image me)
{
return processingContext.DrawImage(me, new Point(0, 0), new GraphicsOptions());
}
&lt;/code>&lt;/pre>
&lt;p>The above method will draw the image together with the previous image, once that has completed this will be saved to the disk.&lt;/p>
&lt;h3 id="the-final-result">The Final Result&lt;/h3>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img src="image-mutation-pipeline-reshaping-and-overlay-images/complete-1.png" alt="" loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;p>It should be noted that the code above is simply a proof in concept, for instance the &lt;code>Clone&lt;/code> methods add overhead and shouldn’t appear in production code.&lt;/p></description></item><item><title>Angular Lazy Loading Modules with Ivy – Uncaught (in promise) error cannot find module</title><link>https://www.ashgrennan.com/post/angular-with-ivy-uncaught-in-promise-error-cannot-find-module/</link><pubDate>Mon, 28 Oct 2019 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/angular-with-ivy-uncaught-in-promise-error-cannot-find-module/</guid><description>&lt;p>This is a quick post on an error I encountered whilst opting into the &lt;a href="https://blog.angular.io/a-plan-for-version-8-0-and-ivy-b3318dfc19f7" target="_blank" rel="noopener">Ivy compiler&lt;/a> (which should be here Nov 2019).&lt;/p>
&lt;p>Once you get through the initial errors, you may see the below in your console log:&lt;/p>
&lt;pre>&lt;code>core.js:6014 ERROR Error: Uncaught (in promise): Error: Cannot find module 'src/app/modules/module/your-module.module'
Error: Cannot find module 'src/app/modules/module/your-module.module'
at $_lazy_route_resource lazy namespace object:5
at ZoneDelegate.invoke (zone-evergreen.js:365)
at Object.onInvoke (core.js:39707)
at ZoneDelegate.invoke (zone-evergreen.js:364)
at Zone.run (zone-evergreen.js:124)
at zone-evergreen.js:851
at ZoneDelegate.invokeTask (zone-evergreen.js:400)
at Object.onInvokeTask (core.js:39688)
at ZoneDelegate.invokeTask (zone-evergreen.js:399)
at Zone.runTask (zone-evergreen.js:168)
at resolvePromise (zone-evergreen.js:793)
at resolvePromise (zone-evergreen.js:752)
at zone-evergreen.js:854
at ZoneDelegate.invokeTask (zone-evergreen.js:400)
at Object.onInvokeTask (core.js:39688)
at ZoneDelegate.invokeTask (zone-evergreen.js:399)
at Zone.runTask (zone-evergreen.js:168)
at drainMicroTaskQueue (zone-evergreen.js:570)
at ZoneTask.invokeTask [as invoke] (zone-evergreen.js:485)
at invokeTask (zone-evergreen.js:1596)
&lt;/code>&lt;/pre>
&lt;p>You’re getting this error due to Angular 8 introduced a new recommended module loading method, previously the default method of lazy loading modules was to specify a string path to a module:
&lt;escape>&lt;!-- more -->&lt;/escape>&lt;/p>
&lt;p>&lt;code>{path: '/admin', loadChildren: './admin/admin.module#AdminModule'}&lt;/code>&lt;/p>
&lt;p>This was something built into the Angular toolchain, and performed some wizardry to parse and load the module from the &lt;code>loadChildren&lt;/code> attribute.&lt;/p>
&lt;p>Since Angular 8, the method of importing modules has changed to the industry recognised / standard, &lt;a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import#Dynamic_Imports" target="_blank" rel="noopener">dynamic import&lt;/a>. So your import should now be changed to:&lt;/p>
&lt;p>&lt;code>loadChildren: () =&amp;gt; import('./admin/admin.module').then(m =&amp;gt; m.AdminModule)&lt;/code>&lt;/p>
&lt;p>Depending upon your IDE choice, you’ll likely also get Intellisense too:&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/post/angular-with-ivy-uncaught-in-promise-error-cannot-find-module/Capture_hu3726f2ed92053b55246cadbc951b0f86_6623_e8563fbc157abf9f3862bb1be8979b99.png 400w,
/post/angular-with-ivy-uncaught-in-promise-error-cannot-find-module/Capture_hu3726f2ed92053b55246cadbc951b0f86_6623_5c1e23e38823136a69232583d91f32b1.png 760w,
/post/angular-with-ivy-uncaught-in-promise-error-cannot-find-module/Capture_hu3726f2ed92053b55246cadbc951b0f86_6623_1200x1200_fit_lanczos_3.png 1200w"
src="https://www.ashgrennan.com/post/angular-with-ivy-uncaught-in-promise-error-cannot-find-module/Capture_hu3726f2ed92053b55246cadbc951b0f86_6623_e8563fbc157abf9f3862bb1be8979b99.png"
width="760"
height="58"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p></description></item><item><title>Broadcast data strategy with .NET Core, SignalR &amp; Angular</title><link>https://www.ashgrennan.com/post/broadcast-data-strategy-with-net-core-signalr-angular/</link><pubDate>Mon, 06 May 2019 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/broadcast-data-strategy-with-net-core-signalr-angular/</guid><description>&lt;p>In today’s post, we’re going to discuss an increasingly common requirement of tasks running within a web application. Depending upon your specialism you can think of these as service works, or simply background tasks. For this demo we’re going to focus on our web application continuously running a task which emits I/O data for the duration of the app’s life time. This data can then be consumed by another service, since our task needs to continuously run, it’s suited for more of a observable pattern on the client side, so we can subscribe and handle new data accordingly. In this scenario, we’re going to use SignalR to trigger invocation to any clients connected.&lt;/p>
&lt;p>First, you’ll need to do a small amount of configuration, I won’t elaborate on this since it’s fairly straight forward
&lt;escape>&lt;!-- more -->&lt;/escape>&lt;/p>
&lt;h3 id="startupcs">Startup.cs&lt;/h3>
&lt;p>Add the following to your &lt;code>ConfigureServices(IServiceCollection services)&lt;/code>&lt;/p>
&lt;p>&lt;code>services.AddSignalR();&lt;/code>
Note: In Core 3, you won’t need this call, as the Core Team are &lt;a href="https://twitter.com/davidfowl/status/1123603857831890944" target="_blank" rel="noopener">tidying up some of the service extensions&lt;/a>&lt;/p>
&lt;p>Next, you’ll want to add an endpoint for your hub in your &lt;code>Configure(IApplicationBuilder app, IHostingEnvironment env)&lt;/code>&lt;/p>
&lt;pre>&lt;code class="language-csharp">app.UseSignalR(routes =&amp;gt;
{
routes.MapHub&amp;lt;ChangeDataHub&amp;gt;(&amp;quot;/changes&amp;quot;);
});
&lt;/code>&lt;/pre>
&lt;p>With the addition of the &lt;code>ChangeDataHub&lt;/code> you’ll need to create a class with inherits from the base class Hub, we’ll leave this blank.&lt;/p>
&lt;pre>&lt;code class="language-csharp">public class ChangeDataHub: Hub
{
}
&lt;/code>&lt;/pre>
&lt;p>Good so far? Next we’ll need a Listener service which will manage the &lt;code>HubManager&lt;/code> allowing us to send invocation messages to anything which has subscribed to our service.&lt;/p>
&lt;p>But, before this we’ll need to think about how we’re going to use our listener service. With .NET Core 1 &amp;amp; 2, Microsoft provided a &lt;code>IWebHost&lt;/code> however, with the addition of 2.1. a new interface IHost was introduced. &lt;code>IHost&lt;/code> is similar to &lt;code>IWebHost&lt;/code> allowing hosted services, DI etc, however it’s more lightweight by the fact it’s designed for background tasks that aren’t used over HTTP. Since we’ll be transmitting our data via web sockets, this is ideal and the right fit for our project.&lt;/p>
&lt;p>Registering a host is easy in .NET Core, within our &lt;code>Startup.cs&lt;/code>, we’ll want to create a singleton instance of our host, we’ll be implementing the &lt;code>IHostedService&lt;/code> which is a great interface provide just two method of type &lt;code>Task&lt;/code> to implement, below is the interface:&lt;/p>
&lt;pre>&lt;code class="language-csharp">namespace Microsoft.Extensions.Hosting
{
//
// Summary:
// Defines methods for objects that are managed by the host.
public interface IHostedService
{
//
// Summary:
// Triggered when the application host is ready to start the service.
Task StartAsync(CancellationToken cancellationToken);
//
// Summary:
// Triggered when the application host is performing a graceful shutdown.
Task StopAsync(CancellationToken cancellationToken);
}
}
&lt;/code>&lt;/pre>
&lt;p>Plugging in our implementation of the IHostedService as described above:&lt;/p>
&lt;pre>&lt;code class="language-csharp">public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton&amp;lt;Microsoft.Extensions.Hosting.IHostedService, ChangeDataListenerService&amp;gt;();
}
&lt;/code>&lt;/pre>
&lt;p>Now it’s time to implement our interface, like most tasks we don’t want to simply run this once, but on an incremental basis. To achieve this we’ll use the static method Task.Delay which will take our delay value.&lt;/p>
&lt;pre>&lt;code class="language-csharp">private readonly HubLifetimeManager&amp;lt;ChangeDataHub&amp;gt; _hubManager;
private readonly ILogger&amp;lt;DefaultLogger&amp;gt; _logger;
private readonly TimeSpan _delay = TimeSpan.FromSeconds(1);
public ChartListenerService(
HubLifetimeManager&amp;lt;ChangeDataHub&amp;gt; hubManager,
ILogger&amp;lt;DefaultLogger&amp;gt; logger)
{
_hubManager = hubManager;
_logger = logger;
}
public async Task StartAsync(CancellationToken cts)
{
_logger.LogInformation(&amp;quot;Listener is starting..&amp;quot;);
while (!cts.IsCancellationRequested)
{
_logger.LogInformation(&amp;quot;Fetching updates..&amp;quot;);
var data = DataManager.Get();
await _hubManager.SendAllAsync(&amp;quot;TransferData&amp;quot;, new object[] { data });
await Task.Delay(_delay, cts);
}
_logger.LogInformation(&amp;quot;Listener has completed..&amp;quot;);
}
&lt;/code>&lt;/pre>
&lt;p>That’s our basic implementation completed. It should be noted that if you’re using a repository which for instance uses a &lt;code>DbContext&lt;/code> this won’t work, since we’ll be creating a DbContext instance that can become a singleton, which can lead to a whole host of problems.&lt;/p>
&lt;p>The solution to this problem is injecting a &lt;code>IServiceScopeFactory&lt;/code> instance and use when we need a scoped instance of a service.&lt;/p>
&lt;pre>&lt;code class="language-csharp">private readonly HubLifetimeManager&amp;lt;ChangeDataHub&amp;gt; _hubManager;
private readonly ILogger&amp;lt;DefaultLogger&amp;gt; _logger;
private readonly TimeSpan _delay = TimeSpan.FromSeconds(1);
private readonly IServiceScopeFactory _scopeFactory;
public ChartListenerService(
HubLifetimeManager&amp;lt;ChangeDataHub&amp;gt; hubManager,
ILogger&amp;lt;DefaultLogger&amp;gt; logger,
IServiceScopeFactory scopeFactory)
{
_hubManager = hubManager;
_logger = logger;
_scopeFactory = scopeFactory;
}
public async Task StartAsync(CancellationToken cts)
{
_logger.LogInformation(&amp;quot;Listener is starting..&amp;quot;);
while (!cts.IsCancellationRequested)
{
// Scoped service generation, resolve and dependencies in here
using (var scope = _scopeFactory.CreateScope())
{
_logger.LogInformation(&amp;quot;Fetching updates..&amp;quot;);
var dataManager = scope.ServiceProvider.GetRequiredService&amp;lt;DataManager&amp;gt;();
await _hubManager.SendAllAsync(&amp;quot;TransferData&amp;quot;, new object[] { dataManager.Get() });
}
await Task.Delay(_delay, cts);
}
_logger.LogInformation(&amp;quot;Listener has completed..&amp;quot;);
}
&lt;/code>&lt;/pre>
&lt;p>This also means we don’t have to constructor DI all our service dependencies, a good thing in a larger, real world example.&lt;/p>
&lt;p>In the next post, I’ll go over how to connect and consume this information on the client side.&lt;/p></description></item><item><title>EF Core – Seed Data Strategy</title><link>https://www.ashgrennan.com/post/ef-core-seed-data-strategy/</link><pubDate>Sun, 06 Jan 2019 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/ef-core-seed-data-strategy/</guid><description>&lt;p>In this post, we’re going to explore the &lt;em>relatively&lt;/em> new entity data seeding method which was introduced with EF Core 2.1.&lt;/p>
&lt;p>&lt;strong>It’s fantastic&lt;/strong>.&lt;/p>
&lt;p>Unlike it’s predecessor EF6, seed data can be associated with migrations and it’s relative entity type as part of your migration strategy. What this means is adding or editing any seed data for any entity will compute the correct insert(s) or updates to push those data changes into your DB, this is incredibly powerful and leverages the benefits of tracking that migrations provide.&lt;/p>
&lt;h3 id="lets-see-some-code">Lets see some code&lt;/h3>
&lt;p>First, you’ll need to override the &lt;code>OnModelCreating&lt;/code> method in your DbContext, chances are you’re already doing this in an existing project.&lt;/p>
&lt;pre>&lt;code class="language-csharp"> protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder)
}
&lt;/code>&lt;/pre>
&lt;p>Next, we’ll call the &lt;code>HasData&lt;/code> method and pass in a populated instance of an entity.&lt;/p>
&lt;pre>&lt;code class="language-csharp"> protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
modelBuilder.Entity().HasData(new Person { PersonId = 1, Name = &amp;quot;Ash&amp;quot; });
}
&lt;/code>&lt;/pre>
&lt;p>Good so far? Before running our &lt;code>add-migration&lt;/code> command, I want to touch on a few key points:&lt;/p>
&lt;ul>
&lt;li>Primary keys for all entities must be specified, this is how the seed data change detection works via comparing if the particular record exist, or if any fields have changed&lt;/li>
&lt;li>Any entities with foreign keys must be explicitly stated&lt;/li>
&lt;li>Previously seeded data that has a primary key change will be removed (this makes sense, since the record can no longer be referred to)&lt;/li>
&lt;li>You may want custom initialization logic depending on your scenario such as temporary data for testing&lt;/li>
&lt;/ul>
&lt;p>Now, running &lt;code>add-migration firstseed&lt;/code> will produce a migration for entering our new records (since their primary keys don’t exist in the table).&lt;/p>
&lt;pre>&lt;code class="language-csharp">migrationBuilder.InsertData(
table: &amp;quot;Persons&amp;quot;,
columns: new[] { &amp;quot;PersonId&amp;quot;, &amp;quot;Name&amp;quot; },
values: new object[] { 1, &amp;quot;Ash&amp;quot; });
&lt;/code>&lt;/pre>
&lt;p>Any changes to this data will result in a new migration with correct behaviour (insert/update/delete) making seed data much easier to progress as your applications develops, rather than a monolithic script of inserts.&lt;/p>
&lt;h3 id="further-points">Further Points&lt;/h3>
&lt;h5 id="structuring-seed-data">Structuring Seed Data&lt;/h5>
&lt;p>Adding seed data with the &lt;code>OnModelCreating&lt;/code> can become difficult to manage, especially with dozens of entities, personally I would opt to create extension methods to keep this method clean.&lt;/p>
&lt;pre>&lt;code class="language-csharp"> protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.AddContractHoursData();
builder.AddLocationData();
builder.AddJobTitleData();
}
&lt;/code>&lt;/pre>
&lt;p>Additionally, creating a single contained class for each data entity was my approach, adhering to the Single Responsibility Principle and violating DRY.&lt;/p>
&lt;pre>&lt;code class="language-csharp"> public static void AddRewardCategoryData(this ModelBuilder model)
{
model.Entity().HasData(new List()
{
new RewardCategory()
{
RewardCategoryId = 1,
Name = &amp;quot;Vouchers&amp;quot;,
Enabled = true
},
new RewardCategory()
{
RewardCategoryId = 2,
Name = &amp;quot;Charity&amp;quot;,
Enabled = true
}
});
}
&lt;/code>&lt;/pre>
&lt;h5 id="creating-identity-users">Creating Identity Users&lt;/h5>
&lt;p>One question I’ve seen people ask is seeding users from Identity (since &lt;code>UserManager&lt;/code> takes care of things like Password Hash).&lt;/p>
&lt;p>We can use Identities &lt;code>PasswordHasher&lt;/code>.&lt;/p>
&lt;p>However there’s a problem with this approach, this will programmatically generate a different hash per run, and therefore bloat every migration with updates. Additionally you’d rather avoid hard coding dozens or hundreds of type &lt;code>User&lt;/code> models.&lt;/p>
&lt;p>My strategy for this approach was the following:&lt;/p>
&lt;ul>
&lt;li>Use a library such as &lt;a href="https://www.nuget.org/packages/Faker.Net/" target="_blank" rel="noopener">Faker&lt;/a> to generate a list of user details&lt;/li>
&lt;li>Iterate through the list, assign a hard-coded GUID from a list you’ve created&lt;/li>
&lt;li>Use the &lt;code>PasswordHasher&lt;/code> to generate the hashed password&lt;/li>
&lt;li>Pass the completed list to the &lt;code>HasData&lt;/code> method&lt;/li>
&lt;li>Copy the data within the AspNetUser table in your database as JSON (I used SQL Operations Studio for this)&lt;/li>
&lt;li>Use some Find and replace with regular expressions to fix formatting errors and form into a list of Users&lt;/li>
&lt;li>You should a list of populated entities, all with hard coded data without tedious data entry&lt;/li>
&lt;/ul></description></item><item><title>Fixing MSBuild CS103, CS012 Compiler Errors</title><link>https://www.ashgrennan.com/post/fixing-msbuild-cs103-cs012-compiler-errors/</link><pubDate>Fri, 01 Jun 2018 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/fixing-msbuild-cs103-cs012-compiler-errors/</guid><description>&lt;p>Recently I needed to use MSBuild to compile a solution for a build server.&lt;/p>
&lt;p>The MSBuild was location at:&lt;/p>
&lt;p>&lt;code>C:\Program Files (x86)\MSBuild\14.0\Bin&lt;/code>&lt;/p>
&lt;p>The following errors were occurring despite this working in the past:&lt;/p>
&lt;p>&lt;code>error CS1525: Invalid expression term ‘decimal’ Syntax error, ‘,’ expected error CS1003: Syntax error, ‘,’ expected [Web.csproj]&lt;/code>&lt;/p>
&lt;p>This was due to C#6/C#7 features which aren’t supported by this MSBuild version.&lt;/p>
&lt;h4 id="the-fix">The Fix&lt;/h4>
&lt;p>Using this MSBuild resolved the issue:&lt;/p>
&lt;p>&lt;code>C:\Program Files (x86)\Microsoft Visual Studio\2017\Professional\MSBuild\15.0\Bin&lt;/code>&lt;/p></description></item><item><title>HTML5 – Unknown JavaScript Web APIs</title><link>https://www.ashgrennan.com/post/html5-unknown-javascript-web-apis/</link><pubDate>Sat, 05 Aug 2017 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/html5-unknown-javascript-web-apis/</guid><description>&lt;p>There&amp;rsquo;s a lot of cool things that HTML5 can do, using local storage for data saving/retrieval or acquiring a users geolocation for your custom Google map. Well it turns out there’s many many more JavaScript APIs than I haven’t seen people mention, below are a few of these.&lt;/p>
&lt;p>Before we go on, I should mention I’ll be focusing on APIs which benefit mobile/tablet devices, since these are really cool useful in modern web applications.&lt;/p>
&lt;h3 id="online-state">Online State&lt;/h3>
&lt;p>This exposes network connection information to web, quite simply we can now determine if a user has a Internet connection within our web application. This is highly useful in cases where the apps streams data in, we can let the user know that there’s a connection issue rather than simply returning nothing creating a much better user experience.&lt;/p>
&lt;p>This API is being updated, things like grabbing a connection speed and adjusting app according would be useful, for example image degradation.&lt;/p>
&lt;pre>&lt;code class="language-javascript">window.addEventListener('offline', networkStatus);
window.addEventListener('online', networkStatus);
function networkStatus(e) {
console.log(e);
}
&lt;/code>&lt;/pre>
&lt;h4 id="support">Support&lt;/h4>
&lt;p>Browser support for this is excellent for recent browser versio8ns, with some of the smaller device specific browsers such as Samung Internet supporting it.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/post/html5-unknown-javascript-web-apis/online-status-web-api_hu537bfaed644d07d9b34f9dd37475f593_69830_f7e651425bf8e49272e169f0d3f1d2c7.png 400w,
/post/html5-unknown-javascript-web-apis/online-status-web-api_hu537bfaed644d07d9b34f9dd37475f593_69830_199fea129cd26d6b3d7223e6839d1e5b.png 760w,
/post/html5-unknown-javascript-web-apis/online-status-web-api_hu537bfaed644d07d9b34f9dd37475f593_69830_1200x1200_fit_lanczos_3.png 1200w"
src="https://www.ashgrennan.com/post/html5-unknown-javascript-web-apis/online-status-web-api_hu537bfaed644d07d9b34f9dd37475f593_69830_f7e651425bf8e49272e169f0d3f1d2c7.png"
width="760"
height="381"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h3 id="device-orientation">Device Orientation&lt;/h3>
&lt;p>From this we have an easy way to determine the orientation of a device. This would be especially useful when dealing with media heavy web apps and ensuring your content can use the new orientation real estate efficiently. Also combined with CSS we can rotate images in a 3D space.&lt;/p>
&lt;pre>&lt;code class="language-javascript">window.addEventListener('deviceorientation', (e) =&amp;gt; {
console.log('alpha:', e.alpha);
console.log('beta:', e.beta);
console.log('gamma:', e.gamma);
});
&lt;/code>&lt;/pre>
&lt;h4 id="support-1">Support&lt;/h4>
&lt;p>Browser support for this isn’t great, partial support with knows issues, fine for fun features and non essential but I wouldn’t rely on it.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/post/html5-unknown-javascript-web-apis/device-orientation-javascript-api_hu14a4b4fa81ea501b4d3b9de51560cb30_79266_d5b2fe78a7d3c7da00928930a118168e.png 400w,
/post/html5-unknown-javascript-web-apis/device-orientation-javascript-api_hu14a4b4fa81ea501b4d3b9de51560cb30_79266_a846f81ad7c90bbba43b9f34d71fa441.png 760w,
/post/html5-unknown-javascript-web-apis/device-orientation-javascript-api_hu14a4b4fa81ea501b4d3b9de51560cb30_79266_1200x1200_fit_lanczos_3.png 1200w"
src="https://www.ashgrennan.com/post/html5-unknown-javascript-web-apis/device-orientation-javascript-api_hu14a4b4fa81ea501b4d3b9de51560cb30_79266_d5b2fe78a7d3c7da00928930a118168e.png"
width="760"
height="398"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h3 id="capture-ambient-light">Capture Ambient Light&lt;/h3>
&lt;p>This is really, really cool. The metric returned from this is &lt;a href="https://en.wikipedia.org/wiki/Lux" target="_blank" rel="noopener">lux&lt;/a> which is used to measure light. You can read about the sensor API more &lt;a href="https://www.w3.org/TR/generic-sensor/" target="_blank" rel="noopener">here&lt;/a>. A use case for this would be switching to a darker or lighter theme depending on available light, enabling the user to choose would certainly be a nice feature and provide a better user experience.&lt;/p>
&lt;pre>&lt;code class="language-javascript">window.addEventListener('devicelight', (e) =&amp;gt; {
console.log(`${e.value} lux`);
})
&lt;/code>&lt;/pre>
&lt;h4 id="support-2">Support&lt;/h4>
&lt;p>Browser support for this is bad, it has been available in Chrome since version 62, however is an experimental feature and has to be enabled.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/post/html5-unknown-javascript-web-apis/ambient-light-api_hu2af8deebf4876ada585f47c2e70aa584_73406_f81ec26a27b15749b5ebaa6e731eec58.png 400w,
/post/html5-unknown-javascript-web-apis/ambient-light-api_hu2af8deebf4876ada585f47c2e70aa584_73406_740808b18df86f82892688ba300df297.png 760w,
/post/html5-unknown-javascript-web-apis/ambient-light-api_hu2af8deebf4876ada585f47c2e70aa584_73406_1200x1200_fit_lanczos_3.png 1200w"
src="https://www.ashgrennan.com/post/html5-unknown-javascript-web-apis/ambient-light-api_hu2af8deebf4876ada585f47c2e70aa584_73406_f81ec26a27b15749b5ebaa6e731eec58.png"
width="760"
height="389"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p>
&lt;h3 id="battery-level">Battery Level&lt;/h3>
&lt;p>We can now detect battery levels, therefore also having the added benefit of determining if a device is plugged into a power source. The &lt;a href="https://w3c.github.io/battery/" target="_blank" rel="noopener">code for this&lt;/a> a little different in that you’re using a promise. Since the W3C example has many code samples, I’ll use one of these.&lt;/p>
&lt;pre>&lt;code class="language-javascript">navigator.getBattery().then(function(battery) {
console.log(battery.level);
battery.addEventListener('levelchange', function() {
console.log(this.level);
});
});
&lt;/code>&lt;/pre>
&lt;h4 id="support-3">Support&lt;/h4>
&lt;p>Browser support for this is pretty poor unless you’re specifically targeting Chrome. Also as FireFox have removed the feature, therefore it doesn’t look promising for the future.&lt;/p>
&lt;p>
&lt;figure >
&lt;div class="d-flex justify-content-center">
&lt;div class="w-100" >&lt;img alt="" srcset="
/post/html5-unknown-javascript-web-apis/battery-status-api_hu99c9fa788c0181c0b41554b38a1e867c_67062_a462bba5becb44fd31deea6e06f06616.png 400w,
/post/html5-unknown-javascript-web-apis/battery-status-api_hu99c9fa788c0181c0b41554b38a1e867c_67062_bef6f369f1c6c0aea6c75b491c4b17f8.png 760w,
/post/html5-unknown-javascript-web-apis/battery-status-api_hu99c9fa788c0181c0b41554b38a1e867c_67062_1200x1200_fit_lanczos_3.png 1200w"
src="https://www.ashgrennan.com/post/html5-unknown-javascript-web-apis/battery-status-api_hu99c9fa788c0181c0b41554b38a1e867c_67062_a462bba5becb44fd31deea6e06f06616.png"
width="760"
height="379"
loading="lazy" data-zoomable />&lt;/div>
&lt;/div>&lt;/figure>
&lt;/p></description></item><item><title>Writing in BEM using LESS</title><link>https://www.ashgrennan.com/post/writing-bem-using-less/</link><pubDate>Sat, 05 Aug 2017 00:00:00 +0000</pubDate><guid>https://www.ashgrennan.com/post/writing-bem-using-less/</guid><description>&lt;h2 id="overview">Overview&lt;/h2>
&lt;p>This is something I found myself thinking about when using the Block Element Module (BEM) methodology when coding using the preprocessor LESS.&lt;/p>
&lt;p>I like this for the follow reasons:&lt;/p>
&lt;ul>
&lt;li>Less repeating code&lt;/li>
&lt;li>Ability to change the block name and auto cascade to the element descendants&lt;/li>
&lt;li>Less lines and easier to read&lt;/li>
&lt;/ul>
&lt;h4 id="the-code">The Code&lt;/h4>
&lt;pre>&lt;code class="language-less"> block {
&amp;amp;__element {
&amp;amp;--modifier-alpha {
color: blue;
}
&amp;amp;--modifier--beta {
color: green;
}
}
}
&lt;/code>&lt;/pre>
&lt;p>So the compiled elements would look like this:&lt;/p>
&lt;pre>&lt;code class="language-less"> block__element--modifier-alpha {
color: blue;
}
block__element--modifier-beta {
color: green;
}
&lt;/code>&lt;/pre></description></item></channel></rss>