{"@attributes":{"version":"2.0"},"channel":{"title":"DEV Community: Galdin Raphael","description":"The latest articles on DEV Community by Galdin Raphael (@galdin).","link":"https:\/\/dev.to\/galdin","image":{"url":"https:\/\/media2.dev.to\/dynamic\/image\/width=90,height=90,fit=cover,gravity=auto,format=auto\/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F15060%2F46b4bd62-158c-4a84-994c-2cfc98ee5300.jpeg","title":"DEV Community: Galdin Raphael","link":"https:\/\/dev.to\/galdin"},"language":"en","item":[{"title":"Build-time configuration for Blazor WebAssembly Apps using MS Build properties","pubDate":"Sun, 28 Jun 2020 12:04:44 +0000","link":"https:\/\/dev.to\/galdin\/build-time-configuration-for-blazor-webassembly-apps-using-ms-build-properties-3pgp","guid":"https:\/\/dev.to\/galdin\/build-time-configuration-for-blazor-webassembly-apps-using-ms-build-properties-3pgp","description":"<p>.NET Core in general has a nice configuration API that I've been fond of since .NET Core 1.x. But since Blazor WebAssembly apps run completely on the client, the configuration works a little differently that one might expect.<\/p>\n\n<p>The way configuration using <code>appsettings.json<\/code> works is that, a HTTP request is sent to a <code>appsettings.json<\/code> file. So if the app is available at <code>https:\/\/xyz.com<\/code>, the request goes to <code>https:\/\/xyz.com\/appsettings.json<\/code>. You can also use another file-name or path if you want to.<\/p>\n\n<p>But if you're just trying to do something like set the Web API's Base URL, a HTTP request on startup can feel like an overkill. I'm gonna try and address that with this post.<\/p>\n\n<p><strong>Source Code:<\/strong> <a href=\"https:\/\/github.com\/gldraphael\/blazor-build-time-configuration\" rel=\"noopener noreferrer\">https:\/\/github.com\/gldraphael\/blazor-build-time-configuration<\/a><\/p>\n\n<p>First, we create a custom <code>Attribute<\/code> to hold our configuration:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight csharp\"><code><span class=\"p\">[<\/span><span class=\"nf\">AttributeUsage<\/span><span class=\"p\">(<\/span><span class=\"n\">AttributeTargets<\/span><span class=\"p\">.<\/span><span class=\"n\">Assembly<\/span><span class=\"p\">,<\/span> <span class=\"n\">Inherited<\/span> <span class=\"p\">=<\/span> <span class=\"k\">false<\/span><span class=\"p\">)]<\/span>\n<span class=\"k\">sealed<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">BuildConfigurationAttribute<\/span> <span class=\"p\">:<\/span> <span class=\"n\">Attribute<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"k\">public<\/span> <span class=\"kt\">string<\/span><span class=\"p\">?<\/span> <span class=\"n\">BaseUrl<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n    <span class=\"k\">public<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">BuildDate<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n\n    <span class=\"k\">public<\/span> <span class=\"nf\">BuildConfigurationAttribute<\/span><span class=\"p\">(<\/span><span class=\"kt\">string<\/span> <span class=\"n\">baseUrl<\/span><span class=\"p\">,<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">buildDate<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">{<\/span>\n        <span class=\"n\">BaseUrl<\/span> <span class=\"p\">=<\/span> <span class=\"kt\">string<\/span><span class=\"p\">.<\/span><span class=\"nf\">IsNullOrWhiteSpace<\/span><span class=\"p\">(<\/span><span class=\"n\">baseUrl<\/span><span class=\"p\">)<\/span> <span class=\"p\">?<\/span> <span class=\"k\">null<\/span> <span class=\"p\">:<\/span> <span class=\"n\">baseUrl<\/span><span class=\"p\">;<\/span>\n        <span class=\"n\">BuildDate<\/span> <span class=\"p\">=<\/span> <span class=\"n\">buildDate<\/span> <span class=\"p\">??<\/span> <span class=\"s\">\"n\/a\"<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Next, we apply this Attribute to the Assembly by passing MS Build properties in the <code>.csproj<\/code> file:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight xml\"><code><span class=\"nt\">&lt;ItemGroup&gt;<\/span>\n  <span class=\"nt\">&lt;AssemblyAttribute<\/span> <span class=\"na\">Include=<\/span><span class=\"s\">\"WasmApp.BuildConfigurationAttribute\"<\/span><span class=\"nt\">&gt;<\/span>\n    <span class=\"nt\">&lt;_Parameter1&gt;<\/span>$(BaseUrl)<span class=\"nt\">&lt;\/_Parameter1&gt;<\/span>\n    <span class=\"nt\">&lt;_Parameter2&gt;<\/span>$(BuildDate)<span class=\"nt\">&lt;\/_Parameter2&gt;<\/span>\n  <span class=\"nt\">&lt;\/AssemblyAttribute&gt;<\/span>\n<span class=\"nt\">&lt;\/ItemGroup&gt;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>We could, optionally, set default values for MS Build properties in the same file, like so:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight xml\"><code><span class=\"nt\">&lt;PropertyGroup&gt;<\/span>\n  <span class=\"nt\">&lt;BaseUrl&gt;<\/span>https:\/\/example.org<span class=\"nt\">&lt;\/BaseUrl&gt;<\/span>\n  <span class=\"nt\">&lt;BuildDate&gt;<\/span>$([System.DateTime]::UtcNow.ToString(\"dd MMM, yyyy\"))<span class=\"nt\">&lt;\/BuildDate&gt;<\/span>\n<span class=\"nt\">&lt;\/PropertyGroup&gt;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Next, we access the <code>ApiConfigurationAttribute<\/code> from <code>Main()<\/code> to configure it with DI, so that it's accessible to the rest of the application in the usual way:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight csharp\"><code><span class=\"k\">public<\/span> <span class=\"k\">static<\/span> <span class=\"k\">async<\/span> <span class=\"n\">Task<\/span> <span class=\"nf\">Main<\/span><span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">[]<\/span> <span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"kt\">var<\/span> <span class=\"n\">builder<\/span> <span class=\"p\">=<\/span> <span class=\"n\">WebAssemblyHostBuilder<\/span><span class=\"p\">.<\/span><span class=\"nf\">CreateDefault<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">);<\/span>\n    <span class=\"n\">builder<\/span><span class=\"p\">.<\/span><span class=\"n\">RootComponents<\/span><span class=\"p\">.<\/span><span class=\"n\">Add<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">App<\/span><span class=\"p\">&gt;(<\/span><span class=\"s\">\"app\"<\/span><span class=\"p\">);<\/span>\n\n    <span class=\"c1\">\/\/ Get an instance of the attribute applied to the assembly<\/span>\n    <span class=\"kt\">var<\/span> <span class=\"n\">apiConfig<\/span> <span class=\"p\">=<\/span> <span class=\"n\">Assembly<\/span><span class=\"p\">.<\/span><span class=\"nf\">GetAssembly<\/span><span class=\"p\">(<\/span><span class=\"k\">typeof<\/span><span class=\"p\">(<\/span><span class=\"n\">Program<\/span><span class=\"p\">)).<\/span><span class=\"n\">GetCustomAttribute<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">BuildConfigurationAttribute<\/span><span class=\"p\">&gt;();<\/span>\n\n    <span class=\"c1\">\/\/ Register the configuration with DI<\/span>\n    <span class=\"kt\">var<\/span> <span class=\"n\">baseUrl<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"nf\">Uri<\/span><span class=\"p\">(<\/span><span class=\"n\">apiConfig<\/span><span class=\"p\">.<\/span><span class=\"n\">BaseUrl<\/span> <span class=\"p\">??<\/span> <span class=\"n\">builder<\/span><span class=\"p\">.<\/span><span class=\"n\">HostEnvironment<\/span><span class=\"p\">.<\/span><span class=\"n\">BaseAddress<\/span><span class=\"p\">);<\/span>\n    <span class=\"n\">builder<\/span><span class=\"p\">.<\/span><span class=\"n\">Services<\/span><span class=\"p\">.<\/span><span class=\"n\">Configure<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">AppOptions<\/span><span class=\"p\">&gt;(<\/span><span class=\"n\">o<\/span> <span class=\"p\">=&gt;<\/span>\n    <span class=\"p\">{<\/span>\n        <span class=\"n\">o<\/span><span class=\"p\">.<\/span><span class=\"n\">BaseUrl<\/span> <span class=\"p\">=<\/span> <span class=\"n\">baseUrl<\/span><span class=\"p\">;<\/span>\n        <span class=\"n\">o<\/span><span class=\"p\">.<\/span><span class=\"n\">BuildDate<\/span> <span class=\"p\">=<\/span> <span class=\"n\">apiConfig<\/span><span class=\"p\">.<\/span><span class=\"n\">BuildDate<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">});<\/span>\n\n    <span class=\"c1\">\/\/ Set the BaseUrl on the HttpClient<\/span>\n    <span class=\"n\">builder<\/span><span class=\"p\">.<\/span><span class=\"n\">Services<\/span><span class=\"p\">.<\/span><span class=\"nf\">AddTransient<\/span><span class=\"p\">(<\/span><span class=\"n\">sp<\/span> <span class=\"p\">=&gt;<\/span> <span class=\"k\">new<\/span> <span class=\"n\">HttpClient<\/span> <span class=\"p\">{<\/span> <span class=\"n\">BaseAddress<\/span> <span class=\"p\">=<\/span> <span class=\"n\">baseUrl<\/span> <span class=\"p\">});<\/span>\n\n    <span class=\"k\">await<\/span> <span class=\"n\">builder<\/span><span class=\"p\">.<\/span><span class=\"nf\">Build<\/span><span class=\"p\">().<\/span><span class=\"nf\">RunAsync<\/span><span class=\"p\">();<\/span>\n<span class=\"p\">}<\/span>\n\n<span class=\"c1\">\/\/ AppOptions is defined as<\/span>\n<span class=\"k\">internal<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">AppOptions<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"k\">public<\/span> <span class=\"n\">Uri<\/span> <span class=\"n\">BaseUrl<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"k\">set<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n    <span class=\"k\">public<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">BuildDate<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"k\">set<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>And now we can use it as usual:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight html\"><code>@page \"\/\"\n@inject IOptions<span class=\"nt\">&lt;AppOptions&gt;<\/span> options\n\n<span class=\"nt\">&lt;pre&gt;<\/span>\n    <span class=\"nt\">&lt;strong&gt;<\/span>Base URL:<span class=\"nt\">&lt;\/strong&gt;<\/span> @options.Value.BaseUrl\n    <span class=\"nt\">&lt;strong&gt;<\/span>Last Build:<span class=\"nt\">&lt;\/strong&gt;<\/span> @options.Value.BuildDate\n<span class=\"nt\">&lt;\/pre&gt;<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>That's it. <code>dotnet run<\/code> or running it within Visual Studio will use the dev-environment-friendly default values:<\/p>\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--XGLD-pZi--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/galdin.dev\/content\/images\/2020\/06\/1.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--XGLD-pZi--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/galdin.dev\/content\/images\/2020\/06\/1.png\" alt=\"Screenshot with defaults\" width=\"502\" height=\"195\"><\/a><\/p>\n\n<p>Now all you need to do to set (or override) the MS Build properties (<code>BaseUrl<\/code> in this case) in the other environments is to use the <code>-p:<\/code> or <code>\/p:<\/code> switch:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>dotnet build <span class=\"nt\">-p<\/span>:BaseUrl<span class=\"o\">=<\/span><span class=\"s2\">\"https:\/\/prod.example.com\"<\/span>\ndotnet run <span class=\"nt\">--no-build<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><a href=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--rLHyXf9y--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/galdin.dev\/content\/images\/2020\/06\/2.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/res.cloudinary.com\/practicaldev\/image\/fetch\/s--rLHyXf9y--\/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800\/https:\/\/galdin.dev\/content\/images\/2020\/06\/2.png\" alt=\"Screenshot with overriden values\" width=\"502\" height=\"217\"><\/a><\/p>\n\n<p>We now have a nice mechanism to use different API Base URLs for different environments, and have environment specific build-time configuration without the need to make a HTTP request.<\/p>\n\n\n\n\n<p>I think the decision of making a HTTP request to the <code>appsettings.json<\/code> file was the right one. Because to me a \"configurable\" app is one that reads configuration at runtime. Build time configuration is like hardcoding the strings \u2014 well, different strings \u2014 for each environment in our case. So if I were to use docker, I'd now need to maintain an image for each environment if I choose to use \"build time configuration\".<\/p>\n\n","category":["blazor","dotnet"]},{"title":"How to post json with comments?","pubDate":"Mon, 20 Jan 2020 18:20:43 +0000","link":"https:\/\/dev.to\/galdin\/how-to-post-json-with-comments-3pfc","guid":"https:\/\/dev.to\/galdin\/how-to-post-json-with-comments-3pfc","description":"<p>Using a <code>json<\/code> codeblock expects strictly valid JSON:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight json\"><code><span class=\"p\">{<\/span><span class=\"w\">\n  <\/span><span class=\"nl\">\"Email\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"p\">{<\/span><span class=\"w\"> <\/span><span class=\"err\">\/\/<\/span><span class=\"w\"> <\/span><span class=\"err\">&lt;--<\/span><span class=\"w\"> <\/span><span class=\"err\">settings<\/span><span class=\"w\"> <\/span><span class=\"err\">grouped<\/span><span class=\"w\"> <\/span><span class=\"err\">under<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"Email\"<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"ClientKey\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"xxx\"<\/span><span class=\"p\">,<\/span><span class=\"w\">\n    <\/span><span class=\"nl\">\"ClientSecret\"<\/span><span class=\"p\">:<\/span><span class=\"w\"> <\/span><span class=\"s2\">\"xxx\"<\/span><span class=\"w\">\n  <\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><span class=\"p\">}<\/span><span class=\"w\">\n<\/span><\/code><\/pre>\n\n<\/div>\n\n\n\n<p>I tried <code>jsonc<\/code> and <code>json5<\/code>, both don't seem to be supported. Anyway to get dev.to to play nice with commented json without marking it as <code>javascript<\/code>?<\/p>\n\n","category":"meta"},{"title":"You don't need IConfiguration outside Startup","pubDate":"Wed, 15 Jan 2020 17:53:00 +0000","link":"https:\/\/dev.to\/galdin\/you-don-t-need-iconfiguration-outside-startup-3p3c","guid":"https:\/\/dev.to\/galdin\/you-don-t-need-iconfiguration-outside-startup-3p3c","description":"<p>I'm writing this for those new to ASP.NET Core, based on what I see on StackOverflow. Most of what I've written here is already in the Docs, so check the links at the end of the post for detailed info.<\/p>\n\n<h2>\n  \n  \n  The ASP.NET Core Web Host\n<\/h2>\n\n<p>Think of the web host as an instance of an application server that processes incoming web requests. We create one (usually in <code>Program.cs<\/code>) as follows:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight csharp\"><code><span class=\"k\">public<\/span> <span class=\"k\">static<\/span> <span class=\"k\">void<\/span> <span class=\"nf\">Main<\/span><span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">[]<\/span> <span class=\"n\">args<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span> \n    <span class=\"nf\">CreateHostBuilder<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">).<\/span><span class=\"nf\">Build<\/span><span class=\"p\">().<\/span><span class=\"nf\">Run<\/span><span class=\"p\">();<\/span>\n\n<span class=\"k\">public<\/span> <span class=\"k\">static<\/span> <span class=\"n\">IHostBuilder<\/span> <span class=\"nf\">CreateHostBuilder<\/span><span class=\"p\">(<\/span><span class=\"kt\">string<\/span><span class=\"p\">[]<\/span> <span class=\"n\">args<\/span><span class=\"p\">)<\/span> <span class=\"p\">=&gt;<\/span>\n    <span class=\"n\">Host<\/span><span class=\"p\">.<\/span><span class=\"nf\">CreateDefaultBuilder<\/span><span class=\"p\">(<\/span><span class=\"n\">args<\/span><span class=\"p\">)<\/span>\n        <span class=\"p\">.<\/span><span class=\"nf\">ConfigureWebHostDefaults<\/span><span class=\"p\">(<\/span><span class=\"n\">webBuilder<\/span> <span class=\"p\">=&gt;<\/span>\n            <span class=\"n\">webBuilder<\/span><span class=\"p\">.<\/span><span class=\"n\">UseStartup<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">Startup<\/span><span class=\"p\">&gt;()<\/span>\n        <span class=\"p\">);<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>The <code>CreateDefaultBuilder()<\/code> sets up the app's configuration. <a href=\"https:\/\/github.com\/aspnet\/AspNetCore\/blob\/v3.0.0\/src\/DefaultBuilder\/src\/WebHost.cs#L168-L190\">Source (v3.0.0)<\/a>. The app's configuration is represented by the <code>IConfiguration<\/code> interface. (You can also manually create your own <code>WebHostBuilder<\/code> instance if the defaults don't work for you, in which case you're responsible for setting up the app configuration.)<\/p>\n\n<p>When the <code>WebHost<\/code> is built using <code>Build()<\/code>, your startup class's <code>ConfigureServices()<\/code> is called. See <a href=\"https:\/\/github.com\/aspnet\/AspNetCore\/blob\/v3.0.0\/src\/Hosting\/Hosting\/src\/WebHostBuilder.cs#L175\">WebHostBuilder.cs L187<\/a>, <a href=\"https:\/\/github.com\/aspnet\/AspNetCore\/blob\/v3.0.0\/src\/Hosting\/Hosting\/src\/Internal\/WebHost.cs#L118\">WebHost.cs L110<\/a> and <a href=\"https:\/\/github.com\/aspnet\/AspNetCore\/blob\/v3.0.0\/src\/DefaultBuilder\/src\/WebHost.cs#L168-L190\">WebHost.cs L180<\/a>.<\/p>\n\n<h2>\n  \n  \n  Using IConfiguration in Startup\n<\/h2>\n\n<p>You can get an instance of <code>IConfiguration<\/code> for use in your Startup class by constructor injection:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight csharp\"><code><span class=\"k\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">Startup<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"k\">private<\/span> <span class=\"n\">IConfiguration<\/span> <span class=\"n\">Configuration<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n    <span class=\"k\">public<\/span> <span class=\"nf\">Startup<\/span><span class=\"p\">(<\/span><span class=\"n\">IConfiguration<\/span> <span class=\"n\">configuration<\/span><span class=\"p\">)<\/span> <span class=\"c1\">\/\/ &lt;-- the framework injects<\/span>\n                                                 <span class=\"c1\">\/\/ a valid instance<\/span>\n    <span class=\"p\">{<\/span>\n        <span class=\"n\">Configuration<\/span> <span class=\"p\">=<\/span> <span class=\"n\">configuration<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ &lt;-- and we save that<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ rest of the class ...<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre><\/div>\n\n\n\n<p>The whole point of <code>IConfiguration<\/code> is to provide a way through which the .NET Core app can read configuration from different sources: configuration files, environment variables, command line arguments, etc.<\/p>\n\n<h2>\n  \n  \n  Using IConfiguration outside Startup\n<\/h2>\n\n<p>You can also inject an <code>IConfiguration<\/code> instance almost anywhere:<br>\n<\/p>\n\n<div class=\"highlight\"><pre class=\"highlight csharp\"><code><span class=\"k\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">EmailSender<\/span> \n<span class=\"p\">{<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">ClientKey<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">ClientSecret<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n\n    <span class=\"k\">public<\/span> <span class=\"nf\">EmailSender<\/span><span class=\"p\">(<\/span><span class=\"n\">IConfiguration<\/span> <span class=\"n\">configuration<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">{<\/span>\n        <span class=\"n\">ClientKey<\/span> <span class=\"p\">=<\/span> <span class=\"n\">configuration<\/span><span class=\"p\">[<\/span><span class=\"s\">\"ClientKey\"<\/span><span class=\"p\">];<\/span>\n        <span class=\"n\">ClientSecret<\/span> <span class=\"p\">=<\/span> <span class=\"n\">configuration<\/span><span class=\"p\">[<\/span><span class=\"s\">\"ClientSecret\"<\/span><span class=\"p\">];<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ rest of the class follows...<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre><\/div>\n\n\n\n<p>Let's just stop for a while and imagine an example: we're in a controller's action and need to send an email. We get an <code>EmailSender<\/code> instance from DI, and use it to send the email. The <code>EmailSender<\/code> gets email credentials from the <code>IConfiguration<\/code> abstraction. It doesn't need to know where it's coming from: appsettings.json, command-line arguments, environment variables, azure vault storage\u2013 could be coming from anywhere and <code>EmailSender<\/code> doesn't need to care about it.<\/p>\n\n<p>There are still areas left wanting though:<\/p>\n\n<ol>\n<li>The configuration is not strongly typed: non-string values will need to be manually parsed.<\/li>\n<li>The email sender above requires <code>ClientKey<\/code> and <code>ClientSecret<\/code> to be defined using the exact configuration keys. So <code>EmailSender<\/code> is sort-of coupled with the way the actual configuration is set.<\/li>\n<\/ol>\n\n<p>The solution to these is the Options Pattern.<\/p>\n\n<h2>\n  \n  \n  Options Pattern\n<\/h2>\n\n<p>Think of this as an additional layer of abstraction. In the <code>EmailService<\/code> example, we'd replace <code>IConfiguration<\/code> with <code>IOptions<\/code>. <code>IConfiguration<\/code> knew how to get the right configuration from the right places for you, <code>IOptions<\/code> knows how to get the relevant configuration from <code>IConfiguration<\/code> for you.<\/p>\n\n<p>Here's a simplified way to use it:<\/p>\n\n<ol>\n<li>\n<p>Group related settings together in your <code>appsettings.json<\/code>:<br>\n<\/p>\n<pre class=\"highlight javascript\"><code><span class=\"p\">{<\/span>\n  <span class=\"dl\">\"<\/span><span class=\"s2\">Email<\/span><span class=\"dl\">\"<\/span><span class=\"p\">:<\/span> <span class=\"p\">{<\/span> <span class=\"c1\">\/\/ &lt;-- settings grouped under \"Email\"<\/span>\n    <span class=\"dl\">\"<\/span><span class=\"s2\">ClientKey<\/span><span class=\"dl\">\"<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">xxx<\/span><span class=\"dl\">\"<\/span><span class=\"p\">,<\/span>\n    <span class=\"dl\">\"<\/span><span class=\"s2\">ClientSecret<\/span><span class=\"dl\">\"<\/span><span class=\"p\">:<\/span> <span class=\"dl\">\"<\/span><span class=\"s2\">xxx<\/span><span class=\"dl\">\"<\/span>\n  <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/li>\n<li>\n<p>Create a class to hold those settings:<br>\n<\/p>\n<pre class=\"highlight csharp\"><code><span class=\"k\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">EmailOptions<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"k\">public<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">ClientKey<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"k\">set<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n    <span class=\"k\">public<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">ClientSecret<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"k\">set<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/li>\n<li>\n<p>Register the Options with the DI container:<br>\n<\/p>\n<pre class=\"highlight csharp\"><code><span class=\"n\">services<\/span><span class=\"p\">.<\/span><span class=\"n\">Configure<\/span><span class=\"p\">&lt;<\/span><span class=\"nf\">EmailOptions<\/span><span class=\"p\">(<\/span><span class=\"n\">Configuration<\/span><span class=\"p\">.<\/span><span class=\"nf\">GetSection<\/span><span class=\"p\">(<\/span><span class=\"s\">\"EmailOptions\"<\/span><span class=\"p\">));<\/span>\n<\/code><\/pre>\n\n<\/li>\n<li>\n<p>Inject it into the service that needs it:<br>\n<\/p>\n<pre class=\"highlight csharp\"><code><span class=\"k\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">EmailSender<\/span> \n<span class=\"p\">{<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">ClientKey<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n    <span class=\"k\">private<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">ClientSecret<\/span> <span class=\"p\">{<\/span> <span class=\"k\">get<\/span><span class=\"p\">;<\/span> <span class=\"p\">}<\/span>\n\n    <span class=\"k\">public<\/span> <span class=\"nf\">EmailSender<\/span><span class=\"p\">(<\/span><span class=\"n\">IOptions<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">EmailOptions<\/span><span class=\"p\">&gt;<\/span> <span class=\"n\">options<\/span><span class=\"p\">)<\/span> <span class=\"c1\">\/\/ &lt;-- here<\/span>\n    <span class=\"p\">{<\/span>\n        <span class=\"n\">ClientKey<\/span> <span class=\"p\">=<\/span> <span class=\"n\">options<\/span><span class=\"p\">.<\/span><span class=\"n\">Value<\/span><span class=\"p\">.<\/span><span class=\"n\">ClientKey<\/span><span class=\"p\">;<\/span>\n        <span class=\"n\">ClientSecret<\/span> <span class=\"p\">=<\/span> <span class=\"n\">options<\/span><span class=\"p\">.<\/span><span class=\"n\">Value<\/span><span class=\"p\">.<\/span><span class=\"n\">ClientSecret<\/span><span class=\"p\">;<\/span>\n    <span class=\"p\">}<\/span>\n\n    <span class=\"c1\">\/\/ rest of the class follows...<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/li>\n<\/ol>\n\n<p>Follow this, and you won't see the need to inject <code>IConfiguration<\/code> anywhere outside <code>Startup<\/code>.<\/p>\n\n\n\n\n<h4>\n  \n  \n  Microsoft Docs links:\n<\/h4>\n\n<ul>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/configuration\/?view=aspnetcore-3.1\">Configuration in ASP.NET Core<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/configuration\/options?view=aspnetcore-3.1\">Options pattern in ASP.NET Core<\/a><\/li>\n<li><a href=\"https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/host\/web-host?view=aspnetcore-3.1\">ASP.NET Core Web Host<\/a><\/li>\n<\/ul>\n\n","category":["net","aspnetcore"]},{"title":"C# scripts using dotnet-script","pubDate":"Fri, 05 Apr 2019 00:30:00 +0000","link":"https:\/\/dev.to\/galdin\/c-scripts-using-dotnet-script-3b1k","guid":"https:\/\/dev.to\/galdin\/c-scripts-using-dotnet-script-3b1k","description":"<p>You know how the python folks can just write some code in a <code>.py<\/code> file and run it with <code>python3 filename.py<\/code>, without going through the \"new project\" and the \"<code>public static void main<\/code>\" ceremony that C# users have to? C# can write scripts too \u2013 something I learnt just like a year back.<\/p>\n\n<p>Roslyn made C# scripts possible. There's a Jan 2016 MSDN blogpost by <a href=\"https:\/\/twitter.com\/@markmichaelis\" rel=\"noopener noreferrer\">Mark Michaelis<\/a> titled <a href=\"https:\/\/msdn.microsoft.com\/en-us\/magazine\/mt614271.aspx\" rel=\"noopener noreferrer\">C# Scripting<\/a> if you're interested.<\/p>\n\n<p>The tool that I've been really fascinated by is <a href=\"https:\/\/github.com\/filipw\/dotnet-script\" rel=\"noopener noreferrer\">dotnet-script<\/a>, which is a cross-platform .NET Core global tool with full intellisense support on VS Code via omnisharp and covers most use-cases for your experimenting needs.<\/p>\n\n<h2>\n  \n  \n  Prerequisites\n<\/h2>\n\n<ol>\n<li>.NET Core SDK 2.1+<\/li>\n<li>VS Code<\/li>\n<li>Official C# Extension for VS Code<\/li>\n<\/ol>\n\n<h2>\n  \n  \n  Installation\n<\/h2>\n\n<p>First make sure you have the latest version of .NET Core SDK installed from <a href=\"https:\/\/dot.net\" rel=\"noopener noreferrer\">dot.net<\/a>. The minimum requirement is .NET Core 2.1.<\/p>\n\n<p>The easiest way to install <code>dotnet-script<\/code> is installing it as a global tool:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>dotnet tool <span class=\"nb\">install<\/span> <span class=\"nt\">--global<\/span> dotnet-script\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>You should now be able to run <code>dotnet script --version<\/code> and it should print the version of the <code>dotnet-script<\/code> tool.<\/p>\n\n<h2>\n  \n  \n  Hello world\n<\/h2>\n\n<ol>\n<li>Create a new directory to store all your scripts.<\/li>\n<li>Init a new script.<\/li>\n<li>Run.\n<\/li>\n<\/ol>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"nb\">mkdir <\/span>console\n<span class=\"nb\">cd <\/span>console\ndotnet script init hello\ndotnet script hello.csx\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ul>\n<li>The init command creates a <code>.csx<\/code> (C# script) file along with an <code>omnisharp.json<\/code> file for intellisense and a VS Code <code>launch.json<\/code> file for debug support. <\/li>\n<li>The csx script is run using <code>dotnet script filename<\/code>.<\/li>\n<\/ul>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgldraphael.com%2Fcontent%2Fimages%2F2019%2F04%2Fdotnet-script-screenshot.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgldraphael.com%2Fcontent%2Fimages%2F2019%2F04%2Fdotnet-script-screenshot.png\"><\/a><\/p>\n\n<p>The generated <code>hello.csx<\/code> file has the following contents:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight csharp\"><code><span class=\"err\">#<\/span><span class=\"p\">!\/<\/span><span class=\"n\">usr<\/span><span class=\"p\">\/<\/span><span class=\"n\">bin<\/span><span class=\"p\">\/<\/span><span class=\"n\">env<\/span> <span class=\"n\">dotnet<\/span><span class=\"p\">-<\/span><span class=\"n\">script<\/span>\n\n<span class=\"n\">Console<\/span><span class=\"p\">.<\/span><span class=\"nf\">WriteLine<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Hello world!\"<\/span><span class=\"p\">);<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The first line is a shebang that *nix users must be familiar with. It means we can run it as <code>.\/hello.csx<\/code> and it'll just work! (Also works on windows, but you'll need to associate <code>.csx<\/code> files with dotnet-script first using <code>dotnet script register<\/code>.)<\/p>\n\n<h2>\n  \n  \n  Another quick example\n<\/h2>\n\n<p>A typical use-case for console applications is to experiment with new libraries, and <code>dotnet-script<\/code> is the perfect tool for the job. Let's say I'm learning about the <a href=\"https:\/\/github.com\/dotnet-state-machine\/stateless\" rel=\"noopener noreferrer\">stateless<\/a> library. Here's how I'd go about experimenting:<\/p>\n\n<ol>\n<li>Create a new script using <code>dotnet script init stateless<\/code>.<\/li>\n<li>Open the folder in VS Code using <code>code .<\/code>.<\/li>\n<li>Import the nuget package using the roslyn <code>#r<\/code> directive.<\/li>\n<li>Go to their GitHub page and copy some sample code over.<\/li>\n<li>Add using statements if needed using <code>Cmd+.<\/code> (or <code>Ctrl+.<\/code>).<\/li>\n<li>Debug within VS code with F5.<\/li>\n<\/ol>\n\n<p>Here's my <code>stateless.csx<\/code> file:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight csharp\"><code><span class=\"err\">#<\/span><span class=\"p\">!\/<\/span><span class=\"n\">usr<\/span><span class=\"p\">\/<\/span><span class=\"n\">bin<\/span><span class=\"p\">\/<\/span><span class=\"n\">env<\/span> <span class=\"n\">dotnet<\/span><span class=\"p\">-<\/span><span class=\"n\">script<\/span>\n<span class=\"err\">#<\/span><span class=\"n\">r<\/span> <span class=\"s\">\"nuget: Stateless, 4.2.1\"<\/span>\n\n<span class=\"c1\">\/\/ Copied from: https:\/\/github.com\/dotnet-state-machine\/stateless\/blob\/dev\/example\/OnOffExample\/Program.cs<\/span>\n<span class=\"k\">using<\/span> <span class=\"nn\">Stateless<\/span><span class=\"p\">;<\/span>\n\n<span class=\"k\">const<\/span> <span class=\"kt\">string<\/span> <span class=\"k\">on<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"On\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">const<\/span> <span class=\"kt\">string<\/span> <span class=\"n\">off<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"Off\"<\/span><span class=\"p\">;<\/span>\n<span class=\"k\">const<\/span> <span class=\"kt\">char<\/span> <span class=\"n\">space<\/span> <span class=\"p\">=<\/span> <span class=\"sc\">' '<\/span><span class=\"p\">;<\/span>\n\n<span class=\"c1\">\/\/ Instantiate a new state machine in the 'off' state<\/span>\n<span class=\"kt\">var<\/span> <span class=\"n\">onOffSwitch<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"n\">StateMachine<\/span><span class=\"p\">&lt;<\/span><span class=\"kt\">string<\/span><span class=\"p\">,<\/span> <span class=\"kt\">char<\/span><span class=\"p\">&gt;(<\/span><span class=\"n\">off<\/span><span class=\"p\">);<\/span>\n\n<span class=\"c1\">\/\/ Configure state machine with the Configure method, supplying the state to be configured as a parameter<\/span>\n<span class=\"n\">onOffSwitch<\/span><span class=\"p\">.<\/span><span class=\"nf\">Configure<\/span><span class=\"p\">(<\/span><span class=\"n\">off<\/span><span class=\"p\">).<\/span><span class=\"nf\">Permit<\/span><span class=\"p\">(<\/span><span class=\"n\">space<\/span><span class=\"p\">,<\/span> <span class=\"k\">on<\/span><span class=\"p\">);<\/span>\n<span class=\"n\">onOffSwitch<\/span><span class=\"p\">.<\/span><span class=\"nf\">Configure<\/span><span class=\"p\">(<\/span><span class=\"k\">on<\/span><span class=\"p\">).<\/span><span class=\"nf\">Permit<\/span><span class=\"p\">(<\/span><span class=\"n\">space<\/span><span class=\"p\">,<\/span> <span class=\"n\">off<\/span><span class=\"p\">);<\/span>\n\n<span class=\"n\">Console<\/span><span class=\"p\">.<\/span><span class=\"nf\">WriteLine<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Press &lt;space&gt; to toggle the switch. Any other key will exit the program.\"<\/span><span class=\"p\">);<\/span>\n\n<span class=\"k\">while<\/span> <span class=\"p\">(<\/span><span class=\"k\">true<\/span><span class=\"p\">)<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"n\">Console<\/span><span class=\"p\">.<\/span><span class=\"nf\">WriteLine<\/span><span class=\"p\">(<\/span><span class=\"s\">\"Switch is in state: \"<\/span> <span class=\"p\">+<\/span> <span class=\"n\">onOffSwitch<\/span><span class=\"p\">.<\/span><span class=\"n\">State<\/span><span class=\"p\">);<\/span>\n    <span class=\"kt\">var<\/span> <span class=\"n\">pressed<\/span> <span class=\"p\">=<\/span> <span class=\"n\">Console<\/span><span class=\"p\">.<\/span><span class=\"nf\">ReadKey<\/span><span class=\"p\">(<\/span><span class=\"k\">true<\/span><span class=\"p\">).<\/span><span class=\"n\">KeyChar<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"c1\">\/\/ Check if user wants to exit<\/span>\n    <span class=\"k\">if<\/span> <span class=\"p\">(<\/span><span class=\"n\">pressed<\/span> <span class=\"p\">!=<\/span> <span class=\"n\">space<\/span><span class=\"p\">)<\/span> <span class=\"k\">break<\/span><span class=\"p\">;<\/span>\n\n    <span class=\"c1\">\/\/ Use the Fire method with the trigger as payload to supply the state machine with an event.<\/span>\n    <span class=\"c1\">\/\/ The state machine will react according to its configuration.<\/span>\n    <span class=\"n\">onOffSwitch<\/span><span class=\"p\">.<\/span><span class=\"nf\">Fire<\/span><span class=\"p\">(<\/span><span class=\"n\">pressed<\/span><span class=\"p\">);<\/span>\n<span class=\"p\">}<\/span>\n\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>Notes for those new to developing using VS Code:<\/p>\n\n<ul>\n<li>If intellisense doesn't work after 3, or no code-actions are available after 5, you might need to restart omnisharp by: <code>Cmd+Shift+P<\/code> --&gt; <code>Omnisharp: Restart Omnisharp<\/code>. See <a href=\"https:\/\/github.com\/filipw\/dotnet-script\/issues\/424\" rel=\"noopener noreferrer\">filipw\/dotnet-script#424<\/a> for more information.<\/li>\n<li>While running the application you'll most likely see this error: \"Cannot read keys when either application does not have a console or when console input has been redirected.\" because VS Code uses the Debug Console by default which doesn't support console input. You can change that by configuring it to use the integrated terminal instead, by adding a <code>\"console\": \"integratedTerminal\"<\/code> property to <code>.vscode\/launch.json<\/code>. More information <a href=\"https:\/\/github.com\/OmniSharp\/omnisharp-vscode\/blob\/master\/debugger-launchjson.md#console-terminal-window\" rel=\"noopener noreferrer\">here<\/a>.<\/li>\n<\/ul>\n\n<p>That's it. If you ask me I think it's pretty slick.<\/p>\n\n\n\n\n<p>What I love about <code>dotnet-script<\/code> is:<\/p>\n\n<ol>\n<li>All <em>relevant<\/em> code, including required nuget packages, can exist in a single file.<\/li>\n<li>Full and reliable intellisense.<\/li>\n<li>Debugger support.<\/li>\n<li>No <code>public static void main<\/code> or <code>.csproj<\/code> files.<\/li>\n<\/ol>\n\n","category":["dotnet","csharp"]},{"title":"C# REPL using mono or dotnet-script","pubDate":"Sat, 13 Oct 2018 11:57:20 +0000","link":"https:\/\/dev.to\/galdin\/c-repl-using-mono-or-dotnet-script-nfe","guid":"https:\/\/dev.to\/galdin\/c-repl-using-mono-or-dotnet-script-nfe","description":"<p>Quite often, all I want to do is check if a single line of code does what I think it does. I've always been a huge fan of <a href=\"https:\/\/www.linqpad.net\/\" rel=\"noopener noreferrer\">LinqPad<\/a> for a use-case like this. But it's Windows-only and that's a bummer since I do most of my development on a Macbook.<\/p>\n\n<p>I began googling around a few days back and was pleasantly surprised to find two great options:<\/p>\n\n<h2>\n  \n  \n  The mono-tools csharp REPL\n<\/h2>\n\n<ol>\n<li>Install mono.<\/li>\n<li>Type <code>csharp<\/code> in your terminal to start a REPL.<\/li>\n<\/ol>\n\n<p>Here's what it looks like:<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0uwjox6us76lc40hf1g.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fx0uwjox6us76lc40hf1g.png\" width=\"800\" height=\"523\"><\/a><\/p>\n\n<p>The REPL is documented <a href=\"https:\/\/www.mono-project.com\/docs\/tools+libraries\/tools\/repl\/\" rel=\"noopener noreferrer\">here<\/a>.<\/p>\n\n<h2>\n  \n  \n  The .NET Core dotnet-script global tool\n<\/h2>\n\n<ol>\n<li>Install .NET Core.<\/li>\n<li>Install the global tool using <code>dotnet tool install -g dotnet-script<\/code>.<\/li>\n<li>Type <code>dotnet script<\/code> in your terminal.<\/li>\n<\/ol>\n\n<p>Here's what it looks like:<\/p>\n\n<p><a href=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0anxw2fbo5cgayi9c07c.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media2.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0anxw2fbo5cgayi9c07c.png\" width=\"800\" height=\"350\"><\/a><\/p>\n\n<p>This tool covers a lot of use-cases beyond a basic REPL and they're all documented in its <a href=\"https:\/\/github.com\/filipw\/dotnet-script\" rel=\"noopener noreferrer\">GitHub repo<\/a>.<\/p>\n\n<p>For me though, a simple REPL with intellisense is all I want!<\/p>\n\n","category":["csharp","dotnet"]},{"title":"Generating PDFs from an ASP.NET Core app using a Node library","pubDate":"Wed, 25 Apr 2018 07:50:13 +0000","link":"https:\/\/dev.to\/galdin\/generating-pdfs-from-an-aspnet-core-app-using-a-node-library-3bp8","guid":"https:\/\/dev.to\/galdin\/generating-pdfs-from-an-aspnet-core-app-using-a-node-library-3bp8","description":"<p>Quick blogpost on converting HTML to PDF from an ASP.NET Core application using a Node library by <a href=\"https:\/\/github.com\/marcbachmann\" rel=\"noopener noreferrer\">Marc Bachmann<\/a> called <a href=\"https:\/\/github.com\/marcbachmann\/node-html-pdf\" rel=\"noopener noreferrer\">html-pdf<\/a>. I've also setup a docker-based <a href=\"https:\/\/github.com\/gldraphael\/PdfGenerationNodeServicesSample\" rel=\"noopener noreferrer\">sample github repository<\/a> if you just want to see the final thing.<\/p>\n\n<h2>\n  \n  \n  Create a new project\n<\/h2>\n\n<p>Let's quickly create a new ASP.NET Core project using the commandline tools:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code><span class=\"c\"># create a new project<\/span>\ndotnet new webapi <span class=\"nt\">--name<\/span> PdfSample\n<span class=\"c\"># run the project<\/span>\n<span class=\"nb\">cd <\/span>PdfSample\ndotnet run\n<span class=\"c\"># browse to localhost:5000<\/span>\n<span class=\"c\"># you should see a 404 error<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Write the node script\n<\/h2>\n\n<p>Install <a href=\"https:\/\/github.com\/marcbachmann\/node-html-pdf\" rel=\"noopener noreferrer\">html-pdf<\/a>:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>npm <span class=\"nb\">install <\/span>html-pdf <span class=\"nt\">--save<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>And add the node script to be invoked by the ASP.NET application in a <code>Node<\/code> folder:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight javascript\"><code><span class=\"c1\">\/\/ File: Node\/createPdf.js<\/span>\n<span class=\"kd\">const<\/span> <span class=\"nx\">pdf<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">require<\/span><span class=\"p\">(<\/span><span class=\"dl\">'<\/span><span class=\"s1\">html-pdf<\/span><span class=\"dl\">'<\/span><span class=\"p\">);<\/span>\n<span class=\"nx\">module<\/span><span class=\"p\">.<\/span><span class=\"nx\">exports<\/span> <span class=\"o\">=<\/span> <span class=\"nf\">function <\/span><span class=\"p\">(<\/span><span class=\"nx\">result<\/span><span class=\"p\">,<\/span> <span class=\"nx\">html<\/span><span class=\"p\">,<\/span> <span class=\"nx\">options<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n    <span class=\"nx\">pdf<\/span><span class=\"p\">.<\/span><span class=\"nf\">create<\/span><span class=\"p\">(<\/span><span class=\"nx\">html<\/span><span class=\"p\">,<\/span> <span class=\"nx\">options<\/span><span class=\"p\">).<\/span><span class=\"nf\">toStream<\/span><span class=\"p\">(<\/span><span class=\"kd\">function<\/span><span class=\"p\">(<\/span><span class=\"nx\">err<\/span><span class=\"p\">,<\/span> <span class=\"nx\">stream<\/span><span class=\"p\">)<\/span> <span class=\"p\">{<\/span>\n        <span class=\"nx\">stream<\/span><span class=\"p\">.<\/span><span class=\"nf\">pipe<\/span><span class=\"p\">(<\/span><span class=\"nx\">result<\/span><span class=\"p\">.<\/span><span class=\"nx\">stream<\/span><span class=\"p\">);<\/span>\n    <span class=\"p\">});<\/span>\n<span class=\"p\">};<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The script calls <code>create()<\/code> from the <code>html-pdf<\/code> package and pipes its output to the Duplex stream <code>result<\/code> accessible by NodeServices. The arguments <code>html<\/code> and <code>options<\/code> will be passed from the ASP.NET application while invoking the script.<\/p>\n\n<h2>\n  \n  \n  Create an action that invokes the node script\n<\/h2>\n\n<p>Let's create a controller-action for the <code>\/<\/code> route that invokes our node script and generates a sample PDF:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight csharp\"><code><span class=\"c1\">\/\/ File: Controllers\/HomeController.cs<\/span>\n<span class=\"k\">public<\/span> <span class=\"k\">class<\/span> <span class=\"nc\">HomeController<\/span> <span class=\"p\">:<\/span> <span class=\"n\">Controller<\/span>\n<span class=\"p\">{<\/span>\n    <span class=\"p\">[<\/span><span class=\"nf\">HttpGet<\/span><span class=\"p\">(<\/span><span class=\"s\">\"\/\"<\/span><span class=\"p\">)]<\/span> <span class=\"c1\">\/\/ action to invoke for the \"\/\" route<\/span>\n    <span class=\"k\">public<\/span> <span class=\"k\">async<\/span> <span class=\"n\">Task<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">IActionResult<\/span><span class=\"p\">&gt;<\/span> <span class=\"nf\">Index<\/span><span class=\"p\">(<\/span>\n        <span class=\"p\">[<\/span><span class=\"n\">FromServices<\/span><span class=\"p\">]<\/span><span class=\"n\">INodeServices<\/span> <span class=\"n\">nodeServices<\/span><span class=\"p\">)<\/span>\n    <span class=\"p\">{<\/span>\n        <span class=\"kt\">var<\/span> <span class=\"n\">html<\/span> <span class=\"p\">=<\/span> <span class=\"s\">\"&lt;h1&gt;Hey!&lt;\/h1&gt;\"<\/span><span class=\"p\">;<\/span> <span class=\"c1\">\/\/ html to be converted<\/span>\n        <span class=\"kt\">var<\/span> <span class=\"n\">options<\/span> <span class=\"p\">=<\/span> <span class=\"k\">new<\/span> <span class=\"p\">{<\/span> <span class=\"p\">};<\/span> <span class=\"c1\">\/\/ html-pdf options<\/span>\n\n        <span class=\"kt\">var<\/span> <span class=\"n\">stream<\/span> <span class=\"p\">=<\/span> <span class=\"k\">await<\/span> <span class=\"n\">nodeServices<\/span><span class=\"p\">.<\/span><span class=\"n\">InvokeAsync<\/span><span class=\"p\">&lt;<\/span><span class=\"n\">Stream<\/span><span class=\"p\">&gt;(<\/span>\n            <span class=\"s\">\".\/Node\/createPdf.js\"<\/span><span class=\"p\">,<\/span> <span class=\"c1\">\/\/ script to invoke<\/span>\n            <span class=\"n\">html<\/span><span class=\"p\">,<\/span>\n            <span class=\"n\">options<\/span>\n        <span class=\"p\">);<\/span>\n        <span class=\"k\">return<\/span> <span class=\"nf\">File<\/span><span class=\"p\">(<\/span>\n            <span class=\"n\">fileStream<\/span><span class=\"p\">:<\/span> <span class=\"n\">stream<\/span><span class=\"p\">,<\/span> \n            <span class=\"n\">contentType<\/span><span class=\"p\">:<\/span> <span class=\"s\">\"application\/pdf\"<\/span>\n        <span class=\"p\">);<\/span>\n    <span class=\"p\">}<\/span>\n<span class=\"p\">}<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<ul>\n<li>We create an action for the <code>\/<\/code> route using <code>[Route(\"\")]<\/code> &amp; <code>[HttpGet(\"\")]<\/code>.<\/li>\n<li>It obtains an <code>INodeServices<\/code> instance from the DI container using the <code>[FromServices]<\/code> annotation.<\/li>\n<li>We invoke the script using the module name relative to the project root and the arguments to be passed to the script.<\/li>\n<\/ul>\n\n<h2>\n  \n  \n  Register NodeServices with the DI\n<\/h2>\n\n<p>Before we can run it we'll need to register it with the DI.<br><br>\nWe do that using an extensionsion method in the <code>Startup<\/code> class' <code>ConfigureServices()<\/code> method:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight csharp\"><code><span class=\"n\">services<\/span><span class=\"p\">.<\/span><span class=\"nf\">AddNodeServices<\/span><span class=\"p\">();<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<h2>\n  \n  \n  Run the Application\n<\/h2>\n\n<p>Run the app using <code>dotnet run<\/code> and the PDF should be served at <code>localhost:5000<\/code>.<\/p>\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgldraphael.com%2Fblog%2Fcontent%2Fimages%2F2018%2F04%2Foutput-screenshot.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgldraphael.com%2Fblog%2Fcontent%2Fimages%2F2018%2F04%2Foutput-screenshot.png\" alt=\"Output Screenshot\"><\/a><\/p>\n\n<h2>\n  \n  \n  Setup for publishing\n<\/h2>\n\n<p>The <code>createPdf.js<\/code> needs to be part of your publish output. You can achieve this by editing the <code>.csproj<\/code> file and adding a section as follows within the <code>&lt;Project&gt;&lt;\/Project&gt;<\/code> tags:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight xml\"><code><span class=\"nt\">&lt;ItemGroup&gt;<\/span>\n  <span class=\"nt\">&lt;Content<\/span> <span class=\"na\">Include=<\/span><span class=\"s\">\"Node\\createPdf.js\"<\/span><span class=\"nt\">&gt;<\/span>\n    <span class=\"nt\">&lt;CopyToOutputDirectory&gt;<\/span>PreserveNewest<span class=\"nt\">&lt;\/CopyToOutputDirectory&gt;<\/span>\n  <span class=\"nt\">&lt;\/Content&gt;<\/span>\n<span class=\"nt\">&lt;\/ItemGroup&gt;<\/span>\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The app can now be published using:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>dotnet publish <span class=\"nt\">-c<\/span> Release\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The output will be in the <code>.\/bin\/Release\/publish<\/code> directory by default.<br><br>\nNote that the <code>node_modules<\/code> folder is not published. You may either use MSBUILD to copy the folder on build\/publish by editing the <code>.csproj<\/code> file like above, or run <code>npm install html-pdf<\/code> as part of your deploy script.<\/p>\n\n<p>I prefer the deploy script because I'd like to avoid publishing the front end packages from <code>node_modules<\/code>.<\/p>\n<h2>\n  \n  \n  Setting up docker\n<\/h2>\n\n<p>I spent more than 8 hours trying to get the setup to work on Docker, which is why I decided to write this post in the first place.<\/p>\n\n<p>I had two issues while writing the docker file, both relating to PhantomJS. The first error was when trying to install <code>html-pdf<\/code> using npm at build time. <code>html-pdf<\/code> downloads a prebuild binary of PhantomJS which is compressed using bzip2. Here's the error message:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight plaintext\"><code>tar (child): bzip2: Cannot exec: No such file or directory\ntar (child): Error is not recoverable: exiting now\ntar: Child returned status 2\ntar: Error is not recoverable: exiting now\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p>The second error was a runtime error where I wasn't able to get a proper error message -- the application would just crash abruptly.<\/p>\n\n<p>The trick was to install <code>bzip2<\/code> for the <code>html-pdf<\/code> installation to succeed and <code>libfontconfig<\/code> for PhantomJS to work as expected. You may do that on debian based systems using:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>apt <span class=\"nb\">install <\/span>bzip2\napt <span class=\"nb\">install <\/span>libfontconfig\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><a href=\"https:\/\/github.com\/gldraphael\/PdfGenerationNodeServicesSample\/blob\/master\/Dockerfile\" rel=\"noopener noreferrer\">Here's the full Dockerfile<\/a>. Add it to the root of your project and run it using:<br>\n<\/p>\n\n<div class=\"highlight js-code-highlight\">\n<pre class=\"highlight shell\"><code>docker build <span class=\"nt\">-t<\/span> aspnetpdf <span class=\"nb\">.<\/span>\ndocker run <span class=\"nt\">-d<\/span> <span class=\"nt\">-p<\/span> 8080:80 aspnetpdf\n<\/code><\/pre>\n\n<\/div>\n\n\n\n<p><a href=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgldraphael.com%2Fblog%2Fcontent%2Fimages%2F2018%2F04%2Fpdf-screenshot.png\" class=\"article-body-image-wrapper\"><img src=\"https:\/\/media.dev.to\/dynamic\/image\/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto\/https%3A%2F%2Fgldraphael.com%2Fblog%2Fcontent%2Fimages%2F2018%2F04%2Fpdf-screenshot.png\" alt=\"Sample repo screenshot\"><\/a><\/p>\n\n<h2>\n  \n  \n  Conclusion\n<\/h2>\n\n<p>That's it. We've seen how to convert HTML to PDF in an ASP.NET Core application using Marc Bachmann's <code>html-pdf<\/code> with NodeServices. Pretty cool if you ask me!<\/p>\n\n<p>If you've come this far, you should totally check the <a href=\"https:\/\/github.com\/gldraphael\/PdfGenerationNodeServicesSample\" rel=\"noopener noreferrer\">GitHub sample<\/a> and run it. No excuse if you already have docker on your machine \ud83d\ude01<\/p>\n\n\n\n\n<p>If you're considering following this approach in a real project, here are a few pointers to save you time:<\/p>\n\n<ul>\n<li>PhantomJS currently has issues with custom fonts on Windows. The font will need to be installed on the Windows instance for it to work.<\/li>\n<li>PhantomJS is based on WebKit which uses GDI+ under the hoods on Windows. Because of this, we couldn't use it in a traditional Azure Web App. <a href=\"https:\/\/github.com\/projectkudu\/kudu\/wiki\/Azure-Web-App-sandbox\" rel=\"noopener noreferrer\">More information here<\/a>. We ended up switching to Azure Web App for Containers.<\/li>\n<\/ul>\n\n","category":["aspnetcore","node","docker"]}]}}