{"id":182,"date":"2023-04-26T20:31:32","date_gmt":"2023-04-26T19:31:32","guid":{"rendered":"https:\/\/daan.wsng.eu\/?p=182"},"modified":"2023-10-11T08:53:09","modified_gmt":"2023-10-11T07:53:09","slug":"monthly-learnings-from-c-april-2023","status":"publish","type":"post","link":"https:\/\/daan.wsng.eu\/index.php\/2023\/04\/26\/monthly-learnings-from-c-april-2023\/","title":{"rendered":"Monthly learnings from C# (April 2023)"},"content":{"rendered":"\nI&#8217;m alive! There are no great things I&#8217;ve learned or need to remember for a while, but I decided that collecting the small things is also worthwhile. So, here are several things I learned about the last month.\n\n\n\n\n<h2>.ToLookup()<\/h2>\n\n\n\n\nSometimes, you have a big list of <code>Thing<\/code>s. A <code>Thing<\/code>, for example, has the properties <code>Id<\/code>, <code>CountryCode<\/code>, <code>Currency<\/code>, <code>Population<\/code> and <code>Name<\/code>. Now, we have a list of <code>Thang<\/code>s ,which we want to match up with one of the <code>Thing<\/code>s. The naive way of doing this, is searching the list of <code>Thing<\/code>s with a simple <code>.Where()<\/code> clause. For example: <code>var matchedCountry = Things.Where(t =&gt; t.CountryCode == thang.CountryCode)<\/code>. Simple, clear, but not very performant. Especially if both lists get very big. So naturally, I would create a <code>Dictionary&lt;string, Thing&gt;<\/code> to create a lookup of sorts. This works if the lookup value is unique, but otherwise you would have to create a <code>Dictionary&lt;string, IEnumerable&lt;Thing&gt;&gt;<\/code> or something and populating that would be a bit ugly. Fortunatly, I found <a href=\"https:\/\/stackoverflow.com\/a\/13362570\" data-type=\"URL\" data-id=\"https:\/\/stackoverflow.com\/a\/13362570\">a post on StackOverflow<\/a> by the great John Skeet, which provided the <code><a href=\"https:\/\/learn.microsoft.com\/en-us\/dotnet\/api\/system.linq.enumerable.tolookup?view=net-8.0\">.ToLookup()<\/a><\/code> functionality. This works great because:\n\n\n\n\n<ul><li>No ugly loops and checking for existing keys when populating<\/li><li><code>lookup[key]<\/code> will return an empty <code> IEnumerable<\/code> when the key is not present instead of an exception that the key is not present<\/li><li>Natively support multiple <code>Thing<\/code>s per key<\/li><li>Lookup is O(1)<\/li><\/ul>\n\n\n\n\n\n<h2><code>with<\/code><\/h2>\n\n\n\n\nI have not been working with <code>record<\/code>s a lot, but I have been trying to use it more. Especially in situations where a <code>class<\/code> is a bit much, but tuples are not enough. Usually, a <code>record<\/code> is immutable, but they have a nice copy function where you can (re)set some or all of the properties: <code>with<\/code>. It works as follows:\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\nrecord Contract(string Person, int Salary, string Location, DateTime Start);\n\nvar contractTemplate = new Contract \n{\n    Location = &quot;Home&quot;,\n    Start = DateTimeOffset.Now,\n} \n\nforeach (var employee in newEmployees)\n{\n    var newContract = contractTemplate with {\n        Person = employee.Name,\n        Salary = employee.Salary\n    };\n    Console.WriteLine(newContract);\n}\n\n<\/pre><\/div>\n\n\nThis will create a new instance of <code>Contract<\/code>, so now there are two instances. Try it! \n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\nConsole.WriteLine(newContract == contractTemplate); \/\/ Output: &quot;False&quot;\n\n<\/pre><\/div>\n\n\nThis is great when you want to create a large number of records, but with a lot of the same property values.\n\n\n\n\n<h2>DbContext in Blazor<\/h2>\n\n\n\n\nI&#8217;m still new to Blazor and its lifecycle, so when I had to use a DbContext in a recent Server side Blazor project, I used what I&#8217;ve always known:\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    \/\/ ...\n    services.AddDbContext&lt;ApplicationDbContext&gt;(\n        options =&gt; options.UseSqlServer(&quot;...&quot;));\n}\n\n<\/pre><\/div>\n\n\nAnd in the repository I injected the context as always:\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\npublic class MyRepository: IMyRepository\n{\n    private readonly ApplicationDbContext _context;\n\n    public MyRepository(ApplicationDbContext context)\n    {\n        _context = context;\n    }\n\n    public Task SaveThing(Thing thing) \n    {\n        _context.Things.Add(thing);\n        return _context.SaveChangesAsync();\n    }\n}\n\n<\/pre><\/div>\n\n\nThis worked for a while, until I had to do two separate database operations on the same page. Suddenly, exception message:\n\n\n\n\n<blockquote class=\"wp-block-quote\"><strong>InvalidOperationException<\/strong>: A second operation started on this context before a previous operation completed. This is usually caused by different threads using the same instance of DbContext. For more information on how to avoid threading issues with DbContext, see&nbsp;<a href=\"https:\/\/go.microsoft.com\/fwlink\/?linkid=2097913\">https:\/\/go.microsoft.com\/fwlink\/?linkid=2097913<\/a><\/p><cite>my buggy app<\/cite><\/blockquote>\n\n\n\n\n\nMy mind was really confused. All dependency injection was correct, I used a pre defined DbContext insertion method so it should be a new one on every operation, right? Well, it turned out I had the MVC pattern still burned in my head. With Blazor, the object lifetime is a bit different. Here, the objects are not created per request (as I expected), but per session. So, once I started browsing the application, the same DbContext was used everywhere. This worked out until I had to do two database actions on the same page. To fix this I had to fix both the injection in the repository as the service registration:\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\npublic void ConfigureServices(IServiceCollection services)\n{\n    \/\/ ...\n    services.AddDbContextFactory&lt;ApplicationDbContext&gt;(\n        options =&gt; options.UseSqlServer(&quot;...&quot;));\n}\n\n<\/pre><\/div>\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">\n\npublic class MyRepository: IMyRepository\n{\n    private readonly IDbContextFactory&lt;ApplicationDbContext&gt; _contextFactory;\n\n    public MyRepository(IDbContextFactory&lt;ApplicationDbContext&gt; contextFactory)\n    {\n        _contextFactory = contextFactory;\n    }\n\n    public async Task SaveThing(Thing thing) \n    {\n        using var context = _contextFactory.CreateContext();\n        context.Things.Add(thing);\n        await context.SaveChangesAsync();\n    }\n}\n\n<\/pre><\/div>\n\n\nAnd all was well again&#8230;\n","protected":false},"excerpt":{"rendered":"<p>I&#8217;m alive! There are no great things I&#8217;ve learned or need to remember for a while, but I decided that collecting the small things is also worthwhile. So, here are several things I learned about the last month. .ToLookup() Sometimes, you have a big list of Things. A Thing, for example, has the properties Id,&#8230;<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"twitterCardType":"","cardImageID":0,"cardImage":"","cardTitle":"","cardDesc":"","cardImageAlt":"","cardPlayer":"","cardPlayerWidth":0,"cardPlayerHeight":0,"cardPlayerStream":"","cardPlayerCodec":""},"categories":[6,4],"tags":[],"_links":{"self":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts\/182"}],"collection":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/comments?post=182"}],"version-history":[{"count":8,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts\/182\/revisions"}],"predecessor-version":[{"id":197,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/posts\/182\/revisions\/197"}],"wp:attachment":[{"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/media?parent=182"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/categories?post=182"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/daan.wsng.eu\/index.php\/wp-json\/wp\/v2\/tags?post=182"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}