Sometimes when I'm talking with other .NET developers, the "I don't understand why Microsoft doesn't provide X functionality" or "Why hasn't Microsoft fixed Y yet?" topic comes up. Also "The documentation for Z really sucks" comes often up as well.

Guess what? You can fix all this yourself! Because .NET Core is open source. You can even contribute documentation since that is open source as well. And in many cases it's not even hard at all.

But why should you? Doesn't Microsoft have people that should be doing this? They do, but those people are just like you and me. They work normal hours, they have prioritized tasks and things simply might not be on their radar. That's why open source is so awesome, because it allows us to take part and fix stuff that we really want fixed if it isn't high on the priority list.

I'm going to demonstrate this with an example of a contribution I did myself a few weeks ago.

I decided to try out the new Microsoft.Data.SqlClient library, whose purpose is to replace the SQL Server client library which is built into .NET Framework and .NET Core to be shipped out-of-band, bringing new features earlier. Adding it to our product was easy, however, when I was trying to gather SQL dependency data for Application Insights, I noticed that I wasn't receiving any. That's when I found this error message in our logs: ERROR: Exception in Command Processing for EventSource Microsoft-AdoNet-SystemData: Event BeginExecute is givien event ID 2 but 1 was passed to WriteEvent.

Ok, obviously something wasn't working and after googling the error message I found that  it was coming from Application Insights, and after looking at the code it was immediately clear what had happened. It was a simple typo, a typical copy-paste error that we have all done many many times in our coding careers.

This was the offending code:

[Event(SqlEventSource.EndExecuteEventId, Keywords = Keywords.SqlClient, Task = Tasks.ExecuteCommand, Opcode = EventOpcode.Stop)]
public void BeginExecute(int objectId, string dataSource, string database, string commandText)
    // we do not use unsafe code for better performance optization here because optimized helpers make the code unsafe where that would not be the case otherwise. 
    // This introduces the question of partial trust, which is complex in the SQL case (there are a lot of scenarios and SQL has special security support).   
    WriteEvent(SqlEventSource.BeginExecuteEventId, objectId, dataSource, database, commandText);

// unfortunately these are not marked as Start/Stop opcodes.  The reason is that we dont want them to participate in 
// the EventSource activity IDs (because they currently don't use tasks and this simply confuses the logic) and 
// because of versioning requirements we don't have ActivityOptions capability (because mscorlib and System.Data version 
// at different rates)  Sigh...
[Event(SqlEventSource.EndExecuteEventId, Keywords = Keywords.SqlClient, Task = Tasks.ExecuteCommand, Opcode = EventOpcode.Stop)]
public void EndExecute(int objectId, int compositeState, int sqlExceptionNumber)
    WriteEvent(SqlEventSource.EndExecuteEventId, objectId, compositeState, sqlExceptionNumber);

Spotted that pretty quickly right? It doesn't seem right that BeginExecute would be using the EndExecuteEventId, and sure enough, if you look at the diff from my changes, it seems to have been a copy paste left-over from the EndExecute event right below. I simply changed that to the correct event id, verified by compiling the library and running it locally, created a pull request, and within days, it was accepted and merged!

And since I'd found this process to be so wonderfully simple I continued. I decided to fix a long standing pet-peeve of mine where the old System.Data.SqlClient only sent the SQL Command Text for stored procedure but omitted it for standard queries when running on the old .NET Framework but it worked fine in .NET Core. So I found that code and fixed that as well. That pull request was also accepted and merged.

// I simply removed this logic!
string commandText = CommandType == CommandType.StoredProcedure ? CommandText : string.Empty;
SqlEventSource.Log.BeginExecute(GetHashCode(), Connection.DataSource, Connection.Database, commandText);

You see?

None of these changes were big, they weren't overly complex, and I was able to fix them myself and submit the changes upstream for others to benefit.

You can even make changes to if you want to add information or code samples, and it's as simple as clicking an "Edit" button to get started.

Is there something you have been dying to fix or wanted to change in .NET? What are you waiting for?! Fork the code and get started. It's easier than you think!