tag:blogger.com,1999:blog-15288051745144524042024-03-15T12:07:03.036-04:00Allen ConwayExploring all things software engineering and beyond...Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.comBlogger197125tag:blogger.com,1999:blog-1528805174514452404.post-41189531996292851302024-02-06T14:10:00.000-05:002024-02-06T14:10:02.295-05:00How to Fix the GitHub Copilot Chat Error: 'Cannot read properties of undefined (reading 'split')'<span style="font-family: arial;">If you're using GitHub Copilot Chat within Visual Studio code, you may begin to see an error unexpectedly after an IDE update that reads as follows when using Copilot Chat:</span><div><span style="font-family: arial;"><blockquote style="text-align: left;"><span style="color: red; font-size: large;"><i>Cannot read properties of undefined (reading 'split')</i></span></blockquote><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiQNZqYuIPz13U0yyGMrJeyCfZDSL6YJ3HzWDsscuYa2cJ8g3wnmyx2gu248O5v9FjGmHgkdP8V1tRBWId9ayB-iYA2pmZlz_0Let8cGn1sdzPKD8JkBP-fxRZsaLS6AyY1Dn2mzuSg4tf6h7TqtSpNQXFOEKmXdcyeMspkxv2HRT33ipdM_Gekwwbc0GX/s569/Error%20after%20update.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="382" data-original-width="569" height="269" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiQNZqYuIPz13U0yyGMrJeyCfZDSL6YJ3HzWDsscuYa2cJ8g3wnmyx2gu248O5v9FjGmHgkdP8V1tRBWId9ayB-iYA2pmZlz_0Let8cGn1sdzPKD8JkBP-fxRZsaLS6AyY1Dn2mzuSg4tf6h7TqtSpNQXFOEKmXdcyeMspkxv2HRT33ipdM_Gekwwbc0GX/w400-h269/Error%20after%20update.png" width="400" /></a></div><p>This is caused by the Copilot Chat extension requiring a reload which can be seen from the extensions menu:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwXmw3SG7XT0eLcu4kw-Y1DlzEey10-P0FyNmPASc9-wEdKqpE7Mg7gbHrMQcqdv18pp3AJ8Y0q0MSd1HKi53zj0Q65Hx4vhIzFyehaE14LbLIsPuZbWTP5p8v91pph2rogp-Uak9HePb93tN0kPqen4D-v8yqlbznGCM4sPMj2yBQd-oV-UWTpgCxHzoU/s1360/Copilot%20chat%20extension%20reload%20required.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="531" data-original-width="1360" height="250" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgwXmw3SG7XT0eLcu4kw-Y1DlzEey10-P0FyNmPASc9-wEdKqpE7Mg7gbHrMQcqdv18pp3AJ8Y0q0MSd1HKi53zj0Q65Hx4vhIzFyehaE14LbLIsPuZbWTP5p8v91pph2rogp-Uak9HePb93tN0kPqen4D-v8yqlbznGCM4sPMj2yBQd-oV-UWTpgCxHzoU/w640-h250/Copilot%20chat%20extension%20reload%20required.png" width="640" /></a></div><p>Once selecting, '<b>Reload Required</b>,' Visual Studio Code will reload, and Copilot Chat will begin working as expected again.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiK51Okvofib5udk5byPxaQ3V91bjrHVtRP7LHd6ZH56DlmgUb5i6L4GqvHFnpkOodryuBO5pUGlsrliT815upCPtHHBlh92F4YavrYosv1FTclIPV7TFDAQTrhrLTdLuhHh6z56YkasQo0GsMYIWUul5k3I4lE6dHpjdFF-_92TJGu0CEDBxNZj4qr1Ba7/s465/Copilot%20chat%20working%20post%20reload.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="356" data-original-width="465" height="306" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiK51Okvofib5udk5byPxaQ3V91bjrHVtRP7LHd6ZH56DlmgUb5i6L4GqvHFnpkOodryuBO5pUGlsrliT815upCPtHHBlh92F4YavrYosv1FTclIPV7TFDAQTrhrLTdLuhHh6z56YkasQo0GsMYIWUul5k3I4lE6dHpjdFF-_92TJGu0CEDBxNZj4qr1Ba7/w400-h306/Copilot%20chat%20working%20post%20reload.png" width="400" /></a></div></span></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-29174103245712761342023-11-12T20:14:00.000-05:002023-11-12T20:14:04.387-05:00Blazor WebAssembly Lazy Loading Changes from .NET 7 to .NET 8<span style="font-family: arial;">Lazy Loading is an essential tool used in web client development to defer loading of resources until requested by the user, as opposed to loading everything up-front which is expensive. Blazor has had the ability to lazy load Razor Class Libraries for the last several versions of .NET, but there are some updates in .NET 8 that aren't well documented.</span><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">To not be completely repetitive, here are the basic steps for implementing lazy loading in your Blazor WebAssembly application direct from the Microsoft docs: <a href="https://learn.microsoft.com/en-us/aspnet/core/blazor/webassembly-lazy-load-assemblies?view=aspnetcore-8.0" target="_blank">Lazy load assemblies in ASP.NET Core Blazor WebAssembly</a></span></div><div><br /></div><div><span style="font-family: arial;">The issue is the </span><i style="font-family: arial;">Project Configuration</i><span style="font-family: arial;"> and <i>Router Configuration </i>sections of the docs as of this post are still not up to date. With .NET 8, the WASM assemblies are now built as .wasm files </span><i style="font-family: arial;">not</i><span style="font-family: arial;"> .dll files and therefore the main update you'll need to make are inside the .csproj file and within the definition of the </span><span style="font-family: courier;">LazyAssemblyLoader </span><span style="font-family: arial;">routing </span><span style="font-family: arial;">code to use the </span><b style="font-family: arial;">.wasm</b><span style="font-family: arial;"> file extension for the referenced .dlls:</span></div><div><span style="font-family: arial;"><br /></span></div><h4 style="text-align: left;"><span style="font-family: arial;">.csproj file updates</span></h4><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGYJQzGO6fRChe8KA0IMPwmQWIpKPiArWDUMji3xS9pXwv-q7Q4-ceN2Px_nrh-HkcVEqcDgH6Zujej7IQdAqus7mOob2zc0DHMOeq8778cBNFfw2qkh7eMG4cgiJBSk7iM-zbAYnt1-hgxRQXjsSArVKdTsO0UzhaSj8lgJodxSjM-c4Kn4HwC5Aazdkw/s974/Blazor%20WASM%20Lazy%20Loading%20files%20NET%208%20II.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="116" data-original-width="974" height="75" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjGYJQzGO6fRChe8KA0IMPwmQWIpKPiArWDUMji3xS9pXwv-q7Q4-ceN2Px_nrh-HkcVEqcDgH6Zujej7IQdAqus7mOob2zc0DHMOeq8778cBNFfw2qkh7eMG4cgiJBSk7iM-zbAYnt1-hgxRQXjsSArVKdTsO0UzhaSj8lgJodxSjM-c4Kn4HwC5Aazdkw/w629-h75/Blazor%20WASM%20Lazy%20Loading%20files%20NET%208%20II.png" width="629" /></a></div><br /><h4 style="text-align: left;"><span style="font-family: arial;">Routing file updates</span></h4></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE8NorwZnwLE2YKuZYqV75cg1t2jd5snYww9oThjqbnE9S5ozYzJZ6tbNXSQSs3m-ljlH4sgIy5w6jeLs1woYIAAas26eIv2NgXthQlpvNezuQkCpRVpkUC4nkflrsSgvPemOPl8htvHm-De1Fa5D_eJq7E8nYd6zNL1x2XP5uyg1BZj0IFXe0t6NnAwsn/s784/Blazor%20WASM%20Lazy%20Loading%20files%20NET%208%20III.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="181" data-original-width="784" height="142" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE8NorwZnwLE2YKuZYqV75cg1t2jd5snYww9oThjqbnE9S5ozYzJZ6tbNXSQSs3m-ljlH4sgIy5w6jeLs1woYIAAas26eIv2NgXthQlpvNezuQkCpRVpkUC4nkflrsSgvPemOPl8htvHm-De1Fa5D_eJq7E8nYd6zNL1x2XP5uyg1BZj0IFXe0t6NnAwsn/w617-h142/Blazor%20WASM%20Lazy%20Loading%20files%20NET%208%20III.png" width="617" /></a></div><br /><div><span style="font-family: arial;">If continuing to use the old code with the .dll extension you would get the following error on building your application:</span></div><div><span style="font-family: arial;"><blockquote><i><b>Unable to find 'EngineAnalyticsWebApp.TestLazy.dll' to be lazy loaded later. Confirm that project or package references are included and the reference is used in the project" error on build</b></i></blockquote></span></div><div><span style="font-family: arial;">Upon making the required updates to your .NET 8 application to prevent the error above, your app should successfully build, and you'll see the correct deferred execution in the browser.</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheO0oomrtzHD8DOvylOkahOje7rsIvXH_3LkOWIaW13Rv5HzjulOvy-cuWwkYWpQXnoyJLzBUjB6wBYY1FpszGu5Ec05g0AqrH2AUj0-tE9KzWgD3rLCGmb9sMXBwWPY04uDWNBvMTDaN0YjwTM-KXFg001Sxu9kf2X5bTYeB3wNTcCy-m8IUPFtv0zALY/s1053/Blazor%20WASM%20Lazy%20Loading%20files%20NET%208.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="367" data-original-width="1053" height="210" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEheO0oomrtzHD8DOvylOkahOje7rsIvXH_3LkOWIaW13Rv5HzjulOvy-cuWwkYWpQXnoyJLzBUjB6wBYY1FpszGu5Ec05g0AqrH2AUj0-tE9KzWgD3rLCGmb9sMXBwWPY04uDWNBvMTDaN0YjwTM-KXFg001Sxu9kf2X5bTYeB3wNTcCy-m8IUPFtv0zALY/w599-h210/Blazor%20WASM%20Lazy%20Loading%20files%20NET%208.png" width="599" /></a></div><br /><span style="font-family: arial;"><br /></span></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-4629286214471273152023-11-03T18:57:00.001-04:002023-11-03T18:57:16.422-04:00Dealing with Time Skew and SAS Azure Blob Token Generation: 403 Failed to Authenticate Error<span style="font-family: arial;">If you're working with the </span><span style="font-family: courier;">Azure.Storage.Blobs</span><span style="font-family: arial;"> SDK in .NET and generating SAS tokens, you might come across an error like the following when making a call to </span><span style="font-family: courier;">GetUserDelegationKeyAsync()</span><span style="font-family: arial;">:</span><div><blockquote style="font-family: arial;"><b>Status 403: The request is not authorized to perform this operation using this permission</b></blockquote><p><span style="font-family: arial;">Here is a sample of code that might throw this error in which the </span><span style="font-family: courier;">startsOn </span><span style="font-family: arial;">value is set to the current time:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieQkLXgIb7rLnOxH7s2Swckc-GjIcFod3gNIftOuptoYqxeCU83C1w4tx0dEx9-uMcQSJ8zhhmn77GtA6iuGdjAe8mLDEaYRDFQzNDc2X4HwQdIhrK7CjcZZR81ID9r18DFFz7BI6dOzFTXjOPQ13HIMfaDp46LWdIkhCXFOEsGX_be2MRLEf0E198Nh6z/s458/Azure%20Blob%20SAS%20Key%20Offset%20Error%20Original%20Code.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="89" data-original-width="458" height="124" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEieQkLXgIb7rLnOxH7s2Swckc-GjIcFod3gNIftOuptoYqxeCU83C1w4tx0dEx9-uMcQSJ8zhhmn77GtA6iuGdjAe8mLDEaYRDFQzNDc2X4HwQdIhrK7CjcZZR81ID9r18DFFz7BI6dOzFTXjOPQ13HIMfaDp46LWdIkhCXFOEsGX_be2MRLEf0E198Nh6z/w640-h124/Azure%20Blob%20SAS%20Key%20Offset%20Error%20Original%20Code.png" width="640" /></a></div><p></p><p><span style="font-family: arial;">Before you start double checking all of the user permissions in Azure and going through all the Access Control and Role Assignments in Blob Storage (assuming you do have them configured correctly), this might be a red herring for a different issue with the </span><span style="font-family: courier;">startsOn </span><span style="font-family: arial;">value for the call to </span><span style="font-family: courier;">GetUserDelegationKeyAsync()</span><span style="font-family: arial;">. The problem is likely with clock skew and differences in times from the server and client.</span></p><p><span style="font-family: arial;">It <i>is </i>documented in SAS best practices from the Azure docs (found <a href="https://learn.microsoft.com/en-us/azure/storage/common/storage-sas-overview?toc=%2Fazure%2Fstorage%2Fblobs%2Ftoc.json&bc=%2Fazure%2Fstorage%2Fblobs%2Fbreadcrumb%2Ftoc.json#best-practices-when-using-sas" target="_blank">here</a>), the following issue with <b>clock skew</b> and how to remedy the issue:</span></p><p></p><blockquote><span style="font-family: arial;"><i>Be careful with SAS start time. If you set the start time for a SAS to the current time, failures might occur intermittently for the first few minutes. This is due to different machines having slightly different current times (known as clock skew). In general, set the start time to be at least 15 minutes in the past. Or, don't set it at all, which will make it valid immediately in all cases. The same generally applies to expiry time as well--remember that you may observe up to 15 minutes of clock skew in either direction on any request. For clients using a REST version prior to 2012-02-12, the maximum duration for a SAS that does not reference a stored access policy is 1 hour. Any policies that specify a longer term than 1 hour will fail.</i></span></blockquote><p><span style="font-family: arial;">There is a simple fix for this as instructed to modify the </span><span style="font-family: courier;">startsOn </span><span style="font-family: arial;">value to be either not set or 15 minutes (or greater) in the past. With this updated code, the 403 error is fixed and will proceed as expected.</span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSMNWWgbxTyhwvpHajP3zvQBZfJM3fploANFkYQhhzsgtSPQARgCk-rynfmLbfFP8ICCEnKnZ592QvetJuDgYBo94It_CNWM_pX6X-YqMR4jJ1EZrkbuuqqxlYKmNwjYwMNAYgnpCDMIew5bDZywFibRSXLZmwLX_EAdMSbejot6uPsA17KHHxXtRrghL2/s493/Azure%20Blob%20SAS%20Key%20Offset%20Error%20Updated%20Code.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="89" data-original-width="493" height="116" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjSMNWWgbxTyhwvpHajP3zvQBZfJM3fploANFkYQhhzsgtSPQARgCk-rynfmLbfFP8ICCEnKnZ592QvetJuDgYBo94It_CNWM_pX6X-YqMR4jJ1EZrkbuuqqxlYKmNwjYwMNAYgnpCDMIew5bDZywFibRSXLZmwLX_EAdMSbejot6uPsA17KHHxXtRrghL2/w640-h116/Azure%20Blob%20SAS%20Key%20Offset%20Error%20Updated%20Code.png" width="640" /></a></div><p></p></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-57137361015753337322023-10-18T19:48:00.006-04:002023-10-18T19:50:20.824-04:00Fixing PowerShell Scripting Error in C# Code: "Exception calling ""ToString"" with ""0"" argument(s). There is no Runspace available to run scripts in this thread."<span><span style="font-family: arial;">A bit of a niche post here, but maybe someone is searching the interwebs and this will help save some time. When running a PowerShell script in C# leveraging the System.Management.Automation library, you might run into some neuanced issues that behave differently than when running PowerShell commands directly via the command line. Here is one instance, take the following PowerShell command to install a new Windows Service:</span><pre style="font-family: arial;"><code class="language-ps">New-Service -Name "MyWindowsService" -BinaryPathName "C:\SomePath\1.0.1\MyWindowsService.exe"
</code></pre><span style="font-family: arial;">
When running this in a PowerShell terminal, it will generate the following output which as <a href="https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/new-service?view=powershell-7.3#outputs" target="_blank">documented</a> is an object representing the new service:</span><pre style="font-family: arial;"><code class="language-ps">Status Name DisplayName
------ ---- -----------
Stopped MyWindowsService MyWindowsService
</code></pre><span style="font-family: arial;">
This is actually helpful output for a human, and maybe even for logging, bu when running this same command in C# via a PowerShell instance, the command will </span><i style="font-family: arial;">technically work</i><span style="font-family: arial;">, but you'll get the following cryptic error:
</span><blockquote><span style="font-family: courier;">"The following exception occurred while retrieving the string: ""Exception calling ""ToString"" with ""0"" argument(s):
""There is no Runspace available to run scripts in this thread. You can provide one in the DefaultRunspace property of the
System.Management.Automation.Runspaces.Runspace type. The script block you attempted to invoke was: $this.ServiceName""""",
System.Object,System.ServiceProcess.ServiceController,System.WeakReference`1[System.Management.Automation.Runspaces.TypeTable],
System.Management.Automation.PSObject+AdapterSet,None,System.Management.Automation.DotNetAdapter,"",System.Management.Automation.PSObject+AdapterSet,
System.ServiceProcess.ServiceController,System.ServiceProcess.ServiceController,"PSStandardMembers {DefaultDisplayPropertySet}",False,False,False,False,False,
"","",None</span></blockquote><span style="font-family: arial;">
OK not very helpful. It took a while but I deduced the output from the </span><span style="font-family: courier;">New-Service</span><span style="font-family: arial;"> cmdlet was causing this issue. There are 2 ways I found to handle this.</span><div><ol style="text-align: left;"><li><span style="font-family: arial;">Suppress the Output: Since this is running in C# without human intervention, pipe in the option to suppress the output if you are not logging it or using it for some meaningful purpose. Remember, you can still get the status by using </span><span style="font-family: courier;">Get-Service</span><span style="font-family: arial;"> to inspect the newly installed service, as opposed to reading the output. Use the updated command to accomplish this:</span><pre style="font-family: arial;"><code class="language-ps">New-Service -Name "MyWindowsService"
-BinaryPathName "C:\SomePath\1.0.1\MyWindowsService.exe" | out-null
</code></pre></li><li style="font-family: arial;">Return the Output to a Variable: The other option is simply to return the output of the cmdlet typically for use to inspect. This could be done with the following updated statement:<pre><code class="language-ps">$newServiceResult = New-Service -Name "MyWindowsService"
-BinaryPathName "C:\SomePath\1.0.1\MyWindowsService.exe"
</code></pre>
Keep in mind he return value is of type System.ServiceProcess.ServiceController, so you can use that as needed.</li></ol><div><span style="font-family: arial;">For my needs I prefer option #1, as I don't need to inspect the return of </span><span style="font-family: courier;">New-Service</span><span style="font-family: arial;"> and as mentioned can use </span><span style="font-family: courier;">Get-Service</span><span style="font-family: arial;"> to further inspect any Windows Service status at this point. With either method though you will no longer get the cryptic error as previously shown.</span></div></div></span>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-65739407227658670432023-09-21T19:33:00.001-04:002023-09-21T19:38:21.161-04:00How to Disable Either Classic or YAML Pipelines in Azure DevOps (ADO)<p><span style="font-family: arial;">If you have pipelines in Azure DevOps that you don't want to trigger automatically either because they are legacy and remain for reference, not currently being used, or just need to temporarily disable, there are different ways to accomplish this based on the type of pipeline.</span></p><h1 style="text-align: left;"><span style="font-family: arial;">Classic Pipelines</span></h1><div><ol style="text-align: left;"><li><span style="font-family: arial;">Select the Classic Pipeline and press the '<b>Edit</b>' button</span></li><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_70g5CCHKDRl844RXOyks3XM17hQIFXyE4Nz_tdNmtCzn1Q-b1J-TbUxuttShzzda1xRXQkHYd2jNtq25jV_ct_lvv2ZKx-0CvGm55Ly3SJPI7GC_PK-XOK9h22MLFUX22wMhtX8husckp0aB4YqMqLCzJd8isgAlM863IF8Wgt5xaUPtU__aRq_XBf2s/s792/ADO%20Classic%20Pipeline%20Edit.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img border="0" data-original-height="64" data-original-width="792" height="44" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_70g5CCHKDRl844RXOyks3XM17hQIFXyE4Nz_tdNmtCzn1Q-b1J-TbUxuttShzzda1xRXQkHYd2jNtq25jV_ct_lvv2ZKx-0CvGm55Ly3SJPI7GC_PK-XOK9h22MLFUX22wMhtX8husckp0aB4YqMqLCzJd8isgAlM863IF8Wgt5xaUPtU__aRq_XBf2s/w544-h44/ADO%20Classic%20Pipeline%20Edit.png" width="544" /></span></a></div><span style="font-family: arial;"><br /></span><div><li><span style="font-family: arial;">Select '<b>Triggers</b>'</span></li><span style="font-family: arial;"><br /></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMDHIbcCP_DXTXqnn1sPfisuzijENAzAmaGXADgx4ttY9booJPFNUZGUJB7itaQJqm7wBg6viwvmYNcAVOjjDTj2Bf_PKJKBYyVorkyFf906gZnaiuQLJb2_aAX1G24YJxToq8vgnBtvH7NH0W89gMNLdSXlbT6mP2EXZ395tLfv3JFYZpVHBnaSGHSraG/s624/ADO%20Classic%20Pipeline%20Triggers.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img border="0" data-original-height="171" data-original-width="624" height="133" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhMDHIbcCP_DXTXqnn1sPfisuzijENAzAmaGXADgx4ttY9booJPFNUZGUJB7itaQJqm7wBg6viwvmYNcAVOjjDTj2Bf_PKJKBYyVorkyFf906gZnaiuQLJb2_aAX1G24YJxToq8vgnBtvH7NH0W89gMNLdSXlbT6mP2EXZ395tLfv3JFYZpVHBnaSGHSraG/w483-h133/ADO%20Classic%20Pipeline%20Triggers.png" width="483" /></span></a></div><span style="font-family: arial;"><br /></span><div><li><span style="font-family: arial;">Uncheck the box for '<b>Enable Continuous Integration</b>'</span></li><span style="font-family: arial;"><br /></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkkjmRYgME1yC5ZNuHoFYURnweKBoRGy6Z7at6cCy7ERXs8sFn-IOvxEuA43QiBdUeMEiit00y5g5m1V_ZU2qxm0cuQRjLZoTSTvAq0oaTbrO83R-Wiv56TnD3XlWZfDQLXvwDn9RUNXuTO2CAaIN43OAC3V0zl64N4DsXZ77DnmxXASn6iKJ95FDCsHmb/s687/ADO%20Classic%20Pipeline%20Disable%20CI.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img border="0" data-original-height="193" data-original-width="687" height="158" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjkkjmRYgME1yC5ZNuHoFYURnweKBoRGy6Z7at6cCy7ERXs8sFn-IOvxEuA43QiBdUeMEiit00y5g5m1V_ZU2qxm0cuQRjLZoTSTvAq0oaTbrO83R-Wiv56TnD3XlWZfDQLXvwDn9RUNXuTO2CAaIN43OAC3V0zl64N4DsXZ77DnmxXASn6iKJ95FDCsHmb/w562-h158/ADO%20Classic%20Pipeline%20Disable%20CI.png" width="562" /></span></a></div><br /><li><span style="font-family: arial;">Save the Pipeline</span></li></div></div></ol><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR2uKZXk9HNpApmjNErsfKPfiiISlnuWmuJyU4tEoC0TqAVqIb2zP-m56tUorgN-9dhlJiTgRNQFFYWiOPbVpbbFYZ5JoVmWBNtyWOAlPZcGcxXoMqOWDjzc7eNoJ-JTyVZJhN7aKHRnNKRQI4YMv6Bb7l4mOrE5JD8ot8BRASXdKMNLfeCcgG_hmtUuJS/s526/ADO%20Classic%20Pipeline%20Save.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img border="0" data-original-height="237" data-original-width="526" height="243" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgR2uKZXk9HNpApmjNErsfKPfiiISlnuWmuJyU4tEoC0TqAVqIb2zP-m56tUorgN-9dhlJiTgRNQFFYWiOPbVpbbFYZ5JoVmWBNtyWOAlPZcGcxXoMqOWDjzc7eNoJ-JTyVZJhN7aKHRnNKRQI4YMv6Bb7l4mOrE5JD8ot8BRASXdKMNLfeCcgG_hmtUuJS/w539-h243/ADO%20Classic%20Pipeline%20Save.png" width="539" /></span></a></div><span style="font-family: arial;"><br /></span><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;"><br /></span></div></div><h1 style="text-align: left;"><span style="font-family: arial;">YAML Pipelines</span></h1><p></p><p></p><ol style="text-align: left;"><li><span style="font-family: arial;">Select the Classic Pipeline and press the '<b>Edit</b>' button</span></li><span style="font-family: arial;"><br /></span><div class="separator" style="clear: both; text-align: center;"><span style="font-family: arial; margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="65" data-original-width="778" height="51" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj8JKzKjxeUT9gEpqN-jIQq58eHAqPpTu9AjOTA6AjtpfFmEaOckbwGKGY8hBhqXjYFisfDoACE9EZ6RmJy-Qi5Lvvmyh_lRzJboY44AxY7znZX2YcqpT-Xb32GJAMepbrOqdpDpIhnfeiw_XuN0wn_pkipHc0HiX6mUFgs30UP7btxhLUTUCfyB2ZTAWym/w603-h51/ADO%20YAML%20Pipeline%20Edit.png" width="603" /></span></div><span style="font-family: arial;"><br /></span><div><li><span style="font-family: arial;">Select the ellipsis (3 dots) in the top-right hand corner, and select '<b>Settings</b>'</span></li><span style="font-family: arial;"><br /></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLLMeD-usAalvPIeLY1AEg-cgdKD4ri48ZkMjK7NFh6bet2StxwTVOd6b5k_nYF46BkJcLqHr9KPoYs3aKfP0lXvc2YR7B55Zl8jm3ba34ahpr1FAFN0rqun6Xa6P6bWM63IEqbT99O6IaGIlh22p1t85Ny6AZD4WLUbh6TpFUP2UNmJXlgh_BdyHFIko0/s309/ADO%20YAML%20Pipeline%20Settings.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img border="0" data-original-height="252" data-original-width="309" height="262" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhLLMeD-usAalvPIeLY1AEg-cgdKD4ri48ZkMjK7NFh6bet2StxwTVOd6b5k_nYF46BkJcLqHr9KPoYs3aKfP0lXvc2YR7B55Zl8jm3ba34ahpr1FAFN0rqun6Xa6P6bWM63IEqbT99O6IaGIlh22p1t85Ny6AZD4WLUbh6TpFUP2UNmJXlgh_BdyHFIko0/w321-h262/ADO%20YAML%20Pipeline%20Settings.png" width="321" /></span></a></div><span style="font-family: arial;"><br /></span><li><span style="font-family: arial;">Select the '<b>Disabled</b>' radio button, and press '<b>Save</b>'</span></li><span style="font-family: arial;"><br /></span><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg85oQ4KrcQdPa8lbCh9-u1Ab2P3i_XrNKUfu52KNBcNv6SArPwQxGTJyU4CYVDNOOfdIZoRpddEJIw4bMIiJc3zlAL4DuvUJuFrbedzSauPaCsHt2mQKhO0crVA-oB2sYGVokuB3jE3WAvFfXoTHG1CE3uhWhtivOWkB_2d6aFpslitGqC8LNEt7xdi5sH/s500/ADO%20YAML%20Pipeline%20Disable%20Option.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img border="0" data-original-height="371" data-original-width="500" height="364" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg85oQ4KrcQdPa8lbCh9-u1Ab2P3i_XrNKUfu52KNBcNv6SArPwQxGTJyU4CYVDNOOfdIZoRpddEJIw4bMIiJc3zlAL4DuvUJuFrbedzSauPaCsHt2mQKhO0crVA-oB2sYGVokuB3jE3WAvFfXoTHG1CE3uhWhtivOWkB_2d6aFpslitGqC8LNEt7xdi5sH/w492-h364/ADO%20YAML%20Pipeline%20Disable%20Option.png" width="492" /></span></a></div><span style="font-family: arial;"><br /></span><div><li><span style="font-family: arial;">The pipeline is confirmed disabled via the label next to the name</span></li><span style="font-family: arial;"><br /></span></div></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguEwJQpVfXwuzS6wfPiY8g2rV6t0HdBtf-MsXJ_B9ICx6pM3gI-b55h7NAbLSxsfo41-4FGsaNeU-5qChsBVjWmwMzI9p6OSXV7imnh6z7Q5SDloeASdZ2VMfpgxYbf1RlMmqDo7c33Mk0plIdlBJPmAK6b-auqBJhC36Vm8jZSU_rgXYcHJ1kLwkBRBtk/s449/ADO%20YAML%20Pipeline%20Disabled.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img border="0" data-original-height="63" data-original-width="449" height="83" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEguEwJQpVfXwuzS6wfPiY8g2rV6t0HdBtf-MsXJ_B9ICx6pM3gI-b55h7NAbLSxsfo41-4FGsaNeU-5qChsBVjWmwMzI9p6OSXV7imnh6z7Q5SDloeASdZ2VMfpgxYbf1RlMmqDo7c33Mk0plIdlBJPmAK6b-auqBJhC36Vm8jZSU_rgXYcHJ1kLwkBRBtk/w590-h83/ADO%20YAML%20Pipeline%20Disabled.png" width="590" /></span></a></div></div></ol><span style="font-family: arial;"><br /></span><div><span style="font-family: arial;"><br /></span></div><div><br /></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-5940137125009566712023-09-20T14:20:00.000-04:002023-09-20T14:20:15.095-04:00Leveraging IntelliSense for Azure DevOps YAML Pipelines in Visual Studio Code<span style="font-family: arial;">If you're building out YAML pipelines for Azure DevOps (ADO) and don't wish to hand roll them in the online editor provided, you can instead build them in Visual Studio Code. The 1st thing you'll be hunting down though is IntelliSense and auto-complete assistance for your .yml pipeline code. Out-of-the-box, VSC doesn't have this support other than generic YAML language services so you'll want an extension. There is an extension for this and name of it is simply, '<b>Azure Pipelines</b>' which can be found in the <a href="https://marketplace.visualstudio.com/items?itemName=ms-azure-devops.azure-pipelines" target="_blank">Marketplace</a>. </span><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4dODhuBWPzqn4pcb2EBjpb7VwLn6AKV47GOHc_OiMFwd5wBbk_mrNjJdtMWK6gdYIWxpscdhC38tGNP4QGO6ZbVjaqFGfn9VK6FLyxe_3T2CB_JhoW_-wZiLMxPDvCjayiSdcipJvZurMsbjxeG3ZkZ70rT5CezrfuuJUeoARokZYni6fRtISZIPLlTlS/s786/Azure%20Pipleines%20Marketplace.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="181" data-original-width="786" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4dODhuBWPzqn4pcb2EBjpb7VwLn6AKV47GOHc_OiMFwd5wBbk_mrNjJdtMWK6gdYIWxpscdhC38tGNP4QGO6ZbVjaqFGfn9VK6FLyxe_3T2CB_JhoW_-wZiLMxPDvCjayiSdcipJvZurMsbjxeG3ZkZ70rT5CezrfuuJUeoARokZYni6fRtISZIPLlTlS/w640-h148/Azure%20Pipleines%20Marketplace.png" width="640" /></a></div><br /></div><div><span style="font-family: arial;">The issue is the Microsoft extension for the ADO pipelines is poorly rated at 2 out of 5 stars which made me wonder if it wasn't worth using. The good news is that rating isn't in reflection for a completely orphaned product as the latest commit was within a week of this writing. The main critique which I verified is after installation it just doesn't seem to do anything. However, with a single-step I got the primary functionality working as desired and have the IntelliSense and auto-complete features I needed.</span></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">The key is to manually switch the 'Language Mode' setting in the bottom-right hand corner to the proper value for the <i>specific</i> code file being created (or use the keyboard shortcut Ctrl + K M). Initially it will show 'YAML' which has been auto-detected, and in this mode none of the extension characteristics work. </span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUab6ec2Y6PX5rvfO9q61cNtdqZMC1FV5_PL1c9EywPsRzetKzt7ZyI4jsupV6CiU1xuAmEqY48EPguXpdpAOVJlcaZblNgekHKitwsHI5UH3HPMbGD8_laIt9FKTI6HX1lOjQWXCi0xlPH75VETDnchQnnLCvxS7ON03G_FqRqT9h6HkNH0WcImp1ewtk/s210/Language%20Mode%20VSCode.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="93" data-original-width="210" height="177" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUab6ec2Y6PX5rvfO9q61cNtdqZMC1FV5_PL1c9EywPsRzetKzt7ZyI4jsupV6CiU1xuAmEqY48EPguXpdpAOVJlcaZblNgekHKitwsHI5UH3HPMbGD8_laIt9FKTI6HX1lOjQWXCi0xlPH75VETDnchQnnLCvxS7ON03G_FqRqT9h6HkNH0WcImp1ewtk/w400-h177/Language%20Mode%20VSCode.png" width="400" /></a></div></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">Click the dropdown and you'll get a selection of languages that can be set. Select, '<b>Azure Pipelines</b>.'</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgss2hywHyvA6VgFa9AIqggNmlOhA4Uptblg66j7jqL3T7HrjV089I0ldbqlmISxKymu0606hTHRfj5N_TGTFXSHKW79ZmGncn3rd5Ek9NJNUHSIxXY5UVf8lTkLBYkVDP70q-xGLYS9ygeLTcDsRDuwGWapCE27kLccI2dS91obAw41FkgXVi6ytQlBAoA/s745/Language%20Mode%20Selection%20VSCode.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="447" data-original-width="745" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgss2hywHyvA6VgFa9AIqggNmlOhA4Uptblg66j7jqL3T7HrjV089I0ldbqlmISxKymu0606hTHRfj5N_TGTFXSHKW79ZmGncn3rd5Ek9NJNUHSIxXY5UVf8lTkLBYkVDP70q-xGLYS9ygeLTcDsRDuwGWapCE27kLccI2dS91obAw41FkgXVi6ytQlBAoA/w640-h384/Language%20Mode%20Selection%20VSCode.png" width="640" /></a></div><br /></div><div><span style="font-family: arial;">Now the .yml file you're working on will have IntelliSense features, auto-complete, and hinting leveraging the installed extension which is helpful in creating pipelines.</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQdUJRIM3UuBOOrrNrYW1LmdzViBojpHUs7ctUpjffH3zQnyG5KCXCRuzO4TqJPmCG9AOirfXHYDe4fAiCat3az_AJjXXg5SmZ8h3RGHogr82Zb-8mLFi3TVdIgAvbHbbhpjDTp7pWA1RxK4NArOkV5YIHQ6hDMbk9u_iCURQTkmUm6KOQ97Cr_Bswk_-F/s599/Pipelines%20Assistance%201.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="264" data-original-width="599" height="176" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQdUJRIM3UuBOOrrNrYW1LmdzViBojpHUs7ctUpjffH3zQnyG5KCXCRuzO4TqJPmCG9AOirfXHYDe4fAiCat3az_AJjXXg5SmZ8h3RGHogr82Zb-8mLFi3TVdIgAvbHbbhpjDTp7pWA1RxK4NArOkV5YIHQ6hDMbk9u_iCURQTkmUm6KOQ97Cr_Bswk_-F/w400-h176/Pipelines%20Assistance%201.png" width="400" /></a></div></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLIDhhqZfnq4UPedwc8xTa6C-vxOGKtoAaGGZj60gBfeMyIrJ7OraM65Ztdb5t6SV_hsFlOQ2BHNwl9_4K_70oOorQUrfZrhKjHjAjmMKkUp_pjqls_HQ2-72gBB0y8QuvmqhDH3FGa37FkWMeFZzi2YN1lezQxVx6sKKZm-TyR5I6BlHy7u6avg8iL6-j/s325/Pipelines%20Assistance%202.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="115" data-original-width="325" height="141" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLIDhhqZfnq4UPedwc8xTa6C-vxOGKtoAaGGZj60gBfeMyIrJ7OraM65Ztdb5t6SV_hsFlOQ2BHNwl9_4K_70oOorQUrfZrhKjHjAjmMKkUp_pjqls_HQ2-72gBB0y8QuvmqhDH3FGa37FkWMeFZzi2YN1lezQxVx6sKKZm-TyR5I6BlHy7u6avg8iL6-j/w400-h141/Pipelines%20Assistance%202.png" width="400" /></a></div></div></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-71058708995677025462023-07-28T13:12:00.003-04:002023-08-02T11:11:50.608-04:00Reading Environment Variables, AppSettings, LocalSettings, and User Secrets Seamlessly Across Environments in ASP.NET<span style="font-family: arial;">One of the biggest challenges we face in modern cloud solutions is making it so sensitive configuration data can be read seamlessly across all environments from the local dev environment all the way to production. This isn't really a new issue, but one that has multiple ways to accomplish some easier than others.</span><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;"><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxFwmzo-FZyAeOzD-LaiCitCZYd6QxKCXpKp1bAp_22_y84ymoTWVMqD6-4pH1qCPVO-i1zDhVI89ptSNehahXqznr8_n09CxzGWvTcniKJ4n_1J3wHfR_oQn0p9oorqDVkLa_mKrNBEjJ8SyLntNe_0lO18zQovnH9aYJS5DKKCqpEB4pms9nHqtFKDDo/s407/Gears.jpeg" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="307" data-original-width="407" height="155" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxFwmzo-FZyAeOzD-LaiCitCZYd6QxKCXpKp1bAp_22_y84ymoTWVMqD6-4pH1qCPVO-i1zDhVI89ptSNehahXqznr8_n09CxzGWvTcniKJ4n_1J3wHfR_oQn0p9oorqDVkLa_mKrNBEjJ8SyLntNe_0lO18zQovnH9aYJS5DKKCqpEB4pms9nHqtFKDDo/w207-h155/Gears.jpeg" width="207" /></a></div><br />For a sample use case, we might have a database connection string with sensitive information that needs to work seamlessly in code for local, Dev, QA, Stage, Prod, etc. without a lot of special hooks or handling in code. One way to handle this in the cloud regardless of deployment resource or setup is to expose a single key name with unique value per-environment. This can be configured via scripting in deployment pipelines per environment to take care of the DevOps side of this equation. However in code we want this single-read of a key to work in all environments. This is where in .NET the Configuration provider offered in Microsoft.Extensions.Configuration works so well.</span></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">Let's say the following environment variable has been configured across Dev, QA, Stage, and Prod environments with respective values already:</span></div><div><span style="font-family: arial;"><b><blockquote>CosmosDbConnectionString | AccountEndpoint=https://cosmos-acct-{env}-eus-001.documents.azure.com:443/;AccountKey=abc123...</blockquote></b></span></div><div><span style="font-family: arial;">For local development we have a couple options as well to configure this value:</span></div><div><ol style="text-align: left;"><li><span style="font-family: arial;">Create your own environment variable on your local OS with the <i>identical</i> key name and whatever value you choose</span></li><li><span style="font-family: arial;">Add the <i>identical</i> key and again whatever value you require as a 'User Secret' within Visual Studio or VS Code (VS Code requires an extension download to work with secrets)</span></li></ol></div><div><span style="font-family: arial;">The above 2 methods are preferred as they do not add to files that get committed to source control. While you <i>can</i> add the key/value pairs to appSettings.json or launchSettings.json (as env variables), these are not advised as it breaks the requirement that we should not be committing secrets to source control. Note - you could also write a PowerShell script to be added to the solution that developers could run initially to pull environment variable key names from the cloud modifying with a local value for an added bonus to be even more automated.</span></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">So moving back to our .NET code, we would like to have a single line that uses 'CosmosDbConnectionString' that will work for <i>all </i>environments.</span></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">To get started, in current versions of ASP.NET, this single line of code in </span><span style="font-family: courier;">program.cs</span><span style="font-family: arial;"> sets us up out of the box:</span></div><div><span style="font-family: arial;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0vizkUmeNSCHAdpf9omzlaGK2NbIqSIrBlpES9BjD5oAbCQIQEJY71ed8D1vmtEI9fmcYDAxPfhnTNBv0UIkkTVbEdk8NOQtGtFxXhbnamblPOXpRtgGcZNUpy6vHIfxFIhVVCbLdCLWuj6aPosvR40Yk75dvjZWUA7pKwS_zGr0UAS3YB69Qdr7Fc9NL/s393/Program_cs%20Configuration.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="56" data-original-width="393" height="70" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi0vizkUmeNSCHAdpf9omzlaGK2NbIqSIrBlpES9BjD5oAbCQIQEJY71ed8D1vmtEI9fmcYDAxPfhnTNBv0UIkkTVbEdk8NOQtGtFxXhbnamblPOXpRtgGcZNUpy6vHIfxFIhVVCbLdCLWuj6aPosvR40Yk75dvjZWUA7pKwS_zGr0UAS3YB69Qdr7Fc9NL/w488-h70/Program_cs%20Configuration.png" width="488" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><span style="font-family: arial;">The absolutely fantastic feature of this black-box is that it will automagically handle the hierarchy of running through multiple different configuration sources <i>including</i> environmental variables! This single line of code (after injecting the IConfiguration configuration service) is all that's needed:</span></div><div><span style="font-family: arial;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPFDcn2WsDfypfm41dOQ_DUQw3MshB5wVzH3F9cz7YanXJHoNt58eBS3VvYztS3tVOyPYfIyivqXjaXC7VlzDf6fHuQumO_8k-hGcrvCv7fDNMGfcVkkO0iwdWgk8RXVMS5lJFZi0U1YcMdR0lS-HIk8hk4n41sPFl9Y7yjCRMfRR4WqoE97KNuxV1Ljpz/s479/ConnectionString.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="52" data-original-width="479" height="61" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPFDcn2WsDfypfm41dOQ_DUQw3MshB5wVzH3F9cz7YanXJHoNt58eBS3VvYztS3tVOyPYfIyivqXjaXC7VlzDf6fHuQumO_8k-hGcrvCv7fDNMGfcVkkO0iwdWgk8RXVMS5lJFZi0U1YcMdR0lS-HIk8hk4n41sPFl9Y7yjCRMfRR4WqoE97KNuxV1Ljpz/w564-h61/ConnectionString.png" width="564" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><span style="font-family: arial;">Here is the official documentation on this from <a href="https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#environment-variable-configuration-provider" target="_blank">Microsoft</a>:</span></div><div><blockquote><span style="font-family: arial;"><i>Using the default configuration, the EnvironmentVariablesConfigurationProvider loads configuration from environment variable key-value pairs after reading appsettings.json, appsettings.Environment.json, and Secret manager. Therefore, key values read from the environment override values read from appsettings.json, appsettings.Environment.json, and Secret manager.</i></span></blockquote></div><div><span style="font-family: arial;">This is great, because now we can add our connection string as a local secret (or local environment variable) and have it read at runtime during debugging as required, but once deployed the configured environment variables per-environment will supersede anything from appSettings, secrets, etc. and continue to work with the <i>same code</i>.</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: left;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLQVHPRrrfVuvcTC-dJ6ldrP4vm8x0lRzoNQzHwdnJOh9atRQbw3uCtq_j_QRqpVNuJnf6wSV78-Yfcbfhdu7-y8VRD1hYtcp0hXwIj9NA8PJ1TCzU49rDi4CyQdUtaEP34UobB6EKfv0tfIfvTnHmkDd8TdvQrj10QTf_AHkPIwAJtVYLpA5hYhPjsKFu/s1069/SecretsConnectionLocal.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="119" data-original-width="1069" height="81" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiLQVHPRrrfVuvcTC-dJ6ldrP4vm8x0lRzoNQzHwdnJOh9atRQbw3uCtq_j_QRqpVNuJnf6wSV78-Yfcbfhdu7-y8VRD1hYtcp0hXwIj9NA8PJ1TCzU49rDi4CyQdUtaEP34UobB6EKfv0tfIfvTnHmkDd8TdvQrj10QTf_AHkPIwAJtVYLpA5hYhPjsKFu/w713-h81/SecretsConnectionLocal.png" width="713" /></a></div><div class="separator" style="clear: both; text-align: left;"><br /></div></div><div><span style="font-family: arial;">This is also the case for <i>non-sensitive</i> data stored in appSettings.json locally vs configuration in a deployed environment like Azure. Any configuration settings in Azure per-environment using the same key name will supersede locally configured values. This use case is more well-known but worth mentioning as it's an anti-pattern to have different environment configs managed at the source control level; it should be managed in deployed environments via DevOps.</span></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">A last point to review is naming conventions when creating environment variables so they work platform agnostic. Per the same MSFT docs linked above:</span></div><div><blockquote><span style="font-family: arial;"><i>The <b>:</b> delimiter doesn't work with environment variable hierarchical keys on all platforms. For example, the <b>:</b> delimiter is not supported by Bash. The double underscore (__), which is supported on all platforms, automatically replaces any <b>:</b> delimiters in environment variables.</i></span></blockquote></div><div><span style="font-family: arial;">Therefore if you need a hierarchical key consider using the following naming structure which will work on Windows and Linux:</span></div><div><span style="font-family: arial;"><b><blockquote>CosmosDb__ConnectionString</blockquote></b></span></div><div><span style="font-family: arial;">This can be read regardless of deployed environment in code with the following line:</span></div><div><span style="font-family: arial;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWdLThhre5Ojz4SnEqBxCQ203A_L3lZMhDoi6e6IrRWMT6x5FcYnjDfKsiC_aJoPK6V15jJ6OxyPzLZxDTUbDAMFJbYcCzbZkcGn3laE10REzuJerTIVSFjHgrawb2OeDNJcKRrgU_SfCuMvA5vILcexmENInA47be2ocnUp8JvBWWixjRSUFIVG7Ga6t4/s488/ConnectionString%20With%20DoubleUnderscore.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="57" data-original-width="488" height="67" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWdLThhre5Ojz4SnEqBxCQ203A_L3lZMhDoi6e6IrRWMT6x5FcYnjDfKsiC_aJoPK6V15jJ6OxyPzLZxDTUbDAMFJbYcCzbZkcGn3laE10REzuJerTIVSFjHgrawb2OeDNJcKRrgU_SfCuMvA5vILcexmENInA47be2ocnUp8JvBWWixjRSUFIVG7Ga6t4/w580-h67/ConnectionString%20With%20DoubleUnderscore.png" width="580" /></a></div><div class="separator" style="clear: both; text-align: center;"><br /></div><div><span style="font-family: arial;">Thanks to the .NET configuration provider having all of this included functionality, we can work across 1..n environments using a multitude of configuration options, yet being able to garner that data at runtime with a single line of code!</span></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-8348661732639057062023-06-08T19:04:00.004-04:002023-06-08T19:04:55.222-04:00How to Reorder the Profiles in the Windows Command Prompt / Terminal<span style="font-family: arial;">The Windows Command Prompt / Terminal tool has gotten more robust over the years, and makes using a tool like <a href="https://conemu.github.io/en/Downloads.html" target="_blank">ConEmu</a> (that I used for years), less of a pressing need. That's because the tabbed profiles are available, and makes selecting new tabs for different profile types (Bash, PowerShell, Azure Cloud Shell) a breeze.
However there isn't a configured setting option for reordering for those of us that like to organize this sort of thing (i.e. making the ones I use the most at the top of the list). There is a feature enhancement on GitHub (<a href="https://github.com/microsoft/terminal/issues/8914" target="_blank">Profile reordering for Settings UI</a>), but for now there's a trivial way to go ahead and modify it today.
Here's a picture of the profiles I have setup currently:
</span><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJaZ2BEfhmmCrgf6h1VHqDnLXM_NIJGGwDxIgMlLcuBBIpQVp42DiGU0d6i4NWh5qbMwRBpCF9p16qwXtaTjRObLmVE7qhuIt106HCoNQkYLGPbyuaDI5Vh6NFlWrrzv0RcAMbIQWXtZkUqSOOfcRH8DmzKcq5qZvINxgFt5I2_lAzw5l-YBYyqdBnPg/s498/Windows%20CL%20Profiles.png" style="display: block; padding: 1em 0px; text-align: center;"><span style="font-family: arial;"><img alt="" border="0" data-original-height="384" data-original-width="498" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJaZ2BEfhmmCrgf6h1VHqDnLXM_NIJGGwDxIgMlLcuBBIpQVp42DiGU0d6i4NWh5qbMwRBpCF9p16qwXtaTjRObLmVE7qhuIt106HCoNQkYLGPbyuaDI5Vh6NFlWrrzv0RcAMbIQWXtZkUqSOOfcRH8DmzKcq5qZvINxgFt5I2_lAzw5l-YBYyqdBnPg/s400/Windows%20CL%20Profiles.png" width="400" /></span></a></div><span style="font-family: arial;">
I want to reorder these, and the easiest way to do this is to open the '<b>Settings</b>' from the dropdown of profiles above and select, '<b>Open JSON File</b>' from the bottom left-hand corner of the dialog:
</span><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtwemVJSHtmp-_k42cD_Quy64EvDYV_EvqmCmpiaPt5N_31fgzQijUkjXbS8200Rj99dzIYbAzA-0O3iorOhhzirJmyabEnI9Mg5OrQfql0fP6BMjqZ74AydQg6XTJXwaDSS9CrnFkPlVt04zV7UQFY1rxNVVLgvwdOA7mSufFIzRbkaK4XzWC8iUEkw/s318/Windows%20CL%20JSON%20Settings.png" style="display: block; padding: 1em 0px; text-align: center;"><span style="font-family: arial;"><img alt="" border="0" data-original-height="171" data-original-width="318" height="215" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtwemVJSHtmp-_k42cD_Quy64EvDYV_EvqmCmpiaPt5N_31fgzQijUkjXbS8200Rj99dzIYbAzA-0O3iorOhhzirJmyabEnI9Mg5OrQfql0fP6BMjqZ74AydQg6XTJXwaDSS9CrnFkPlVt04zV7UQFY1rxNVVLgvwdOA7mSufFIzRbkaK4XzWC8iUEkw/w400-h215/Windows%20CL%20JSON%20Settings.png" width="400" /></span></a></div><span style="font-family: arial;">
Now it's simply an act of rearranging the index in the array collection within the settings file. The index location in the array will dicate the order of the profiles in the command prompt window:
</span><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtZSaz3xSP2ZoQpEn_JSs21w4qo0y1ZCDazuPPfQr2iR0QteTnni4XtxrXaKuNOozBgFpG_rqzUIeD_9qc3xMhW8lK9eueiMd0tbisyS3xS-9Wl7JWkMUtauE_HlMppEAU5P3-QXV8VZ1nn6mDirSnGB0PyChrLQJKB4_vcGEFPJqwugZQ4yb_2ymB8w/s784/JSON%20Settings%20Reorder.png" style="display: block; padding: 1em 0px; text-align: center;"><span style="font-family: arial;"><img alt="" border="0" data-original-height="521" data-original-width="784" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhtZSaz3xSP2ZoQpEn_JSs21w4qo0y1ZCDazuPPfQr2iR0QteTnni4XtxrXaKuNOozBgFpG_rqzUIeD_9qc3xMhW8lK9eueiMd0tbisyS3xS-9Wl7JWkMUtauE_HlMppEAU5P3-QXV8VZ1nn6mDirSnGB0PyChrLQJKB4_vcGEFPJqwugZQ4yb_2ymB8w/w640-h426/JSON%20Settings%20Reorder.png" width="640" /></span></a></div><span style="font-family: arial;">
Once the changes are complete, save the file, restart the command prompt, and you'll see the new order of the profiles!
</span><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitiE__bAeEjEZ9sJBKqfogaLaQh8-jq1z4-8AiNJumPOsxbAaOfNu7HJJwdB1j_bctGEFrbgUlqKjoZ5dOpqig1KHIEJxO_-GaRzONxG7jBmQ-VxyJ0m21e2AGwFj5Bp0Qc5GD603vyVFZPjmv2iVW4WzlA8L00xhfHPgazwSeX_D3T4s52AvHxF5GzQ/s446/Windows%20CL%20Profiles%20Updated.png" style="display: block; padding: 1em 0px; text-align: center;"><span style="font-family: arial;"><img alt="" border="0" data-original-height="386" data-original-width="446" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitiE__bAeEjEZ9sJBKqfogaLaQh8-jq1z4-8AiNJumPOsxbAaOfNu7HJJwdB1j_bctGEFrbgUlqKjoZ5dOpqig1KHIEJxO_-GaRzONxG7jBmQ-VxyJ0m21e2AGwFj5Bp0Qc5GD603vyVFZPjmv2iVW4WzlA8L00xhfHPgazwSeX_D3T4s52AvHxF5GzQ/s400/Windows%20CL%20Profiles%20Updated.png" width="400" /></span></a></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-62108060317514895052023-02-13T17:42:00.006-05:002023-02-13T17:44:14.311-05:00The State of JavaScript and Modern Web Client DevelopmentHere is a link to a white paper I wrote named, '<i>The State of JavaScript and Modern Web Client Development</i>.' If you need help navigating the waters at a high-level in the modern web landscape, make sure to check out the article.
<div class="separator" style="clear: both;"><a href="https://medium.com/cognizantsoftvision-guildhall/the-state-of-javascript-and-modern-web-client-development-bb5c34f9a07c" style="display: block; padding: 1em 0; text-align: center;" target="_blank"><img alt="" border="0" width="400" data-original-height="405" data-original-width="720" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDKazZpzb7ZXeQccffAdBQoXzAdX9H0VL5zNYrCgl4zd9jallYbrkanJDeWTpx42tGhWLwRc55Uu5aIZVeB3fh-eXB8F-roBHnMgsuejaBiVgwFIZ5j8dBB3BqUJ4jd69TFh_Wdp61Dnm-6K6_b-4LrvaBUAVycD14RyvkKrBD-FEkhKLDF3baKF6QoA/s400/CSV.webp"/></a></div>
<div style="text-align:center">
<a href="https://medium.com/cognizantsoftvision-guildhall/the-state-of-javascript-and-modern-web-client-development-bb5c34f9a07c" target="_blank"><h3>The State of JavaScript and Modern Web Client Development</h3></a></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-58078171390289967932022-11-07T18:50:00.004-05:002022-11-08T22:32:53.279-05:00Overloaded Methods in TypeScript<p><span style="font-family: arial;">If you've ever worked with a language like C# or Java you're probably often using overloaded method signatures to provide callers with an opportunity to have a similar outcome by passing a different number or type of parameters. However in TypeScript which is just a superset of JavaScript and adhering to all things JS under the covers, method overloading doesn't work the same with identical method names and parameter signature because there are no types to differentiate between. If you have (2) identical methods in JS being called the latter defined method on the prototype will be called, and the former ignored.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirOGZhzJVxBm1Ha5NX-2UdUYnVBoegs99iAyBAN9rNN7F98CqX0_0JC21kcCLGtho4HDG87yaTqQ8aDf-_5mdKZV10fe52wEn2A-H0Ev1k7dDdbroPzdX_0GBWd0uQ0e_4-CQKtE4_bc_1EqXHZA-hCfBxJmmc3GkLulYMIeY_CTBE2gCjkxkZ_g2TbA/s595/JS%20method%20overloading.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="310" data-original-width="595" height="297" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEirOGZhzJVxBm1Ha5NX-2UdUYnVBoegs99iAyBAN9rNN7F98CqX0_0JC21kcCLGtho4HDG87yaTqQ8aDf-_5mdKZV10fe52wEn2A-H0Ev1k7dDdbroPzdX_0GBWd0uQ0e_4-CQKtE4_bc_1EqXHZA-hCfBxJmmc3GkLulYMIeY_CTBE2gCjkxkZ_g2TbA/w568-h297/JS%20method%20overloading.png" width="568" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie3ObeLWLN1oC0dQFtrbWfPVO6NJaReo9tt7sbbX7Zs8YPfJLKtyT9CP1J1EgtHyOwvaGpcOLTXEpOEDBRpF3wI-Tg19YC-jAl-7aeMdX13bTSIxniFeLe9u6fsQdk3huX-V1iX3EPWiezocRakxw7tOAW2gX8YVMEAO94FMvIbz0cQh_BAMD24qfAfw/s483/JS%20method%20overloading%20debugging.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="128" data-original-width="483" height="162" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEie3ObeLWLN1oC0dQFtrbWfPVO6NJaReo9tt7sbbX7Zs8YPfJLKtyT9CP1J1EgtHyOwvaGpcOLTXEpOEDBRpF3wI-Tg19YC-jAl-7aeMdX13bTSIxniFeLe9u6fsQdk3huX-V1iX3EPWiezocRakxw7tOAW2gX8YVMEAO94FMvIbz0cQh_BAMD24qfAfw/w608-h162/JS%20method%20overloading%20debugging.png" width="608" /></a></div><p></p><p><span style="font-family: arial;">TypeScript has the benefit of type definitions <i>at build time</i> so method overloading is possible... kind of. If the goal is to have intellisense to see multiple definitions of the same overloaded method, we can certainly achieve that. If the goal is to have multiple definitions of the same method name with different parameter signatures and separate, different implementations, this out of the box is not possible and won't be like traditionally static typed, structured languages like C#. Regardless let's see how overloading does work in the vanilla form (I'll hint at conditional types at the end) using TypeScript and you can decide if you can leverage for your benefit.</span></p><p><span style="font-family: arial;">The recipe for overloaded methods in TypeScript is that you can create 1...n method signatures, but only have <i>a single implemented method</i> representing any of the possible call combinations. Let's look at a code sample:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ6-TDaT3KJjFouadNc91OxJ17l7d_tHkzkPjUg6AjJLuvwBL5Z0WddaBCBRnRsvDYP2uwHbCozZdDG1GHHIuTRc_WzLXh03c8QAfQscH34VeigV1_hJNgb7gxAs6UuACAPeAPw9jWRVsSijxfNm8u7nKd6aX_IF_RKwa0g6n46JoOgo9XIWWiQd28ew/s839/TS%20Overloaded%20Methods.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="746" data-original-width="839" height="505" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZ6-TDaT3KJjFouadNc91OxJ17l7d_tHkzkPjUg6AjJLuvwBL5Z0WddaBCBRnRsvDYP2uwHbCozZdDG1GHHIuTRc_WzLXh03c8QAfQscH34VeigV1_hJNgb7gxAs6UuACAPeAPw9jWRVsSijxfNm8u7nKd6aX_IF_RKwa0g6n46JoOgo9XIWWiQd28ew/w567-h505/TS%20Overloaded%20Methods.png" width="567" /></a></div><p></p><p><span style="font-family: arial;">Above we have the overloaded method named </span><span style="background-color: #eeeeee; font-family: courier;">start</span><span style="font-family: arial;">, that represents the potential to provide the different procedures to start an engine, based on the various engine types. Note the (5) overloaded method signatures, but only a <i>single</i> implemented method. The reason for this is the overloaded behavior and differentiation of methods is a <i>design</i>/<i>build time only</i> feature available due to the fact we are using TypeScript. In fact if you look at the transpiled JavaScript the <i>only</i> method shown is the single implemented method:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQLGE7n1gqZ0BL_JYGk7QsSWDoC-liWJNbcZPkB9KYcZKBdMXC8UVQpS71dKKj9lwElySmgOMDlcKoVnNzR3bSKsKaE9GEykqGojloeoJZpdY_FfqVbb0LwPs3otHSloxNP80wuu2Mr0viT7nRxQc-wNipnsmpQ8FGXBZ6xxK4KnBIKOwAHzNR6f9cwg/s852/JS%20Transpiled%20Overloaded%20Methods.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="507" data-original-width="852" height="321" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQLGE7n1gqZ0BL_JYGk7QsSWDoC-liWJNbcZPkB9KYcZKBdMXC8UVQpS71dKKj9lwElySmgOMDlcKoVnNzR3bSKsKaE9GEykqGojloeoJZpdY_FfqVbb0LwPs3otHSloxNP80wuu2Mr0viT7nRxQc-wNipnsmpQ8FGXBZ6xxK4KnBIKOwAHzNR6f9cwg/w541-h321/JS%20Transpiled%20Overloaded%20Methods.png" width="541" /></a></div><p></p><p><span style="font-family: arial;">If you do try and use implementations on more than 1 method with the same name, TypeScript will warn you with a, "</span><span style="background-color: #eeeeee; font-family: courier;">Duplicate function implementation</span><span style="font-family: arial;">" warning.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJShLueKNzTQ5Ew7E_yCaqdSLpsi5gWAPe-DuLv8PfKkyVqAMARrzfXom7ClPiXWfDEHbK9bPcvYeh_8Lj7UXF7wK7l14El5Yszb5Ep0Ppo9p9YcAm9qFCFWiCIRwGukRRYhljidsyyAH2Ciqde2zw8ZHMVKXbE3F6FbBCHk--HtwxEcQlSVBfFcmJ9g/s807/TS%20Duplicate%20Function%20Declaration.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="209" data-original-width="807" height="148" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJShLueKNzTQ5Ew7E_yCaqdSLpsi5gWAPe-DuLv8PfKkyVqAMARrzfXom7ClPiXWfDEHbK9bPcvYeh_8Lj7UXF7wK7l14El5Yszb5Ep0Ppo9p9YcAm9qFCFWiCIRwGukRRYhljidsyyAH2Ciqde2zw8ZHMVKXbE3F6FbBCHk--HtwxEcQlSVBfFcmJ9g/w569-h148/TS%20Duplicate%20Function%20Declaration.png" width="569" /></a></div><p></p><p><span style="font-family: arial;">Looping back to our original goal using the properly implemented code, as the method caller </span><span style="font-family: arial;">if we want to see</span><span style="font-family: arial;"> </span><i style="font-family: arial;">at design time</i><span style="font-family: arial;"> a list of the various signatures, we have indeed accomplished that goal as you may scroll through and see the multiple, overloaded definitions:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiygdEm7lTPS1_ub3kQzPXms687Es50ZUSE1JgDraKVV9NWpCl9nrkvbP4OTM8Z_RPab4vHfXjXWKBL-pwo_Oumg4V9oUvI6O7u0ROSvSOUL3R4dusCAPFmeslOY10s_VFZFS83PSibmOyE3SM1t547WicJltskft7NRvHcv4BXcuC06xdZltXhWhOsbw/s700/TS%20Overloaded%20Methods%20IDE.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="127" data-original-width="700" height="107" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiygdEm7lTPS1_ub3kQzPXms687Es50ZUSE1JgDraKVV9NWpCl9nrkvbP4OTM8Z_RPab4vHfXjXWKBL-pwo_Oumg4V9oUvI6O7u0ROSvSOUL3R4dusCAPFmeslOY10s_VFZFS83PSibmOyE3SM1t547WicJltskft7NRvHcv4BXcuC06xdZltXhWhOsbw/w589-h107/TS%20Overloaded%20Methods%20IDE.png" width="589" /></a></div><p></p><p><span style="font-family: arial;">However this comes at a bit of a sloppy cost for that single implemented method. In order to make this work the method signature must encapsulate <i>all</i> potential values that <i>could</i> be sent to satisfy the TypeScript compiler. This usually equates to using a Union type in the method signature to account for all possible types. The next hurdle is because overloaded methods are really a façade, you must manually pick apart what's sent and reverse engineer what you received at runtime. This usually equates to type guards, if statement, switch statements, or some combination to sniff out what you received, so you can proceed forward. All of this logic is that code above within our implemented method to determine <i>what exactly</i> we received.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRH7ItB68PAhqmjFDlZ9pgg4wrD_1P2LS9i4hK-PLPz_Tj2WDnSXFc7oTH6wfv1KewH30AZ8_nPxqbPXmefssjraO_TWR3jqQEi-lP17JjzCthQB9RHz_WUHmMK6i1sg4Sen7cp4t3AgfudVyLYJbczlhWTjPAn3o_53QlBfZreJhWwYoYQk8LJ78Y5w/s805/TS%20Determine%20type.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="255" data-original-width="805" height="184" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRH7ItB68PAhqmjFDlZ9pgg4wrD_1P2LS9i4hK-PLPz_Tj2WDnSXFc7oTH6wfv1KewH30AZ8_nPxqbPXmefssjraO_TWR3jqQEi-lP17JjzCthQB9RHz_WUHmMK6i1sg4Sen7cp4t3AgfudVyLYJbczlhWTjPAn3o_53QlBfZreJhWwYoYQk8LJ78Y5w/w584-h184/TS%20Determine%20type.png" width="584" /></a></div><p></p><p><span style="font-family: arial;">It's even trickier to determine what's sent if you have (2) identical method signatures that are only differentiated by variable name like our 1st two methods below. This is not advisable even though it does work:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjISxWtpVEfxDwRJ3o8PvxdeaTF8xe2JTNonGoXQLuWkKoz_Mk0H2ZYbt8f622VzGup5pz_p1tBemUKh0HHSvLQKdZrYFtqa3oBjCQah_Al5k3-NUi53lRP-iTqO-D6x9AzPSNVe-lbwyR85X_Ti5ICgZoHSs4aVc3WSD5kKmwtASf9_yOyauHFJzeiXA/s599/TS%20Identical%20Overloaded%20methods.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="48" data-original-width="599" height="49" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjISxWtpVEfxDwRJ3o8PvxdeaTF8xe2JTNonGoXQLuWkKoz_Mk0H2ZYbt8f622VzGup5pz_p1tBemUKh0HHSvLQKdZrYFtqa3oBjCQah_Al5k3-NUi53lRP-iTqO-D6x9AzPSNVe-lbwyR85X_Ti5ICgZoHSs4aVc3WSD5kKmwtASf9_yOyauHFJzeiXA/w612-h49/TS%20Identical%20Overloaded%20methods.png" width="612" /></a></div><p></p><p><span style="font-family: arial;">The long and the short of method overloading in TypeScript is that it <i>is</i> possible, but with a few caveats that may not make it sensible. I think if you only have (2) different method signatures, that are easily discernable at runtime in the implemented code, then this might make sense. However as the signature list expands, the logic to differentiate the potential values sent can get unwieldly. </span></p><p><span style="font-family: arial;">Lastly another potential option may be to use conditional types in the method signatures which rely on generics to sort out the types based on what the caller is sending. This could reduce the need for the implemented method to contain all the logic to sort out <i>which</i> values it was sent as it will be know already. However in this post I wanted to strictly do a 1:1 look at the concept of overloading as it may be known from other languages, and how it can be accomplished in TypeScript.</span></p>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-67241020289779649752022-10-26T10:56:00.000-04:002022-10-26T10:56:02.322-04:00How to View Deployed Files for a Web App Using the Azure Portal<p><span style="font-family: arial;">When debugging a web app and tracking down problems, especially newly created and deployed apps that aren't working, sometimes all that's needed is to look and see what's deployed to help determine the issue. This is trivial to do using the <b>App Service Editor</b> available from the Azure Portal.</span></p><p><span style="font-family: arial;">Once logged into the portal, navigate to the website or specific deployment slot of the app where you'd like to browse the files. Viewing the menu of options on the left-hand side, select <b>App Service Editor</b>:</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8oDHLFCgkMjZ76uHFjptvJITROkflRMtfwNURX7wtMQzYH5Ya0EdeIJ0BLBD8RUlJR-j4ePJGY4SZoNE-ytAYtbpT-xJJmYupkHdPkH_guBCqYKeYZG1NGjIk-zaHhZE5P76q_jcDeAlr5l8OOVLVU0b4oMKQdr7mJiOX2uLq_ZU4DWhj0q2whO8MMg/s375/Azure%20App%20Service%20Editor.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="375" data-original-width="304" height="418" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8oDHLFCgkMjZ76uHFjptvJITROkflRMtfwNURX7wtMQzYH5Ya0EdeIJ0BLBD8RUlJR-j4ePJGY4SZoNE-ytAYtbpT-xJJmYupkHdPkH_guBCqYKeYZG1NGjIk-zaHhZE5P76q_jcDeAlr5l8OOVLVU0b4oMKQdr7mJiOX2uLq_ZU4DWhj0q2whO8MMg/w338-h418/Azure%20App%20Service%20Editor.png" width="338" /></a></div><p></p><p><span style="font-family: arial;">This will redirect to a location in a new browser tab which will show the folder structure and physical files present. </span><span style="font-family: arial;">Within the utility there are other useful functions available along the left-hand side in addition to the logging output to help diagnose and have insight into your deployed site.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf-BzNl_ZmdO0MxfjUWT1jjyGg2qIUsO3r4gLC52rYidqT-SVf0UsmIk6ClT3PapUDBh0YqZ-SqfIIuzm-urhxkTjfkFtVy1SNAr6jBjwlprzwpBL8hU8V7aqMgnE-t6Yy8QvJPvjdoc8dD3QDh7bkaEDjCJ7_1FAuyTvgUTSD0MTcmN_WChHPH9pIzA/s758/Azure%20App%20Service%20Editor%20utility.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="463" data-original-width="758" height="343" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgf-BzNl_ZmdO0MxfjUWT1jjyGg2qIUsO3r4gLC52rYidqT-SVf0UsmIk6ClT3PapUDBh0YqZ-SqfIIuzm-urhxkTjfkFtVy1SNAr6jBjwlprzwpBL8hU8V7aqMgnE-t6Yy8QvJPvjdoc8dD3QDh7bkaEDjCJ7_1FAuyTvgUTSD0MTcmN_WChHPH9pIzA/w563-h343/Azure%20App%20Service%20Editor%20utility.png" width="563" /></a></div><p></p><p><span style="font-family: arial;">This feature is still in 'Preview' mode so expect some changes over time to the utility, possibly being renamed, and on occasion being down. As noted you can always FTP into the directory as well as a secondary option.</span></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh06IL4mrNSwItUNndWHMXNQcmg7FNhJU-DvFmcZRubs1T8ewyaaoeNGnboUMAa5nxWCj5x97GN8N-Hmy-HKzOxbJzApJiFq1356s08FmFznuZOxpwUyZRAcUc9LwLWe7XFr3cgnSmWNbfbpUeuKes69cBLZ0m_ZFAqI2UtMfH7OrCm55Xbm5DZZ8jYHA/s891/Azure%20Service%20Editor%20down.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="317" data-original-width="891" height="202" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh06IL4mrNSwItUNndWHMXNQcmg7FNhJU-DvFmcZRubs1T8ewyaaoeNGnboUMAa5nxWCj5x97GN8N-Hmy-HKzOxbJzApJiFq1356s08FmFznuZOxpwUyZRAcUc9LwLWe7XFr3cgnSmWNbfbpUeuKes69cBLZ0m_ZFAqI2UtMfH7OrCm55Xbm5DZZ8jYHA/w568-h202/Azure%20Service%20Editor%20down.png" width="568" /></a></div><br /><p><br /></p>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-57097692370305958392022-10-19T18:03:00.009-04:002022-10-26T10:56:49.360-04:00Generate YAML from an Existing Azure DevOps Pipeline<p><span style="font-family: arial;">Here's a quick tip if needing to generate a .yml file for CI/CD configuration from an existing Azure DevOps pipeline. There are several ways to build the .yml configuration file:</span></p><p></p><ul style="text-align: left;"><li><span style="font-family: arial;">Make one from scratch</span></li><li><span style="font-family: arial;">Use a template from GitHub or another similar project</span></li><li><span style="font-family: arial;">Use the AzureDevOps pipeline editor and assistant</span></li><li><span style="font-family: arial;">Use an auto-generated one created from a cloud portal (i.e. Azure portal)</span></li></ul><div><span style="font-family: arial;">However if the above solutions or any other aren't providing to be fruitful to your deployment configuration, you can leverage the <i>classic editor</i> from ADO to create a pipeline configuration visually via steps. This is often a means to an end to get working syntax in a methodical manner via form input, rather than through raw configuration.</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQUrbQyGEH8vdCLvsRIC3C7CcmPc6foHi_pMeGNOc9pmQjGvstt1dvN_3wwUZui_ocy3Bk6SMJdLkFxoYR611lfXXZdcEicjiQ-XFKHnJtxrZlrrZB96Gzk8tbQahjxAXOsLyOlCgwwajYIAeOOgKkl3YIeLibWCxcvwaMjEvqciLsZ4PPIn_JbW4ZbQ/s620/ADO%20Classic%20Editor.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="561" data-original-width="620" height="426" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQUrbQyGEH8vdCLvsRIC3C7CcmPc6foHi_pMeGNOc9pmQjGvstt1dvN_3wwUZui_ocy3Bk6SMJdLkFxoYR611lfXXZdcEicjiQ-XFKHnJtxrZlrrZB96Gzk8tbQahjxAXOsLyOlCgwwajYIAeOOgKkl3YIeLibWCxcvwaMjEvqciLsZ4PPIn_JbW4ZbQ/w470-h426/ADO%20Classic%20Editor.png" width="470" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDhYQVLsrdswz1QoIdolFZdLPQ-_6udE6FikkCXXQtWgyPQSLnNVtwhlLcLOmYmfm3EvL40G6OQ1lj1ZX5lUryaSr-z_S6xegLXobMABQK7tLkpXfygOemEcHv8mor0tVoJRZe5kUGowGj1DcC1hNuQ_todU1V8AxS-3PwectMZZ2c1jHFhTwZJvpkOw/s640/ADO%20Pipeline%20Steps.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="368" data-original-width="640" height="273" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDhYQVLsrdswz1QoIdolFZdLPQ-_6udE6FikkCXXQtWgyPQSLnNVtwhlLcLOmYmfm3EvL40G6OQ1lj1ZX5lUryaSr-z_S6xegLXobMABQK7tLkpXfygOemEcHv8mor0tVoJRZe5kUGowGj1DcC1hNuQ_todU1V8AxS-3PwectMZZ2c1jHFhTwZJvpkOw/w474-h273/ADO%20Pipeline%20Steps.png" width="474" /></a></div><br /></div><div><span style="font-family: arial;">Once you have a working pipeline however, it's ideal to get this configuration into your GitHub repository. This allows source control tracking on the configuration which is preferred to a pipeline used in a vacuum. If you used the classic editor to build a working pipeline, generating a .yml configuration is trivial. </span></div><div><br /></div><div><span style="font-family: arial;">In ADO, navigate to the pipeline and find the ellipse next to, '<b>Run Pipeline</b>.' From this menu you'll see an option to, '<b>Export to YAML</b>.'</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMXO_x05tTkzF8o6YcVTlFTL5lHjP46g0xsuJmhv1pvsjUAuvs_LBTl4rCUP-A91NohyqtFUauo_jJlLODY7E7aucJMhp9D6tEUEzhRf6h8KewD7bzCMLPJjxHq-kh2IWn96B28H10dZgQHr313ZJ2L9N_lFAjlYHveIaImnDcKy1EId_u_Z99hZHJ2g/s498/ADO%20Export%20to%20YAML.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="498" data-original-width="267" height="479" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMXO_x05tTkzF8o6YcVTlFTL5lHjP46g0xsuJmhv1pvsjUAuvs_LBTl4rCUP-A91NohyqtFUauo_jJlLODY7E7aucJMhp9D6tEUEzhRf6h8KewD7bzCMLPJjxHq-kh2IWn96B28H10dZgQHr313ZJ2L9N_lFAjlYHveIaImnDcKy1EId_u_Z99hZHJ2g/w257-h479/ADO%20Export%20to%20YAML.png" width="257" /></a></div><br /></div><div><span style="font-family: arial;">This will generate a .yml configuration file based on your working pipeline.</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA4sYZRs-QWMecu3j70ITlPOT8EATOQ620c2XnHH2emaYYlag70Mc7NT1q7g5J2tj1cijEvITc9fvi8RZnmTCcRyKKBUT4SmbSIyFlH0aAcmOg-INITCaZu6o4d-i2f1M57ixx4_FKvkmAxKJQ2YlOAr224gzO6d0yClkC1c6VADRtHwOxK-O_ATSSGw/s552/YAML%20Sample.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="432" data-original-width="552" height="305" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjA4sYZRs-QWMecu3j70ITlPOT8EATOQ620c2XnHH2emaYYlag70Mc7NT1q7g5J2tj1cijEvITc9fvi8RZnmTCcRyKKBUT4SmbSIyFlH0aAcmOg-INITCaZu6o4d-i2f1M57ixx4_FKvkmAxKJQ2YlOAr224gzO6d0yClkC1c6VADRtHwOxK-O_ATSSGw/w391-h305/YAML%20Sample.png" width="391" /></a></div></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">At this point you could add the .yml file to source control and create a <i>new</i> Azure pipeline connecting to your source control provider that leverages the newly created file.</span></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;">Note different deployment systems use different YAML syntax or 'actions' so this may not be directly portable to another workflow for deployment. For example the</span><span style="font-family: arial;"> </span><b style="font-family: arial;">.github/workflows</b><span style="font-family: arial;"> directory in GitHub can connect to the repo from the Azure Portal in the Deployment configuration and use a .yml file. However the syntax is different for GitHub Actions, so the .yml file downloaded would only be a guide and require further massaging.</span></div><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOBzUjPFv_M7nElJOnAkj832ln_Oyca1aVnx9ZySDF7UjdB0CGdsSZr9me4z2UPynAAWnkWspnkq8D7JTPyXYFZuSu8FMY5u5qspNXhMcEOAF5Cw3kY5xM08Z9zRhrS-Crd4EWUoJqJ_FotYRMD9QGKq7XAfUgPf0k888LFaFHatc-sLOinT0An-M5ug/s1083/GitHub%20Actions.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="326" data-original-width="1083" height="172" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhOBzUjPFv_M7nElJOnAkj832ln_Oyca1aVnx9ZySDF7UjdB0CGdsSZr9me4z2UPynAAWnkWspnkq8D7JTPyXYFZuSu8FMY5u5qspNXhMcEOAF5Cw3kY5xM08Z9zRhrS-Crd4EWUoJqJ_FotYRMD9QGKq7XAfUgPf0k888LFaFHatc-sLOinT0An-M5ug/w574-h172/GitHub%20Actions.png" width="574" /></a></div><span style="font-family: arial;"><br /></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyS4E_XfWzvXFyMmaV0l8VvjzUgB259BW2lJwBQrHAciEolH6rRaFWwvc0QJZZHgO4Sak4bK5oKUZMOcinYbVef_HUKk_gBmSCka5BmdKxIAHwPfEdJwfl48D8jzfBOOjODqX9nSp7F-84LtNBr2w1gMdHA3KDjgItoyPRXtiw35Apd2o9SIHWf4Y2Qg/s717/Azure%20Deployment%20GitHub%20Actions.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="611" data-original-width="717" height="499" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyS4E_XfWzvXFyMmaV0l8VvjzUgB259BW2lJwBQrHAciEolH6rRaFWwvc0QJZZHgO4Sak4bK5oKUZMOcinYbVef_HUKk_gBmSCka5BmdKxIAHwPfEdJwfl48D8jzfBOOjODqX9nSp7F-84LtNBr2w1gMdHA3KDjgItoyPRXtiw35Apd2o9SIHWf4Y2Qg/w585-h499/Azure%20Deployment%20GitHub%20Actions.png" width="585" /></a></div><br /><p></p>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-2073706050996134922022-10-18T13:17:00.001-04:002022-10-26T10:56:28.946-04:00How to Activate an Azure Monthly Credit With Another Account When Subscription Login Denies Benefit<span style="font-family: arial;"><b>Scenario:</b> You've been assigned Visual Studio Subscription (AKA MSDN subscription back in the day) by your organization, and would like to activate your free $150 (or similar) credit. Upon attempting the credit you get an error along the lines of, "You're not eligible with this benefit. Your organization does not allow activating this benefit." </span><span style="font-family: arial;">However you know the Azure credit is a benefit as it's listed as such on your subscription. Why an organization would block this benefit, I'm not sure nor how to inquire about resolving, but there's a simple solution.</span><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;"><b>Context:</b> You switch companies, switch emails, a subscription expires, another is activated. This inconsistency creates havoc for your personal development and OSS work as all of your Azure resources have to be recreated over and over for new subscriptions (Note: moving resources is typically not an option as you can only do this across the <i>same</i> underlying subscription; see: <a href="https://github.com/MicrosoftDocs/azure-docs/blob/main/articles/azure-resource-manager/management/move-resource-group-and-subscription.md" target="_blank">Move Azure Resources</a>). Now you've gone to login to your new subscription to use the Azure credit, and the benefit isn't allowed to be activated. Ideally you have a single, static, non-changing account login that you can associate varying subscriptions with over the years. The recommendation IMO is to use your personal GitHub login to associate Azure credits for 1...n Visual Studio Subscriptions. <br /></span><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;"><b>Solution:</b> You can add an 'Alternate Account' to your Visual Studio subscription, that can be assigned the credit instead to associate with your current subscription. </span></div></div><div><span style="font-family: arial;"><br /></span></div><div><span style="font-family: arial;"><b>Breakdown:</b></span></div><div><ol style="text-align: left;"><li><span style="font-family: arial;">Log into your active and current Visual Studio subscription. Under the 'Benefits' tab there will be a box to active your Azure monthly credit:</span></li><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxzukE9Z_69HzBfC0N_dh1wPl1FFw5y1P6Fj7LHNm9fnyRcx1jXng5AVYsn66lsW5LocF-45HR2JGc50X2XGDGlCvbLqqUy3cjU5sUptKisXCq9BWOb7iEhHpbifKDQTJNn6ln5S-SZqGbBezR52YK4FerOUc-pPw0HrtGqqqEDPAACxF-ngwSng13ug/s639/Azure%20Credit%20Benefit.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="298" data-original-width="639" height="200" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgxzukE9Z_69HzBfC0N_dh1wPl1FFw5y1P6Fj7LHNm9fnyRcx1jXng5AVYsn66lsW5LocF-45HR2JGc50X2XGDGlCvbLqqUy3cjU5sUptKisXCq9BWOb7iEhHpbifKDQTJNn6ln5S-SZqGbBezR52YK4FerOUc-pPw0HrtGqqqEDPAACxF-ngwSng13ug/w430-h200/Azure%20Credit%20Benefit.png" width="430" /></a></div><div style="text-align: center;"><br /></div><li><span style="font-family: arial;">Upon selecting 'Activate' you'll be presented with a Microsoft login to proceed to the Azure Portal. If you select logging in with your organization's login which is the same as your Visual Studio subscription login, you get an error that the benefit is not allowed to be used for this ID: </span></li><div><div class="separator" style="clear: both; text-align: center;"><br /></div></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdcWgj8i_3Jjrwc91TLQFR1GWB-TpJCXZN2eS2zNbxrqzkIUq9OVZfsp0XtTdNw3cNhYFtGWoJrOjEc_Nfqw98n70Z2w3MqTpkAPX2sylwq9OxlMineLd4uydlGEDf2Gq3ud4llOUZOqFfXaVF8B-AoGjW3cRXSVMshrHZiBUNfAHj9QKfuhb1OFa_Ew/s637/Azure%20not%20eligable.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="92" data-original-width="637" height="58" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdcWgj8i_3Jjrwc91TLQFR1GWB-TpJCXZN2eS2zNbxrqzkIUq9OVZfsp0XtTdNw3cNhYFtGWoJrOjEc_Nfqw98n70Z2w3MqTpkAPX2sylwq9OxlMineLd4uydlGEDf2Gq3ud4llOUZOqFfXaVF8B-AoGjW3cRXSVMshrHZiBUNfAHj9QKfuhb1OFa_Ew/w400-h58/Azure%20not%20eligable.png" width="400" /></a></div><span style="font-family: arial;"><br /></span></div><li><span style="font-family: arial;">Back in Visual Studio subscriptions, head over to the 'Subscriptions' tab:</span></li><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu0kk9n8eyw56fSmwss_z79FdrQN3VBHaY38QPAQa4boYc1xHRQ9RY8mQN-_ytuy6XtOzR2aNIptFZQ1jvglc5kUjgPxNlqTXSy7a4unFGZfrfaSqsLNaFPEeY2C98UYgNYZAThVZWsj3jwT89-qN8tE4ciCvePFzqjhkWdfLMYVVt8pM-ukTlBpf7Hw/s851/VS%20Subscriptions.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="291" data-original-width="851" height="166" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiu0kk9n8eyw56fSmwss_z79FdrQN3VBHaY38QPAQa4boYc1xHRQ9RY8mQN-_ytuy6XtOzR2aNIptFZQ1jvglc5kUjgPxNlqTXSy7a4unFGZfrfaSqsLNaFPEeY2C98UYgNYZAThVZWsj3jwT89-qN8tE4ciCvePFzqjhkWdfLMYVVt8pM-ukTlBpf7Hw/w489-h166/VS%20Subscriptions.png" width="489" /></a></div><span style="font-family: arial;"><br /></span><li><span style="font-family: arial;">Add an alternate email that you'd like to associate with your Azure credit. Essentially this allows using that credit, with another valid Microsoft or SSO login. My <i>suggestion</i> is to associate the email with your personal GitHub login. This will help set you up in the future to be able to re-associate new subscriptions with the same login to ease transition. Note - whichever account you choose, this whole process will be much easier if it's already established as a Microsoft account and have previously logged into the Azure portal (https://portal.azure.com/). </span></li><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjM3Oei5EjkAGjN7dA4dqvf7Z5EbO_wTOzLyaafHuLEDqPKBD12Rgn5a80mDe9239KbwvjgZ2cvm2sc_iNzogc7o8-_At5js3ywX8C0PHBqZYoJDK2Q58RAlVjTbodLY-m-fmTg92pCn56RTBLlyqI-iSCfCncVa6UtfolGxP9H44QGDsyyoeJ30LIWg/s1311/VS%20Subscriptions%20Azure%20Alternate%20Email.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="718" data-original-width="1311" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjM3Oei5EjkAGjN7dA4dqvf7Z5EbO_wTOzLyaafHuLEDqPKBD12Rgn5a80mDe9239KbwvjgZ2cvm2sc_iNzogc7o8-_At5js3ywX8C0PHBqZYoJDK2Q58RAlVjTbodLY-m-fmTg92pCn56RTBLlyqI-iSCfCncVa6UtfolGxP9H44QGDsyyoeJ30LIWg/w585-h320/VS%20Subscriptions%20Azure%20Alternate%20Email.png" width="585" /></a></div><span style="font-family: arial;"><br /></span><li><span style="font-family: arial;">After adding the alternate email, go back to the 'Benefits' tab and press 'Activate' for the Azure credit again (Step #1). This time when presented with the login, use the <i>alternate email </i>credentials. For a GitHub login, select 'Sign on options' and SSO authenticate with GitHub. If you used another Microsoft login as the alternate account, use those credentials.</span></li><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOYlptx_0rkbUyb5JSQawjwX5oEEqvA_h0vCaEvNApp2xQQPV7Ad3dUz_0RCknuU0nq4fb8hBkx1Au0CTlh-WmAlHYXWI5mxWj1zS0NKVbqoRh9g8KV0-jzzG8pNQJaViYnd8itL_3ACN0T-96oPBXUIBW9INvkmo6UajTPgwWB4oWSqBGp0v5YQHYKg/s521/Azure%20Portal%20Sign%20On.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="521" data-original-width="499" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOYlptx_0rkbUyb5JSQawjwX5oEEqvA_h0vCaEvNApp2xQQPV7Ad3dUz_0RCknuU0nq4fb8hBkx1Au0CTlh-WmAlHYXWI5mxWj1zS0NKVbqoRh9g8KV0-jzzG8pNQJaViYnd8itL_3ACN0T-96oPBXUIBW9INvkmo6UajTPgwWB4oWSqBGp0v5YQHYKg/s320/Azure%20Portal%20Sign%20On.png" width="306" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiczuw8-enGFRCdAD34uxX2wf0kSqtdC0pdLD8iZxNoIJK5IoZjxQv_tngLnhuuoSyLI1VACa6twcefphqI6rrbZWCe8zv61dJ778CF2HLiTk9WYSabKiZl79qbu5GBe4N_u5LgleX-d8FOuCXrLl3JCDJcsibeckRXcR4iofjVDn1gGtS5vr6KP-CqFg/s513/Azure%20GitHub%20SSO.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="482" data-original-width="513" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiczuw8-enGFRCdAD34uxX2wf0kSqtdC0pdLD8iZxNoIJK5IoZjxQv_tngLnhuuoSyLI1VACa6twcefphqI6rrbZWCe8zv61dJ778CF2HLiTk9WYSabKiZl79qbu5GBe4N_u5LgleX-d8FOuCXrLl3JCDJcsibeckRXcR4iofjVDn1gGtS5vr6KP-CqFg/s320/Azure%20GitHub%20SSO.png" width="320" /></a></div><span style="font-family: arial;"><br /></span><li><span style="font-family: arial;">If you get a login error regarding STS or federation error (i.e. AADSTS900043 or similar), just close the browser tab and reopen portal.azure.com. This seems to be a 1-off issue with the handshake and has nothing to do with this overall process.</span></li><div class="separator" style="clear: both; text-align: center;"><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3GndzVW1kYALjSmyTyF80aVZOGVsNblYJFoIDG1mp8glAKleiXByto3rO3ohOCAmGTEGAEeDo1c7bcPJsJtEEwgHQMHLivglD2gBFHDhoNr_GNo8QLiUWuFhYkhpVF41E6Uk-U245ikleCjgFJ_Yx9zrbZxrmkYsE8wYaJmYHrLZSY-YWsKhlUehLjA/s666/Azure%20GitHub%20SSO%20Error.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="360" data-original-width="666" height="232" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3GndzVW1kYALjSmyTyF80aVZOGVsNblYJFoIDG1mp8glAKleiXByto3rO3ohOCAmGTEGAEeDo1c7bcPJsJtEEwgHQMHLivglD2gBFHDhoNr_GNo8QLiUWuFhYkhpVF41E6Uk-U245ikleCjgFJ_Yx9zrbZxrmkYsE8wYaJmYHrLZSY-YWsKhlUehLjA/w430-h232/Azure%20GitHub%20SSO%20Error.png" width="430" /></a></div><span style="font-family: arial;"><br /></span><li><span style="font-family: arial;">Once successfully logged in your Azure monthly credit will be applied to the alternate email ID login you configured. To check the status, you can view your subscription(s) from the 'Settings.' </span></li><br /><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjTJ5h6Onm60yjo8I702mMWZigF2MBha-SkCNhS4_vCu8guhqJ2ztPyXyscIVLxL1k1562O8kxkJ68De4ITzjQVpKjWDIF8sJN8ON8kHTjMSVgInTDzhL4ZsQNZB4ZFEPtJn6CAG-M9Uii_bo1MSOZIIYI7ogHWyXL6Dae-MEggElT5w9lHd3CUpE19g/s1035/Azure%20Portal%20Subscriptions.png" style="margin-left: 1em; margin-right: 1em; text-align: center;"><img border="0" data-original-height="317" data-original-width="1035" height="180" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhjTJ5h6Onm60yjo8I702mMWZigF2MBha-SkCNhS4_vCu8guhqJ2ztPyXyscIVLxL1k1562O8kxkJ68De4ITzjQVpKjWDIF8sJN8ON8kHTjMSVgInTDzhL4ZsQNZB4ZFEPtJn6CAG-M9Uii_bo1MSOZIIYI7ogHWyXL6Dae-MEggElT5w9lHd3CUpE19g/w589-h180/Azure%20Portal%20Subscriptions.png" width="589" /></a></ol></div><div class="separator" style="clear: both; text-align: center;"><span style="font-family: arial;"><br /></span></div><span style="font-family: arial;">One final note - once this process is done and as expected, if you try and activate again with another login (i.e. your organization's login, another email, etc.), you'll be presented with the message that this benefit is already used and can't be activated again. I'm not sure on how to re-link the monthly credit, so ensure the login you setup is the one you want to use.</span><div><span style="font-family: arial;"><br /></span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib5ZU3kUQritpsmAklZWPPxLZjid7_JGKZKP_47obr5aO3Hv7hp-NizEFBXyX4SH1NRqhWTSAM4BY6LPQ0s5JyXjxO9kGMBsuyVQlSj01TrRrbml3TielwezHUCLI_9Fd_uGa8lspvMr_As2DeTrzRTx8d6h6rino2G44OsDMrG7sHb3DXqNmR6Oum7g/s766/Azure%20cant%20regiister%20more%20than%201%20time%20credit.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="274" data-original-width="766" height="190" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEib5ZU3kUQritpsmAklZWPPxLZjid7_JGKZKP_47obr5aO3Hv7hp-NizEFBXyX4SH1NRqhWTSAM4BY6LPQ0s5JyXjxO9kGMBsuyVQlSj01TrRrbml3TielwezHUCLI_9Fd_uGa8lspvMr_As2DeTrzRTx8d6h6rino2G44OsDMrG7sHb3DXqNmR6Oum7g/w533-h190/Azure%20cant%20regiister%20more%20than%201%20time%20credit.png" width="533" /></a></div><br /><span style="font-family: arial;"><br /></span></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-31677644951589420122020-12-04T17:08:00.003-05:002020-12-04T17:22:56.769-05:00The Absence of Pattern Thinking for Web Client Code<p><span style="font-family: arial;">With 20 years of experience as a software engineer moving through the stack and using a lot of different languages throughout the years, I've seen a lot of good and conversely poor development implementations. I've also had the privilege of being able to work with languages (like C#) that placed a heavy emphasis as a community in enterprise development around the mindset of using patterns and practices to make code more readable, reusable, and easier to communicate redundant and repeatable ways of creating applications and services. This has helped me immensely and provided me with a mindset on how to think and truly engineer a well built solution.</span></p><h3 style="text-align: left;"><span style="font-family: arial;">The priority of pattern thinking is missing</span></h3><p><span style="font-family: arial;">The problem I've seen over the last 5-10 years as a primarily focused JavaScript web client developer is the absence of this type of thinking. So much of the code I see written is just jammed into a file as a means to an end to complete a needed goal. I think unfortunately the explosion in JavaScript development and rapidly created JS developers due to demand has been partly to blame. I also think there has been so much focus on, "which framework/library," that has had a byproduct of having to learn so much just to get code implemented, that pattern thinking is just not at the forefront. Plain and simple there hasn't been time to organize thoughts or thinking around a sound architectural implementation using known patterns when the web client developer is just trying to get their head above water learning the framework, array of JS libraries, state management, CSS, responsive design, offline capabilities, mobile-like features, new work, enhancements, etc.. This in contrast to more stable back end languages that have had similar implementations going on for decades (albeit with new ways to wrap code or deploy; i.e. cloud) where the tenured experience has helped provide an environment where pattern thinking is much more prominent. I know this to be true, because I've been on that side of the fence as well.</span></p><h3 style="text-align: left;"><span style="font-family: arial;">Has it always been this way?</span></h3><p><span style="font-family: arial;">This isn't to say there has never been a focus on pattern for front-end code. Industry leaders such as John Papa were advocating for the module and reveling module patterns with ES5 code years ago, and even today alongside Dan Wahlin to carry the flag for architecting Angular apps and having a mindset for patterns and practices. Therefore a voice does exist from advocates for sound and well written code, but overall I just don't see the concrete evidence as much as I did when working with server-side code in C#/.NET. </span></p><p><span style="font-family: arial;">It's time we as a web client community when building enterprise web application push harder to use some forethought into <i>how</i> we implement our code borrowing concepts from known patterns and practices. It's not enough just to cram thousands of lines of code into a monolithic style .js/.ts file. This as an aside is one reason I'm not a <i>huge </i>fan of CSS in JS because it adds to desegregation of code and cramming everything into a single file. I don't consider myself old school to like separation of concerns (SoC), as it's really about organization of thought and practice. Much like the UI web component code we like to implement today with a mindset around segregating code into smaller, cohesive pieces of functionality, we must too apply that same style of thinking to the imperative code we write in JavaScript/TypeScript.</span></p><h3 style="text-align: left;"><span style="font-family: arial;">A high-level use case</span></h3><p><span style="font-family: arial;">Let me cherry pick a scenario I see more often than not in Angular. At a high-level speaking broadly, most modern Angular code has a thin service code file that makes an API call, and immediately returns an Observable with the result. The real result is that data is consumed and subscribed to in the component, and <i>all</i> presentation logic, data massaging, and appropriate (or sometimes inappropriate because it's IP) business logic is <i>all</i> done in said component. The result? A massive multi-thousand line big-ball-of-mud that's out of control and really difficult to maintain. It didn't start that way, right? The <i>original </i>MVP implementation was just a simple return and binding of data. However like any software that evolves, so does the need for more code and the initial pattern set forth, is scaled good or bad. In this case bad, and the component is out of control.</span></p><p><span style="font-family: arial;">What if though something like the Command Pattern (or ideas from it) had be used from the inception? The component only acts as an air-traffic controller of sorts; it doesn't really know how to do anything except direct the traffic. It assembles all needed information, builds up and executes the command on the service where the real work happens (in 1..n services). This pattern also lends itself to creating immutable models in the component and they are only ever changed in the service. The service streams the data from an Observable, and all the component does (with minor exceptions) is bind to the new data. This is a much cleaner approach and a highly repeatable pattern for any experience level. Even if this particular approach seems heavy as you're building a smaller application, knowing patterns and their purpose for use will <i>still</i> lend your design ideas about how to better implement and organize your code. </span></p><p><span style="font-family: arial;">In contrast to OO patterns and practices but still with critical and planned thinking at the forefront, we could also use a functional programming paradigm (and patterns specific to FP), and leverage things like pure functions to avoid side effects with a goal of consistency and having more readable and logical implementation. Any of these options are better than the absence of any plan, which results in a poor implementation that's prone to bugs and being difficult to maintain.</span></p><p><span style="font-family: arial;">In the end we didn't complicate the code, we just implemented it differently for the major gain or readability, reusability, and testability. I liken it to these images I used over 10 years ago when talking about patterns and practices in C#. Both containers below have the same content, but which one would you rather grab to get what you need? The answer is simple; the one that is organized.</span></p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://lh3.googleusercontent.com/-6maZmzJf4DI/X8qwyFjlUpI/AAAAAAAACuI/ARStFQE__WkHJXyvrs-LFHQDG38I-XXLACLcBGAsYHQ/image.png" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: arial;"><img alt="" data-original-height="326" data-original-width="846" height="205" src="https://lh3.googleusercontent.com/-6maZmzJf4DI/X8qwyFjlUpI/AAAAAAAACuI/ARStFQE__WkHJXyvrs-LFHQDG38I-XXLACLcBGAsYHQ/w640-h246/image.png" width="533" /></span></a></div><span style="font-family: arial;"><div><span style="font-family: arial;"><br /></span></div></span><h3 style="text-align: left;"><span style="font-family: arial;">The plan forward</span></h3><p></p><p><span style="font-family: arial;">The question is how do we learn about these patterns and when to apply them in our code? Well the answer is a combination of getting educated on well known patterns and gaining experience using them. It is however an art, and there is a balance to be had on how to use them most effectively. The cynics hear 'patterns' and sometimes get scared off saying, "that will overcomplicate the code!" There are times I agree. How can I spot the difference? Experience. If you don't have any, learn from others. One of my favorite words in the industry is 'pragmatic.' The ability to know balance in code and when and how to use powerful patterns to aid not hinder code. If the two ends of the spectrum are anarchy and over-architecture we want to be somewhere close to the middle. The problem is in my experience, we're too often close to the anarchy-style of implementation on the web client. I think the crazy saving grace that we back into is that since web client frameworks and libraries have only a 2-4 year tenure on average before some major overhaul, all this bad code is made obsolete before it really begins to stink things up. However during that time period it would behoove us to write code that is implemented with better patterns and practices to help extend the life and make the journey a whole lot easier.</span></p><div class="separator" style="clear: both; text-align: center;"><span style="font-family: arial;"><br /></span></div><span style="font-family: arial;"><br /></span><p><br /></p>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-10159672127994781832019-12-20T17:25:00.000-05:002019-12-20T17:33:09.801-05:00How to Prevent Visual Studio from Compiling TypeScript<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-qhQK_LXQHOA/Xf1E8V3Et0I/AAAAAAAACkE/Mjnm-jwLjtoJTzrWYiIFKn4B2CBn2su9QCLcBGAsYHQ/s1600/typescript-logo.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><img border="0" data-original-height="150" data-original-width="300" height="100" src="https://1.bp.blogspot.com/-qhQK_LXQHOA/Xf1E8V3Et0I/AAAAAAAACkE/Mjnm-jwLjtoJTzrWYiIFKn4B2CBn2su9QCLcBGAsYHQ/s200/typescript-logo.png" width="200" /></span></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">If you are building a Single Page Application / JavaScript Web application using Visual Studio, you've probably already run into the overlap between tooling that surrounds npm and the tooling within Visual Studio. As web development moves further away from the bells and whistles needed from the IDE (unlike heavy server-side web technologies like ASP.NET MVC that are heavily dependent upon the IDE), separating a project from these 'features' can be not quite straight forward. While the practice of using Visual Studio for modern web development isn't as prevalent these days with much of the coding taking place in streamlined IDEs like Visual Studio Code, there are still a lot of projects that exist and have a hard time decoupling from Visual Studio, MSBuild, and ASP.NET because of their coupled nature. This process will help in this interim stage while the code is still fully integrated and run from Visual Studio.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-zHjD6XCYFdw/Xf1GPmfijrI/AAAAAAAACkg/VY88rhuvPSIXveCP-tbHmexbp-oDyzTAwCLcBGAsYHQ/s1600/VSWinIcon_100x.png" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><img border="0" data-original-height="150" data-original-width="150" height="150" src="https://1.bp.blogspot.com/-zHjD6XCYFdw/Xf1GPmfijrI/AAAAAAAACkg/VY88rhuvPSIXveCP-tbHmexbp-oDyzTAwCLcBGAsYHQ/s200/VSWinIcon_100x.png" width="150" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">One of these tasks is preventing Visual Studio from being responsible for building TypeScript and </span><span style="font-family: "arial" , "helvetica" , sans-serif;">allowing your tooling (i.e. Webpack, Gulp, Grunt) to be in charge instead. The idea here is that your tooling has been configured to lint, minify, build, concat, bundle, copy, whatever all of your project files exactly as you desire. At this point you don't really need MSBuild involved in transpiling your JavaScript to TypeScript as it would be redundant and often times problematic. To prevent Visual Studio from doing any compilation of TypeScript preform the following steps:</span><br />
<h4 style="text-align: left;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">1. Ensure a tsconfig file is added to the project and configured correctly</span></h4>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">TypeScript and any build process you are using will work together based on the configuration in tsconfig.json. This file can be hand-rolled from scratch, or may have been generated for your project from a process like <b>ng new</b> and the Angular CLI. You can also generate a default tsconfig file (recommended approach as opposed to creating from scratch) using the following command:</span></div>
<div>
<code><br />
tsc --init<br />
</code></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">This will generate a default configuration file for TypeScript compilation. Your web-client's code build process will need to point to this file and using it as a driver for the TypeScript compilation behavior.</span></div>
<h4 style="text-align: left;">
<span style="font-family: "arial" , "helvetica" , sans-serif;">2. Modify the .csproj project file to prevent TypeScript from compiling</span></h4>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Within Visual Studio, right-click your project and select the option to edit the .csproj file. These options are in a XML format and the following needs to be added:</span></div>
<div>
<code><br />
<PropertyGroup><br />
<TypeScriptCompileBlocked><b>true</b></TypeScriptCompileBlocked><br />
</PropertyGroup><br />
</code></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">If you still want MSBuild to handle your TypeScript compilation there are several options that will change the behavior: </span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div>
<a href="https://www.typescriptlang.org/docs/handbook/compiler-options-in-msbuild.html" target="_blank"><span style="font-family: "arial" , "helvetica" , sans-serif;">TypeScript Compiler Options in MSBuild</span></a></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">One of the only primary use cases I can think allowing MSBuild to handle TypeScript compilation is for using TypeScript independently of a framework/app like Angular or React when using standalone in an ASP.NET MVC application. Otherwise the native build processes of your front-end stack are much better off being used to build TypeScript as opposed to MSBuild.</span></div>
</div>
Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-9238633846603922692019-10-22T13:42:00.000-04:002019-10-22T13:42:33.197-04:00State of the Union: Future and Historic Thoughts on WebAssembly, JavaScript, and .NET<div dir="ltr" style="text-align: left;" trbidi="on">
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">With all the goodness happening in the world of WebAssembly it's important to keep an eye on what's happening and how this will positively impact development going forward. In the world of JavaScript there are questions about how the worlds will converge. This maybe in contrast with a portion of the .NET community, which seems at times they don't want it to converge; they want JS dev to be thrown out with the garbage as evidence by the sly remarks toward our community over the years (which as a JS dev I've digested kindly). This sentiment is also supported via the primary description of Blazor:</span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<blockquote class="tr_bq">
<span style="font-family: Arial, Helvetica, sans-serif;">Blazor lets you build interactive web UIs using C# <i>instead of JavaScript</i></span></blockquote>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">Although that picture gets clearer as I realize their baby (web in .NET) was called ugly for the last decade so they are salivating for Blazor to feel at home again on the web. (zing!) OK back on track and in all seriousness, Blazor is a rich platform to build modern apps using C#, and I do fully appreciate the excitement of being able to run the same code on the client and server. This is a significant strength in addition to several other bullet points about the stack. </span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">BTW, I qualify to make these remarks as I've been both a .NET developer and a JavaScript developer, so I've been on both sides of the fence for extended periods of time. Just look at the header image on this blog; it's a legacy Visual Studio logo representing the numerous years I've spent as a .NET developer.</span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">History will show though without JS, the development community as a whole I don't think would be near where they are today and still creating per-platform apps like 15 years ago. The ability to write-once and deploy platform agnostic for the last 10 years is unparalleled until recent advancements. </span><span style="font-family: Arial, Helvetica, sans-serif;">It's historic significance can't be ignored.</span><span style="font-family: Arial, Helvetica, sans-serif;"> </span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">Also there is no hidden agenda here to resist change or remain some kind of isolated JS developer wearing blinders. I'm not that dogmatic in my career path as I've typically moved along with change remaining modern to where mainstream development has gone, and not tried to hang on to a stack out of stubbornness. I'll adopt change as the community does, and always excited about the advancements of the future.</span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="copy-paste-block" itemprop="copy-paste-block">
<span style="font-family: Arial, Helvetica, sans-serif;">The reality is there is too much momentum in JavaScript development for companies/customers/clients to pump the brakes and change everything. This process is always an evolution. There is also the fact that not all development is greenfield, so the question arises about how to have the best of both worlds (JS and WASM)? </span></div>
<div class="copy-paste-block" itemprop="copy-paste-block">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="copy-paste-block" itemprop="copy-paste-block">
<span style="font-family: Arial, Helvetica, sans-serif;">Being pragmatic and assessing the current landscape, I think the real step forward for folks not purely on a single stack like C#/.NET, or any narrow/single stack for that matter will be a hybrid one (by definition hybrid); at least in the beginning. This is even suggested straight from the horse's mouth: <a href="https://webassembly.org/docs/faq/" title="https://webassembly.org/docs/faq/">https://webassembly.org/docs/faq/</a></span></div>
<div class="copy-paste-block" itemprop="copy-paste-block">
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-Jp5VWAz2i8w/Xa8zbDVBGeI/AAAAAAAACjQ/pfDaEMfp5NofESKn171aM-KMexrsGYsQgCLcBGAsYHQ/s1600/WebAssembly%2Band%2BJS.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" data-original-height="465" data-original-width="730" height="253" src="https://1.bp.blogspot.com/-Jp5VWAz2i8w/Xa8zbDVBGeI/AAAAAAAACjQ/pfDaEMfp5NofESKn171aM-KMexrsGYsQgCLcBGAsYHQ/s400/WebAssembly%2Band%2BJS.png" width="400" /></span></a></div>
<div class="copy-paste-block" itemprop="copy-paste-block">
<div>
<span contenteditable="false"></span><div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
</div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">I feel like bullet points 2 and 3 above will emerge in the 1st 3-5 years as a prevalent way of developing modern web apps. A hybrid approach that uses both JavaScript and compiled WASM modules referenced within to produce performant and modern web applications. The language used to create and target a WASM module will be dependent on the team's experience. </span></div>
<div>
</div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">Here are some interesting examples that do just this:</span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b>Angular:</b></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://boyan.io/angular-wasm/" title="https://boyan.io/angular-wasm/">https://boyan.io/angular-wasm/</a></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://github.com/boyanio/angular-wasm" title="https://github.com/boyanio/angular-wasm">https://github.com/boyanio/angular-wasm</a></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><b>React:</b></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><a href="https://dev.to/brightdevs/using-webassembly-with-react-1led" title="https://dev.to/brightdevs/using-webassembly-with-react-1led">https://dev.to/brightdevs/using-webassembly-with-react-1led</a></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span></div>
<div>
<span style="font-family: Arial, Helvetica, sans-serif;">It's important to continually modernize our stack and remain fluid with the direction the community guides us. WebAssembly plays an important role in the future of all types of development. What are your thoughts on how this will evolve?</span></div>
</div>
</div>
Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-84978877444820524402019-04-01T23:17:00.002-04:002019-04-01T23:17:57.888-04:00Using Quokka.js for Real-Time Feedback in TypeScript<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: "arial" , "helvetica" , sans-serif;">I'm always looking for cool VS Code extensions and Quokka.js certainly hits the spot. It provides real-time feedback on JavaScript and TypeScript directly in VS Code in a variety of forms. For example if you're testing some code via </span><span style="font-family: Courier New, Courier, monospace;">console.log</span><span style="font-family: "arial" , "helvetica" , sans-serif;">, you can get the output directly inline to the right of the code which is awesome.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Once installed, all I needed to do was open the command pallet in VS Code (Ctrl+Shift+P) and select, '<b>Quokka.js: Start on Current File</b>' as shown below:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-3gm40yCxsU0/XKLPjsSjOII/AAAAAAAACdY/skPMuZ9lmxAm12m6bzubSkb7LK3i7hnAwCEwYBhgL/s1600/Quokka%2BStart%2Bon%2Bcurrent%2Bfile.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="53" data-original-width="576" height="48" src="https://1.bp.blogspot.com/-3gm40yCxsU0/XKLPjsSjOII/AAAAAAAACdY/skPMuZ9lmxAm12m6bzubSkb7LK3i7hnAwCEwYBhgL/s640/Quokka%2BStart%2Bon%2Bcurrent%2Bfile.png" width="518" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">After initiating the extension, as seen below I was getting live logging directly in the code.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif; margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="324" data-original-width="513" height="324" src="https://2.bp.blogspot.com/-LIfTGjiVs5A/XKLPHd7cgxI/AAAAAAAACdQ/pxa8wGgNoAgcJNCT_RUDwAKWIaQpotbiwCEwYBhgL/s640/Live%2BLogging.png" width="513" /></span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">If there's a value not provided in the scope of the file, Quokka.js obviously can't produce an output and this was expected behavior:</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<span style="font-family: "arial" , "helvetica" , sans-serif; margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="80" data-original-width="307" height="104" src="https://3.bp.blogspot.com/-Ar6fd3vBuYw/XKLQpswWawI/AAAAAAAACdg/20SVdq1hTA0RA-p-3izzA0b0bHMRMjJRwCLcBGAs/s400/No%2Blogging%2Bparameter%2Bnot%2Bprovided.png" width="400" /></span></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">There is quite a bit more functionality offered like code coverage assessment (as it pertains to code execution paths, not unit testing), and a provided value explorer. There is also a Pro edition with additional tools available.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Check out the links below to get started:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <a href="https://quokkajs.com/docs/#getting-started" target="_blank"><span style="color: blue; font-family: "arial" , "helvetica" , sans-serif;">Quokka.js</span></a><br />
<a href="https://marketplace.visualstudio.com/items?itemName=WallabyJs.quokka-vscode" target="_blank"><span style="color: blue; font-family: "arial" , "helvetica" , sans-serif;">VS Code Extension for Quokka.js</span></a></div>
Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-60362896206832083292019-01-30T23:04:00.000-05:002019-01-31T11:26:31.210-05:00I'm excited about WebAssembly, but not as much about my beloved .NET, Blazor's implementation<div dir="ltr" style="text-align: left;" trbidi="on">
<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: "arial" , "helvetica" , sans-serif;">As a web client developer these days, I'm sold on WebAssembly and looking forward to it's adoption by the multiple languages that can compile to it. However interestingly one of the things I'm beginning to feel is <i>my personal </i>dislike for the Blazor syntax and implementation. I suppose my multiple years being entrenched in JS/TS with really enjoying TypeScript + the SPA frameworks that have a relatively clean separation of markup (declarative) and logic (imperative) has made me have a bit of dislike for lacing the view directly with imperative view logic like this in Blazor:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<pre class="brush:html; highlight: [7,11,17]">@page "/myorders"
@inject HttpClient HttpClient
<div class="main">
</div>
@if (ordersWithStatus == null)
{
<text>Loading...</text>
}
else if (ordersWithStatus.Count == 0)
{
<h2>No orders placed</h2>
<a class="btn btn-success"
href="https://www.blogger.com/2404">Order some pizza</a>
}
else
{
<text>TODO: show orders</text>
}
</pre>
</div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"> </span> <span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><span style="font-family: "arial" , "helvetica" , sans-serif;"><i>As a side of humor, to format code blocks on this blog I have to select a 'brush' for the language formatting. Case in point, in the above snippet I wasn't sure if I should have picked HTML, C#, or Blazor.</i></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">This is probably because I was never a fan of the classic ASP, MVC Razor, or even Blazor implementations where view logic is interlaced with the markup (for web client code I'd even throw in JSX - as explained <a href="https://www.reddit.com/r/reactjs/comments/660moa/i_dont_get_why_people_hate_on_jsx_it_seems_like_a/dgev3dg" target="_blank">here</a>). This doesn't matter a pile of beans really because this is all subjective and has absolutely no bearing on how successful Blazor or any other language targeting WebAssembly will be. I actually love the .NET stack and was carved from that block since the beginnings of my professional career, but I just don't like that particular style of implementation <i>for the web</i>. Shoot for all of ASP.NET's webforms shortcomings, the view overall was relatively clean (keeping logic in code separate from the markup) and pure aside the fact the tags may have been ASP.NET server-side controls but still took the shape of HTML tags (analogous in form to today's custom HTML elements).</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">I also do not like the JSInterop style in Blazor. You can invoke JavaScript functions from within C#, and that alone is handy I suppose, but messy. The functions you want to invoke <i>must be available on the global scope of <b>window</b>. </i>Yuck. JavaScript scope and encapsulation was difficult enough to manage through the years, I'd rather not go back to the days of hanging code off the window object making everything globally available. In 100 level examples this seems fine, but get to 10's or 100's of thousands of lines of code in an enterprise app and this could get ugly.</span> <br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<pre class="brush:js;"><script>
window.MyFunction = (someValue) => {
//JS code here...
};
</script>
</pre>
<br />
<pre class="brush:csharp;">using Microsoft.JSInterop;
public class JsInteropExample
{
public static Task<string> MethodName(strings someValue)
{
return JSRuntime.Current.InvokeAsync<string>("MyFunction", someValue);
}
}
</string></string></pre>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><span style="font-family: "arial" , "helvetica" , sans-serif;">I'm probably not alone in my opinions, and that's why I'll be keeping an eye on the ability to use TypeScript as a target for WA. I like JS/TS and am comfortable with it for developing web applications. I feel many client side developers may have a similar sentiment and not want to either learn a server-side language, or just prefer the front-end languages they've been using for years. TS on it's own won't be enough (it's just a language), so it would have to be TS + some web framework (??) and we'll have to wait for the pieces to come together.</span><br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-TQ_DOtZuoeg/XFJxELpne0I/AAAAAAAACaU/nmSondwgKgQav1695vQWPLzDrJrNftlAACLcBGAs/s1600/AssemblyScript.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em; margin-top: 1em;"><img border="0" data-original-height="182" data-original-width="182" height="91" src="https://2.bp.blogspot.com/-TQ_DOtZuoeg/XFJxELpne0I/AAAAAAAACaU/nmSondwgKgQav1695vQWPLzDrJrNftlAACLcBGAs/s200/AssemblyScript.png" width="91" /></a></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">To that end I'll keep an eye on things like <b>assemblyscript </b>which is a TypeScript to WebAssembly compiler. It doesn't appear to have the traction some of the other compilers do at the moment, but I'm sure it or something similar will gain momentum as WA picks up and the masses of web developers may not feel like using C#, C++, or Rust.</span><br />
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><a href="https://github.com/AssemblyScript/assemblyscript" target="_blank">AssemblyScript: a TypeScript to WebAssembly compiler</a></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"></span><br />
<a href="https://github.com/AssemblyScript/assemblyscript/wiki/Status-and-Roadmap" target="_blank"><span style="font-family: "arial" , "helvetica" , sans-serif;">AssemblyScript: Status and Roadmap</span></a><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">I'm not counting Blazor out for sure, and it's still going to evolve as it's only an experimental project at the moment. I really enjoy developing in C# so it seems like a great match, but in it's early stages it's rough around the edges and maybe that's just my opinion that's shaped as a front-end developer. I'm pragmatic and will not count out the usefulness of developing on a single-stack and this is where Blazor shines for .NET developers. </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">I'd be interested in feedback or thoughts about using TypeScript to transpile to WebAssembly or anything else along these lines, so please feel free to leave a comment and let me know.</span></div>
Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com1tag:blogger.com,1999:blog-1528805174514452404.post-56260375918154903652018-09-28T01:05:00.000-04:002018-09-28T10:58:03.198-04:00Named vs Fat Arrow Functions in TypeScript<div dir="ltr" style="text-align: left;" trbidi="on">
<span style="font-family: "arial" , "helvetica" , sans-serif;">When working with TypeScript, it's important to understand some of the key differences between named and fat arrow functions. Let's have a look at a basic class with one of each type of function defined, and also the resulting ES5 that TypeScript transpiles to for a better understanding.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Here is a sample TypeScript class with the two different types of functions.</span><br />
<br />
<pre class="brush:js">class MyTsClass {
private myValue: number = 0;
myNamedFunction(): void {
setTimeout(function () {
console.log(`Inside myNamedFunction, this.myValue = ${this.myValue}`);
}, 1000);
}
myFatArrowFunction = (someValue: number) => {
this.myValue = someValue;
console.log(`Inside myFatArrowFunction, this.myValue = ${this.myValue}`);
}
}
const myClass = new MyTsClass();
myClass.myFatArrowFunction(1);
myClass.myNamedFunction();</pre>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Here is the resulting transpiled ES5 JavaScript.</span><br />
<br />
<pre class="brush:js; highlight: [4]">"use strict";
var MyTsClass = /** @class */ (function () {
function MyTsClass() {
var _this = this;
this.myValue = 0;
this.myFatArrowFunction = function (someValue) {
_this.myValue = someValue;
console.log("Inside myFatArrowFunction, this.myValue = " + _this.myValue);
};
}
MyTsClass.prototype.myNamedFunction = function () {
var _this = this;
setTimeout(function () {
console.log("Inside myNamedFunction, this.myValue = " + _this.myValue);
}, 1000);
};
return MyTsClass;
}());
var myClass = new MyTsClass();
myClass.myFatArrowFunction(1);
myClass.myNamedFunction();
</pre>
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">For the purpose of this post, we'll concentrate on (2) main aspects of the code</span><br />
<ol style="text-align: left;">
<li><span style="font-family: "arial" , "helvetica" , sans-serif;">Where the method is created on the object, and the resulting <b>performance </b>impact</span></li>
<li><span style="font-family: "arial" , "helvetica" , sans-serif;">How the </span><span style="font-family: "courier new" , "courier" , monospace;"><b><span style="background-color: #cccccc;">this</span> </b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">keyword behaves</span></li>
</ol>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">It's important to understand the differences because there is a performance impact. Notice how the named function on the class is created and attached on the <i>object's prototype</i>. In this manner, the method is stored in memory only one time, as objects created from the same constructor point to a single prototype object. This is the more memory efficient implementation.</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Now inspect the fat arrow's function in the ES5 code. Because the method is declared and created in the object's constructor (instance member), it will be declared again per each new instance of this type of object created. This has a memory and performance overhead. As a note, this is the identical resulting behavior to explicitly creating methods within the class constructor in TypeScript.</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">At this point we might be thinking, "Well that's enough let's just use named functions which will be declared on the object's prototype and be done with it!" There is more than meets the eye and the fat arrow function is quite useful. One of the main advantages is that fat arrow functions lexically capture the context of </span><b style="font-family: "Courier New", Courier, monospace;">this </b><span style="font-family: "arial" , "helvetica" , sans-serif;">in TypeScript. This is critically important in functions that contain callbacks or where re-assignment of instance variables might occur. The former use case is one that we run into often with observable callbacks in say Angular components. You may have run into issues with the </span><b><span style="font-family: "courier new" , "courier" , monospace;">this</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;"> keyword and noticed it wasn't the correct context. The issue is if not using the fat arrow syntax, the context of the </span><span style="font-family: "courier new" , "courier" , monospace;"><b>this</b> </span><span style="font-family: "arial" , "helvetica" , sans-serif;">keyword will be undefined. If strict mode isn't enabled, the context of </span><span style="font-family: "courier new" , "courier" , monospace;"><b>this</b> </span><span style="font-family: "arial" , "helvetica" , sans-serif;">will be of the </span><b><span style="font-family: "courier new" , "courier" , monospace;">window </span></b><span style="font-family: "arial" , "helvetica" , sans-serif;">object. If you look in the ES5 tanspiled code, you'll notice </span><span style="font-family: "courier new" , "courier" , monospace;"><b>this</b> </span><span style="font-family: "arial" , "helvetica" , sans-serif;">is captured from outside the function body allowing our context to be captured correctly.</span><br />
<br />
<pre class="brush:js">var _this = this;
</pre>
<br /></div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Let's look at the console output from the original code above. Notice in the setTimeout call the use of </span><b><span style="font-family: "courier new" , "courier" , monospace;">this</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;">. However in this instance it's not the proper context resulting in </span><span style="font-family: "courier new" , "courier" , monospace;"><b>undefined </b></span><span style="font-family: "arial" , "helvetica" , sans-serif;">when accessed. </span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-4YLw6ICrE0Y/W62wzWRsu-I/AAAAAAAACUY/zNJbmZRaJvIN9wcEXgZp97gbvdqu-hlsgCLcBGAs/s1600/This%2BUndefined.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="46" data-original-width="347" height="52" src="https://3.bp.blogspot.com/-4YLw6ICrE0Y/W62wzWRsu-I/AAAAAAAACUY/zNJbmZRaJvIN9wcEXgZp97gbvdqu-hlsgCLcBGAs/s400/This%2BUndefined.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
</div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">The fix is to update the callback to use the fat arrow syntax which will capture the correct context of </span><b><span style="font-family: "courier new" , "courier" , monospace;">this</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;">. </span><br />
<br />
<pre class="brush:js; highlight: [2]">myNamedFunction(): void {
setTimeout(() => {
console.log(`Inside myNamedFunction, this.myValue = ${this.myValue}`);
}, 1000);
}
</pre>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">If we run the code again, we get the console output we expect.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-CBX9B875ffA/W62wtH28LUI/AAAAAAAACUU/8rIdxGioRxUJ3kD67Huv4ybCYSrtV8G8gCLcBGAs/s1600/this%2Bcorrect%2Bcontext.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="44" data-original-width="345" height="50" src="https://4.bp.blogspot.com/-CBX9B875ffA/W62wtH28LUI/AAAAAAAACUU/8rIdxGioRxUJ3kD67Huv4ybCYSrtV8G8gCLcBGAs/s400/this%2Bcorrect%2Bcontext.png" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
<br /></div>
<span style="font-family: "arial" , "helvetica" , sans-serif;">In a TypeScript project with the default configuration of </span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;">"noImplicitThis": true</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> set in the tsconfig.json file, you'll actually be warned in the IDE of this scenario, " </span><span style="font-family: "courier new" , "courier" , monospace;"><i>'this' implicitly has type 'any' because it does not have a type annotation.</i></span><span style="font-family: "arial" , "helvetica" , sans-serif;">" This would be an indication you need to use the fat arrow function instead.</span><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-cjdRQ0Rv4mo/W62yNjvnE2I/AAAAAAAACUo/LIvNo5-MQM0qzdpjeNN4HmaK39-Fh6X1QCLcBGAs/s1600/noImplicitThis%2Btrue%2Bwarning.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="121" data-original-width="633" height="76" src="https://4.bp.blogspot.com/-cjdRQ0Rv4mo/W62yNjvnE2I/AAAAAAAACUo/LIvNo5-MQM0qzdpjeNN4HmaK39-Fh6X1QCLcBGAs/s400/noImplicitThis%2Btrue%2Bwarning.png" width="400" /></a></div>
</div>
<div>
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">There are other use cases beyond the ones I'm mentioning here today in regards to the behavior of </span><b><span style="font-family: "courier new" , "courier" , monospace;">this </span></b><span style="font-family: "arial" , "helvetica" , sans-serif;">with inheritance and calling the parent class as well as other differences. However these are two key areas that should be understood, as I see the usage flip-flop without intent, and developers should be aware of the performance and behavior differences and create the correct type where appropriate. They have separate purposes, so I'm not a fan of just one or the other. Using only fat arrow functions have their performance impact, but shouldn't be avoided all together as they are instrumental on capturing the correct context of </span><span style="font-family: "courier new" , "courier" , monospace;"><b>this</b> </span><span style="font-family: "arial" , "helvetica" , sans-serif;">when needed. </span></div>
</div>
Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-41608559181125347792018-09-18T22:38:00.000-04:002018-09-20T15:34:46.896-04:00Visual Studio Code Snippet - Triple Slash Directive<div dir="ltr" style="text-align: left;" trbidi="on"><span style="font-family: "arial" , "helvetica" , sans-serif;">Sticking with the theme of my last blog post, <a href="http://www.allenconway.net/2018/08/running-es6-modules-native-in-browser.html" target="_blank">Running ES6 Modules Native in the Browser using TypeScript</a>, this post looks at pure JavaScript/TypeScript projects (i.e. NodeJS), that might not be using a framework or module loader, yet still need the ability to reference dependencies from other files. We've been doing this for years using the <a href="https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html" target="_blank">Triple-Slash Directive</a> like the following:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <pre class="brush:js">/// <reference path="./src/ts/myClass.ts" />
</pre><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;">In Visual Studio Code I was looking for an extension, snippet, or shortcut to type out the above. Interestingly I came up with nothing. Maybe it's inside another extension I hadn't seen, but rather than look for a needle in a haystack, I decided to quickly </span><a href="https://code.visualstudio.com/docs/editor/userdefinedsnippets" style="font-family: arial, helvetica, sans-serif;" target="_blank">hand-roll my own snippet</a><span style="font-family: "arial" , "helvetica" , sans-serif;">. This is trivial to do in Visual Studio Code. Here is the snippet for a triple-slash directive, and it can be used with the following prefix name: "</span><b><span style="font-family: "courier new" , "courier" , monospace;">tripSlash</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;">"</span></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><pre class="brush:js">{
"Triple_Slash_Directive": {
"prefix": "tripSlash",
"scope": "javascript,typescript",
"body": [
"/// <reference path=\"${1:path}\" />",
],
"description": "Triple Slash Directive used for declaring dependencies between files when no module loader is used"
}
}
</pre></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-71449321170370222222018-08-13T15:44:00.000-04:002018-08-13T15:46:23.526-04:00Running ES6 Modules Native in the Browser using TypeScript<div dir="ltr" style="text-align: left;" trbidi="on"><span style="font-family: "arial" , "helvetica" , sans-serif;">ES6 Modules have a clean and intuitive syntax, and it's nice to know that there is now widespread support natively to use them in the browser. The main drawback to date is that not <i>every</i> browser version dating back supports ES6 modules and thus a module/loader bundler is still required for production applications (only one of many reasons). However it can be a lot of work to spin up Webpack or SystemJS just to throw together a small test application. Another use case might be if building an intranet app in a controlled/known environment using a supported browser. Regardless of the reason here is how you can use ES6 modules natively in the browser using TypeScript or JavaScript. <i>(This post will focus on TypeScript, but you can use plain JS too)</i></span><br />
<div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><h4 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">1. Create an ES6 module</span></h4><div><div class="separator" style="clear: both; text-align: center;"></div><span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;">A module is nothing more than a self-contained set of functionality, executed within their own scope and not on the global scope. We'll use the </span><b style="font-family: arial, helvetica, sans-serif;"><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;">export</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;"> keyword to expose that functionality outside the module, and the </span><span style="font-family: "courier new" , "courier" , monospace;"><b style="background-color: #cccccc;">import</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> keyword to use that exposed functionality in another module.</span></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><pre class="brush:js">export class Person {
getAddress():string{
return '123 Pine St.';
}
}</pre></div><h3 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></h3><h4 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">2. Create another ES6 module importing the module created previously</span></h4><div><pre class="brush:js; highlight: [1]">import { Person } from "./Person.js";
export class ContactInfo{
getContactInfo() {
const person = new Person();
const address = person.getAddress();
console.log(`The address is: ${address}`)
}
}</pre><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">Make sure to note that "bare" modules are not supported. This restriction allows for browsers to scale in the future when using module loaders, and allow "bare" modules to contain special meaning or functionality. This syntax below is not supported and you'll get the following error in the browser, even though the application might build correctly:</span><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><br />
<pre class="brush:js">import { Person } from "Person";</pre><blockquote class="tr_bq"><span style="font-family: "arial" , "helvetica" , sans-serif;">"Uncaught TypeError: Failed to resolve module specifier "Person". Relative references must start with either "/", "./", or "../"."</span></blockquote><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">The correct syntax is to reference the exact file directly. </span></div><h3 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></h3><h4 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">3. Configure tsconfig.json</span></h4><div><span style="font-family: "arial" , "helvetica" , sans-serif;">Configure the module type to be "ES6." Using anything else will ultimately yield in errors in the browser at runtime as the other module types are not supported. </span><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><br />
<pre class="brush:js; highlight: [2]">"compilerOptions": {
"module": "es6"
}</pre></div><h3 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></h3><h4 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">4. Leverage the "module" type in index.html</span></h4><div><span style="font-family: "arial" , "helvetica" , sans-serif;">As this isn't a classic script, we must identify the file as being a module using the </span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;"><b>type="module"</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> attribute. Note you can use the </span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;"><b>async</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> attribute with modules if desired which will execute the script as soon as possible, without a guarantee of order, and also not waiting for the HTML parsing to finish. There is also no need to add the </span><b style="background-color: #cccccc;"><span style="font-family: "courier new" , "courier" , monospace;">defer</span></b><span style="font-family: "arial" , "helvetica" , sans-serif;"> attribute as it behaves like this by default; a module script can't block the parser.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><pre class="brush:xml"><script src="scripts/typescript/Person.js" type="module"></script>
<script src="scripts/typescript/ContactInfo.js" type="module"></script></pre></div><h3 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></h3><h4 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">5. Run and check for errors</span></h4><div><span style="font-family: "arial" , "helvetica" , sans-serif;">If you see any errors such as "exports is not defined" or "define is not defined" then you probably have the tsconfig.json configured incorrectly and it's instead transpiling to another module type that is unsupported in the browser (i.e. commonjs, amd, etc..) natively without a module loader. If testing the basic functionality above, upon calling </span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;">getContactInfo()</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> you should see the output in the debugger.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://1.bp.blogspot.com/-DQ3LEPH1XC8/W3HCRYL0DvI/AAAAAAAACTQ/KyDeZ2jhAgcl3B67BBaIcxn1IHtdqez-QCLcBGAs/s1600/ES6%2BModule%2BConsole%2BLog.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="209" data-original-width="511" height="162" src="https://1.bp.blogspot.com/-DQ3LEPH1XC8/W3HCRYL0DvI/AAAAAAAACTQ/KyDeZ2jhAgcl3B67BBaIcxn1IHtdqez-QCLcBGAs/s400/ES6%2BModule%2BConsole%2BLog.png" width="400" /></a></div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;">For a full list of browser compatibility on ES6 module support, see the following link:</span></div><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><a href="https://caniuse.com/#feat=es6-module" target="_blank">JavaScript modules via script tag</a></span><br />
<br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">If you're wondering about the </span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;"><b>.mjs</b></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> module file extension support in TypeScript, see the following discussion on GitHub: <a href="https://github.com/Microsoft/TypeScript/issues/18442" target="_blank">Support '.mjs' output</a></span></div></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-59593560203197116572018-03-25T18:22:00.001-04:002018-03-25T18:22:14.099-04:00Buyer Beware: the client has burned us before, put stock in code on the server<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-Z1MqZZYhruk/WrgZWlo3sGI/AAAAAAAACOA/OWawZCt38ToCmAc2eyxmUHhinx4WDXf3QCLcBGAs/s1600/bad-poker-hand.jpg" imageanchor="1" style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" data-original-height="360" data-original-width="640" height="111" src="https://1.bp.blogspot.com/-Z1MqZZYhruk/WrgZWlo3sGI/AAAAAAAACOA/OWawZCt38ToCmAc2eyxmUHhinx4WDXf3QCLcBGAs/s200/bad-poker-hand.jpg" width="200" /></span></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;">Have you ever played poker? Do you like a full house? A royal flush? Those are amazing but the hand you're dealt is two 3's, a 5, a jack, and a 9. Software development and its future, often has speculation laced in but sometimes we need to deal with the hand we're dealt. As primarily a web developer these days and on and off over the last 15+ years, there has always been that "next thing in the pipeline that will save the horrors of web development." Sounds kind of like a gambler that says, "if I can just play one more hand, I'll win it all back and more!"</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://1.bp.blogspot.com/-M-pbM8h00KM/WrgbSeuFEbI/AAAAAAAACOk/UctIvY2DvOsRoOTDzbjAxLOyWEz6epnjgCLcBGAs/s1600/JSMess.png" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" data-original-height="900" data-original-width="1600" height="179" src="https://1.bp.blogspot.com/-M-pbM8h00KM/WrgbSeuFEbI/AAAAAAAACOk/UctIvY2DvOsRoOTDzbjAxLOyWEz6epnjgCLcBGAs/s320/JSMess.png" width="320" /></span></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;">This all builds up to be a bit cynical, but the reality is web development is and always has been an ever changing, volatile platform for which to develop. There probably is no better group of people accustomed to change than your savvy modern day web developer. I don't think anyone should label web developers as 'in love' with how modern web development is implemented in general. It's a kludge of open source libraries and techniques that defines the very word 'web.' That being a <i>tangled web</i> of various libraries and techniques all pointing back to that love-hate relationship with JavaScript. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">JavaScript in some respects is that mediocre poker hand we were dealt. However in the web world it's perceived weaknesses are at the same time it's strengths. Albeit a dynamic language that frustrates many, it's also flexible and powerful providing us with that "write once run anywhere" ability due to the fact of browsers all being able to interpret and run JavaScript.The language has IMO matured exponentially in the last 5-10 years, and with the addition of high level superset languages like TypeScript, working with JavaScript isn't the nightmare it once was.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">However, you won't see any "I love JavaScript" bumper stickers on the back of my car. I spent years working in various languages like WinBatch, VB, VBA, VB.NET, and C# on the server or client. The reality is <i>today</i> those do us no good in web development on the client. Ah but you say, WebAssembly is here to save the day! Yeah I've heard this tune played before (cough, cough, Silverlight). C# running on the client, same business rules on the client and server, our woes are over, etc. etc.. Listen, I <i>know</i> Silverlight and WebAssembly are <b>not the same</b> at all. The only analogy I'm making is it's not the 1st time in history something has been deemed the "savior" to web development. Call WebAssembly 'x' for this purpose, and "project x will save the day!" In reality I'm actually quite <i>optimistic </i>about where WebAssembly is going to take us on the client. Imagine using C# for everything? That would be beautiful. For an optimistic view of WebAssembly and it's future with smart client development, check out Rocky Lhotka's post: <a href="http://www.lhotka.net/weblog/ABrightFutureForTheSmartClient.aspx" target="_blank">A Bright Future for the Smart Client</a></span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://3.bp.blogspot.com/-teIf1448nWM/WrgZz2X9-9I/AAAAAAAACOE/rHDrFMvhCZwsuofuuyFXBvv3BUO-9mSYwCLcBGAs/s1600/pump-your-brakes.jpg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" data-original-height="418" data-original-width="500" height="166" src="https://3.bp.blogspot.com/-teIf1448nWM/WrgZz2X9-9I/AAAAAAAACOE/rHDrFMvhCZwsuofuuyFXBvv3BUO-9mSYwCLcBGAs/s200/pump-your-brakes.jpg" width="200" /></span></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;">Let's pump the brakes for a minute though. It's early 2018 and I'm expected to deliver <i>today </i>using the hand I'm dealt. In that case we are looking at a host of JS libraries and frameworks to help us build a responsive SPA when it comes to web development. I also have the option of using server-side heavy tech, but for the purpose of this post, I'll focus on the more mainstream approach these days using JS and building responsive JS apps. The bright side of all this is there isn't that "one way" to do development. I suppose that's a double edged sword, but the reality is it gives us options. Like ES6? Use it. Don't like JS? Use TypeScript? Like Angular? Nope. Use React or Vue. Like LESS? Nope. Use SASS. The options go on and on and on. I do agree in some ways this stinks. I often talk about the days early in my career where being really awesome at VB6 meant you could conquer the world, finish your job, and not have to worry about 1,000 surrounding technologies, languages, and libraries. I feel like times were a bit more straight forward. However back in 2002, it was accepted that everybody and their brother was using Windows + IE and that was it. Times have changed and so has the web. The expectation today is run <i>anywhere</i>. Thankfully, JavaScript has provided that flexible nature to allow use to be fluid and make our way to being platform and browser agnostic. Thus we can reach a lot of people with a single line of code.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">So what does this all mean? Well I can say for one thing <i>today</i>: the web is a volatile space and likely to continue beings so in the near future. Even if WebAssembly or any other technology comes along and truly revolutionizes web development as promised, it will take a <i>long</i> time to wash out the gabillion lines of JS out there running the web today. That and the fact we'll probably be in a scenario where, "1/5th of the APIs are available with new tech 'x', and a roadmap is available for the remainder." Point being, set yourself up well to play this hand you're dealt <i>today</i> no matter how it plays out. Be smart and architect your application properly to be successful today and in the future no matter what technologies throw their hat in the ring to save web development. This includes the next best JS framework ever to be head and shoulders above them all!</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<h3 style="text-align: left;">
<span style="font-family: Arial, Helvetica, sans-serif;">Put stock in your code on the server</span></h3>
<span style="font-family: Arial, Helvetica, sans-serif;">How do we play our hand to isolate ripple effects as much as possible as technology proves to be volatile? The answer might be in looking at statistics from the past, rather than looking into a crystal ball. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Let's take a walk through history for a moment in web development starting 18 years ago in 2000. If you were to build say a banking or financial web application beginning at that time and continuing to keep current on a mix of .NET and client technologies, here is the journey you would might have taken:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Classic ASP -> ASP.NET Webforms -> ASP.NET Webforms + AJAX Control Toolkit -> ASP.NET Webforms + Silverlight -> ASP.NET MVC (aspx engine) -> ASP.NET MVC (razor engine) -> AngularJS -> Angular 2,3,4,5....</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">What does this all mean? The web layer is and always has been volatile. Maybe the buck stops with WebAssembly in the future, but that is still yet to be proven; that's another crystal ball moment. I want to use the history of the journey we've taken to help make sound decisions <i>today</i>. This leads me to the point that I'd take little stock in the front-end of our application, and put stock in the server-side code.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Here's an example. Back in 2002, you wrote that financial or banking application using C#. If you at the time had used sound OO techniques dating back to the 70's, unit tested the code, and wrapped it in abstractions to deliver the data, that code <i>could</i> be mostly intact today. I couldn't say that for probably a single line of code on the front-end. </span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">I'm not oblivious to the changes in both C# and .NET technologies, so odds are code was probably refactored. However the most volatile part on the server is that being the manner in accessing the data and the manner in delivering the data. Sure there is volatility there as well. Maybe those core classes and business logic were once deliver via .NET Remoting, then an ASMX Web Service, followed by WCF, than WebAPI. However those should be <i>ultra-thin</i> layers acting as a means to an end to deliver the data. Same applies to accessing the data. You started with ADO.NET, then to LINQ to SQL, then to Entity Framework and through all of its versions. Again, this didn't necessarily need to change all of your core code; this is another layer that should be understood as being volatile.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">So back to the web, <i>today</i>. I want to view the front-end layer as a <i>thin</i> and volatile layer that as history has shown has about an average of a 1-3 year lifespan it seems. I want the meat and potatoes of my code that <i>matters</i> on the server. I won't even get into the intellectual property or security considerations of why code should be on the server as I think that should be obvious with today's tech stack. I want to leverage the front-end code for <i>only front-end matters</i>. I want a pristine viewmodel of sorts returned via a service, where the only logic happening in the presentation layer is that of <i>view manipulation and presentation logic</i>. I've been on enough projects where IP and rules heavy work was done on the client (why, because you can!), only to have year long projects to refactor that code back to the server behind services.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Using an oversimplified view of the layers, let's look at the following using physical size to demonstrate placement and emphasis of code. Instead of a heavy client-side implementation like shown below:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-ufSUctqhniM/WrgZ-P24gWI/AAAAAAAACOM/aLo1j1h_MVExUWavOIAiY32Fazui0RecACLcBGAs/s1600/FatFrontEndClient.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" data-original-height="425" data-original-width="301" height="320" src="https://2.bp.blogspot.com/-ufSUctqhniM/WrgZ-P24gWI/AAAAAAAACOM/aLo1j1h_MVExUWavOIAiY32Fazui0RecACLcBGAs/s320/FatFrontEndClient.jpg" width="226" /></span></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">I believe the implementation should be more along the lines of this based on everything discussed:</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://2.bp.blogspot.com/-NDLhzGdVUjM/WrgaC7IY22I/AAAAAAAACOQ/C2qMCw4LDRgEZtsAnTBEuS1t2iXHZwHlACLcBGAs/s1600/ThinFrontEndClient.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><span style="font-family: Arial, Helvetica, sans-serif;"><img border="0" data-original-height="425" data-original-width="301" height="320" src="https://2.bp.blogspot.com/-NDLhzGdVUjM/WrgaC7IY22I/AAAAAAAACOQ/C2qMCw4LDRgEZtsAnTBEuS1t2iXHZwHlACLcBGAs/s320/ThinFrontEndClient.jpg" width="226" /></span></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">Put stock in your code on the server. History shows that in the battle of volatility the server-side wins out and the web is just too dynamic. Add to this security, IP considerations, and the unbelievably volatile and ever-changing world that is the 'web' it really is the <i>smart</i> move to make. The cynics will bring up leveraging CPUs on the client vs the server, but the world has changed. Data is small and efficient. The server has oodles of horsepower and is a known entity; we control it. The client is a wildcard; we don't know what they have. Long gone are the days where we know the client is a Windows machine controlled by an organization with a spec machine.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://4.bp.blogspot.com/-HinGxPRLEoA/WrggeYc3nTI/AAAAAAAACO4/IsrDWd-hly86F0AXTWlEk09f_lYz3V3GQCLcBGAs/s1600/FastTrain.jpeg" imageanchor="1" style="clear: left; float: left; margin-bottom: 1em; margin-right: 1em;"><img border="0" data-original-height="530" data-original-width="750" height="226" src="https://4.bp.blogspot.com/-HinGxPRLEoA/WrggeYc3nTI/AAAAAAAACO4/IsrDWd-hly86F0AXTWlEk09f_lYz3V3GQCLcBGAs/s320/FastTrain.jpeg" width="320" /></a></div>
<span style="font-family: Arial, Helvetica, sans-serif;">When analyzing data, as opposed to fat SOAP payloads of the past, payloads now are concise and to the point leveraging HTTP standards to deliver data as lean as possible. One must also yield to the fact that the days of 4GLTE and blazing fast WiFi and networking speeds are becoming the norm and will only continue to get better. It's pointless to argue that all apps must work flawlessly offline because that isn't reality across the board. We're in a world where if we aren't connected, things just don't work. Don't plan on making any airline reservations or bank account transfers when your device has no connectivity. I'll also avoid edge cases at this point as I understand there could be web apps made for 3rd world countries or the like where bandwidth is a premium, so data across the wire must be under the microscope. I'm sticking with mainstream, modern day, web development here. I'll leave the door open for you to evaluate edge cases that don't fit the 80/20 rule and call for an exception.</span><br />
<span style="font-family: Arial, Helvetica, sans-serif;"><br /></span>
<span style="font-family: Arial, Helvetica, sans-serif;">I can always go to the server and scrape off the services layer and re-introduce a new tech to replace that abstraction if needed. There are architectural recommendations within the server as well to make sure to thin-out the services facade and keep lightweight as that too as mentioned is know to be volatile over time. On the front-end, I want this same flexibility. Odds are I'll be asked to rewrite my web app in a few years to 'project x' tech which is the best thing ever for the web! I need to be lean up top and be able to scrape that thin veneer or icing off the cake, and put a new layer on easily. This isn't so easy to do if I've put the majority of my code on the client. When the boss or architect comes to me and says, "we are redoing our financial app using new front-end tech" I'll be positioned to say, "no problem, we can mitigate the ripple affect because the key logic and inner-workings of our app are stable and on the server, so we'll just need to redo the thin veneer that is the web-client code."</span></div>
Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com0tag:blogger.com,1999:blog-1528805174514452404.post-68599580342004317792018-01-15T23:46:00.001-05:002018-01-15T23:53:22.817-05:00Strict Property Initialization Checks in TypeScript 2.7<div dir="ltr" style="text-align: left;" trbidi="on"><span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;">The upcoming version 2.7 release of TypeScript has a new compiler option available named "</span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;">strictPropertyInitialization</span><span style="font-family: "arial" , "helvetica" , sans-serif;">" This when set to true causes</span></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> the compiler to ensure all properties in class instances are initialized. If they are not, a compiler error will be generated upon building for each uninitialized property.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span><span style="font-family: "arial" , "helvetica" , sans-serif;">As an aside, to get the most current version of TypeScript installed that hasn't yet been officially released you can run the following npm command:</span><br />
<br />
<pre class="brush:ps">npm install -g typescript@next
</pre><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">This installs the most recent nightly build which will allow me to have access to the new compiler option:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <b><span style="font-family: "arial" , "helvetica" , sans-serif;">+ typescript@2.7.0-dev.20180113</span></b><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><b style="font-family: arial, helvetica, sans-serif;"><br />
</b><span style="font-family: "arial" , "helvetica" , sans-serif;"> If you are beginning a new project, wait to initialize your TypeScript project until after the newest version is installed, so you can easily see all the new compiler options. You can also add them manually to your existing tsconfig.json file. Upon initializing a fresh tsconfig file (</span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;">tsc --init</span><span style="font-family: "arial" , "helvetica" , sans-serif;">), you will see the new </span><span style="font-family: "courier new" , "courier" , monospace;"><span style="background-color: #cccccc;">strictPropertyInitialization</span> </span><span style="font-family: "arial" , "helvetica" , sans-serif;">check:</span></span><br />
<br />
<pre class="brush:js">/* Enable strict checking of property initialization in classes.*/
"strictPropertyInitialization": true,
</pre><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">To test this, let's use the current simple TypeScript class:</span> <br />
<br />
<pre class="brush:js">class Person {
firstName: string;
lastName: string;
address1: string;
address2: number;
}
</pre><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">With </span><span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "courier new" , "courier" , monospace;">"<span style="background-color: #cccccc;">strictPropertyInitialization":true</span></span><span style="font-family: "arial" , "helvetica" , sans-serif;"> set, the following compiler errors will be emitted upon building:</span></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS2564: Property 'firstName' has no initializer and is not definitely assigned in the constructor.</span><br />
<span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS2564: Property 'lastName' has no initializer and is not definitely assigned in the constructor.</span><br />
<span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS2564: Property 'address1' has no initializer and is not definitely assigned in the constructor.</span><br />
<span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS2564: Property 'address2' has no initializer and is not definitely assigned in the constructor.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">This is exactly what we would expect. One way to satisfy the check we can do is mark the parameter as optional using the </span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;">?</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> as we might with address2. This will remove the error related with this field, as undefined is acceptable:</span><br />
<br />
<pre class="brush:js">class Person {
firstName: string;
lastName: string;
address1: string;
address2?: number; //Optional field, type includes undefined
}
</pre><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">The build now only generates 3 errors:</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS2564: Property 'firstName' has no initializer and is not definitely assigned in the constructor.</span><br />
<span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS2564: Property 'lastName' has no initializer and is not definitely assigned in the constructor.</span><br />
<span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS2564: Property 'address1' has no initializer and is not definitely assigned in the constructor.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">To satisfy the strict property initialization for the rest of the class, we can initialize the remaining properties and we will get a successful build:</span><br />
<br />
<pre class="brush:js">class Person {
firstName: string = "Allen";
lastName: string = "Conway";
address1: string = "123 Main St";
address2?: number;
}</pre><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">There is also a way if needed to individually suppress the property initialization checks on an individual basis. This can be done by including a definite assignment assertion using a </span><span style="background-color: #cccccc; font-family: "courier new" , "courier" , monospace;">!</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> mark immediately after the property name. This will allow the following to build successfully:</span><br />
<br />
<pre class="brush:js">class Person {
firstName: string = "Allen";
lastName: string = "Conway";
address1!: string; // Suppress strict initialization check
address2?: number;
}</pre></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com4tag:blogger.com,1999:blog-1528805174514452404.post-79731706939327666332018-01-15T22:37:00.000-05:002018-01-15T22:38:56.639-05:00Visual Studio Code Error with TypeScript Project: "Option 'project' cannot be mixed with source files on a command line"<div dir="ltr" style="text-align: left;" trbidi="on">
<div class="tr_bq">
<span style="font-family: "arial" , "helvetica" , sans-serif;">If you create a TypeScript project in Visual Studio code in a path that contains spaces, you might end up getting the following error after configuring your build task and building the application:</span></div>
<blockquote>
<span style="font-family: "arial" , "helvetica" , sans-serif;">> Executing task: tsc -p "c:\Projects\Test Harness Applications\TypeScript\MyTypeScriptApp\tsconfig.json" <</span><br />
<span style="color: #990000; font-family: "arial" , "helvetica" , sans-serif;">error TS5042: Option 'project' cannot be mixed with source files on a command line.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">The terminal process terminated with exit code: 1</span></blockquote>
<span style="font-family: "arial" , "helvetica" , sans-serif;">Notice the path I used to create the application contained spaces: </span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">"<b>c:\Projects\Test<span style="background-color: yellow;"> </span>Harness<span style="background-color: yellow;"> </span>Applications\TypeScript\MyTypeScriptApp</b>"</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br /></span>
<span style="font-family: "arial" , "helvetica" , sans-serif;">After a little digging I found this GitHub open issue: <a href="https://github.com/Microsoft/vscode/issues/32400">https://github.com/Microsoft/vscode/issues/32400</a>. The good news is according to the information within that link, this is in process to be fixed in an upcoming version of Visual Studio Code (currently 2/2018). In the interim the solution is just to make sure the full path to your application does <i>not</i> contain any spaces. I verified that by doing this, the compiler issue will go away, and the project build successfully.</span></div>
Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com1tag:blogger.com,1999:blog-1528805174514452404.post-44685896494860623672017-12-19T23:42:00.000-05:002017-12-19T23:48:27.798-05:00How to Inject and Use AngularJS Services in Angular<div dir="ltr" style="text-align: left;" trbidi="on"><span style="font-family: "arial" , "helvetica" , sans-serif;">Angular developers looking to upgrade their codebase from AngularJS to Angular (v2+) will probably use a hybrid approach via the </span><span style="background-color: #eeeeee; font-family: "courier new" , "courier" , monospace;">UpgradeModule</span><span style="background-color: white; font-family: "courier new" , "courier" , monospace;"> </span><span style="font-family: "arial" , "helvetica" , sans-serif;">and migrate their code over time. During this process you'll probably need to inject and re-use one of your existing AngularJS services in an Angular component or provider. You may also need an existing built in AngularJS service (i.e. $routeParams, $location, etc.). This isn't difficult to do, and the steps are below.</span><br />
<br />
<h3 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">1. Upgrade the AngularJS service/provider to Angular</span></h3><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><span style="font-family: "arial" , "helvetica" , sans-serif;">In your Angular app module, use an Angular factory provider that will request the service from the AngularJS </span><span style="background-color: #eeeeee;"><span style="font-family: "courier new" , "courier" , monospace;">$injector</span></span><span style="font-family: "arial" , "helvetica" , sans-serif;">.</span></span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><pre class="brush:js">providers: [
{ provide: 'myAngularJsService', useFactory: ($injector: any) => $injector.get('myAngularJsService'), deps: ['$injector'] },
{ provide: '$routeParams', useFactory: ($injector: any) => $injector.get('$routeParams'), deps: ['$injector'] }
]
</pre><div><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><h3 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">2. Inject the upgraded service in Angular</span></h3><div><span style="font-family: "arial" , "helvetica" , sans-serif;">Using </span><span style="background-color: #eeeeee; font-family: "courier new" , "courier" , monospace;">@Inject</span><span style="font-family: "arial" , "helvetica" , sans-serif;"> you will be able to inject your upgraded service for use in an Angular component or provider.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><pre class="brush:js">export class MyAngularComponent{
constructor(
@Inject('myAngularJsService') private myAngularJsService,
@Inject('$routeParams') private $routeParams
)
//Implementation...
myAngularJsService.doSomething();
}
</pre><br />
<h3 style="text-align: left;"><span style="font-family: "arial" , "helvetica" , sans-serif;">3. Optionally create your own service factory</span></h3><div><span style="font-family: "arial" , "helvetica" , sans-serif;">It's advisable to create a separate factory so it is easier to reference and then upon full migration of code easily delete as well. One note that can be the Achilles heel of this method - it requires the ability to be able to ES6 style import your external module. If your legacy AngularJS code is sill using internal modules and not external modules, this will not be possible as using an old style internal module reference in Angular will not work. So if your entire app is already using external modules you can set up your own factory as shown below.</span><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span></div><pre class="brush:js">import { MyAngularJsService} from './my-angularJs.service';
export function myAngularJsServiceFactory(i: any) {
return i.get('myAngularJsService');
}
export const myAngularJsServiceProvider = {
provide: MyAngularJsService,
useFactory: myAngularJsServiceFactory,
deps: ['$injector']
};
</pre><br />
<span style="font-family: "arial" , "helvetica" , sans-serif;">Now it can be registered in the app module via the exported provider created above.</span><br />
<br />
<pre class="brush:js">import { myAngularJsServiceProvider } from './upgraded-providers';
//app module or module implementation...
providers: [myAngularJsServiceProvider]
</pre><span style="font-family: "arial" , "helvetica" , sans-serif;"><br />
</span> <span style="font-family: "arial" , "helvetica" , sans-serif;">In the Angular component or provider where injected, you can just import the service and use directly in the constructor.</span><br />
<br />
<pre class="brush:js">import { MyAngularJsService} from './my-angularJs.service';
export class MyAngularComponent{
constructor(
private myAngularJsService: MyAngularJsService
)
//Implementation...
myAngularJsService.doSomething();
}
</pre><br />
<div><span style="font-family: "arial" , "helvetica" , sans-serif;">The advantage of the above method is now upon injecting, you don't have to use the string handle and will get proper type checking.</span></div></div>Allen Conwayhttp://www.blogger.com/profile/07010967958393033081noreply@blogger.com3