{"record":{"id":"d172b1cf60930d1e","repo":"dotnet/yarp","slug":"tconsumer-must-implement-at-least-one-imetricscons","errorCode":null,"errorMessage":"TConsumer must implement at least one IMetricsConsumer interface.","messagePattern":"TConsumer must implement at least one IMetricsConsumer interface\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/TelemetryConsumption/TelemetryConsumptionExtensions.cs","lineNumber":248,"sourceCode":"            services.AddSingleton(services => (IMetricsConsumer<NameResolutionMetrics>)services.GetRequiredService<TConsumer>());\n            implementsAny = true;\n        }\n\n        if (typeof(IMetricsConsumer<NetSecurityMetrics>).IsAssignableFrom(typeof(TConsumer)))\n        {\n            services.AddSingleton(services => (IMetricsConsumer<NetSecurityMetrics>)services.GetRequiredService<TConsumer>());\n            implementsAny = true;\n        }\n\n        if (typeof(IMetricsConsumer<SocketsMetrics>).IsAssignableFrom(typeof(TConsumer)))\n        {\n            services.AddSingleton(services => (IMetricsConsumer<SocketsMetrics>)services.GetRequiredService<TConsumer>());\n            implementsAny = true;\n        }\n\n        if (!implementsAny)\n        {\n            throw new ArgumentException(\"TConsumer must implement at least one IMetricsConsumer interface.\", nameof(TConsumer));\n        }\n\n        services.TryAddSingleton<TConsumer>();\n\n        services.AddTelemetryListeners();\n\n        return services;\n    }\n}\n","sourceCodeStart":230,"sourceCodeEnd":258,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/TelemetryConsumption/TelemetryConsumptionExtensions.cs#L230-L258","documentation":"The generic AddMetricsConsumer<TConsumer>() uses IsAssignableFrom to detect each closed IMetricsConsumer<TMetrics> interface on TConsumer and register a forwarding factory. With no generic constraint, a TConsumer that implements none triggers ArgumentException(paramName: TConsumer) at startup.","triggerScenarios":"Calling services.AddMetricsConsumer<MyClass>() where MyClass implements no IMetricsConsumer<...> interface.","commonSituations":"Forgetting the interface on the consumer; version change that renamed/removed a metrics type so IsAssignableFrom no longer matches; passing a telemetry-only type to the metrics generic overload.","solutions":["Implement at least one IMetricsConsumer<TMetrics> interface on TConsumer.","If the type handles telemetry events, switch to AddTelemetryConsumer<TConsumer>().","Add a compile-time `where TConsumer : IMetricsConsumer<HttpClientMetrics>` constraint on a wrapper to force a build error instead."],"exampleFix":"// before\npublic class MyConsumer { ... }\nservices.AddMetricsConsumer<MyConsumer>();\n\n// after\npublic class MyConsumer : IMetricsConsumer<SocketsMetrics> { ... }\nservices.AddMetricsConsumer<MyConsumer>();","handlingStrategy":"type-guard","validationCode":"static bool ImplementsAnyMetricsConsumer<T>() =>\n    typeof(IMetricsConsumer<HttpClientMetrics>).IsAssignableFrom(typeof(T))\n    || typeof(IMetricsConsumer<SocketsMetrics>).IsAssignableFrom(typeof(T))\n    || typeof(IMetricsConsumer<NetSecurityMetrics>).IsAssignableFrom(typeof(T));\n\nif (ImplementsAnyMetricsConsumer<MyConsumer>())\n    services.AddMetricsConsumer<MyConsumer>();","typeGuard":"public static IServiceCollection AddMyMetricsConsumer<TConsumer>(this IServiceCollection services)\n    where TConsumer : class, IMetricsConsumer<HttpClientMetrics>\n    => services.AddMetricsConsumer<TConsumer>();","tryCatchPattern":null,"preventionTips":["Add a generic constraint on your wrapper extension to force a build-time error.","Verify the closed IMetricsConsumer<> generic argument matches a type YARP actually emits.","Unit-test that each metrics consumer implements the expected interface."],"tags":["telemetry","metrics","di-registration","interface","generic","validation","yarp"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T00:17:13.853Z"}