{"record":{"id":"48250e2736f51217","repo":"abpframework/abp","slug":"servicekey-can-not-be-null-use-exposeservicesattr","errorCode":null,"errorMessage":"serviceKey can not be null! Use ExposeServicesAttribute instead.","messagePattern":"serviceKey can not be null! Use ExposeServicesAttribute instead\\.","errorType":"exception","errorClass":"AbpException","httpStatus":null,"severity":"error","filePath":"framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ExposeKeyedServiceAttribute.cs","lineNumber":15,"sourceCode":"using System;\n\nnamespace Volo.Abp.DependencyInjection;\n\n[AttributeUsage(AttributeTargets.Class, AllowMultiple = true)]\npublic class ExposeKeyedServiceAttribute<TServiceType> : Attribute, IExposedKeyedServiceTypesProvider\n    where TServiceType : class\n{\n    public ServiceIdentifier ServiceIdentifier { get; }\n\n    public ExposeKeyedServiceAttribute(object serviceKey)\n    {\n        if (serviceKey == null)\n        {\n            throw new AbpException($\"{nameof(serviceKey)} can not be null! Use {nameof(ExposeServicesAttribute)} instead.\");\n        }\n\n        ServiceIdentifier = new ServiceIdentifier(serviceKey, typeof(TServiceType));\n    }\n\n    public ServiceIdentifier[] GetExposedServiceTypes(Type targetType)\n    {\n        return new[] { ServiceIdentifier };\n    }\n}\n","sourceCodeStart":1,"sourceCodeEnd":26,"githubUrl":"https://github.com/abpframework/abp/blob/7ed43b1931b9df46a50c0c59148a18645641d0df/framework/src/Volo.Abp.Core/Volo/Abp/DependencyInjection/ExposeKeyedServiceAttribute.cs#L1-L26","documentation":"Thrown by the ExposeKeyedServiceAttribute<TServiceType> constructor (generic form) when the serviceKey argument is null. ABP tells you to use ExposeServicesAttribute instead, because a null key has no meaning for keyed service registration. It is an AbpException.","triggerScenarios":"Decorating a class with [ExposeKeyedServiceAttribute<TService>(null)] or passing a null-typed constant/field as serviceKey at the attribute level.","commonSituations":"Mistakenly passing null (or an uninitialized static field) as the keyed-service key, or confusing the keyed attribute with the non-keyed ExposeServicesAttribute.","solutions":["Pass a concrete non-null key (a string, enum, or object) to the attribute.","If you do not need keying at all, switch to [ExposeServices(typeof(TService))].","If the key comes from a constant, ensure the constant is initialized and non-null."],"exampleFix":"// before\n[ExposeKeyedServiceAttribute<IMyService>(null)]\npublic class MyService : IMyService { }\n\n// after\n[ExposeKeyedServiceAttribute<IMyService>(\"primary\")]\npublic class MyService : IMyService { }","handlingStrategy":"validation","validationCode":"// Attributes are compile-time; 'validate' by never passing null.\n// Use a real key literal or switch to ExposeServicesAttribute.","typeGuard":null,"tryCatchPattern":"try { /* attribute ctor runs at reflection time */ }\ncatch (AbpException ex) when (ex.Message.Contains(\"serviceKey\"))\n{\n    logger.LogError(ex, \"Keyed service attribute misconfigured on {Type}\", type);\n}","preventionTips":["Always pass a concrete key (string/enum/object) to ExposeKeyedServiceAttribute.","If you do not need keying, use [ExposeServices(typeof(T))] instead.","Avoid [ExposeKeyedServiceAttribute<T>(someField)] where someField could be null."],"tags":["di","dependency-injection","keyed-services","attribute","abp-core"],"backgroundTag":null,"analyzedSha":"7ed43b1931b9df46a50c0c59148a18645641d0df","analyzedAt":"2026-08-13T16:26:11.351Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}