Friday, March 17, 2023

A short list of C# coding issues.

Injecting services into entities

It been bugging me for a while now that to use services in a entity can be a bit of pain. It usually starts with a little entity class to do X. Then, oh, I'd like to be able to do some logging, so take an ILogger<X> as constructor problem..

Woops; now I need a wrapper or some outer factory style XFactory to provide the logger service... It's not too bad I suppose, just a bit cumbersome. 

Entities with async construction

Ok, yes, I know; a constructor should be a fairly dumb operation. The constructor's goal is (mor or less) to validate and preserve input parameters. 

But some times.. particularly if your trying to break out of a Service + DTO view of the world, an entity may need to call an async service method during creation.

Years ago this problem presented with C++ on windows, generally solved with a 2-phase construction.

2-phase is a valid pattern for richer entities, but id does introduce:
  • Created entity is NOT immediately usable.
  • Entity code now generally needs safety code to throw if not fully initialised 

Typed strings with serialization

Not quite sure what to call this. 

Often data is expressed as a string, but with some constraints. For instance a PathString will always start with a '/'. This can be a very useful constraint, particularly for string concatenation etc.

 I also find myself writing constrained string classes for jobs like ensuring a valid Kubernetes entity name.

But as I've done a few times now, I then need patterns to serialize / deserialize these typed-strings, and to cleanly use them with other code.


I'm hoping to soon publish a package for these issues; currently trialling a pattern, we'll see.

Wednesday, March 15, 2023

Introducing kwd.CoreUtil

 I built this a while ago; others may find it handy.


It's a small library focussing primarily on syntax sugar  for C#

kwd.CoreUtil v1.1.0:  Git / Nuget

The main code is a set of extensions to make working with FileInfo and DirectoryInfo more natural.

In addition there are some other utilities for strings and file streams.


Originally the design was to restrict this to ONLY depend on standard .NET Core packages. 

But more recently I stumbled onto System.IO.Abstractions; since the package is lite, and provides significant benefit; I've take it as a dependency


 So what's it good for?

Well, my favourite is the Ensure* extensions. 
Super handy to ensure a directory exists before used.

Have a look and provide some feedback :)

Tuesday, April 26, 2016

LIMO - LeastInMostOut methods

I've been experimenting with different guidelines to help me construct better code. In particular I've been pondering 'how to decide the best arguments for a method'. I started to consider this question a little more, while reviewing another colleagues code. I was struggling to understand what I didn't like about their code, and why. Finally I think I have a 'reason' why their code has a bad flavor to me.

The code was simple enough, but it took large, full agg-roots as parameters. What smelt funny was, only one little VO was needed, yet the class was now coupled to the full AR, without much reason.

As a result the class method was now coupled to the full AR, though it could have been much more reusable, simply by taking just the bit(s) needed. After some googling, and asking other seniors, I couldn't find anything to 'point at' and say, see this guy recons it's better not to couple the classes like that.

So now, here a post to 'point at'.

Guideline:

Methods should take least in arguments to do their job. They should return most out to callers (LIMO).

Why?
Taking the Least-in reduces coupling by only requiring the information needed by the method. It also improves readability by making it clear what the method needs. 

Return the Most-out data you can, this improves re-use of the method while reducing the need for change in the future (Open-closed principal).

Notes:

This does not mean every argument should be a string or some other native type. An arguments type help describes the constraints. For example a method "GetDataFromAServer()" should take a URI rather than just a String.

Another Trick I find useful is to look at how a method argument is used directly inside the method. If the argument is immediately converted to something else, then sometimes this is a clue that some refactoring may be needed.

I tend to return the 'most-data' so the caller can decided what is relevant to them. Some might think this leads to exposing internal class-structure, and I would agree. In my code 'returning the most' helps with unit tests, it also reduces re-coding. If / when I want to return less information, I generally have an interface to express this.

One last trick; at the moment I'm returning this on methods which would normally be void-return. The idea is that by returning this, I'm providing some info to the caller and making caller code flow more. I'm not wed to the idea, this does have a down-side. I now have some difficulty knowing if a method returns a new instance, or the same instance.


Thursday, April 14, 2016

Lifetime trick when migrating to mvc.net core 1

Recently while migrating projects from MVC.Net 5 to core 1 rc1 (mvc6 / vNext) I ran into an IoC problem. I was using Autofac as my container, and had just migrated some MVC filters. The filters were registered in the container using Autofac, and bound to MVC as global filters using ServiceFilterAttribute; following the post http://www.strathweb.com/2015/06/action-filters-service-filters-type-filters-asp-net-5-mvc-6/>here
Unfortunately at run time Autofac threw an error “No Scope with a Tag Matching ‘AutofacWebRequest’ “ . There is a reference to the problem on the Autofac site here
The error indicates either
  1. Trying to bind a long-life (singleton) object with a short-life (per request) object.
  2. Trying to resolve a per-request object before there is a request scope.
With these clues I finally worked out the problem, I have a combination of ‘binding’ approaches in my project.
Some services are bound using Autofac modules, here I was using InstancePerRequest() lifetimes. Other services were bound using the MVC container interface, in particular using IServiceCollection.AddScoped().
Using the Autofac MVC extensions, I add the MVC container bindings to the Autofac continer via ContainerBuilder.Populate(). This method maps the service registrations into Autofac. The mapping converts IServiceCollection Scoped bindings to InstancePerLifetimeScope().
Bingo
So some services were bound with InstancePerReqest(), while others with InstancePerLifetimeScope(). After consolidating my bindings to all use InstancePerLifetimeScope(), problem solved.

Tuesday, June 25, 2013

A stupid Team City build error

I've finally got Team City to run on Azure with the built-in database. But I was having terrible trouble getting my unit tests (MSTest) to run.

The error: 'Could not load file or assembly Autofac ...'

Every thing looked fine. Local build / test worked like a dream. NuGet packages loaded. CI build log showed Autofac was nu-get downloaded, and build success... I even fell back to RDP to build-box and run tests; again, success.

So what was the problem?

I used a simple short-hand to tell team city where the test assembly was: src/core.tests/**/*.tests.dll. This was (unexpected, by me at least) picking up both

  1. src/core.tests/bin/debug/core.tests.dll AND
  2. src/core.tests/obj/Debug/core.tests.dll

Fixing it

The fix is simple, just use a more exact setting in Team City src/core.tests/bin/Debug/*.tests.dll

Thursday, January 3, 2013

Resolving a content item url in Orchard

Recently I needed to create a link to edit a content item in Orchard. Orchard uses a url like http://mysite/Home/Admin/Contents/Edit/123, where the id corresponds to the content item id.

My first thought was to hand-craft the url, replacing the content id as needed. But I found a better way: use the item's meta-data. Firstly inject the orchard IContentManager as usual, then call IContentManager.GetItemMetadata() The returned ContentItemMetadata contains MVC route's, for my particular case, EditorRouteValues had all the data I needed.

In my exploration of Orchard, I am continually finding myself having to dive into the code to work out how to do things. So here is 'how' I finally stumbled on the meta data solution.

Firstly I knew the Content Control Wrapper performed some 'magic' which added a link to a content item's edit.
Alas so-far I have no special trick for getting from a feature to the code that implements it. But eventually I found Orchard.Core/Contents/ControlWrapper.cs which implements the feature as a IShapeTableProvider. In here we see Content is wrapped with a Content_ControlWrapper shape.

Since nothing particularly enlightening is happening, I went to the view for the shape: Orchard.Core/Views/Content.ControlWrapper.cshtml. In the view the Html.ItemEditLinkWithReturnUrl() caught my eye.

This ItemEditLinkWithReturnUrl() is an extension, tracked down to Orchard.Framework/Mvc/Html/ContentItemExtensions.cs

Navigating to find the core ItemEditLink helper, bingo, I found how the content item meta-data is used for route values.

Wednesday, December 19, 2012

Using async/await (TPL) with Orchard

While working on a module for Orchard CMS I ran into some problems trying to glue async (Task) based code with (classic) synchronous code.

Here's the set-up:
  • Service TheMovieDb to call themovedb.org api.
  • Service MovieInfo service to integrate TheMovieDb with Orchard.
  • AdminController for front-end to call MovieInfo and coordinate views.

TheMoveDb uses Tasks, so I don't have to wait around for across-the-wire calls. MovieInfo uses Tasks, and integrates with orchard services. AdminController uses normal Action methods.

Being a TDD developer, all the pieces looked fine. But as soon as I put it together... splat.

It all starts with a deadlock (doesn't it always!). A quick google gets to Stephen Cleary (via SO) Don't Block on Async Code and Async and Await Armed with this I now at-least understand the problem.

Alas, at least in Orchard 1.6, async controllers are a no-go. It took a fair bit of searching, I finally found an SO article describing the problem. So (for now) I've settled on a sync / async solution.

Putting it all together:
  • TheMoveDb service stays as a normal async service.
  • MovieInfo service calls TheMoveDb with ConfigureAwait(false).
  • AdminController stay synchronous; blocks on calls to MovieInfo, waiting for Result.

There was one last gotcha; anything after the await in MovieInfo service executes on its own thread. So no access to orchard services (such as WorkContext etc). To get around this I just had to take care to no need the 'orchard friendly' thread context after the await.

A short list of C# coding issues.

Injecting services into entities It been bugging me for a while now that to use services in a entity can be a bit of pain. It usually starts...