{"record":{"id":"7c50480d9d2ebb1c","repo":"dotnet/yarp","slug":"the-consumer-must-implement-at-least-one-imetricsc","errorCode":null,"errorMessage":"The consumer must implement at least one IMetricsConsumer interface.","messagePattern":"The consumer must implement at least one IMetricsConsumer interface\\.","errorType":"validation","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"src/TelemetryConsumption/TelemetryConsumptionExtensions.cs","lineNumber":194,"sourceCode":"            services.TryAddEnumerable(ServiceDescriptor.Singleton(nameResolutionMetricsConsumer));\n            implementsAny = true;\n        }\n\n        if (consumer is IMetricsConsumer<NetSecurityMetrics> netSecurityMetricsConsumer)\n        {\n            services.TryAddEnumerable(ServiceDescriptor.Singleton(netSecurityMetricsConsumer));\n            implementsAny = true;\n        }\n\n        if (consumer is IMetricsConsumer<SocketsMetrics> socketsMetricsConsumer)\n        {\n            services.TryAddEnumerable(ServiceDescriptor.Singleton(socketsMetricsConsumer));\n            implementsAny = true;\n        }\n\n        if (!implementsAny)\n        {\n            throw new ArgumentException(\"The consumer must implement at least one IMetricsConsumer interface.\", nameof(consumer));\n        }\n\n        services.AddTelemetryListeners();\n\n        return services;\n    }\n\n    /// <summary>\n    /// Registers a consumer singleton for every IMetricsConsumer interface it implements.\n    /// </summary>\n    public static IServiceCollection AddMetricsConsumer<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TConsumer>(this IServiceCollection services)\n        where TConsumer : class\n    {\n        var implementsAny = false;\n\n        if (typeof(IMetricsConsumer<ForwarderMetrics>).IsAssignableFrom(typeof(TConsumer)))\n        {\n            services.AddSingleton(services => (IMetricsConsumer<ForwarderMetrics>)services.GetRequiredService<TConsumer>());","sourceCodeStart":176,"sourceCodeEnd":212,"githubUrl":"https://github.com/dotnet/yarp/blob/bd11867bee7df522e7fd3effb08a9c85fd616908/src/TelemetryConsumption/TelemetryConsumptionExtensions.cs#L176-L212","documentation":"AddMetricsConsumer(object consumer) mirrors the telemetry overload but checks the IMetricsConsumer<TMetrics> interfaces (IMetricsConsumer<HttpClientMetrics>, IMetricsConsumer<SocketsMetrics>, IMetricsConsumer<NetSecurityMetrics>, ...). If the instance implements none, it throws ArgumentException(paramName: consumer) since there are no metrics to forward.","triggerScenarios":"Calling services.AddMetricsConsumer(someObject) where someObject does not implement any IMetricsConsumer<...> interface, e.g. passing a telemetry-only consumer or a plain object.","commonSituations":"Using the metrics overload for a class that only implements I*TelemetryConsumer; refactor that removed the IMetricsConsumer interface; passing a consumer designed for a different metrics type that is not among the recognized ones.","solutions":["Implement at least one recognized IMetricsConsumer<TMetrics> interface on the consumer.","If the type only handles telemetry events, call AddTelemetryConsumer instead.","Use the generic AddMetricsConsumer<TConsumer>() and confirm the closed IMetricsConsumer<> interface matches one YARP emits."],"exampleFix":"// before\npublic class MyConsumer { ... }\nservices.AddMetricsConsumer(new MyConsumer());\n\n// after\npublic class MyConsumer : IMetricsConsumer<HttpClientMetrics> { ... }\nservices.AddMetricsConsumer(new MyConsumer());","handlingStrategy":"type-guard","validationCode":"static bool ImplementsAnyMetricsConsumer(object c) =>\n    c is IMetricsConsumer<HttpClientMetrics>\n    || c is IMetricsConsumer<SocketsMetrics>\n    || c is IMetricsConsumer<NetSecurityMetrics>;\n\nif (ImplementsAnyMetricsConsumer(consumer))\n    services.AddMetricsConsumer(consumer);","typeGuard":"static bool ImplementsAnyMetricsConsumer(object c) =>\n    c is IMetricsConsumer<HttpClientMetrics>\n    || c is IMetricsConsumer<SocketsMetrics>\n    || c is IMetricsConsumer<NetSecurityMetrics>;","tryCatchPattern":null,"preventionTips":["Keep metrics consumers separate from telemetry-event consumers to avoid calling the wrong overload.","Add a unit test asserting the consumer implements at least one IMetricsConsumer<>.","After a YARP upgrade, confirm the closed IMetricsConsumer<TMetrics> types still match."],"tags":["telemetry","metrics","di-registration","interface","validation","yarp"],"backgroundTag":null,"analyzedSha":"bd11867bee7df522e7fd3effb08a9c85fd616908","analyzedAt":"2026-08-13T21:29:49.359Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}