Skip to content

Modernize Examples for the current release wave #32

Description

@tillig

I just shipped updated versions across all the Autofac libraries, and this repo has fallen behind far enough that several examples no longer reflect what we actually publish. This issue tracks getting it current, gating it so it stays current, and closing the biggest coverage gaps.

Why this is more than a version bump

Three findings from the audit shape the work:

The .NET Framework integration packages target net481 now. Confirmed at the release tags — Autofac.Mvc5 v7.0.0, Autofac.Wcf v8.0.0, Autofac.Web v8.0.0, Autofac.Owin v8.0.0. The six net472 projects in here cannot take current packages without retargeting. They are also the furthest behind: still on Autofac 6.5.0 against a current 9.3.2.

Four org repos have no published package, so they can't have copy-pasteable examples: Autofac.Analyzers, Autofac.AspNetCore, Autofac.Extensions.Hosting, Autofac.Extras.AggregateService.SourceGenerator. Notably that rules out using our own analyzer package to raise code quality in here.

dotnet format fails today — missing UTF-8 BOM in the three ASP.NET Core projects, import ordering, final newlines, and one whitespace error. All auto-fixable, but it means adding the CI gate and fixing the code have to land together.

Two bugs also turned up that have nothing to do with modernization:

  • WebFormsExample.csproj sets RootNamespace and AssemblyName to MvcExample. Combined with OutputPath=bin/ and AppendTargetFrameworkToOutputPath=false, its output collides with the real MvcExample.
  • ci.yml triggers on develop and gates pull requests against develop, but this repo only has main — it's one of our non-Gitflow repos. PR builds never fire.

Decisions

Recording these so the tasks below don't get relitigated:

  • Retarget the legacy examples to net481 rather than freezing them on Autofac 6.x. Examples that don't match what we ship are worse than no examples.
  • Keep CI local to this repo. The org's shared ci.yml assumes default.proj, a codecov upload, and NuGet publishing — none of which apply to a repo with no packages and no tests. Adding inputs for a single consumer isn't worth the conditional complexity.
  • .editorconfig plus AnalysisLevel=latest-recommended, and no StyleCop. Nullable on, warnings-as-errors in Release. StyleCop wants file headers and XML docs on public members, which is a lot of ceremony wrapped around ten-line teaching samples.
  • No test projects except where testing is the point. The Moq and FakeItEasy examples are the only ones that should carry tests, and both are deferred below.

Work

Ordered, because they stack. Each lands as its own pull request against main.

  • 1. Root config refresh. Replace .editorconfig with the current one from the core repo (ours is the pre-2020 version — no per-filetype sections, no dotnet_diagnostic severities). Add .markdownlint.json; pre-commit runs markdownlint with no config today. Bump the markdownlint hook to v0.49.1 to match core. Relax the global.json pin from 10.0.203 to 10.0.100 so any 10.0 SDK can build this. Fix the develop triggers in ci.yml. Clean up the README: dead AppVeyor badge, Examples.sln should be Examples.slnx, and it still advertises a ServiceFabric example that was deleted in cae30c6. Verify: pre-commit run --all-files is clean.
  • 2. CI gates. Add dotnet format and pre-commit jobs to build.yml, mirroring the org workflow's job bodies minus the default.proj, codecov, and publish steps. The format job needs windows-latestnet481 projects won't restore on Linux. Also port the org workflow's gate job: Refresh root configuration and normalize the repo #33 built twice for one commit, once for the branch push and once for the pull request, and adding two more jobs would triple that waste. Verify: all jobs run, fail loudly on a deliberate violation, and only one run happens per change.
  • 3. Dependency updates, net10.0 projects. Autofac and the integration packages to current, plus Microsoft.Extensions.*. Split from the retarget below so a net481 surprise can't block the modern examples. Verify: dotnet build Examples.slnx -c Release clean.
  • 4. Retarget net472net481. All six legacy projects, with every Autofac package to current, plus Microsoft.AspNet.Mvc, Newtonsoft.Json, Microsoft.Bcl.AsyncInterfaces, and Microsoft.NETFramework.ReferenceAssemblies. Verify: dotnet build Examples.slnx -c Release clean on Windows.
  • 5. Code standards pass. Add a root Directory.Build.props — there is none today — carrying Nullable, ImplicitUsings, EnforceCodeStyleInBuild, AnalysisLevel, and TreatWarningsAsErrors in Release, so policy lives in one place instead of fifteen csproj files. Then fix the fallout: file-scoped namespaces everywhere (ccd9b35 claimed to do this but GenericHostBuilderExample, AttributeMetadataExample, and the net472 projects still use block scope), drop usings made redundant by ImplicitUsings, remove the one remaining // ReSharper comment, normalize the stray csproj blank lines, and fix the WebFormsExample assembly name bug. Applied as a scripted pass over the project list so the diffs are identical by construction. Verify: zero warnings in Release, dotnet format --verify-no-changes clean.
  • 6. VS Code integration. launch.json still has configurations for AspNetCore3Example and AspNetCore3ChildLifetimeScope, neither of which exists anymore, and every surviving one points at a bin/Debug/net6.0/ path for a project that targets net10.0. AspNetCoreChildLifetimeScope and AspNetCoreNoStartupExample do exist and have no configuration at all. Environment variables move out of launch.json and into the per-project launchSettings.json — all eight web projects already have one — referenced from the launch configuration via launchSettingsProfile so there's a single place to set them. Switch to DOTNET_ENVIRONMENT; the ASPNETCORE_-prefixed form is the older pattern. Only the three ASP.NET Core projects actually matter there, since classic ASP.NET reads neither prefix and the .NET Framework entries are inert. settings.json still carries omnisharp.* keys the Roslyn language server ignores, and extensions.json recommends a test explorer for a repo with no tests. Depends on item 4, because the launch paths embed target frameworks. Verify: every configuration in launch.json starts the project it names.
  • 7. Navigation. A table in the README — example, what it demonstrates, packages, link to the matching docs page. A short README per example: what it shows, how to run it, link to the doc page, and nothing else. Group Examples.slnx into solution folders by area instead of one flat /src/. Leaving the src/ layout alone; restructuring it churns every inbound docs link for no gain once the table exists. Verify: every src/ directory has a README.
  • 8. New examples. DynamicProxy interception, Autofac.Pooling, Autofac.Diagnostics.DotGraph, Autofac.AspNetCore.Multitenant, and a middleware example for More middleware examples Documentation#160. All net10.0, all cross-platform. Verify: each builds and runs.
  • 9. Documentation repo follow-up. All ten cross-links into this repo point at /tree/master/... and our default branch is main — GitHub's rename redirect isn't something to rely on. Same pull request adds the middleware section that closes More middleware examples Documentation#160 and links the four new examples from their doc pages.

Middleware examples for autofac/Documentation#160

advanced/pipelines.rst covers the mechanics thoroughly, but its only sample is the Hello World logging lambda, and that issue asks for concrete real-world cases. Scenarios to cover, in priority order:

  1. Blanket AOP across every registration — the Hook/Extension point modifying IRegistrationBuilder Autofac#1337 case that issue cites. Wrapping every resolved service via the Registered event or IServiceMiddlewareSource, with no per-registration extension call. This is the one that wasn't obvious, so it's the point.
  2. Resolve timing and instrumentation — measuring activation cost per service.
  3. Short-circuiting — returning a cached instance without calling next.
  4. Ambient parameter injection — pushing a correlation ID or tenant into every activation through ResolveRequestContext.
  5. Fail-fast scope validation — service middleware that throws something readable when a service is resolved from the wrong scope.

Coverage gaps deferred

The goal is one example per non-deprecated library. After item 8, these are still uncovered:

Package Disposition
Autofac.Extras.Moq Worth doing. xUnit test project — one of the two places tests belong here.
Autofac.Extras.FakeItEasy Worth doing, same shape as Moq.
Autofac.Extras.AggregateService Worth doing. Small console app.
Autofac.Mef Worth doing. Small console app.
Autofac.Mvc5.Owin Low value, and better as an addition to the existing OWIN self-host example than a new project.
Autofac.SignalR2 Low value. net481, ASP.NET SignalR 2. Legacy, but it is a shipping package.
Autofac.Extras.CommonServiceLocator Not planning to cover. CSL upstream is abandoned; not formally deprecated, but not worth teaching.
Autofac.ServiceFabric Not planning to cover. Deliberately deleted in cae30c6; the SF SDK is Windows-only and isn't on GitHub runners, so any example we add here will rot. The tagged history still has the old one.
Autofac.Analyzers, Autofac.AspNetCore, Autofac.Extensions.Hosting, Autofac.Extras.AggregateService.SourceGenerator Blocked. Unpublished, so an example wouldn't be runnable by anyone reading it.

Separately, there are documented core features with no example anywhere — decorators and composites, keyed services, registration sources, delegate factories, owned instances, native AOT and trimming — and integration/blazor.rst and integration/azurefunctions.rst have docs with no example. That's a real gap against "one example per documented feature," but it's much larger in scope than one-per-library and belongs in its own issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions