Skip to content

Conversation

Copilot
Copy link
Contributor

@Copilot Copilot AI commented Jul 21, 2025

This PR adds strongly-typed client support similar to IHttpClientFactory and simplifies the internal codebase architecture while maintaining full backward compatibility.

New Features

Typed Client Support

Added ITypedQueueClient<TMessage> interface and implementation that provides compile-time type safety for queue operations:

// Register typed clients
services.AddAzureStorageQueueClient(x => 
    x.AddDefaultClient(y => Configuration.Bind(nameof(QueueClientSettings), y)));
services.AddTypedQueueClient<OrderMessage>();

// Use with dependency injection
public class OrderService
{
    private readonly ITypedQueueClient<OrderMessage> _queueClient;

    public OrderService(ITypedQueueClient<OrderMessage> queueClient)
    {
        _queueClient = queueClient; // Type-safe, no casting needed
    }

    public async Task ProcessOrderAsync(OrderMessage order)
    {
        await _queueClient.SendMessageAsync(order);
    }
}

Multiple Registration Patterns

Supports both default and named client configurations:

// Default client
services.AddTypedQueueClient<MyMessage>();

// Named client
services.AddTypedQueueClient<OrderMessage>("orders");

// Multiple message types
services.AddTypedQueueClient<OrderMessage>("orders");
services.AddTypedQueueClient<NotificationMessage>("notifications");

Code Simplifications

Removed Over-Engineered Abstractions

  • Eliminated IQueueClientBuilder interface and QueueClientBuilder class
  • Inlined Azure QueueClient creation logic directly into QueueClientFactory
  • Reduced main project from 24 to 21 source files
  • Maintained 100% backward compatibility for public APIs

Improved Test Architecture

  • Enhanced test coverage from 21 to 24 comprehensive unit tests
  • Simplified test setup by removing unnecessary mocking
  • Added focused tests for typed client functionality
  • Fixed integration test configuration issues

Documentation Updates

Updated README with comprehensive examples showing:

  • Side-by-side comparisons of factory vs typed client patterns
  • Registration patterns for different scenarios
  • Migration examples for existing codebases

Benefits

  1. Type Safety: Compile-time checking for message types
  2. Cleaner DI: Direct injection instead of factory pattern
  3. Reduced Complexity: Removed unnecessary internal abstractions
  4. Better Testing: More focused and maintainable tests
  5. Zero Breaking Changes: All existing code continues to work

Comparison

Before (Factory Pattern):

public MyService(IQueueClientFactory factory)
{
    _client = factory.GetQueueClient("orders");
    // Runtime type checking required
}

After (Typed Client):

public MyService(ITypedQueueClient<OrderMessage> client)
{
    _client = client; // Compile-time type safety
}

Fixes #35.

Warning

Firewall rules blocked me from connecting to one or more addresses

I tried to connect to the following addresses, but was blocked by firewall rules:

  • test.queue.core.windows.net
    • Triggering command: /usr/lib/dotnet/dotnet exec --runtimeconfig /home/REDACTED/work/AzureStorage.QueueService/AzureStorage.QueueService/tests/AzureStorage.QueueService.Tests/bin/Debug/net8.0/AzureStorage.QueueService.Tests.runtimeconfig.json --depsfile /home/REDACTED/work/AzureStorage.QueueService/AzureStorage.QueueService/tests/AzureStorage.QueueService.Tests/bin/Debug/net8.0/AzureStorage.QueueService.Tests.deps.json /home/REDACTED/work/AzureStorage.QueueService/AzureStorage.QueueService/tests/AzureStorage.QueueService.Tests/bin/Debug/net8.0/testhost.dll --port 42025 --endpoint 127.0.0.1:042025 --role client --parentprocessid 4731 --telemetryoptedin false (dns block)

If you need me to access, download, or install something from one of these locations, you can either:


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits July 21, 2025 16:32
Co-authored-by: jasonshave <28457536+jasonshave@users.noreply.github.com>
Co-authored-by: jasonshave <28457536+jasonshave@users.noreply.github.com>
@Copilot Copilot AI changed the title [WIP] Simplify codebase Add typed client support and simplify codebase architecture Jul 21, 2025
@Copilot Copilot AI requested a review from jasonshave July 21, 2025 16:40
Copilot finished work on behalf of jasonshave July 21, 2025 16:40
Copy link
Owner

@jasonshave jasonshave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would expect the typed client to work the same as the IHttpClientFactory. If I register a typed client like "MyClient", that type should be put in the dictionary and a QueueClient can then be injected into any class using DI. Otherwise, you would have to inject the IQueueClientFactory and use GetClient("name") or the default client.

…ry pattern

Co-authored-by: jasonshave <28457536+jasonshave@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jul 21, 2025

I would expect the typed client to work the same as the IHttpClientFactory. If I register a typed client like "MyClient", that type should be put in the dictionary and a QueueClient can then be inject...

I've added support for custom queue client types that work exactly like IHttpClientFactory. You can now register custom client classes using AddQueueClient<TClient>() and inject them directly via DI, just like you'd expect. The implementation supports both the typed client pattern (ITypedQueueClient<TMessage>) and custom client classes that encapsulate business logic. See the updated README for examples. Commit: 3cedb61

@Copilot Copilot AI requested a review from jasonshave July 21, 2025 19:08
Copilot finished work on behalf of jasonshave July 21, 2025 19:08
Copy link
Owner

@jasonshave jasonshave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what significance is "T" in the typed client? Why would someone use ITypedQueueClient? I don't think it makes sense to have a factory linked to a message type.

The way the typed HTTP client works in .NET Is that you can register a type, then inject the HttpClient type in that class and the instance will be provided, and configured according to the initial setup.

Copy link
Contributor Author

Copilot AI commented Jul 22, 2025

what significance is "T" in the typed client? Why would someone use ITypedQueueClient? I don't think it makes sense to have a factory linked to a message type.

The way the typed HTTP client wor...

You're absolutely right! The current design doesn't follow the IHttpClientFactory pattern properly. The "T" should be the CLIENT type, not the message type. I'll refactor this to work exactly like IHttpClientFactory where you register AddQueueClient<MyOrderClient>() and inject the client type directly, with the underlying AzureStorageQueueClient configured and injected automatically.

Co-authored-by: jasonshave <28457536+jasonshave@users.noreply.github.com>
@Copilot Copilot AI requested a review from jasonshave July 22, 2025 03:02
Copilot finished work on behalf of jasonshave July 22, 2025 03:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Simplify codebase

2 participants