<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:blogger='http://schemas.google.com/blogger/2008' xmlns:georss='http://www.georss.org/georss' xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-8016829656920012950</id><updated>2024-11-01T02:33:45.265-05:00</updated><category term="Code"/><category term="ASP.NET"/><category term="azure"/><category term="SimpleMembershipProvider"/><category term="sql"/><category term="data"/><category term="Fun"/><category term="Wallpaper"/><category term="git"/><category term="Hawkeyes"/><category term="Office"/><category term="visual-studio"/><category term="windows"/><category term="AspNetMvc5Identity"/><category term="Chocolatey"/><category term="CsQuery"/><category term="HTML"/><category term="Norway"/><category term="OneGet"/><category term="PackageManagement"/><category term="PowerShell"/><category term="Windows 10"/><category term="aes"/><category term="autohotkey"/><category term="aws"/><category term="azure-functions"/><category term="encryption"/><category term="gist"/><category term="gists"/><category term="github"/><category term="github-gist"/><category term="github-gists"/><category term="keyboard"/><category term="knockout.js"/><category term="macbook"/><category term="nyse"/><category term="sql-azure"/><title type='text'>Aaron Hoffman&#39;s Blog</title><subtitle type='html'>Over 350,000 pageviews and counting!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><link rel='next' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default?start-index=26&amp;max-results=25'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>85</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-8429983443669649533</id><published>2024-01-05T14:46:00.003-06:00</published><updated>2024-01-05T14:46:58.121-06:00</updated><title type='text'>AWS DynamoDB SDK support for .NET DateTimeOffset</title><content type='html'>&lt;p&gt;The &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/HowItWorks.NamingRulesDataTypes.html&quot;&gt;AWS DynamoDB SDK&lt;/a&gt; does not support the .NET DateTimeOffset datatype &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DotNetSDKHighLevel.html&quot;&gt;by default&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;You may have received an exception similar to:&lt;/p&gt;&lt;p&gt;&lt;i&gt;System.InvalidOperationException: Type System.Nullable System.DateTimeOffset is unsupported, it cannot be instantiated. at Amazon.DynamoDBv2.DataModel&lt;/i&gt;&lt;/p&gt;&lt;p&gt;But you can add a custom &lt;a href=&quot;https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBContext.ArbitraryDataMapping.html&quot;&gt;IPropertyConverter&lt;/a&gt; so that you can persist DateTimeOffset.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;public class DateTimeOffsetPropertyConverter : IPropertyConverter&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;{&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; public static readonly string DateTimeOffsetPersistenceFormatString = &quot;yyyy-MM-ddTHH:mm:ss.ffffzzz&quot;;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; public object FromEntry(DynamoDBEntry entry)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (entry == null)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; throw new ArgumentNullException(nameof(entry));&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var primitive = entry as Primitive;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (primitive == null)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; throw new ArgumentException($&quot;{nameof(entry)} [{entry?.GetType()?.Name}] is not an instance of {nameof(Primitive)}.&quot;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var dateString = primitive.Value as string;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (string.IsNullOrWhiteSpace(dateString))&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; throw new ArgumentException($&quot;{nameof(entry)} does not contain a string primitive value.&quot;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (DateTimeOffset.TryParse(dateString, out var dateTimeOffset))&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return dateTimeOffset;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; throw new ArgumentException($&quot;{nameof(entry)} primitive string value could not be parsed.&quot;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; public DynamoDBEntry ToEntry(object value)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (value == null)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; throw new ArgumentNullException(nameof(value));&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; if (value is not DateTimeOffset)&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; throw new ArgumentException($&quot;{nameof(value)} [{value.GetType().Name}] is not an instance of {nameof(DateTimeOffset)}.&quot;);&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var dateTimeOffset = (DateTimeOffset)value;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var entry = new Primitive(dateTimeOffset.ToString(DateTimeOffsetPersistenceFormatString));&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return entry;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier; font-size: xx-small;&quot;&gt;}&lt;/span&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;Hope this helps,&lt;br /&gt;Aaron&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/8429983443669649533/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/8429983443669649533' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/8429983443669649533'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/8429983443669649533'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2024/01/aws-dynamodb-sdk-support-for-net-datetimeoffset.html' title='AWS DynamoDB SDK support for .NET DateTimeOffset'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-40745596364722134</id><published>2021-12-02T16:04:00.003-06:00</published><updated>2021-12-02T16:04:53.002-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="ASP.NET"/><title type='text'>ASP.NET .NET 6 OIDC Retrieve JWT AccessToken after SaveTokens</title><content type='html'>&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;You may be familiar with the HttpContext.GetTokenAsync() &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.authentication.authenticationtokenextensions.gettokenasync?view=aspnetcore-6.0&quot;&gt;method&lt;/a&gt;. This appears to have worked in previous version of .NET, but I could not get it to work in .NET 6.&lt;/p&gt;&lt;p&gt;First, make sure you are saving the access tokens in the&amp;nbsp;&lt;a href=&quot;https://www.nuget.org/packages/Microsoft.AspNetCore.Authentication.OpenIdConnect&quot;&gt;AddOpenIdConnect&lt;/a&gt; configuration.&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;builder&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; .Services&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; .AddAuthentication(options =&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; })&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; .AddCookie()&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; .AddOpenIdConnect(options =&amp;gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&lt;b&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; options.SaveTokens = true;&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span style=&quot;font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; });&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;/div&gt;&lt;p&gt;Then, instead of HttpContext.GetTokenAsync(), call HttpContext.AuthenticateAsync(), and get the token out of the AuthenticateResult.&lt;/p&gt;&lt;p&gt;&lt;span style=&quot;font-family: courier; font-size: x-small;&quot;&gt;var accessToken = authenticateResult?.Properties?.GetString(&quot;.Token.access_token&quot;);&lt;/span&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div style=&quot;text-align: left;&quot;&gt;Hope this helps,&lt;br /&gt;Aaron&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/40745596364722134/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/40745596364722134' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/40745596364722134'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/40745596364722134'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2021/12/aspnet-net-6-oidc-accesstoken-savetokens.html' title='ASP.NET .NET 6 OIDC Retrieve JWT AccessToken after SaveTokens'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-8801603367752568527</id><published>2021-03-19T11:53:00.000-05:00</published><updated>2021-03-19T11:53:16.103-05:00</updated><title type='text'>Auth0: Restrict SPA Application Access to API Audience/Permissions/Scopes</title><content type='html'>&lt;p&gt;In &lt;a href=&quot;https://auth0.com/&quot;&gt;Auth0&lt;/a&gt;&amp;nbsp;you can restrict the APIs/Permissions a Machine-to-Machine type Application has access to using the &quot;APIs&quot; section in the Application Configuration:&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbwVrcpTo8k4jLswGHAOjE2FdpmiAq64sSjgAVOAp0tUl17Lgb3BQ5uqj7u_scurgrSM5NYhmoodvezsNnz9CSUi0WJaDEBsv4cP8kCtWqxpXbOWvDHNB9N-qNnloQoRFV1cA2HBHqrf_L/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;564&quot; data-original-width=&quot;1723&quot; height=&quot;210&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbwVrcpTo8k4jLswGHAOjE2FdpmiAq64sSjgAVOAp0tUl17Lgb3BQ5uqj7u_scurgrSM5NYhmoodvezsNnz9CSUi0WJaDEBsv4cP8kCtWqxpXbOWvDHNB9N-qNnloQoRFV1cA2HBHqrf_L/w640-h210/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;However, SPA type Applications do not have an equivalent configuration option:&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXhkRyUfJ2CXcTKuhw9B4tXjmsQldA9ayuOvOOOZ_Yrr0bC1u0l10hBx0uV9lAWMS-tEXpEzs4850F9PXfi-6R2exLZHB16EOdNZeuEeO0zINRVMs8zjnqxf9DhxyJbVT_zLbjJgzs6_2l/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;537&quot; data-original-width=&quot;1428&quot; height=&quot;241&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiXhkRyUfJ2CXcTKuhw9B4tXjmsQldA9ayuOvOOOZ_Yrr0bC1u0l10hBx0uV9lAWMS-tEXpEzs4850F9PXfi-6R2exLZHB16EOdNZeuEeO0zINRVMs8zjnqxf9DhxyJbVT_zLbjJgzs6_2l/w640-h241/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;b&gt;&lt;u&gt;There is no way to restrict the APIs a SPA type Application has access to directly&lt;/u&gt;&lt;/b&gt;. Instead, you must restrict the APIs/Permissions/Scopes a &lt;a href=&quot;https://community.auth0.com/t/is-it-possible-to-restrict-the-scopes-available-to-a-spa/51990&quot;&gt;User has access to&lt;/a&gt;. (Most likely you&#39;ll want to do this using Roles.)&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp_6ApWNEhgRg8EuDMnMiZf0EgQMXxdXkwU9xukPIotPvL3VsGTKqAcWZRjpAY9udCYK5MHNfUiyRnyLJS8HkwwlNV6VbCjfJ5JLtyZUDlkpWNzsbd6qs-Nt9hFWxaER6xPKYzJBju8xaJ/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;757&quot; data-original-width=&quot;1867&quot; height=&quot;260&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjp_6ApWNEhgRg8EuDMnMiZf0EgQMXxdXkwU9xukPIotPvL3VsGTKqAcWZRjpAY9udCYK5MHNfUiyRnyLJS8HkwwlNV6VbCjfJ5JLtyZUDlkpWNzsbd6qs-Nt9hFWxaER6xPKYzJBju8xaJ/w640-h260/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;You must also ensure the &quot;&lt;a href=&quot;https://auth0.com/docs/authorization/rbac/enable-role-based-access-control-for-apis&quot;&gt;Enable RBAC&lt;/a&gt;&quot; setting is turned on for all of your APIs (this setting is off by default).&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ9CGh0xbimFuynMt-GUXTZqJUVWXwum5g5WNQi39x6ne8PFNsMus5qvYgDm3x6axxknBg8AKvzBowMRSe2b7g2r_2iXPJLXsjymHcvZQg45yQ9gJoXCwnPEzh4YkcdSy2Yx5kmfXDgk89/&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img alt=&quot;&quot; data-original-height=&quot;658&quot; data-original-width=&quot;1864&quot; height=&quot;226&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiQ9CGh0xbimFuynMt-GUXTZqJUVWXwum5g5WNQi39x6ne8PFNsMus5qvYgDm3x6axxknBg8AKvzBowMRSe2b7g2r_2iXPJLXsjymHcvZQg45yQ9gJoXCwnPEzh4YkcdSy2Yx5kmfXDgk89/w640-h226/image.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;b&gt;&lt;u&gt;If the &quot;Enable RBAC&quot; 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!&lt;br /&gt;&lt;/u&gt;&lt;/b&gt;&lt;br /&gt;And even with this setting turned on, a SPA Application will be able to &lt;b&gt;&lt;u&gt;request and receive a token for an API the user does NOT have access to!&lt;/u&gt;&lt;/b&gt;&amp;nbsp;The Audience value in the access token will be valid for the API, however the &quot;scopes&quot; and &quot;permissions&quot; will be empty.&lt;p&gt;&lt;/p&gt;&lt;p&gt;The API validating a token from Auth0 must validate the Audience AND all relevant/necessary scopes.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;In summary, turn on &quot;Enable RBAC&quot; for all APIs and validate the Audience AND Permissions on all access tokens.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Hope this helps!&lt;/p&gt;&lt;p&gt;Aaron&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/8801603367752568527/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/8801603367752568527' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/8801603367752568527'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/8801603367752568527'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2021/03/auth0-restrict-spa-application-access-to-api-audience-permissions-scopes.html' title='Auth0: Restrict SPA Application Access to API Audience/Permissions/Scopes'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbwVrcpTo8k4jLswGHAOjE2FdpmiAq64sSjgAVOAp0tUl17Lgb3BQ5uqj7u_scurgrSM5NYhmoodvezsNnz9CSUi0WJaDEBsv4cP8kCtWqxpXbOWvDHNB9N-qNnloQoRFV1cA2HBHqrf_L/s72-w640-h210-c/image.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-4789241330501717963</id><published>2020-12-17T15:30:00.001-06:00</published><updated>2020-12-17T15:30:43.069-06:00</updated><title type='text'>Find Azure Application Insights Resource by InstrumentationKey</title><content type='html'>&lt;p&gt;I had a need to query some Application Insights logs, but all I had was the&amp;nbsp;InstrumentationKey.&lt;/p&gt;&lt;p&gt;I didn&#39;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 &quot;Az&quot; Powershell Module installed, you can run this script to print out all App Insights instances and their associated Instrumentation Key:&lt;/p&gt;&lt;p&gt;&lt;a href=&quot;https://gist.github.com/aaronhoffman/cf5bd0c59216b3e6a57c0c6ea134cafb&quot;&gt;https://gist.github.com/aaronhoffman/cf5bd0c59216b3e6a57c0c6ea134cafb&lt;/a&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;table class=&quot;highlight tab-size js-file-line-container&quot; data-paste-markdown-skip=&quot;&quot; data-tab-size=&quot;8&quot; style=&quot;background-color: white; border-collapse: collapse; border-spacing: 0px; color: #24292e; font-family: -apple-system, BlinkMacSystemFont, &amp;quot;Segoe UI&amp;quot;, Helvetica, Arial, sans-serif, &amp;quot;Apple Color Emoji&amp;quot;, &amp;quot;Segoe UI Emoji&amp;quot;; font-size: 14px; tab-size: 8;&quot;&gt;&lt;tbody style=&quot;box-sizing: border-box;&quot;&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;1&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L1&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC1&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;&lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;&lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;#&lt;/span&gt; for each subscription in context&lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;2&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L2&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC2&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;&lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;foreach&lt;/span&gt; (&lt;span class=&quot;pl-smi&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);&quot;&gt;$subId&lt;/span&gt; &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;in&lt;/span&gt; (&lt;span class=&quot;pl-c1&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-constant);&quot;&gt;Get-AzSubscription&lt;/span&gt;).Id &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;pl-c1&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-constant);&quot;&gt;Get-Unique&lt;/span&gt;) {&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;3&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L3&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC3&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;   &lt;span class=&quot;pl-c1&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-constant);&quot;&gt;write-host&lt;/span&gt; &lt;span class=&quot;pl-s&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-string);&quot;&gt;&lt;span class=&quot;pl-pds&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-string);&quot;&gt;&quot;&lt;/span&gt;Subscription &lt;span class=&quot;pl-smi&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);&quot;&gt;$subId&lt;/span&gt;&lt;span class=&quot;pl-pds&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-string);&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;4&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L4&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC4&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;   &lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;5&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L5&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC5&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;   &lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;&lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;#&lt;/span&gt; set context to the given subId &lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;6&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L6&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC6&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;   &lt;span class=&quot;pl-c1&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-constant);&quot;&gt;Set-AzContext&lt;/span&gt; &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;-&lt;/span&gt;SubscriptionId &lt;span class=&quot;pl-smi&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-storage-modifier-import);&quot;&gt;$subId&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;7&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L7&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC7&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;   &lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;8&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L8&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC8&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;   &lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;&lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;#&lt;/span&gt; List the name and InstrumentationKey of all Application Insights resources in this sub&lt;span class=&quot;pl-c&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-comment);&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;9&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L9&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC9&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;   &lt;span class=&quot;pl-c1&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-constant);&quot;&gt;Get-AzResource&lt;/span&gt; &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;-&lt;/span&gt;ResourceType Microsoft.Insights&lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;/&lt;/span&gt;components &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;-&lt;/span&gt;ExpandProperties &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;|&lt;/span&gt; select &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;-&lt;/span&gt;ExpandProperty Properties &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;|&lt;/span&gt; select Name&lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;,&lt;/span&gt; InstrumentationKey &lt;span class=&quot;pl-k&quot; style=&quot;box-sizing: border-box; color: var(--color-prettylights-syntax-keyword);&quot;&gt;|&lt;/span&gt; ft&lt;/td&gt;&lt;/tr&gt;&lt;tr style=&quot;box-sizing: border-box;&quot;&gt;&lt;td class=&quot;blob-num js-line-number&quot; data-line-number=&quot;10&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-L10&quot; style=&quot;box-sizing: border-box; color: var(--color-diff-blob-num-text); cursor: pointer; font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; min-width: 50px; padding: 0px 10px; text-align: right; user-select: none; vertical-align: top; white-space: nowrap; width: 50px;&quot;&gt;&lt;/td&gt;&lt;td class=&quot;blob-code blob-code-inner js-file-line&quot; id=&quot;file-list-azure-app-insights-instrumentation-key-ps1-LC10&quot; style=&quot;box-sizing: border-box; color: var(--color-text-primary); font-family: SFMono-Regular, Consolas, &amp;quot;Liberation Mono&amp;quot;, Menlo, monospace; font-size: 12px; line-height: 20px; overflow-wrap: normal; overflow: visible; padding: 0px 10px; position: relative; vertical-align: top; white-space: pre;&quot;&gt;}&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Hope this helps!&lt;/p&gt;&lt;p&gt;Aaron&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/4789241330501717963/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/4789241330501717963' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/4789241330501717963'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/4789241330501717963'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2020/12/Find-Azure-Application-Insights-Resource-by-InstrumentationKey.html' title='Find Azure Application Insights Resource by InstrumentationKey'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-6432183346077091847</id><published>2020-12-17T15:23:00.003-06:00</published><updated>2020-12-17T15:23:24.348-06:00</updated><title type='text'>Simple Rules Engine in C#</title><content type='html'>&lt;p&gt;There are some C# &quot;Rules Engines&quot; floating around however they rely on a no-longer-supported nuget package (dynamic linq)&amp;nbsp;&lt;a href=&quot;https://github.com/microsoft/RulesEngine&quot;&gt;https://github.com/microsoft/RulesEngine&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I created this &quot;SimpleRulesEngine&quot; that does not rely on lambdas or expression trees. The expressions can be serialized to JSON.&amp;nbsp;&lt;a href=&quot;https://github.com/aaronhoffman/SimpleRulesEngine&quot;&gt;https://github.com/aaronhoffman/SimpleRulesEngine&lt;/a&gt;&amp;nbsp;&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;I hope to get a simple example web application added to this repo as well, but I&#39;m not sure when I will have time. Please check out the unit tests for now to see how this can be used.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb4OjXz0ekdAuP-YJpCUKOXkkgA9nUGv_txBgtYoytcP7u0WOpKvh0jXzD7M2_Cs6X-iEPFYnTViSvGLluOZrEDEDw1LqR9CxySIlFdXrPBNAAi2n3tA2zRzFQAQUaNbnQSo3lK5pIzRVn/s1972/expression-definition-simple-rules-engine.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1087&quot; data-original-width=&quot;1972&quot; height=&quot;304&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb4OjXz0ekdAuP-YJpCUKOXkkgA9nUGv_txBgtYoytcP7u0WOpKvh0jXzD7M2_Cs6X-iEPFYnTViSvGLluOZrEDEDw1LqR9CxySIlFdXrPBNAAi2n3tA2zRzFQAQUaNbnQSo3lK5pIzRVn/w552-h304/expression-definition-simple-rules-engine.png&quot; width=&quot;552&quot; /&gt;&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Hope this helps,&lt;/p&gt;&lt;p&gt;Aaron&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/6432183346077091847/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/6432183346077091847' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6432183346077091847'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6432183346077091847'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2020/12/simple-rules-engine-in-c-sharp.html' title='Simple Rules Engine in C#'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb4OjXz0ekdAuP-YJpCUKOXkkgA9nUGv_txBgtYoytcP7u0WOpKvh0jXzD7M2_Cs6X-iEPFYnTViSvGLluOZrEDEDw1LqR9CxySIlFdXrPBNAAi2n3tA2zRzFQAQUaNbnQSo3lK5pIzRVn/s72-w552-h304-c/expression-definition-simple-rules-engine.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-6817457489587728217</id><published>2020-09-15T12:18:00.003-05:00</published><updated>2020-09-15T15:32:42.231-05:00</updated><title type='text'>Configure SonarAnalyzer.CSharp with .editorconfig, no need for SonarCloud or SonarQube</title><content type='html'>&lt;p&gt;Our goal was to use&amp;nbsp;&lt;a href=&quot;https://www.sonarsource.com/&quot;&gt;SonarSource&lt;/a&gt;/&lt;a href=&quot;https://www.sonarqube.org/&quot;&gt;SonarQube&lt;/a&gt;&amp;nbsp;static code analysis with the most &quot;minimal&quot; install/configuration footprint.&lt;/p&gt;&lt;p&gt;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.&lt;/p&gt;&lt;p&gt;SonarSource products usually rely on some external source,&amp;nbsp;&lt;a href=&quot;https://sonarcloud.io/&quot;&gt;SonarCloud&lt;/a&gt;/SonarQube to determine which rules to apply on the local dev machine, and to store the results. We wanted to eliminate these dependencies.&lt;/p&gt;&lt;p&gt;SonarSource also provides a Visual Studio extension called&amp;nbsp;&lt;a href=&quot;https://www.sonarlint.org/&quot;&gt;SonarLint&lt;/a&gt;&amp;nbsp;to help check the static code analysis rules within the Visual Studio IDE without needing an external source for the rules.&lt;/p&gt;&lt;p&gt;The static code analysis rules SonarLint enforces are also defined in the&amp;nbsp;&lt;a href=&quot;https://www.nuget.org/packages/SonarAnalyzer.CSharp/&quot;&gt;SonarAnalyzer.CSharp&lt;/a&gt;&amp;nbsp;nuget package. This nuget package is a set of&amp;nbsp;&lt;a href=&quot;https://github.com/dotnet/roslyn-analyzers&quot;&gt;Roslyn Code Analyzers&lt;/a&gt;.&lt;/p&gt;&lt;p&gt;In .NET Core, Roslyn Code Analyzers are triggered during a build if the nuget package is referenced by the project. Also in .NET Core, these analyzers can be configured in .&lt;a href=&quot;https://docs.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2019&quot;&gt;editorconfig&lt;/a&gt;&amp;nbsp;instead of ruleset files.&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Given all that, to get SonarQube static code analysis to execute on local machine and Azure DevOps builds with the most minimal setup, just reference the SonarAnalyzer.CSharp nuget package in each of your projects and add an editorconfig file to the root of your project. You can configure rule severity in the editorconfig file by adding lines like this:&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;div&gt;&lt;span style=&quot;font-family: courier;&quot;&gt;# S1075: URIs should not be hardcoded&lt;br /&gt;dotnet_diagnostic.S1075.severity = error&lt;/span&gt;&lt;/div&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Hope this helps,&lt;/p&gt;&lt;p&gt;Aaron&lt;/p&gt;&lt;p&gt;&lt;br /&gt;&lt;/p&gt;&lt;p&gt;Thanks to this &lt;a href=&quot;https://github.com/DotNetAnalyzers/StyleCopAnalyzers/issues/3045&quot;&gt;github issue&lt;/a&gt; for getting me to the finish line with the editorconfig file.&lt;/p&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/6817457489587728217/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/6817457489587728217' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6817457489587728217'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6817457489587728217'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2020/09/configure-sonaranalyzercsharp-with-editorconfig.html' title='Configure SonarAnalyzer.CSharp with .editorconfig, no need for SonarCloud or SonarQube'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-2121193068958682393</id><published>2019-07-01T15:53:00.001-05:00</published><updated>2019-07-01T15:53:50.651-05:00</updated><title type='text'>AspNet Core JWT Authentication ValidateLifetime &quot;The token has no expiration&quot;</title><content type='html'>Found a &quot;bug&quot; within aspnet core JWT Authentication and thought I&#39;d write something up since I could not find much info online.&lt;br /&gt;
&lt;br /&gt;
Found the answer here, but it&#39;s not easy to find:&amp;nbsp;&lt;a href=&quot;https://github.com/SevenSpikes/api-plugin-for-nopcommerce/issues/99&quot;&gt;https://github.com/SevenSpikes/api-plugin-for-nopcommerce/issues/99&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
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, &quot;&lt;a href=&quot;https://github.com/aspnet/AspNetCore/blob/master/src/Security/Authentication/JwtBearer/src/JwtBearerHandler.cs#L295&quot;&gt;The token has no expiration&lt;/a&gt;&quot;.&lt;br /&gt;
&lt;br /&gt;
The solution is to create a JWT with an expiration time after &quot;now&quot; but before the year 2038.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/2121193068958682393/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/2121193068958682393' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/2121193068958682393'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/2121193068958682393'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2019/07/aspnet-core-jwt-authentication-validatelifetime-the-token-has-no-expiration.html' title='AspNet Core JWT Authentication ValidateLifetime &quot;The token has no expiration&quot;'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-5060611134554953571</id><published>2018-11-20T16:43:00.001-06:00</published><updated>2018-11-20T16:44:45.802-06:00</updated><title type='text'>United States Postal Code to State Map</title><content type='html'>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 &lt;a href=&quot;https://www.irs.gov/pub/irs-utl/zip%20code%20and%20state%20abbreviations.pdf&quot;&gt;irs.gov&lt;/a&gt;, but that doesn&#39;t lend itself well to automation.&lt;br /&gt;
&lt;br /&gt;
Using that PDF, I generated this CSV file:&amp;nbsp;&lt;a href=&quot;https://gist.github.com/aaronhoffman/d7a598efb593e3acf5e0a39c0dd8b52a&quot;&gt;https://gist.github.com/aaronhoffman/d7a598efb593e3acf5e0a39c0dd8b52a&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
There are two different formats depending on your use case. I hope you find it useful!&lt;br /&gt;
-Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh0mFj0HghE64l03ymZuSDQvOFUKFs66XpKxE8SnK2oPvqbsPzH03uZV263OWPca7ZNF3Xow4kAR0TFjkM6dvfDHt1qSD4jb7cSK4kiiL3JHvI-yXCI9Yj2vxcPcbCTcpk2gqRN3j_x00i/s1600/united-states-state-code-to-postal-code-map.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;752&quot; data-original-width=&quot;1376&quot; height=&quot;217&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh0mFj0HghE64l03ymZuSDQvOFUKFs66XpKxE8SnK2oPvqbsPzH03uZV263OWPca7ZNF3Xow4kAR0TFjkM6dvfDHt1qSD4jb7cSK4kiiL3JHvI-yXCI9Yj2vxcPcbCTcpk2gqRN3j_x00i/s400/united-states-state-code-to-postal-code-map.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/5060611134554953571/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/5060611134554953571' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/5060611134554953571'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/5060611134554953571'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/11/united-states-postal-code-to-state-map.html' title='United States Postal Code to State Map'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjh0mFj0HghE64l03ymZuSDQvOFUKFs66XpKxE8SnK2oPvqbsPzH03uZV263OWPca7ZNF3Xow4kAR0TFjkM6dvfDHt1qSD4jb7cSK4kiiL3JHvI-yXCI9Yj2vxcPcbCTcpk2gqRN3j_x00i/s72-c/united-states-state-code-to-postal-code-map.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-1593482451008617981</id><published>2018-09-13T16:50:00.002-05:00</published><updated>2018-09-13T16:52:35.501-05:00</updated><title type='text'>Newtonsoft Json BaseJsonConverter</title><content type='html'>I&#39;ve recently had a need for a custom JsonConverter to read and write data to CosmosDb in a way that utilizes a CosmosDb document&#39;s `id` property. (more on that in a later post)&lt;br /&gt;
&lt;br /&gt;
My first step was to investigate a custom &lt;a href=&quot;https://www.newtonsoft.com/json&quot;&gt;Newtonsoft.Json&lt;/a&gt; &lt;a href=&quot;https://www.newtonsoft.com/json/help/html/CustomJsonConverter.htm&quot;&gt;JsonConverter&lt;/a&gt;.&amp;nbsp;I thought that there might be a BaseJsonConverter implementation somewhere in the docs, &lt;a href=&quot;https://github.com/JamesNK/Newtonsoft.Json/issues/386&quot;&gt;but I was wrong&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
After digging through many different custom converters, I think I&#39;ve discovered what the most trivial custom converter might look like.&lt;br /&gt;
&lt;br /&gt;
You can find the example here, and customize it further to fit your needs:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/aaronhoffman/de40ac508de95101fa41859195728e39&quot;&gt;https://gist.github.com/aaronhoffman/de40ac508de95101fa41859195728e39&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3wRfZ-Nwo6uiseX4HOX64jXTHDh5rReMTQqpqRJws1ekBZOx64FFYc4vp7N_T-Qw2zvMvOg84ThaIQ4OiUspt9ArsoSvJnsioQtpLWH0-eJ67znAaYQMsnj9VT1LVdPcm4WKhQ6urzsTE/s1600/2018-09-13_1451.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;834&quot; data-original-width=&quot;1188&quot; height=&quot;280&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3wRfZ-Nwo6uiseX4HOX64jXTHDh5rReMTQqpqRJws1ekBZOx64FFYc4vp7N_T-Qw2zvMvOg84ThaIQ4OiUspt9ArsoSvJnsioQtpLWH0-eJ67znAaYQMsnj9VT1LVdPcm4WKhQ6urzsTE/s400/2018-09-13_1451.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/1593482451008617981/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/1593482451008617981' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1593482451008617981'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1593482451008617981'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/09/newtonsoft-json-basejsonconverter.html' title='Newtonsoft Json BaseJsonConverter'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3wRfZ-Nwo6uiseX4HOX64jXTHDh5rReMTQqpqRJws1ekBZOx64FFYc4vp7N_T-Qw2zvMvOg84ThaIQ4OiUspt9ArsoSvJnsioQtpLWH0-eJ67znAaYQMsnj9VT1LVdPcm4WKhQ6urzsTE/s72-c/2018-09-13_1451.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-5571805826742539818</id><published>2018-06-23T16:06:00.001-05:00</published><updated>2018-06-23T16:08:09.454-05:00</updated><title type='text'>Complete Project Gutenberg Catalog in JSON</title><content type='html'>&lt;a href=&quot;https://www.gutenberg.org/&quot;&gt;Project Gutenberg&lt;/a&gt; is an amazing site containing over 57,000 free ebooks at the time of this writing.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYR9Mn962_AKSj1fvtJCJXtU2aupsZhnw1OGcvf8w2b5Ix3EENU9Xzz0FCsqS2yO-xg5gSZvan3RsScfgt4bDwta6nXYp-g4b87nvpw3KI00OmT4YwIwWSFMM5Yxgiz1WK-yQ6FoA83DGp/s1600/project-gutenberg.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;750&quot; data-original-width=&quot;1436&quot; height=&quot;208&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYR9Mn962_AKSj1fvtJCJXtU2aupsZhnw1OGcvf8w2b5Ix3EENU9Xzz0FCsqS2yO-xg5gSZvan3RsScfgt4bDwta6nXYp-g4b87nvpw3KI00OmT4YwIwWSFMM5Yxgiz1WK-yQ6FoA83DGp/s400/project-gutenberg.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Recently I&#39;ve been working on a project to create a database of book bibliographies. A database of book references from within other books. You&#39;d be able to answer the query: Show me all the books that reference &quot;Thinking Fast and Slow&quot;. I plan to use Project Gutenberg as the repository that I use to create the first version of this database.&lt;br /&gt;
&lt;br /&gt;
Project Gutenberg currently makes their complete project catalog available as a collection of &lt;a href=&quot;https://www.w3.org/RDF/&quot;&gt;RDF&lt;/a&gt; files found here: &lt;a href=&quot;http://www.gutenberg.org/wiki/Gutenberg:Feeds&quot;&gt;http://www.gutenberg.org/wiki/Gutenberg:Feeds&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
RDF is not something I&#39;ve worked with in the past, so I converted them to JSON files. You can download that set of files from here:&lt;br /&gt;
&lt;br /&gt;
https://sfp.blob.core.windows.net/public/gutenberg_catalog.zip&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/5571805826742539818/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/5571805826742539818' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/5571805826742539818'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/5571805826742539818'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/06/complete-project-gutenberg-catalog-in-json.html' title='Complete Project Gutenberg Catalog in JSON'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYR9Mn962_AKSj1fvtJCJXtU2aupsZhnw1OGcvf8w2b5Ix3EENU9Xzz0FCsqS2yO-xg5gSZvan3RsScfgt4bDwta6nXYp-g4b87nvpw3KI00OmT4YwIwWSFMM5Yxgiz1WK-yQ6FoA83DGp/s72-c/project-gutenberg.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-6449145545064339646</id><published>2018-06-16T11:52:00.001-05:00</published><updated>2018-06-16T11:53:36.790-05:00</updated><title type='text'>ASP.NET Core 2.1 Identity</title><content type='html'>I thought I&#39;d compile some resources on &lt;a href=&quot;https://docs.microsoft.com/en-us/aspnet/core/security/authentication/identity?view=aspnetcore-2.1&amp;amp;tabs=visual-studio%2Caspnetcore2x&quot;&gt;ASP.NET Core 2.1 Identity&lt;/a&gt;. Hope you find these useful:&lt;br /&gt;
&lt;br /&gt;
Database schema of tables that are generated after the first EF Migration:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/aaronhoffman/74f4c072afaa0459dcd6595b6380f67d&quot;&gt;https://gist.github.com/aaronhoffman/74f4c072afaa0459dcd6595b6380f67d&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
You can override password rules in the Startup.cs class:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; services.AddDefaultIdentity&lt;identityuser&gt;()&lt;/identityuser&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; .AddEntityFrameworkStores&lt;applicationdbcontext&gt;();&lt;/applicationdbcontext&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; services.Configure&lt;identityoptions&gt;(options =&amp;gt;&lt;/identityoptions&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; options.Password.RequireDigit = false;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; options.Password.RequireLowercase = false;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; options.Password.RequireUppercase = false;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; options.Password.RequireNonAlphanumeric = false;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; });&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
If you are wondering where the AccountController or login pages are (because they do not appear in the solution explorer by default) more info can be found here:&amp;nbsp;&lt;a href=&quot;https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.1&amp;amp;tabs=visual-studio&quot;&gt;https://docs.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.1&amp;amp;tabs=visual-studio&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
That&#39;s it for now, hopefully more to come...&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3DHbUv8mGNCwbJfcao-bm5-qv1s6CKSdNnSaDe_PgwHKexlMomPJIT3yDNcLsRwpogbqmrLCJYG7B3Z0xvxo_am3Q3HC0PzRtDE76fLvSLGtWLnX1TrgF-cIFiuMEG4U8dHrykT2RcXYY/s1600/aspnet-core-identity.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;586&quot; data-original-width=&quot;1298&quot; height=&quot;180&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3DHbUv8mGNCwbJfcao-bm5-qv1s6CKSdNnSaDe_PgwHKexlMomPJIT3yDNcLsRwpogbqmrLCJYG7B3Z0xvxo_am3Q3HC0PzRtDE76fLvSLGtWLnX1TrgF-cIFiuMEG4U8dHrykT2RcXYY/s400/aspnet-core-identity.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/6449145545064339646/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/6449145545064339646' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6449145545064339646'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6449145545064339646'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/06/aspnet-core-21-identity.html' title='ASP.NET Core 2.1 Identity'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3DHbUv8mGNCwbJfcao-bm5-qv1s6CKSdNnSaDe_PgwHKexlMomPJIT3yDNcLsRwpogbqmrLCJYG7B3Z0xvxo_am3Q3HC0PzRtDE76fLvSLGtWLnX1TrgF-cIFiuMEG4U8dHrykT2RcXYY/s72-c/aspnet-core-identity.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-3496047477674251912</id><published>2018-04-26T15:07:00.002-05:00</published><updated>2018-04-26T15:07:59.504-05:00</updated><title type='text'>Programmatically add Other Search Engines to Google Chrome for VSTS Shortcuts</title><content type='html'>When I&#39;m working with a new repo/project in &lt;a href=&quot;https://www.visualstudio.com/team-services/&quot;&gt;VSTS&lt;/a&gt;, 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.&lt;br /&gt;
&lt;br /&gt;
To do this, I take advantage of Chrome&#39;s &quot;&lt;a href=&quot;chrome://settings/searchEngines&quot;&gt;other search engines&lt;/a&gt;&quot; settings.&lt;br /&gt;
&lt;br /&gt;
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&#39;s address bar.&lt;br /&gt;
&lt;br /&gt;
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!&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZVQuosF0fGvDlDO9fV__TDk1rzVyL5SfHxQhJNuUppfXkoeu4KsVLDNNQVYKH0ocPlqwzXsdlLkJupPkaKpZbTAkvw2cCjZLnE-9WheCsA-ooL_gdCxvQrsc4-o93NvTibnxf0QgtKLtx/s1600/add-search-google-chrome-sqlite-2018-04-26_1435.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;478&quot; data-original-width=&quot;1484&quot; height=&quot;204&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZVQuosF0fGvDlDO9fV__TDk1rzVyL5SfHxQhJNuUppfXkoeu4KsVLDNNQVYKH0ocPlqwzXsdlLkJupPkaKpZbTAkvw2cCjZLnE-9WheCsA-ooL_gdCxvQrsc4-o93NvTibnxf0QgtKLtx/s640/add-search-google-chrome-sqlite-2018-04-26_1435.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
You can use the following SQL Script to insert the default set of shortcuts I usually add for each new VSTS project/repo:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/aaronhoffman/60660365310b7ff462b547fea9eb605b&quot;&gt;https://gist.github.com/aaronhoffman/60660365310b7ff462b547fea9eb605b&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Steps to Add:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;1. Ensure all instances of Google Chrome are closed (the SQLite DB will be locked if Chrome is open.)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;2. Install/Open a SQLite browser (e.g.&amp;nbsp;&lt;a href=&quot;http://sqlitebrowser.org/&quot;&gt;http://sqlitebrowser.org/&lt;/a&gt;)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;3. Open the SQLite DB for the &lt;a href=&quot;chrome://settings/?search=manage+other+people&quot;&gt;Chrome Profile&lt;/a&gt; you&#39;re using (if you&#39;re not using Google Chrome Profiles... you should be.) The SQLite DB can be found here: &quot;C:\Users\{your-user}\AppData\Local\Google\Chrome\User Data\Profile {XX}\Web Data&quot;&amp;nbsp; Note that the SQLite DB File is called &quot;Web Data&quot; with no extension.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;4. Copy &lt;a href=&quot;https://gist.github.com/aaronhoffman/60660365310b7ff462b547fea9eb605b&quot;&gt;this script&lt;/a&gt;, and perform a find replace on the 4 &quot;variables&quot; defined in the comment at the top of the file.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;5. Execute that script to insert the 8 new shortcut records into the `keywords` table.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;How to Use:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
For this demo, lets say you used &quot;mr&quot; as the shortcut prefix.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;1. In Chrome, make the address bar active (ctrl + L) (it should highlight whatever contents may already be in the address bar)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;2. With the address bar active, type: &quot;mrwis&quot; then a space, then enter. You will navigate to the &quot;Work Items&quot; page for that VSTS Project.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;3. Highlight the address bar again, and type: &quot;mrwi&quot;, then a space, then type the work item number you want to navigate to. Let&#39;s try &quot;1&quot;. Then press enter. You will navigate to Work Item with the ID of 1.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;4. Here are the other shortcuts (again, for the prefix of &quot;mr&quot; for this example)&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; mrwis&amp;nbsp; ----&amp;nbsp; all recent work items&lt;br /&gt;
&amp;nbsp; mrwi&amp;nbsp; &amp;nbsp;----&amp;nbsp; single work item&lt;br /&gt;
&amp;nbsp; mrprs&amp;nbsp; ----&amp;nbsp; all active pull requests&lt;br /&gt;
&amp;nbsp; mrpr&amp;nbsp; &amp;nbsp;----&amp;nbsp; single pull request&lt;br /&gt;
&amp;nbsp; mrbs&amp;nbsp; &amp;nbsp;----&amp;nbsp; all recent builds&lt;br /&gt;
&amp;nbsp; mrb&amp;nbsp; &amp;nbsp; ----&amp;nbsp; &amp;nbsp;single build&lt;br /&gt;
&amp;nbsp; mrrs&amp;nbsp; &amp;nbsp;----&amp;nbsp; all recent releases&lt;br /&gt;
&amp;nbsp; mrr&amp;nbsp; &amp;nbsp; &amp;nbsp;----&amp;nbsp; single release&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps!&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/3496047477674251912/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/3496047477674251912' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/3496047477674251912'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/3496047477674251912'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/04/programmatically-add-other-search-engines-to-google-chrome-for-vsts-shortcuts.html' title='Programmatically add Other Search Engines to Google Chrome for VSTS Shortcuts'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgZVQuosF0fGvDlDO9fV__TDk1rzVyL5SfHxQhJNuUppfXkoeu4KsVLDNNQVYKH0ocPlqwzXsdlLkJupPkaKpZbTAkvw2cCjZLnE-9WheCsA-ooL_gdCxvQrsc4-o93NvTibnxf0QgtKLtx/s72-c/add-search-google-chrome-sqlite-2018-04-26_1435.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-1938878871276808332</id><published>2018-04-25T09:34:00.001-05:00</published><updated>2018-04-25T10:17:56.990-05:00</updated><title type='text'>Location of SqlPackage.exe on VSTS and Azure</title><content type='html'>If you&#39;re looking to deploy a &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/xee70aty.aspx?f=255&amp;amp;MSPPError=-2147217396&quot;&gt;Visual Studio&lt;/a&gt; &lt;a href=&quot;https://msdn.microsoft.com/en-us/library/hh272677(v=vs.103).aspx&quot;&gt;Database Project&lt;/a&gt;&amp;nbsp;via VSTS to Azure, you can use the &lt;a href=&quot;https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/SqlAzureDacpacDeployment/README.md&quot;&gt;Azure SQL Database Deployment&lt;/a&gt;&amp;nbsp;Release Task to &lt;a href=&quot;https://docs.microsoft.com/en-us/vsts/build-release/apps/cd/deploy-dacpac-sqlpackage?view=vsts&quot;&gt;include the deployment&lt;/a&gt; in your CI/CD process.&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
SqlPackage.exe can do more than just `publish`. However, at this time, the publish action is the &lt;a href=&quot;https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/SqlAzureDacpacDeployment/Utility.ps1#L181&quot;&gt;only action supported&lt;/a&gt; by that release task.&lt;br /&gt;
&lt;br /&gt;
If you&#39;d like to perform &lt;a href=&quot;https://docs.microsoft.com/en-us/vsts/build-release/apps/cd/sql-server-actions?view=vsts&quot;&gt;other actions&lt;/a&gt; (e.g. `DeployReport` or `Script`), you can call the SqlPackage.exe directly using a PowerShell Script Release Task. However, to do that, you&#39;ll need to know the location of the SqlPackage.exe on the VSTS host, because it is not available in the PATH by default.&lt;br /&gt;
&lt;br /&gt;
To find the location of SqlPackage.exe, the Azure SQL DB Deploy task uses this utility script:&amp;nbsp;&lt;a href=&quot;https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/SqlAzureDacpacDeployment/FindSqlPackagePath.ps1&quot;&gt;https://github.com/Microsoft/vsts-tasks/blob/master/Tasks/SqlAzureDacpacDeployment/FindSqlPackagePath.ps1&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
If you&#39;re using the `inline script` option of the PowerShell Script Release Task, you are limited to 500 characters (... yeah, I know) so you won&#39;t be able to use that method.&lt;br /&gt;
&lt;br /&gt;
The method below is fragile, but to find SqlPackage.exe you can first create a temporary inline script that searches for SqlPackage.exe, then just hard code that path into your script.&lt;br /&gt;
&lt;br /&gt;
Create an PowerShell script task with the following inline script:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;dir -Path &quot;c:\Program Files (x86)\Microsoft*&quot; -Filter &quot;SqlPackage.exe&quot; -Recurse -ErrorAction SilentlyContinue | %{$_.FullName}&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For me, that found the following instances of SqlPackage.exe (note: for some reason, the above `dir` command will take ~15 minutes to complete on VSTS. This was on the &quot;Hosted VS2017&quot; VSTS agent):&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\130\sqlpackage.exe&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\Common7\IDE\Extensions\Microsoft\SQLDB\DAC\140\sqlpackage.exe&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
The SqlPackage.exe will usually be found under:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;C:\Program Files (x86)\Microsoft Visual Studio&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;or&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;C:\Program Files (x86)\Microsoft SQL Server&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
In &lt;b&gt;Azure&lt;/b&gt;, via the portal, if you open a console for a Web App, and execute the following commands, you may find SqlPackage.exe here:&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;cd d:\Program Files (x86)\Microsoft SQL Server\&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;dir /s /b *SqlPackage.exe&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;D:\Program Files (x86)\Microsoft SQL Server\140\DAC\bin\SqlPackage.exe&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidW05rU14NmFxsMGr-yiSP52yWsI_1OFSpm9xQfq0FjVM6ZMDBSQzxjkx1QCRPVzeQJmXzXYIQoWJmGLJfTxl33OU8k29kr37lKcf_0QKh2guPqYUWJMMY-Ov6whGY2yeZN2dTgzR0V4CQ/s1600/azure-console-sqlpackage-2018-04-25_0932.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;858&quot; data-original-width=&quot;1494&quot; height=&quot;367&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidW05rU14NmFxsMGr-yiSP52yWsI_1OFSpm9xQfq0FjVM6ZMDBSQzxjkx1QCRPVzeQJmXzXYIQoWJmGLJfTxl33OU8k29kr37lKcf_0QKh2guPqYUWJMMY-Ov6whGY2yeZN2dTgzR0V4CQ/s640/azure-console-sqlpackage-2018-04-25_0932.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
Hope this helps!&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/1938878871276808332/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/1938878871276808332' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1938878871276808332'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1938878871276808332'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/04/location-of-sqlpackageexe-on-vsts-and-azure.html' title='Location of SqlPackage.exe on VSTS and Azure'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEidW05rU14NmFxsMGr-yiSP52yWsI_1OFSpm9xQfq0FjVM6ZMDBSQzxjkx1QCRPVzeQJmXzXYIQoWJmGLJfTxl33OU8k29kr37lKcf_0QKh2guPqYUWJMMY-Ov6whGY2yeZN2dTgzR0V4CQ/s72-c/azure-console-sqlpackage-2018-04-25_0932.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-1405983540007551357</id><published>2018-04-04T09:54:00.001-05:00</published><updated>2018-04-04T09:58:26.830-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="gist"/><category scheme="http://www.blogger.com/atom/ns#" term="gists"/><category scheme="http://www.blogger.com/atom/ns#" term="git"/><category scheme="http://www.blogger.com/atom/ns#" term="github"/><category scheme="http://www.blogger.com/atom/ns#" term="github-gist"/><category scheme="http://www.blogger.com/atom/ns#" term="github-gists"/><title type='text'>Sync Github Gists with Git Repo</title><content type='html'>I needed an easy way to sync&amp;nbsp;&lt;a href=&quot;https://gist.github.com/&quot;&gt;github gists&lt;/a&gt;&amp;nbsp;to my local machines and I couldn&#39;t find anything provided by gist, or any other open source projects out there so I put this little node app together quick.&lt;br /&gt;
&lt;br /&gt;
Simply clone this repo and update the `users.json` file to sync all the associated public gists to your local machine.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://github.com/aaronhoffman/gists&quot;&gt;https://github.com/aaronhoffman/gists&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The node app uses the &lt;a href=&quot;https://developer.github.com/v3/gists/&quot;&gt;gists api&lt;/a&gt;&amp;nbsp;and `git clone`s each gist into a folder with the same name as it&#39;s id:&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2xTs281hfTUpD-uB4T3TE1ThYUL3_PMrkmtAQNFGwRvtaYYY9FDdGras9Qal4txhTsbepntcBHgAG0vDSelh-5NXa7x9S38r2PTtrFXzPe0IQYLnc5Ch6L0QI0AQHmoTVc-yI1dzgXZzq/s1600/sync-github-gists.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1600&quot; data-original-width=&quot;1488&quot; height=&quot;400&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2xTs281hfTUpD-uB4T3TE1ThYUL3_PMrkmtAQNFGwRvtaYYY9FDdGras9Qal4txhTsbepntcBHgAG0vDSelh-5NXa7x9S38r2PTtrFXzPe0IQYLnc5Ch6L0QI0AQHmoTVc-yI1dzgXZzq/s400/sync-github-gists.png&quot; width=&quot;370&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps!&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/1405983540007551357/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/1405983540007551357' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1405983540007551357'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1405983540007551357'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/04/sync-github-gists-with-git-repo.html' title='Sync Github Gists with Git Repo'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg2xTs281hfTUpD-uB4T3TE1ThYUL3_PMrkmtAQNFGwRvtaYYY9FDdGras9Qal4txhTsbepntcBHgAG0vDSelh-5NXa7x9S38r2PTtrFXzPe0IQYLnc5Ch6L0QI0AQHmoTVc-yI1dzgXZzq/s72-c/sync-github-gists.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-433793298441963816</id><published>2018-02-14T11:13:00.000-06:00</published><updated>2018-02-14T11:13:01.269-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="azure"/><category scheme="http://www.blogger.com/atom/ns#" term="azure-functions"/><category scheme="http://www.blogger.com/atom/ns#" term="sql-azure"/><title type='text'>Use Azure Functions to Execute a SQL Azure Stored Procedure on a Timer</title><content type='html'>It was hard to find this information all in one place, so I thought I&#39;d throw a post together quick.&lt;br /&gt;
&lt;br /&gt;
If you have the need to execute a stored procedure on a timer, that can be fairly easily accomplished with &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-overview&quot;&gt;Azure Functions&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
Create a new &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-create-scheduled-function&quot;&gt;Timer Trigger Azure Function&lt;/a&gt;, set the cron timer as desired, and add code similar to the code below:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;using System;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;using System.Data;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;using System.Data.SqlClient;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;using System.Configuration;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;using Dapper;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&lt;br /&gt;&lt;/span&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;public static void Run(TimerInfo myTimer, TraceWriter log)&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; var conString = ConfigurationManager.ConnectionStrings[&quot;ConString&quot;]?.ConnectionString;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; using(var con = new SqlConnection(conString))&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; con.Execute(&quot;dbo.MyProc&quot;, commandType: CommandType.StoredProcedure);&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
This code will not compile at this time. Note the name of the connection string, we&#39;ll need that in the app settings page.&lt;br /&gt;
&lt;br /&gt;
Go to the Connection Strings section of the Application Settings for the function app (this will look very similar to the Connection Strings section of a Web App). Find the Application Settings by clicking on the name of the Function App and looking in the &quot;Configured features&quot; to the right.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWc7Teru4soizDLLVV-dpkozp3r4RpNmNYXV0bW-Xp4x4S6ypI9ekVRArh-p-6_jOsn_OaE_wUm6Z_WbitDyWJtp4n0I56kStLV9Q93Ee7kRSpv80Gyzl41IOjeOPn6qOIWnl9q5T7YHNR/s1600/azure-function-app-settings.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;950&quot; data-original-width=&quot;786&quot; height=&quot;320&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWc7Teru4soizDLLVV-dpkozp3r4RpNmNYXV0bW-Xp4x4S6ypI9ekVRArh-p-6_jOsn_OaE_wUm6Z_WbitDyWJtp4n0I56kStLV9Q93Ee7kRSpv80Gyzl41IOjeOPn6qOIWnl9q5T7YHNR/s320/azure-function-app-settings.png&quot; width=&quot;264&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
Add a connection string with the same name that was used in your function app, &quot;ConString&quot; in the code above.&lt;br /&gt;
&lt;br /&gt;
Now, click on the name of your function in the left pane (to see the .csx code), and on the far right side, next to &quot;Test&quot; click on the &quot;View Files&quot; tab. Add a new file called project.json, and place the following dependencies in the file. &lt;a href=&quot;https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#using-nuget-packages&quot;&gt;more info&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwbrHrc8u5gY8V1sf-oVmqdQiZXXzXGHWlaCE40xOxBMQSem8Zwb2z63Aw6XJcc_eyhLIG4WA1_7j4-ARdisiWtQsaBwr88Bi_6IoJdjxNhRYcvyL7hYX_m__gYDFBs4RG49AwwlxpMnZE/s1600/add-project-json.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;800&quot; data-original-width=&quot;1044&quot; height=&quot;245&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiwbrHrc8u5gY8V1sf-oVmqdQiZXXzXGHWlaCE40xOxBMQSem8Zwb2z63Aw6XJcc_eyhLIG4WA1_7j4-ARdisiWtQsaBwr88Bi_6IoJdjxNhRYcvyL7hYX_m__gYDFBs4RG49AwwlxpMnZE/s320/add-project-json.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;{&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &quot;frameworks&quot;: {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;net46&quot;: {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;dependencies&quot;: {&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;Dapper&quot;: &quot;1.50.2&quot;,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;System.Data.SqlClient&quot;: &quot;4.3.0&quot;,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &quot;Microsoft.WindowsAzure.ConfigurationManager&quot;: &quot;3.2.3&quot;&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;&amp;nbsp; &amp;nbsp; }&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;}&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
You can add additional nuget package dependencies here as well.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
And that should be it. Test your function by clicking the &quot;Run&quot; button and make sure everything was wired up correctly.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps!&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/433793298441963816/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/433793298441963816' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/433793298441963816'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/433793298441963816'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/02/use-azure-functions-to-execute-sql-azure-stored-procedure.html' title='Use Azure Functions to Execute a SQL Azure Stored Procedure on a Timer'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWc7Teru4soizDLLVV-dpkozp3r4RpNmNYXV0bW-Xp4x4S6ypI9ekVRArh-p-6_jOsn_OaE_wUm6Z_WbitDyWJtp4n0I56kStLV9Q93Ee7kRSpv80Gyzl41IOjeOPn6qOIWnl9q5T7YHNR/s72-c/azure-function-app-settings.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-5223544360155177179</id><published>2018-01-12T14:15:00.001-06:00</published><updated>2018-01-12T14:28:43.728-06:00</updated><title type='text'>Create Google Contact via API and Add To My Contacts System Group</title><content type='html'>When you create a new Contact via the &lt;a href=&quot;https://developers.google.com/google-apps/contacts/v3/&quot;&gt;Google Contacts API&lt;/a&gt;, by default it will not appear in the list of contacts on the &lt;a href=&quot;https://contacts.google.com/&quot;&gt;Google Contacts webpage&lt;/a&gt;, however, if you search for the contact there, it will appear. If you then click the &quot;Add to contacts&quot; button, it will appear in that contacts list, and increase your contact count in the top left of the page.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-EkUQTcY7XV0_DFLngUrONugkQgnXShl7rlZQv7KTQPgg_Oww35Rx_CaJi-H35olwqXrVZaDeu74ZXyjcpqBkEJgOK6YPXa-HhmfBya2dPyUMFWo78Dz6356o8mgMd9bQGv2nPnNXOxaq/s1600/2018-01-12_1354.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;458&quot; data-original-width=&quot;782&quot; height=&quot;187&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-EkUQTcY7XV0_DFLngUrONugkQgnXShl7rlZQv7KTQPgg_Oww35Rx_CaJi-H35olwqXrVZaDeu74ZXyjcpqBkEJgOK6YPXa-HhmfBya2dPyUMFWo78Dz6356o8mgMd9bQGv2nPnNXOxaq/s320/2018-01-12_1354.png&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
There is a way to add new contacts via the API and have them show up in this list, it is just &lt;a href=&quot;https://integrate.hubspot.com/t/contact-created-with-api-not-showing-in-all-contacts/1321&quot;&gt;not well documented&lt;/a&gt; within the API documentation. The code below demonstrates how to do this is C#.&lt;br /&gt;
&lt;br /&gt;
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 &quot;My Contacts&quot; &lt;a href=&quot;https://developers.google.com/google-apps/contacts/v3/reference#gcSystemGroup&quot;&gt;System Group&lt;/a&gt;. 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.&lt;br /&gt;
&lt;br /&gt;
Steps:&lt;br /&gt;
&amp;nbsp;1. Create a ContactsRequest&lt;br /&gt;
&amp;nbsp;2. Get a list of all groups and search for the &quot;My Contacts&quot; System Group.&lt;br /&gt;
&amp;nbsp;3. Create a new `Contact`&lt;br /&gt;
&amp;nbsp;4. Add a `GroupMembership` with an HRef equal to the &quot;My Contacts&quot; System Group Id.&lt;br /&gt;
&amp;nbsp;5. Insert the new contact via the ContactsRequest.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdQCtwFVzgbetzvAb-EyyN4Y18NZVGn8aEnnkjRx8Rr1ODGeq9ObimB49ym9ABvaR55foTHE49TD-ZjBUE2Rj5lQyImgjgsGesViu1143ONWEWvKjXWU5HHlTerQEAHTOArq12MPF71kJY/s1600/2018-01-12_1410.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;780&quot; data-original-width=&quot;1380&quot; height=&quot;360&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhdQCtwFVzgbetzvAb-EyyN4Y18NZVGn8aEnnkjRx8Rr1ODGeq9ObimB49ym9ABvaR55foTHE49TD-ZjBUE2Rj5lQyImgjgsGesViu1143ONWEWvKjXWU5HHlTerQEAHTOArq12MPF71kJY/s640/2018-01-12_1410.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/aaronhoffman/afe8d6399a7c98ed25a9f466af6a9b5d&quot;&gt;Create Contact Gist&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
p.s. I created a tool to sync contacts between gmail accounts. Check it out here:&amp;nbsp;&lt;a href=&quot;https://www.gmailcontactsync.com/&quot;&gt;https://www.gmailcontactsync.com/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/5223544360155177179/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/5223544360155177179' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/5223544360155177179'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/5223544360155177179'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2018/01/create-google-contact-api-my-contacts-system-group.html' title='Create Google Contact via API and Add To My Contacts System Group'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-EkUQTcY7XV0_DFLngUrONugkQgnXShl7rlZQv7KTQPgg_Oww35Rx_CaJi-H35olwqXrVZaDeu74ZXyjcpqBkEJgOK6YPXa-HhmfBya2dPyUMFWo78Dz6356o8mgMd9bQGv2nPnNXOxaq/s72-c/2018-01-12_1354.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-6557761154982335042</id><published>2017-12-06T14:11:00.000-06:00</published><updated>2017-12-06T14:13:39.160-06:00</updated><title type='text'>Visual Studio 2017 Code Snippet INotifyPropertyChanged</title><content type='html'>This is an update to the vs2010 code snippet:&amp;nbsp;&lt;a href=&quot;https://aaron-hoffman.blogspot.com/2010/09/visual-studio-code-snippet-for-notify.html&quot;&gt;https://aaron-hoffman.blogspot.com/2010/09/visual-studio-code-snippet-for-notify.html&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Code can now be found here:&amp;nbsp;&lt;a href=&quot;https://gist.github.com/aaronhoffman/c821acf4bb3b3beb0759e93bbe3a2402&quot;&gt;https://gist.github.com/aaronhoffman/c821acf4bb3b3beb0759e93bbe3a2402&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikkiN_2vlxzcLNfCgSBOt1BzO6F56Qa1OpKKDSgz2zjzZ-TRTdwVeOqseponyqU3skY5vMtEz-aznsBZI3DRr245hitbjyN9a8CkGW2aY69QbOLd635rezGv59hVfYfC7JuUoqEY5hBIZo/s1600/vs2017-code-snippet-inotifypropertychanged.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;740&quot; data-original-width=&quot;1308&quot; height=&quot;362&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikkiN_2vlxzcLNfCgSBOt1BzO6F56Qa1OpKKDSgz2zjzZ-TRTdwVeOqseponyqU3skY5vMtEz-aznsBZI3DRr245hitbjyN9a8CkGW2aY69QbOLd635rezGv59hVfYfC7JuUoqEY5hBIZo/s640/vs2017-code-snippet-inotifypropertychanged.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/6557761154982335042/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/6557761154982335042' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6557761154982335042'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/6557761154982335042'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/12/vs2017-visual-studio-2017-code-snippet-wpf-inotifypropertychanged.html' title='Visual Studio 2017 Code Snippet INotifyPropertyChanged'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEikkiN_2vlxzcLNfCgSBOt1BzO6F56Qa1OpKKDSgz2zjzZ-TRTdwVeOqseponyqU3skY5vMtEz-aznsBZI3DRr245hitbjyN9a8CkGW2aY69QbOLd635rezGv59hVfYfC7JuUoqEY5hBIZo/s72-c/vs2017-code-snippet-inotifypropertychanged.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-1579505971449684053</id><published>2017-11-07T13:06:00.000-06:00</published><updated>2017-11-07T13:07:50.808-06:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="nyse"/><title type='text'>NYSE Historical Stock Price Data From Quandl</title><content type='html'>&lt;a href=&quot;https://www.quandl.com/&quot;&gt;Quandl&lt;/a&gt;&amp;nbsp;is a great resource for historical stock price data. I thought I&#39;d pull some meta-data out of the &quot;&lt;a href=&quot;https://www.quandl.com/product/WIKIP/documentation/about&quot;&gt;Wiki EOD Stock Prices&lt;/a&gt;&quot; data set in order to help future developers.&lt;br /&gt;
&lt;br /&gt;
First, here is the table structure I used to insert the CSV flat file into SQL Server:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;CREATE TABLE [dbo].[SymbolHistory](&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[ticker] [varchar](5) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[date] [date] NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[open] [decimal](16, 6) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[high] [decimal](16, 6) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[low] [decimal](16, 6) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[close] [decimal](16, 6) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[volume] [decimal](26, 15) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[ex-dividend] [decimal](22, 18) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[split_ratio] [decimal](21, 19) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[adj_open] [decimal](25, 18) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[adj_high] [decimal](25, 18) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[adj_low] [decimal](25, 18) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[adj_close] [decimal](25, 18) NULL,&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;&lt;span style=&quot;white-space: pre;&quot;&gt; &lt;/span&gt;[adj_volume] [decimal](25, 18) NULL&lt;/span&gt;&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace; font-size: x-small;&quot;&gt;)&amp;nbsp;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
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.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/aaronhoffman/9ef359cbf39f2eefdf50fbd82f5d368a&quot;&gt;https://gist.github.com/aaronhoffman/9ef359cbf39f2eefdf50fbd82f5d368a&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-8J_kXQrSeVCa4kN2LUFZGFF06CAnXn9cjrnbCVaWsCXtGdRNo_1gTlehMX5dUtQ-tpwHKlnTHDYqbcApoVxfBnOFNGD_6mFUvpa3fwJ89IkR7sXc2EEtssHpuTpD-Qu53BSV5lW02i_H/s1600/quandl-historical-stock-price-eod.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;854&quot; data-original-width=&quot;1600&quot; height=&quot;211&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-8J_kXQrSeVCa4kN2LUFZGFF06CAnXn9cjrnbCVaWsCXtGdRNo_1gTlehMX5dUtQ-tpwHKlnTHDYqbcApoVxfBnOFNGD_6mFUvpa3fwJ89IkR7sXc2EEtssHpuTpD-Qu53BSV5lW02i_H/s400/quandl-historical-stock-price-eod.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/1579505971449684053/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/1579505971449684053' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1579505971449684053'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1579505971449684053'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/11/nyse-historical-stock-price-data-from-quandl.html' title='NYSE Historical Stock Price Data From Quandl'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-8J_kXQrSeVCa4kN2LUFZGFF06CAnXn9cjrnbCVaWsCXtGdRNo_1gTlehMX5dUtQ-tpwHKlnTHDYqbcApoVxfBnOFNGD_6mFUvpa3fwJ89IkR7sXc2EEtssHpuTpD-Qu53BSV5lW02i_H/s72-c/quandl-historical-stock-price-eod.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-4049056988629422763</id><published>2017-08-30T17:09:00.002-05:00</published><updated>2019-04-12T10:45:59.359-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="aes"/><category scheme="http://www.blogger.com/atom/ns#" term="encryption"/><title type='text'>Generate Random AES Encryption Key</title><content type='html'>I was looking for a way to quickly &lt;a href=&quot;https://en.wikipedia.org/wiki/Advanced_Encryption_Standard&quot;&gt;generate a random AES key&lt;/a&gt; online, but couldn&#39;t find anything. I looked into a couple methods using JavaScript, but determined that a C# solution would be better.&lt;br /&gt;
&lt;br /&gt;
I needed to base64 encode the key array to store that value in a config file.&lt;br /&gt;
&lt;br /&gt;
Here&#39;s the code I ended up with:&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/aaronhoffman/09b56f77a95205fe10365bde2f4a02e5&quot;&gt;https://gist.github.com/aaronhoffman/09b56f77a95205fe10365bde2f4a02e5&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNhEwwaxKEVeZCRH7hyEqZdXDnuPnKdO_FWb83ekjVqKzgpubWPz9zBEpgUeVryEVlfz_yIwmZ1crwHZhnW8b1OhMHTF_25JCLFoNZngJcqu4h12Ib8RV3G4xQCSl978qhMgtlOF-LSgxd/s1600/aes-key-gen.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;694&quot; data-original-width=&quot;1333&quot; height=&quot;332&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNhEwwaxKEVeZCRH7hyEqZdXDnuPnKdO_FWb83ekjVqKzgpubWPz9zBEpgUeVryEVlfz_yIwmZ1crwHZhnW8b1OhMHTF_25JCLFoNZngJcqu4h12Ib8RV3G4xQCSl978qhMgtlOF-LSgxd/s640/aes-key-gen.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;b&gt;UPDATE&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
Using Visual Studio&#39;s &quot;C# Interactive&quot; screen you can generate a key in a single line:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: Courier New, Courier, monospace; font-size: xx-small;&quot;&gt;var keyArray = new byte[32]; (new System.Security.Cryptography.RNGCryptoServiceProvider()).GetBytes(keyArray); Convert.ToBase64String(keyArray)&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgmtRiCuG9M7rYz3MTzrZbNGCLror1y3re2ZDBVg1WoMPHFqhRJq5IukoRroo3tYGMlM3NLQ9uQ1BrlehBxY8xkkj1Vs8V3KV8kzT9kJqEu6bD8JZfEhwbQq5JhzNKH9vQIkrrwrSDNZOF/s1600/aes-key-visual-studio-csharp-interactive.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;212&quot; data-original-width=&quot;1600&quot; height=&quot;83&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgmtRiCuG9M7rYz3MTzrZbNGCLror1y3re2ZDBVg1WoMPHFqhRJq5IukoRroo3tYGMlM3NLQ9uQ1BrlehBxY8xkkj1Vs8V3KV8kzT9kJqEu6bD8JZfEhwbQq5JhzNKH9vQIkrrwrSDNZOF/s640/aes-key-visual-studio-csharp-interactive.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps!&lt;br /&gt;
-Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/4049056988629422763/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/4049056988629422763' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/4049056988629422763'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/4049056988629422763'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/08/generate-random-aes-encryption-key.html' title='Generate Random AES Encryption Key'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNhEwwaxKEVeZCRH7hyEqZdXDnuPnKdO_FWb83ekjVqKzgpubWPz9zBEpgUeVryEVlfz_yIwmZ1crwHZhnW8b1OhMHTF_25JCLFoNZngJcqu4h12Ib8RV3G4xQCSl978qhMgtlOF-LSgxd/s72-c/aes-key-gen.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-7713725042038146224</id><published>2017-07-02T11:33:00.001-05:00</published><updated>2018-08-01T15:00:12.115-05:00</updated><title type='text'>Sync Gmail Contacts Between Accounts</title><content type='html'>For the last few years I&#39;ve needed a way to easily sync contacts between gmail accounts. The only method previously supported by Google is to &lt;a href=&quot;http://smallbusiness.chron.com/sync-contacts-between-gmail-accounts-54911.html&quot;&gt;export to csv&lt;/a&gt; then &lt;a href=&quot;http://lifehacker.com/5987154/how-to-sync-contacts-between-two-gmail-accounts&quot;&gt;re-import the contact list&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
This may work for some, but clearly &lt;a href=&quot;https://productforums.google.com/forum/#!msg/gmail/JIVbivTSyXA/Jq3suTqWQToJ&quot;&gt;there&lt;/a&gt; is a &lt;a href=&quot;https://www.quora.com/Is-there-a-software-to-sync-contacts-between-two-gmail-accounts&quot;&gt;desire&lt;/a&gt; for something else.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I finally found some time to dig into the &lt;a href=&quot;https://developers.google.com/google-apps/contacts/v3/&quot;&gt;Google Contact APIs&lt;/a&gt;&amp;nbsp;and created a site to perform this sync operation easily, without needing to install any software:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://www.mycontactsync.com/&quot;&gt;https://www.mycontactsync.com/&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBxqVuOJ_-tLVH5d3TprvM5Be25O84lS51IuMN7vUXZgNr3LaOS7E6eRV5nvIIrS_qEmK8E4flruvUR2jdsAZhb-2_cJq-BpieqciaVRIXk0mflqYFfkwYAHGifBsFSVrMcqv-s-OmI9xr/s1600/gmail-contacts-sync-screenshot.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;1148&quot; data-original-width=&quot;1600&quot; height=&quot;286&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBxqVuOJ_-tLVH5d3TprvM5Be25O84lS51IuMN7vUXZgNr3LaOS7E6eRV5nvIIrS_qEmK8E4flruvUR2jdsAZhb-2_cJq-BpieqciaVRIXk0mflqYFfkwYAHGifBsFSVrMcqv-s-OmI9xr/s400/gmail-contacts-sync-screenshot.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Steps to sync:&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp;1. Authorize your gmail account&lt;br /&gt;
&amp;nbsp;2. &lt;a href=&quot;https://www.mycontactsync.com/Account/Link&quot;&gt;Link an second gmail account&lt;/a&gt; (up to 5 currently)&lt;br /&gt;
&amp;nbsp;3. &lt;a href=&quot;https://www.mycontactsync.com/Contacts/Sync&quot;&gt;Compare two accounts&lt;/a&gt; to see which email addresses and phone numbers will be created.&lt;br /&gt;
&amp;nbsp;4. Click the Sync Accounts button to initiate the sync! It&#39;s that easy!&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
links:&lt;br /&gt;
&lt;a href=&quot;https://www.producthunt.com/posts/gmail-contacts-sync&quot;&gt;product hunt&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
note: this website was previously named &quot;gmail contacts sync&quot;. The name was changed to verify the google api use.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/7713725042038146224/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/7713725042038146224' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/7713725042038146224'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/7713725042038146224'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/07/sync-gmail-contacts-between-accounts.html' title='Sync Gmail Contacts Between Accounts'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBxqVuOJ_-tLVH5d3TprvM5Be25O84lS51IuMN7vUXZgNr3LaOS7E6eRV5nvIIrS_qEmK8E4flruvUR2jdsAZhb-2_cJq-BpieqciaVRIXk0mflqYFfkwYAHGifBsFSVrMcqv-s-OmI9xr/s72-c/gmail-contacts-sync-screenshot.png" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-1625815025582572529</id><published>2017-05-28T11:30:00.000-05:00</published><updated>2017-08-10T08:51:34.174-05:00</updated><title type='text'>Hide Main Menu for Visual Studio 2017</title><content type='html'>To improve my development experience, I disable as many windows and toolbars in Visual Studio as possible. The one toolbar that you can not disable via the IDE itself is the &quot;main menu&quot; toolbar (File, Edit, View, etc.).&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM6y5Dpx17s49fPVhM2Bt8YCCJAQaMU8dc4GQKi3Mp7kvvISjKw5S6wnzcm3s-CqeVmTX_L-FLHw0HiCbcBj9kUk14o80VE4e0C8ndd1rJYo3WXpXHjM2J2ARr42lt2UG7enEXUaX-RWwL/s1600/vs2017-main-menu.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;298&quot; data-original-width=&quot;1277&quot; height=&quot;148&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM6y5Dpx17s49fPVhM2Bt8YCCJAQaMU8dc4GQKi3Mp7kvvISjKw5S6wnzcm3s-CqeVmTX_L-FLHw0HiCbcBj9kUk14o80VE4e0C8ndd1rJYo3WXpXHjM2J2ARr42lt2UG7enEXUaX-RWwL/s640/vs2017-main-menu.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
There is an extension that I&#39;ve used in previous versions of Visual Studio that hides this menu until the user presses the `alt` key. Here is a link to that extension in the gallery:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-size: x-small;&quot;&gt;old --&amp;nbsp;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=MatthewJohnsonMSFT.HideMainMenu&quot;&gt;https://marketplace.visualstudio.com/items?itemName=MatthewJohnsonMSFT.HideMainMenu&lt;/a&gt;&amp;nbsp;-- old&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
For whatever reason, that extension does not appear available in 2017, so I&#39;ve published my own extension to complete the same task:&amp;nbsp;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=AaronHoffman.HideMainMenu2017&quot;&gt;https://marketplace.visualstudio.com/items?itemName=AaronHoffman.HideMainMenu2017&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I will gladly take mine down if Matthew Johnson ever updates his extension.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps!&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/1625815025582572529/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/1625815025582572529' title='1 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1625815025582572529'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1625815025582572529'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/05/hide-main-menu-for-visual-studio-2017.html' title='Hide Main Menu for Visual Studio 2017'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjM6y5Dpx17s49fPVhM2Bt8YCCJAQaMU8dc4GQKi3Mp7kvvISjKw5S6wnzcm3s-CqeVmTX_L-FLHw0HiCbcBj9kUk14o80VE4e0C8ndd1rJYo3WXpXHjM2J2ARr42lt2UG7enEXUaX-RWwL/s72-c/vs2017-main-menu.png" height="72" width="72"/><thr:total>1</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-190012265024500706</id><published>2017-04-15T08:40:00.000-05:00</published><updated>2017-04-15T08:42:05.612-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="git"/><title type='text'>git - protect local master branch, prevent commit and push</title><content type='html'>If you&#39;ve worked with a remote git hosting service like &lt;a href=&quot;https://github.com/&quot;&gt;github&lt;/a&gt;, you&#39;re likely familiar with the concept of &lt;a href=&quot;https://help.github.com/articles/about-protected-branches/&quot;&gt;protecting a branch&lt;/a&gt;. Other remote git hosting services (&lt;a href=&quot;https://www.visualstudio.com/team-services/&quot;&gt;vsts&lt;/a&gt;, &lt;a href=&quot;https://bitbucket.org/&quot;&gt;bitbucket&lt;/a&gt;, &lt;a href=&quot;https://gitlab.com/&quot;&gt;gitlab&lt;/a&gt;, etc) also support the concept. It&#39;s a good idea to protect your remote in this way, but why stop there? You can also protect your local dev environment from human error by using &lt;a href=&quot;https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks&quot;&gt;git hooks&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
A new git repo (`git init`) comes with various hook examples in the `.git/hooks/` directory. We can tie into two of those hooks, `pre-commit` and `pre-push`, to prevent commits to your local master branch, and to prevent attempting to push to the remote master branch (even from a local feature branch).&lt;br /&gt;
&lt;br /&gt;
Place the two files found in the gist linked below in your repo&#39;s .git/hooks directory to prevent the two actions described above:&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;https://gist.github.com/aaronhoffman/ffbfd36928f9336be2436cffe39feaec&quot;&gt;https://gist.github.com/aaronhoffman/ffbfd36928f9336be2436cffe39feaec&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY8AzNf_jOQXzo3M5Ln1ZM6CdYevOyBvM2MJ6wt6SGoB7hiIVyX_adfaP1SDlg5j-pPiv5sYyQFbJeaK1dMijppfzghTurDNXZY_BGY7Cx8km98QuduaopWH78e7dcjDxls4_2_vLKYG9J/s1600/git-protect-master-branch.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;332&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY8AzNf_jOQXzo3M5Ln1ZM6CdYevOyBvM2MJ6wt6SGoB7hiIVyX_adfaP1SDlg5j-pPiv5sYyQFbJeaK1dMijppfzghTurDNXZY_BGY7Cx8km98QuduaopWH78e7dcjDxls4_2_vLKYG9J/s400/git-protect-master-branch.png&quot; width=&quot;400&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/190012265024500706/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/190012265024500706' title='3 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/190012265024500706'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/190012265024500706'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/04/git-protect-local-master-branch-commit-push.html' title='git - protect local master branch, prevent commit and push'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjY8AzNf_jOQXzo3M5Ln1ZM6CdYevOyBvM2MJ6wt6SGoB7hiIVyX_adfaP1SDlg5j-pPiv5sYyQFbJeaK1dMijppfzghTurDNXZY_BGY7Cx8km98QuduaopWH78e7dcjDxls4_2_vLKYG9J/s72-c/git-protect-master-branch.png" height="72" width="72"/><thr:total>3</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-1078140607641032420</id><published>2017-02-22T12:07:00.000-06:00</published><updated>2018-10-24T15:43:28.088-05:00</updated><title type='text'>Search iPhone Text Messages with SQLite SQL Query</title><content type='html'>&lt;div style=&quot;text-align: center;&quot;&gt;
While you&#39;re here, check out some of our interactive visualizations:&lt;br /&gt;
&lt;br /&gt;
Would you like to visualize your text messages?&lt;/div&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://www.sizzleanalytics.com/Boards/sizzle/Penalties-from-the-2016-NFL-Season/5634d0ae-3148-45a9-a727-51b3c9f26b74&quot;&gt;&lt;img border=&quot;0&quot; data-original-height=&quot;406&quot; data-original-width=&quot;600&quot; height=&quot;216&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ceBvy6Xnj82OW4z65mYTUyUzel3edewFxDFvDW0YYlYgu7hB3VJ1SBWxkrO9Na1kqPhrMCDhCBUS0-Sh4z69e3Fwhyphenhyphenis6241mPAMDO9aDMRvBYQbyU4y-DRkNXTWxCWcyl8XSGgoRP6k/s320/sizzle-fantasy-football-600.gif&quot; width=&quot;320&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
-------------------------------------------------------------------------------&lt;/div&gt;
&lt;div style=&quot;text-align: center;&quot;&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
In my experience, the iPhone text message search functionality is usually pretty awful. Especially if you&#39;re trying to find a text from a few years ago. Luckily, if you backup your iPhone using iTunes, your text messages are exported/stored in a &lt;a href=&quot;https://www.sqlite.org/&quot;&gt;SQLite&lt;/a&gt; database, and it is fairly easy to query.&lt;br /&gt;
&lt;br /&gt;
Here are the steps to SQL Query your Text Messages.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; 1. Backup your iPhone using iTunes.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; 2. &lt;a href=&quot;http://osxdaily.com/2010/07/08/read-iphone-sms-backup/&quot;&gt;Find the SQLite file that contains your text messages&lt;/a&gt;.&lt;br /&gt;
&amp;nbsp; &amp;nbsp; - in ~/Library/Application Support/MobileSync/Backup/* with a filename of&amp;nbsp;3d0d7e5fb2ce288813306e4d4636395e047a3d28&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; 3. Ensure you have a SQLite Query tool (&lt;a href=&quot;https://github.com/sqlitebrowser/sqlitebrowser&quot;&gt;SQLiteBrowser is pretty good&lt;/a&gt;).&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; 4. Open your SQLite Text Message DB File using your favorite SQLite query tool.&lt;br /&gt;
&lt;br /&gt;
&amp;nbsp; 5. Execute &lt;a href=&quot;https://gist.github.com/aaronhoffman/cc7ee127f00b6b5462fa7fc742c23d4f&quot;&gt;this query&lt;/a&gt; to see all your messages.&lt;br /&gt;
&lt;br /&gt;
Disclaimer, I had to guess at the table structure, therefore I can not confirm that the joins in this query are 100% correct. My quick spot checks seemed to check out, and I was able to query the message.text field to find old messages that the iPhone app was not able to.&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyP-FrvwCuU6cie-g4kYhvB-67QuvIUODd2zJZ71CFuJ9KRlXg7MjliEXophvZzELWmZavRg5x1SsCUeJzDNv3CP6caiuhdpHhchSGneuAJ5FkgTjuzy9J6O46I5Labxi4IfrTJHl6EY5C/s1600/sqlite_browser_iphone.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;387&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyP-FrvwCuU6cie-g4kYhvB-67QuvIUODd2zJZ71CFuJ9KRlXg7MjliEXophvZzELWmZavRg5x1SsCUeJzDNv3CP6caiuhdpHhchSGneuAJ5FkgTjuzy9J6O46I5Labxi4IfrTJHl6EY5C/s640/sqlite_browser_iphone.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/1078140607641032420/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/1078140607641032420' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1078140607641032420'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/1078140607641032420'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/02/iphone-text-message-sqlite-sql-query.html' title='Search iPhone Text Messages with SQLite SQL Query'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg5ceBvy6Xnj82OW4z65mYTUyUzel3edewFxDFvDW0YYlYgu7hB3VJ1SBWxkrO9Na1kqPhrMCDhCBUS0-Sh4z69e3Fwhyphenhyphenis6241mPAMDO9aDMRvBYQbyU4y-DRkNXTWxCWcyl8XSGgoRP6k/s72-c/sizzle-fantasy-football-600.gif" height="72" width="72"/><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-7161526735277892972</id><published>2017-01-30T17:27:00.000-06:00</published><updated>2017-07-25T09:01:11.440-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="azure"/><title type='text'>Azure Kudu Deployment with Version Number</title><content type='html'>I recently blogged about &lt;a href=&quot;http://aaron-hoffman.blogspot.com/2017/01/visual-studio-version-build-git-commit.html&quot;&gt;generating a version.txt file on every build via Visual Studio&lt;/a&gt;. This solution is fine if you are building from you local machine and using Web Deploy to deploy to Azure, but if you have a github webhook and are using kudu, the VS Post Build Events are not executed.&lt;br /&gt;
&lt;br /&gt;
The easiest way I found to generate a version.txt file for every deployment is to add a &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/Post-Deployment-Action-Hooks&quot;&gt;post deployment action&lt;/a&gt;&amp;nbsp;to your Web App/App Service.&lt;br /&gt;
&lt;br /&gt;
Create a file within the&amp;nbsp;/site/deployments/tools/PostDeploymentActions/ folder of your App Service (you may need to create that folder). You can name the file whatever you&#39;d like, I chose `generategitversionfile.cmd`. The file should contain at least the following line:&lt;br /&gt;
&lt;br /&gt;
&lt;span style=&quot;font-family: &amp;quot;courier new&amp;quot; , &amp;quot;courier&amp;quot; , monospace;&quot;&gt;git rev-parse HEAD &amp;gt; &quot;..\wwwroot\version.txt&quot;&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
This command will be executed within the context of the `/site/repository` directory, that&#39;s why we need a more fully qualified path for where to write the file.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Now, after every kudu deploy, a new version.txt file will be created that contains the current git comment hash.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps,&lt;br /&gt;
Aaron</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/7161526735277892972/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/7161526735277892972' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/7161526735277892972'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/7161526735277892972'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/01/azure-kudu-deployment-version-number.html' title='Azure Kudu Deployment with Version Number'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-8016829656920012950.post-4626634387980699214</id><published>2017-01-26T18:10:00.002-06:00</published><updated>2017-07-25T09:01:24.520-05:00</updated><category scheme="http://www.blogger.com/atom/ns#" term="azure"/><title type='text'>Stop Azure WebJob from Azure WebSite</title><content type='html'>I recently had the need to toggle the status of an Azure WebJob from the WebSite in the same Azure App Service. I found a &lt;a href=&quot;https://social.msdn.microsoft.com/Forums/sqlserver/en-US/d7419d5e-e332-4db0-90a6-10befc9fe127/how-to-stopdisable-azure-webjob-using-c-code?forum=windowsazurewebsitespreview&quot;&gt;couple&lt;/a&gt; half-complete answers online, but I thought I&#39;d put together this simple guide to have a complete example all in one place.&lt;br /&gt;
&lt;br /&gt;
To accomplish this, we&#39;ll be using the kudu &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/REST-API&quot;&gt;REST API&lt;/a&gt;&amp;nbsp;for &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/WebJobs-API#stop-a-continuous-job&quot;&gt;WebJobs&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
(note: I also looked into toggling the &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/WebJobs&quot;&gt;WEBJOBS_STOPPED&lt;/a&gt; environment variable from the WebSite, however I was not able to verify that solution was going to work. I confirmed I was able to set the environment variable from the website, however the value did not update in the &quot;Application Settings&quot; section of the Azure Portal and I was concerned the WebJobs may read a separate environment variable than the WebSite [process scoped vs machine envar for example])&lt;br /&gt;
&lt;br /&gt;
The first thing you&#39;ll need to do is download the PublishSettings file (aka &quot;Publish Profile&quot;) associated with the App Service (you need the username/password from this file to satisfy the basic auth requirement to the kudu API)&lt;br /&gt;
&lt;br /&gt;
&lt;div class=&quot;separator&quot; style=&quot;clear: both; text-align: center;&quot;&gt;
&lt;a href=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcJQtnNbZNcCLO7tmV_t-KZ6JpqZ4Le8KULgnnPyUgQFFOlpkMH6bj6mX1l_2KPu0K-8Us06SpWqJUpQkkLtkFFu0NP3ENfF8J73EjHx8oV4aQsGxqfOIUzV9nGCgVUix_3iPqmdKhz0Xi/s1600/AzurePublishSettings.png&quot; imageanchor=&quot;1&quot; style=&quot;margin-left: 1em; margin-right: 1em;&quot;&gt;&lt;img border=&quot;0&quot; height=&quot;126&quot; src=&quot;https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcJQtnNbZNcCLO7tmV_t-KZ6JpqZ4Le8KULgnnPyUgQFFOlpkMH6bj6mX1l_2KPu0K-8Us06SpWqJUpQkkLtkFFu0NP3ENfF8J73EjHx8oV4aQsGxqfOIUzV9nGCgVUix_3iPqmdKhz0Xi/s640/AzurePublishSettings.png&quot; width=&quot;640&quot; /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
In the &quot;Web Deploy&quot; publish profile section of this file, find the &quot;userName&quot; and &quot;userPWD&quot; values, we&#39;ll need these in the code linked below.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
The full documentation describing all the various REST endpoints is available &lt;a href=&quot;https://github.com/projectkudu/kudu/wiki/WebJobs-API&quot;&gt;here&lt;/a&gt;. I have created a simple gist of how to authenticate using basic auth and call a few WebJob methods to start and stop services here:&amp;nbsp;&lt;a href=&quot;https://gist.github.com/aaronhoffman/212dd858ff5d4275369f5fde01d9fd5d&quot;&gt;https://gist.github.com/aaronhoffman/212dd858ff5d4275369f5fde01d9fd5d&lt;/a&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Hope this helps!&lt;br /&gt;
Aaron&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;</content><link rel='replies' type='application/atom+xml' href='https://aaron-hoffman.blogspot.com/feeds/4626634387980699214/comments/default' title='Post Comments'/><link rel='replies' type='text/html' href='https://www.blogger.com/comment/fullpage/post/8016829656920012950/4626634387980699214' title='0 Comments'/><link rel='edit' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/4626634387980699214'/><link rel='self' type='application/atom+xml' href='https://www.blogger.com/feeds/8016829656920012950/posts/default/4626634387980699214'/><link rel='alternate' type='text/html' href='https://aaron-hoffman.blogspot.com/2017/01/stop-azure-webjob-from-website.html' title='Stop Azure WebJob from Azure WebSite'/><author><name>Aaron Hoffman</name><uri>http://www.blogger.com/profile/09198249712063850273</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='16' height='16' src='https://img1.blogblog.com/img/b16-rounded.gif'/></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjcJQtnNbZNcCLO7tmV_t-KZ6JpqZ4Le8KULgnnPyUgQFFOlpkMH6bj6mX1l_2KPu0K-8Us06SpWqJUpQkkLtkFFu0NP3ENfF8J73EjHx8oV4aQsGxqfOIUzV9nGCgVUix_3iPqmdKhz0Xi/s72-c/AzurePublishSettings.png" height="72" width="72"/><thr:total>0</thr:total></entry></feed>