Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

IsRegistered() doesn't behave like Resolve() #366

Open
DrEsteban opened this issue Dec 20, 2024 · 0 comments
Open

IsRegistered() doesn't behave like Resolve() #366

DrEsteban opened this issue Dec 20, 2024 · 0 comments
Labels
bug Something isn't working

Comments

@DrEsteban
Copy link
Contributor

DrEsteban commented Dec 20, 2024

Reqnroll Version

2.2.1

Which test runner are you using?

MSTest

Test Runner Version Number

2.2.1

.NET Implementation

.NET 8.0

Test Execution Method

Visual Studio Test Explorer

Content of reqnroll.json configuration file

(shouldn't be necessary for this issue)

Issue Description

I believe this is a long-known inconsistency of BoDi, but I believe there's an opportunity to improve it with Reqnroll.

IMHO, user expectation is "I can use IsRegistered() to determine whether I can Resolve() something. If it returns true, I can resolve it. If it returns false, I can't."

This is not how the DI works today. IsRegistered() could return false for a particular dependency, even though a Resolve() operation would work because the dependency was registered at a higher level! In other words, Resolve() will walk up the inheritance chain to see if a dependency has been registered at the Feature or Global level. IsRegistered() simply looks at the current level.

This has lead me to introduce this extension method for my project:

/// <summary>
/// Checks if a type is registered at any level in the container hierarchy.
/// </summary>
public static bool IsRegisteredAtAnyLevel<T>(this IObjectContainer container, string? name = null)
{
    do
    {
        if (container.IsRegistered<T>(name))
        {
            return true;
        }
    } while (container is ObjectContainer c && (container = c.BaseContainer) != null);

    return false;
}

I could understand if you didn't want to introduce a breaking change by updating the current behavior of IsRegistered()... There might be some valid use-cases where you truly only want to check the current level. But I'm logging this Issue to argue that a method similar to the above should be incorporated directly into Reqnroll, so users don't have to implement it themselves!

Steps to Reproduce

[BeforeFeature]
public static void RegisterFeatureDependencies(IObjectContainer container)
{
  container.RegisterInstanceAs(new MyDependency());
}

// -----

[When("I use my dependency")]
public void UseMyDependency()
{
  if (!container.IsRegistered<MyDependency>())
  {
    // This will throw!
    throw new Exception("Cannot use MyDependency!");
  }

  // Even though the dependency *is* registered (at the Feature level) and would resolve just fine...
  var dep = container.Resolve<MyDependency>();
  dep.DoStuff();
}

This example is a bit contrived, but in my project we're attempting to provide more human-readable errors to guide users into doing the right thing. For example, we have common step definitions like "Given I am an authorized user", which will grab an auth token and register some things with DI. And for perf reasons, we register those things at the feature level so we don't have to grab a new auth token for every single scenario.

So rather than have an error message like "Couldn't resolve AuthToken", we're trying to proactively use IsRegistered() and hand-written exception messages to guide users into doing the right thing. E.g. "No auth token available. Please ensure your scenario specifies \"Given I am an authorized user\"".

I know this is a niche use-case, but I wanted to provide an example of situations where having an IsRegistered() variant that behaves like Resolve() would be useful 🙂

Link to Repro Project

No response

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant