Posts

Showing posts from March, 2021

C# Static Constructors

Image
Static constructors in C# are a bit tricky to use. Static classes and methods go against OOP principals in the first place, so their use should be limited to only where they make sense. Here are some basic behaviors about static constructors: View code on GitHub

LINQ in sets of

Thanks to this Stackoverflow answer for showing how to easily return LINQ results in sets: public static IEnumerable < T [ ] > InSetsOf < T > ( this IEnumerable < T > source , int max ) { List < T > toReturn = new List < T > ( max ) ; foreach ( var item in source ) { toReturn . Add ( item ) ; if ( toReturn . Count = = max ) { yield return toReturn . ToArray ( ) ; toReturn = new List < T > ( max ) ; } } if ( toReturn . Any ( ) ) { yield return toReturn . ToArray ( ) ; } }

Project Properties

I’m working on standardizing my code using the latest and greatest .NET features. For me, that currently means adding the following to the first <PropertyGroup> section in my csproj file: <LangVersion>latest</LangVersion> <Nullable>enable</Nullable> <TreatWarningsAsErrors>true</TreatWarningsAsErrors> <WarningsAsErrors /> LangVersion : Allows me to use the latest features in C#, like switch expressions, tuple patterns, and using declarations. Nullable : Incorporating nullable reference types, which is new and weird, but it’s a fantastic way to greatly reduce unnecessary null-checking and NullReferenceException errors. TreatWarningsAsErrors and WarningsAsErrors : Honestly, I started reading what the difference is between these, and I gave up, so I just said screw it and put both in there. This marks compiler warnings as errors, forcing me to follow my own standards. My configuration in Visual Studio (in 2019: Tools/Options/Text Editor/C#/

Ninject in MVC5

I’ve found dozens of blogs and articles online about how to use Ninject in ASP.NET. It seems all of them are either a little outdated, or a little confusing. So I put together a basic working application for reference. This uses Visual Studio 2017, with ASP.NET MVC 5 which will run in regular IIS. I only know the very basics when it comes to Ninject, and I don’t even know if this is the best practice when building an app. But this does work, and does allow you to bind to different modules from different projects, which would allow you to do things like mocking database results or skipping error notifications. If you have suggestions for how to improve this basic project (without complicating it too much), or any corrections or best practices I should consider, please let me know. The basic idea is pretty straightforward: Build interfaces and production implementations in separate projects. Build a production module project which maps the two together. In your live ASP.NET project, make

JSON casing in ASP.NET Core

Some mallethead decided that they wanted to take UpperCamelCase names of properties and change them to lowerCamelCase when sending JSON to the client. Sure, maybe this fits standard naming conventions, but it means that you’ll end up with different property names. public JsonResult GetFoo ( ) { return Json ( new Foo { Name = " Jane Doe " , Age = 32 } ) ; } This returns the following content: { " name " : " Jane Doe " , " age " : 32 } Personally, I want the properties to match. Here’s the change to make that happen: // dotnet add package Microsoft.AspNetCore.Mvc.NewtonsoftJson // Startup.cs: in ConfigureServices services . AddNewtonsoftJson ( options = > { options . UseMemberCasing ( ) ; } ) ; Now the same code produces: { " Name " : " Jane Doe " , " Age " : 32 }

Mount drive in Windows Subsystem for Linux

To mount a drive with a letter, including a network drive: sudo mkdir /mnt/g sudo mount -t drvfs G: /mnt/g To mount a network share: sudo mkdir /mnt/folder sudo mount -t '\\server\folder' /mnt/folder With specific credentials: net.exe use f: \\server\folder /user:Bob LetMeIn Unmounting: sudo umount /mnt/folder Source: Chris Hoffman on HowToGeek

Check progress of SQL Server restore

From MSSQLTips : SELECT session_id as SPID , command , a . text AS Query , start_time , percent_complete , dateadd ( second , estimated_completion_time / 1000 , getdate ( ) ) as estimated_completion_time FROM sys . dm_exec_requests r CROSS APPLY sys . dm_exec_sql_text ( r . sql_handle ) a WHERE r . command in ( 'BACKUP DATABASE' , 'RESTORE DATABASE' )

Brotli in .NET

Brotli  is a compression algorithm like GZip - it tends to have smaller compressed files at the expense of a small amount of extra time. Implementing in .NET is just as easy as with GZip: public class Brotli { public static void Compress ( Stream inputStream , Stream outputStream ) { using var gzip = new BrotliStream ( outputStream , CompressionMode . Compress ) ; byte [ ] buffer = new byte [ 8192 ] ; int count ; while ( ( count = inputStream . Read ( buffer , 0 , buffer . Length ) ) > 0 ) { gzip . Write ( buffer , 0 , count ) ; } } public static void Decompress ( Stream inputStream , Stream outputStream ) { using var gzip = new BrotliStream ( inputStream , CompressionMode . Decompress ) ; byte [ ] buffer = new byte [ 8192 ] ; int count ; while ( ( count = gzip . Read ( buffer , 0 , buffer . Length ) ) > 0 )

Exception logging in ASP.NET Core

public void HandleException ( IApplicationBuilder app ) { app . Run ( async requestContext = > { try { string path = requestContext . Request . Path ; var exceptionHandlerPathFeature = requestContext . Features . Get < IExceptionHandlerPathFeature > ( ) ; var exception = exceptionHandlerPathFeature ? . Error ; User ? user = null ; try { user = /* implementation */ Cast requestContext . User into your custom user type } catch ( Exception ex ) { Debug . WriteLine ( ex ) ; } if ( exception != null ) { new Thread ( ( ) = > { // Using a new thread to escape any open transactions that are getting rolled back try { using var conn = new SqlConnection ( Configuration . GetConnectionString ( " connstr " ) ) ; conn . Open ( ) ; using var comm = conn . CreateCommand (

Restore all Glacier objects in S3 bucket

If you've got an entire bucket in S3 with items in Glacier or Glacier Deep Archive storage class, and you want to restore them to download them, this C# code will restore all of the files. Just set the constant values at the top and it'll go through the items one-by-one and submit a restore request. No notifications or anything when the restore is done, so maybe just give it a day or so and come back. using static System . Console ; using Amazon ; using Amazon . Runtime ; using Amazon . S3 ; using Amazon . S3 . Model ; const string ACCESS_KEY = " XXXXXXXXXXXXXXXX " ; const string SECRET_KEY = " XXXXXXXXXXXXXXXX " ; var regionEndpoint = RegionEndpoint . XXXXXXXXXXXXXXXX ; const string BUCKET_NAME = " XXXXXXXXXXXXXXXX " ; const int NUM_DAYS = 15 ; var client = new AmazonS3Client ( new BasicAWSCredentials ( ACCESS_KEY , SECRET_KEY ) , regionEndpoint ) ; var request = new ListObjectsRequest { BucketName =

Retrieve SSIS package contents

Here's a quick .NET console application to retrieve the DTSX XML from SQL Server for an SSIS package: using System . Collections . Generic ; using System . Data ; using System . IO ; using Microsoft . Data . SqlClient ; async IAsyncEnumerable < byte [ ] > ReadFileAsync ( ) { int startingByte = 1 ; while ( true ) { byte [ ] bytes ; using var conn = new SqlConnection ( " server=XXXXX;database=msdb;integrated security=true; " ) ; await conn . OpenAsync ( ) . ConfigureAwait ( false ) ; using var comm = conn . CreateCommand ( ) ; comm . CommandText = @"             SELECT substring(packagedata, @StartingByte, 8000) [FileContents]             FROM msdb.dbo.sysssispackages             WHERE name = 'MyPackageName' -- assuming your package has a unique name on the server          " ; comm . Parameters . Add ( new SqlParameter ( " @StartingByte "

Get SQL Server Index Fragmentation

Modified from RedGate SQL Scripts Manager DECLARE @SchemaName SYSNAME = N 'dbo' ; DECLARE @TableName SYSNAME = N 'MyTableName' ; DECLARE @object_id INT ; SELECT @object_id = [ object_id ] FROM sys . tables WHERE [ schema_id ] = SCHEMA_ID ( @SchemaName ) AND [ name ] = @TableName ; --fragmentation SELECT i . [ name ] [ index ] , ddips . [ index_type_desc ] , ddips . [ avg_fragmentation_in_percent ] [ FragmentationPercent ] , ddips . [ fragment_count ] , ddips . [ page_count ] FROM sys . dm_db_index_physical_stats ( DB_ID ( ) , NULL , NULL , NULL , 'limited' ) ddips JOIN sys . [ indexes ] i ON ddips . [ object_id ] = i . [ object_id ] AND ddips . [ index_id ] = i . [ index_id ] WHERE ddips . [ object_id ] = @object_id AND ddips . alloc_unit_type_desc = 'IN_ROW_DATA' ORDER BY ddips . [ avg_fragmentation_in_percent ] DESC ;

Get SQL Server Index Size

Modified from this SQLShack article . DECLARE @SchemaName SYSNAME = N 'dbo' ; DECLARE @TableName SYSNAME = N 'MyTableName' ; DECLARE @object_id INT ; SELECT @object_id = [ object_id ] FROM sys . tables WHERE [ schema_id ] = SCHEMA_ID ( @SchemaName ) AND [ name ] = @TableName ; SELECT tn . [ name ] [ TableName ] , ix . [ name ] [ IndexName ] , FORMAT ( SUM ( sz . [ used_page_count ] ) * 8 / 1024 , '#,##0' ) AS [ Index size ( MB ) ] FROM sys . dm_db_partition_stats AS sz INNER JOIN sys . indexes ix ON sz . [ object_id ] = ix . [ object_id ] AND sz . [ index_id ] = ix . [ index_id ] INNER JOIN sys . tables tn ON tn . OBJECT_ID = ix . object_id WHERE tn . [ object_id ] = @object_id GROUP BY tn . [ name ] , ix . [ name ] ORDER BY SUM ( sz . [ used_page_count ] ) * 8 DESC ;

SQL Server Merge

Image
SQL Server has a MERGE statement that lets you do multiple actions in one statement - possibly inserts, updates, and deletes all at once. Here's an example that shows this in action. View code on GitHub

XML Serialization Helpers

public static class Serialization { private static readonly Encoding _defaultEncoding = Encoding . UTF8 ; public static T DeserializeXmlFile < T > ( string fileName ) { if ( ! File . Exists ( fileName ) ) throw new FileNotFoundException ( ) ; var serializer = new XmlSerializer ( typeof ( T ) ) ; using ( var xmlReader = new XmlTextReader ( fileName ) ) { return ( T ) serializer . Deserialize ( xmlReader ) ; } } public static T Deserialize < T > ( TextReader textReader ) { if ( textReader = = null ) throw new ArgumentNullException ( " textReader " ) ; var serializer = new XmlSerializer ( typeof ( T ) ) ; return ( T ) ( serializer . Deserialize ( textReader ) ) ; } public static T Deserialize < T > ( string serializedObject ) { if ( string . IsNullOrEmpty ( serializedObject