Posts

AWS DynamoDB SDK support for .NET DateTimeOffset

The AWS DynamoDB SDK does not support the .NET DateTimeOffset datatype by default . You may have received an exception similar to: System.InvalidOperationException: Type System.Nullable System.DateTimeOffset is unsupported, it cannot be instantiated. at Amazon.DynamoDBv2.DataModel But you can add a custom IPropertyConverter so that you can persist DateTimeOffset. public class DateTimeOffsetPropertyConverter : IPropertyConverter {     public static readonly string DateTimeOffsetPersistenceFormatString = "yyyy-MM-ddTHH:mm:ss.ffffzzz";     public object FromEntry(DynamoDBEntry entry)     {         if (entry == null)         {             throw new ArgumentNullException(nameof(entry));         }         var primitive = entry as Primitive;         if (primitive == null)         {         ...

ASP.NET .NET 6 OIDC Retrieve JWT AccessToken after SaveTokens

I was not able to find the docs for retrieving the JWT AccessToken in ASP.NET .NET 6 after they are saved so I decided to document it here. You may be familiar with the HttpContext.GetTokenAsync() method . This appears to have worked in previous version of .NET, but I could not get it to work in .NET 6. First, make sure you are saving the access tokens in the  AddOpenIdConnect configuration. builder     .Services     .AddAuthentication(options =>     {         options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;         options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;     })     .AddCookie()     .AddOpenIdConnect(options =>     {         options.SaveTokens = true;     }); Then, instead of HttpContext.GetTokenAsync(), call HttpContext.AuthenticateAsync(), and get the token out of the Authe...

Auth0: Restrict SPA Application Access to API Audience/Permissions/Scopes

Image
In Auth0  you can restrict the APIs/Permissions a Machine-to-Machine type Application has access to using the "APIs" section in the Application Configuration: However, SPA type Applications do not have an equivalent configuration option: There is no way to restrict the APIs a SPA type Application has access to directly . Instead, you must restrict the APIs/Permissions/Scopes a User has access to . (Most likely you'll want to do this using Roles.) You must also ensure the " Enable RBAC " setting is turned on for all of your APIs (this setting is off by default). If the "Enable RBAC" setting is NOT turned on, a SPA Application will be able to request a token for any API/Permission/Scope combination and Auth0 will return a valid token! And even with this setting turned on, a SPA Application will be able to request and receive a token for an API the user does NOT have access to!  The Audience value in the access token will be valid for the API, however the...

Find Azure Application Insights Resource by InstrumentationKey

I had a need to query some Application Insights logs, but all I had was the InstrumentationKey. I didn't want to open each of the Application Insights instances and check the key (there were a lot), but as long as you have the Azure "Az" Powershell Module installed, you can run this script to print out all App Insights instances and their associated Instrumentation Key: https://gist.github.com/aaronhoffman/cf5bd0c59216b3e6a57c0c6ea134cafb # for each subscription in context foreach ( $subId in ( Get-AzSubscription ).Id | Get-Unique ) { write-host " Subscription $subId " # set context to the given subId Set-AzContext - SubscriptionId $subId # List the name and InstrumentationKey of all Application Insights resources in this sub Get-AzResource - ResourceType Microsoft.Insights / components - ExpandProperties | select - ExpandProperty Properties | select Name , InstrumentationKey | ft } Hope this helps! Aaron

Simple Rules Engine in C#

Image
There are some C# "Rules Engines" floating around however they rely on a no-longer-supported nuget package (dynamic linq)  https://github.com/microsoft/RulesEngine   I created this "SimpleRulesEngine" that does not rely on lambdas or expression trees. The expressions can be serialized to JSON.  https://github.com/aaronhoffman/SimpleRulesEngine   I hope to get a simple example web application added to this repo as well, but I'm not sure when I will have time. Please check out the unit tests for now to see how this can be used. Hope this helps, Aaron

Configure SonarAnalyzer.CSharp with .editorconfig, no need for SonarCloud or SonarQube

Our goal was to use  SonarSource / SonarQube  static code analysis with the most "minimal" install/configuration footprint. We wanted the static code analysis to break/fail the build on the local developer machines as well as our CI/CD Azure DevOps environment if a rule was violated. SonarSource products usually rely on some external source,  SonarCloud /SonarQube to determine which rules to apply on the local dev machine, and to store the results. We wanted to eliminate these dependencies. SonarSource also provides a Visual Studio extension called  SonarLint  to help check the static code analysis rules within the Visual Studio IDE without needing an external source for the rules. The static code analysis rules SonarLint enforces are also defined in the  SonarAnalyzer.CSharp  nuget package. This nuget package is a set of  Roslyn Code Analyzers . In .NET Core, Roslyn Code Analyzers are triggered during a build if the nuget package is referenced by...

AspNet Core JWT Authentication ValidateLifetime "The token has no expiration"

Found a "bug" within aspnet core JWT Authentication and thought I'd write something up since I could not find much info online. Found the answer here, but it's not easy to find:  https://github.com/SevenSpikes/api-plugin-for-nopcommerce/issues/99 Essentially, if you create a valid JWT with an expiration time after the year 2038, the default aspnet core JWT Auth will determine that it is invalid saying, " The token has no expiration ". The solution is to create a JWT with an expiration time after "now" but before the year 2038. Hope this helps, Aaron

United States Postal Code to State Map

Image
I had a need to determine the State code given a zip code/postal code and could not find a concise list I could use as the base of the map. There is a PDF available on irs.gov , but that doesn't lend itself well to automation. Using that PDF, I generated this CSV file:  https://gist.github.com/aaronhoffman/d7a598efb593e3acf5e0a39c0dd8b52a There are two different formats depending on your use case. I hope you find it useful! -Aaron

Newtonsoft Json BaseJsonConverter

Image
I've recently had a need for a custom JsonConverter to read and write data to CosmosDb in a way that utilizes a CosmosDb document's `id` property. (more on that in a later post) My first step was to investigate a custom Newtonsoft.Json JsonConverter . I thought that there might be a BaseJsonConverter implementation somewhere in the docs, but I was wrong . After digging through many different custom converters, I think I've discovered what the most trivial custom converter might look like. You can find the example here, and customize it further to fit your needs: https://gist.github.com/aaronhoffman/de40ac508de95101fa41859195728e39 Hope this helps, Aaron

Complete Project Gutenberg Catalog in JSON

Image
Project Gutenberg is an amazing site containing over 57,000 free ebooks at the time of this writing. Recently I've been working on a project to create a database of book bibliographies. A database of book references from within other books. You'd be able to answer the query: Show me all the books that reference "Thinking Fast and Slow". I plan to use Project Gutenberg as the repository that I use to create the first version of this database. Project Gutenberg currently makes their complete project catalog available as a collection of RDF files found here: http://www.gutenberg.org/wiki/Gutenberg:Feeds RDF is not something I've worked with in the past, so I converted them to JSON files. You can download that set of files from here: https://sfp.blob.core.windows.net/public/gutenberg_catalog.zip Hope this helps, Aaron

ASP.NET Core 2.1 Identity

Image
I thought I'd compile some resources on ASP.NET Core 2.1 Identity . Hope you find these useful: Database schema of tables that are generated after the first EF Migration: https://gist.github.com/aaronhoffman/74f4c072afaa0459dcd6595b6380f67d You can override password rules in the Startup.cs class:             services.AddDefaultIdentity ()                 .AddEntityFrameworkStores ();             services.Configure (options =>             {                 options.Password.RequireDigit = false;                 options.Password.RequireLowercase = false;                 options.Password.RequireUppercase = false;                 options.Password.RequireNonAlphanumeric = false;   ...

Programmatically add Other Search Engines to Google Chrome for VSTS Shortcuts

Image
When I'm working with a new repo/project in VSTS , I like to set up shortcuts in Google Chrome to be able to quickly jump to a specific Work Item, PR, Build, or Release based on the ID. To do this, I take advantage of Chrome's " other search engines " settings. You can manually add these by specifying a Short Name, a Keyword, and the URL to navigate to when that keyword is typed into the browser's address bar. Until now, I would manually add these URLs one at a time, but being a lazy developer, I wanted a way to automate this process. I discovered that Chrome uses a SQLite database to store these values, and you can side-load new entries by simply performing a SQL Insert into the `keywords` table of that SQLite database! You can use the following SQL Script to insert the default set of shortcuts I usually add for each new VSTS project/repo: https://gist.github.com/aaronhoffman/60660365310b7ff462b547fea9eb605b Steps to Add:  1. Ensure all instan...

Location of SqlPackage.exe on VSTS and Azure

Image
If you're looking to deploy a Visual Studio Database Project  via VSTS to Azure, you can use the Azure SQL Database Deployment  Release Task to include the deployment in your CI/CD process. When a .dbproj builds, it creates a .dacpac file that contains the database definition/schema. The DB Deployment Release Task uses the SqlPackage.exe executable to deploy/sync the target database with the definitions in the dacpac file. SqlPackage.exe can do more than just `publish`. However, at this time, the publish action is the only action supported by that release task. If you'd like to perform other actions (e.g. `DeployReport` or `Script`), you can call the SqlPackage.exe directly using a PowerShell Script Release Task. However, to do that, you'll need to know the location of the SqlPackage.exe on the VSTS host, because it is not available in the PATH by default. To find the location of SqlPackage.exe, the Azure SQL DB Deploy task uses this utility script:  https://g...

Sync Github Gists with Git Repo

Image
I needed an easy way to sync  github gists  to my local machines and I couldn't find anything provided by gist, or any other open source projects out there so I put this little node app together quick. Simply clone this repo and update the `users.json` file to sync all the associated public gists to your local machine. https://github.com/aaronhoffman/gists The node app uses the gists api  and `git clone`s each gist into a folder with the same name as it's id: Hope this helps! Aaron

Use Azure Functions to Execute a SQL Azure Stored Procedure on a Timer

Image
It was hard to find this information all in one place, so I thought I'd throw a post together quick. If you have the need to execute a stored procedure on a timer, that can be fairly easily accomplished with Azure Functions . Create a new Timer Trigger Azure Function , set the cron timer as desired, and add code similar to the code below: using System; using System.Data; using System.Data.SqlClient; using System.Configuration; using Dapper; public static void Run(TimerInfo myTimer, TraceWriter log) {     var conString = ConfigurationManager.ConnectionStrings["ConString"]?.ConnectionString;          using(var con = new SqlConnection(conString))     {         con.Execute("dbo.MyProc", commandType: CommandType.StoredProcedure);     } } This code will not compile at this time. Note the name of the connection string, we'll need that in the app settings page. Go to the Connection Strings secti...

Create Google Contact via API and Add To My Contacts System Group

Image
When you create a new Contact via the Google Contacts API , by default it will not appear in the list of contacts on the Google Contacts webpage , however, if you search for the contact there, it will appear. If you then click the "Add to contacts" button, it will appear in that contacts list, and increase your contact count in the top left of the page. There is a way to add new contacts via the API and have them show up in this list, it is just not well documented within the API documentation. The code below demonstrates how to do this is C#. What appears to be a list of all contacts on the Google Contacts page is actually just a subset of all your contacts, it is actually the "My Contacts" System Group . When you create a new contact via the API, you must specify that this new contact is part of that system group for it to appear on the contacts page without searching. Steps:  1. Create a ContactsRequest  2. Get a list of all groups and search for t...

Visual Studio 2017 Code Snippet INotifyPropertyChanged

Image
This is an update to the vs2010 code snippet:  https://aaron-hoffman.blogspot.com/2010/09/visual-studio-code-snippet-for-notify.html Code can now be found here:  https://gist.github.com/aaronhoffman/c821acf4bb3b3beb0759e93bbe3a2402 Hope this helps, Aaron

NYSE Historical Stock Price Data From Quandl

Image
Quandl  is a great resource for historical stock price data. I thought I'd pull some meta-data out of the " Wiki EOD Stock Prices " data set in order to help future developers. First, here is the table structure I used to insert the CSV flat file into SQL Server: CREATE TABLE [dbo].[SymbolHistory]( [ticker] [varchar](5) NULL, [date] [date] NULL, [open] [decimal](16, 6) NULL, [high] [decimal](16, 6) NULL, [low] [decimal](16, 6) NULL, [close] [decimal](16, 6) NULL, [volume] [decimal](26, 15) NULL, [ex-dividend] [decimal](22, 18) NULL, [split_ratio] [decimal](21, 19) NULL, [adj_open] [decimal](25, 18) NULL, [adj_high] [decimal](25, 18) NULL, [adj_low] [decimal](25, 18) NULL, [adj_close] [decimal](25, 18) NULL, [adj_volume] [decimal](25, 18) NULL )  Second, here is a list of all 3,194 NYSE symbols in the Quandl flat file as of 2017-11-06, and the min and max dates that they appeared. https://gist.github.com/aaronhoffman/9ef359cbf39f2eefdf5...

Generate Random AES Encryption Key

Image
I was looking for a way to quickly generate a random AES key online, but couldn't find anything. I looked into a couple methods using JavaScript, but determined that a C# solution would be better. I needed to base64 encode the key array to store that value in a config file. Here's the code I ended up with: https://gist.github.com/aaronhoffman/09b56f77a95205fe10365bde2f4a02e5 UPDATE Using Visual Studio's "C# Interactive" screen you can generate a key in a single line: var keyArray = new byte[32]; (new System.Security.Cryptography.RNGCryptoServiceProvider()).GetBytes(keyArray); Convert.ToBase64String(keyArray) Hope this helps! -Aaron

Sync Gmail Contacts Between Accounts

Image
For the last few years I've needed a way to easily sync contacts between gmail accounts. The only method previously supported by Google is to export to csv then re-import the contact list . This may work for some, but clearly there is a desire for something else. I finally found some time to dig into the Google Contact APIs  and created a site to perform this sync operation easily, without needing to install any software: https://www.mycontactsync.com/ Steps to sync:  1. Authorize your gmail account  2. Link an second gmail account (up to 5 currently)  3. Compare two accounts to see which email addresses and phone numbers will be created.  4. Click the Sync Accounts button to initiate the sync! It's that easy! Hope this helps, Aaron links: product hunt note: this website was previously named "gmail contacts sync". The name was changed to verify the google api use.