EcovadisCode / Ev.ServiceBus

A wrapper to use Azure Service Bus in a ASP.NET Core project
MIT License
20 stars 9 forks source link

Fix ServiceDescriptor access for keyed services #71

Open amcorch opened 7 months ago

amcorch commented 7 months ago

Fixes issue where System.InvalidOperationException: 'This service descriptor is keyed. Your service provider may not support keyed services.' is thrown during startup if keyed services are registered.

benspeth commented 7 months ago

Hi. Can you give me some details on how to reproduce this bug you are trying to fix ?

amcorch commented 7 months ago

Here is a sample that should reproduce the issue I'm seeing.

  <ItemGroup>
    <PackageReference Include="Ev.ServiceBus" Version="5.0.1" />
    <PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
    <PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.0.0" />
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
  </ItemGroup>
using Azure.Messaging.ServiceBus;
using Ev.ServiceBus.Abstractions;
using Microsoft.Extensions.Hosting;
using System.Text;
using Ev.ServiceBus;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;

using var host = new HostBuilder()
    .ConfigureServices(services =>
    {
        services.AddKeyedSingleton<INotificationService, SmsNotificationService>("sms");
        services.AddKeyedSingleton<INotificationService, EmailNotificationService>("email");

        services.AddServiceBus(
                settings =>
                {
                    settings.WithConnection("string", new ServiceBusClientOptions());
                })
            .WithPayloadSerializer<MessagePayloadSerializer>();

        services.RegisterServiceBusDispatch().ToQueue("ServiceBusResources.MyQueue", builder =>
        {
            builder.RegisterDispatch<WeatherForecast[]>();
        });

    })
    .Build();

await host.StartAsync();

[Serializable]
public class WeatherForecast
{
}

public class MessagePayloadSerializer : IMessagePayloadSerializer
{
    private static readonly JsonSerializerSettings Settings = new()
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        Formatting = Formatting.None,
        Converters =
        {
            new StringEnumConverter()
        },
        NullValueHandling = NullValueHandling.Ignore
    };

    public SerializationResult SerializeBody(object objectToSerialize)
    {
        var json = JsonConvert.SerializeObject(objectToSerialize, Formatting.None, Settings);
        return new SerializationResult("application/json", Encoding.UTF8.GetBytes(json));
    }

    public object DeSerializeBody(byte[] content, Type typeToCreate)
    {
        var @string = Encoding.UTF8.GetString(content);
        return JsonConvert.DeserializeObject(@string, typeToCreate, Settings)!;
    }
}

public interface INotificationService
{
    string Notify(string message);
}

public class SmsNotificationService : INotificationService
{
    public string Notify(string message) => $"[SMS] {message}";
}

public class EmailNotificationService : INotificationService
{
    public string Notify(string message) => $"[Email] {message}";
}