Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ private void DiscoverHubMethods(bool disableImplicitFromServiceParameters)
}

var methodName =
methodInfo.GetCustomAttribute<HubMethodNameAttribute>()?.Name ??
methodInfo.GetCustomAttribute<HubMethodNameAttribute>(inherit: true)?.Name ??
methodInfo.Name;

if (_methods.ContainsKey(methodName))
Expand Down Expand Up @@ -894,4 +894,4 @@ private static void SetActivityError(Activity? activity, Exception ex)
activity?.SetTag("error.type", ex.GetType().FullName);
activity?.SetStatus(ActivityStatusCode.Error);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1367,24 +1367,59 @@ public bool SingleService([FromService] Service1 service)
return true;
}

public bool ServiceWithAttribute([FromService] Service1 service)
{
return true;
}

public int ServiceWithStringAttribute([FromService] Service1 service, string value)
{
return 115;
}

public bool MultipleServices([FromService] Service1 service, [FromService] Service2 service2, [FromService] Service3 service3)
{
return true;
}

public async Task<int> ServicesAndParams(int value, [FromService] Service1 service, ChannelReader<int> channelReader, [FromService] Service2 service2, bool value2)
public bool MultipleServicesWithAttribute([FromService] Service1 service, [FromService] Service2 service2)
{
return true;
}

public int MixedParamsWithAttribute(int num, string text, [FromService] Service1 service, [FromService] Service2 service2)
{
return 111;
}

public int ServiceAttributeBeforeParam([FromService] Service1 service, int num)
{
return num + 1;
}

public async Task<int> UploadWithServiceAttribute(int value, [FromService] Service1 service, ChannelReader<int> channelReader)
{
int total = 0;
while (await channelReader.WaitToReadAsync())
{
total += await channelReader.ReadAsync();
}
return total + value;
return total + value + 1;
}
public int ServiceWithStringAttribute([FromService] Service1 service, string value)

public int ServiceWithOptionalParam([FromService] Service1 service, int value = 42)
{
return 115;
return value + 1;
}

public async Task<int> ServicesAndParams(int value, [FromService] Service1 service, ChannelReader<int> channelReader, [FromService] Service2 service2, bool value2)
{
int total = 0;
while (await channelReader.WaitToReadAsync())
{
total += await channelReader.ReadAsync();
}
return total + value;
}

public int ServiceWithoutAttribute(Service1 service)
Expand Down Expand Up @@ -1469,4 +1504,4 @@ public override async Task OnConnectedAsync()
await Clients.Client(id).SendAsync("Test", 1);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,6 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Diagnostics;
using System.Globalization;
using System.IO.Pipelines;
using System.Security.Claims;
using System.Text;
using System.Threading.Channels;
using MessagePack;
using MessagePack.Formatters;
using MessagePack.Resolvers;
Expand All @@ -29,6 +22,14 @@
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System.Buffers;
using System.Diagnostics;
using System.Globalization;
using System.IO.Pipelines;
using System.Security.Claims;
using System.Text;
using System.Threading.Channels;
using static Microsoft.AspNetCore.SignalR.Tests.Internal.TypedClientBuilderTests;

namespace Microsoft.AspNetCore.SignalR.Tests;

Expand Down Expand Up @@ -5347,6 +5348,197 @@ public async Task GracefulCloseDisablesReconnect()
}
}

[Fact]
public async Task HubMethodCanInjectServiceWithAttribute()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
var res = await client.InvokeAsync(nameof(ServicesHub.ServiceWithAttribute)).DefaultTimeout();
Assert.True(Assert.IsType<bool>(res.Result));
}
}

[Fact]
public async Task HubMethodCanInjectServiceWithStringParameterAndAttribute()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
var res = await client.InvokeAsync(nameof(ServicesHub.ServiceWithStringAttribute), "test").DefaultTimeout();
Assert.Equal(115L, res.Result);
}
}

[Fact]
public async Task HubMethodWithFromServicesAttributeFailsIfServiceNotFound()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSignalR(o => o.EnableDetailedErrors = true);
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
var res = await client.InvokeAsync(nameof(ServicesHub.ServiceWithAttribute)).DefaultTimeout();
Assert.Equal("An unexpected error occurred invoking 'ServiceWithAttribute' on the server. InvalidOperationException: No service for type 'Microsoft.AspNetCore.SignalR.Tests.Service1' has been registered.", res.Error);
}
}

[Fact]
public async Task HubMethodWithMultipleFromServicesAttributes()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
provider.AddSingleton<Service2>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
var res = await client.InvokeAsync(nameof(ServicesHub.MultipleServicesWithAttribute)).DefaultTimeout();
Assert.True(Assert.IsType<bool>(res.Result));
}
}

[Fact]
public async Task HubMethodWithMixedParametersAndFromServicesAttribute()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
provider.AddSingleton<Service2>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
var res = await client.InvokeAsync(nameof(ServicesHub.MixedParamsWithAttribute), 10, "test").DefaultTimeout();
Assert.Equal(111L, res.Result);
}
}

[Fact]
public async Task HubMethodWithFromServicesAttributeAndNullParameter()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
var res = await client.InvokeAsync(nameof(ServicesHub.ServiceWithStringAttribute), (string)null).DefaultTimeout();
Assert.Equal(115L, res.Result);
}
}

[Fact]
public async Task HubMethodWithFromServicesAttributeBeforeRegularParameter()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
var res = await client.InvokeAsync(nameof(ServicesHub.ServiceAttributeBeforeParam), 42).DefaultTimeout();
Assert.Equal(43L, res.Result);
}
}

[Fact]
public async Task HubMethodWithFromServicesAttributeAndUploadStream()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
await client.BeginUploadStreamAsync("invocation", nameof(ServicesHub.UploadWithServiceAttribute), new[] { "id" }, new object[] { 5 }).DefaultTimeout();

await client.SendHubMessageAsync(new StreamItemMessage("id", 10)).DefaultTimeout();
await client.SendHubMessageAsync(new StreamItemMessage("id", 20)).DefaultTimeout();
await client.SendHubMessageAsync(CompletionMessage.Empty("id")).DefaultTimeout();

var response = Assert.IsType<CompletionMessage>(await client.ReadAsync().DefaultTimeout());
Assert.Equal(31L, response.Result);
}
}

[Theory]
[InlineData(true)]
[InlineData(false)]
public async Task HubMethodWithFromServicesAttributeRespectsDisableImplicitOption(bool disableImplicit)
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSignalR(options =>
{
options.EnableDetailedErrors = true;
options.DisableImplicitFromServicesParameters = disableImplicit;
});
provider.AddSingleton<Service1>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
// ServiceWithAttribute explicitly uses [FromServices] so it should work regardless of DisableImplicitFromServicesParameters
var res = await client.InvokeAsync(nameof(ServicesHub.ServiceWithAttribute)).DefaultTimeout();
Assert.True(Assert.IsType<bool>(res.Result));
}
}

[Fact]
public async Task HubMethodWithFromServicesAttributeOnOptionalParameter()
{
var serviceProvider = HubConnectionHandlerTestUtils.CreateServiceProvider(provider =>
{
provider.AddSingleton<Service1>();
});
var connectionHandler = serviceProvider.GetService<HubConnectionHandler<ServicesHub>>();

using (var client = new TestClient())
{
var connectionHandlerTask = await client.ConnectAsync(connectionHandler).DefaultTimeout();
// Call with value
var res = await client.InvokeAsync(nameof(ServicesHub.ServiceWithOptionalParam), 100).DefaultTimeout();
Assert.Equal(101L, res.Result);

// Call without value (using default)
res = await client.InvokeAsync(nameof(ServicesHub.ServiceWithOptionalParam)).DefaultTimeout();
Assert.Equal(43L, res.Result);
}
}

#pragma warning disable CA2252 // This API requires opting into preview features
private class TestReconnectFeature : IStatefulReconnectFeature
#pragma warning restore CA2252 // This API requires opting into preview features
Expand Down Expand Up @@ -5477,4 +5669,4 @@ public static async Task<IEnumerable<T>> ReadAllAsync<T>(this IAsyncEnumerable<T

return result;
}
}
}
Loading