Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
SignalR Hub methods now support injecting services from your Dependency Injection (DI) container. In rare cases, this can break apps that have a type in DI that is also accepted in Hub methods from SignalR client messages.
Version introduced
ASP.NET Core 7.0
Previous behavior
If you accepted a type in your Hub method that was also in your Dependency Injection container, the type would always be resolved from a message sent by the client.
Services.AddScoped<SomeCustomType>();
class MyHub : Hub
{
// type always comes from the client, never comes from DI
public Task Method(string text, SomeCustomType type) => Task.CompletedTask;
}
New behavior
Types in DI are checked at app startup using IServiceProviderIsService to determine if an argument in a Hub method comes from DI or from the client.
In the following example, which assumes you're using the default DI container, SomeCustomType
comes from the DI container instead of from the client. If the client tries to send SomeCustomType
, it gets an error:
Services.AddScoped<SomeCustomType>();
class MyHub : Hub
{
// comes from DI by default
public Task Method(string text, SomeCustomType type) => Task.CompletedTask;
}
Type of breaking change
This change affects source compatibility.
Reason for change
This change improves the user experience when using different services in different Hub methods. It also improves performance by not requiring the user to inject all dependencies in the Hub's constructor.
The likelihood of breaking apps is low as it isn't common to have a type in DI and as an argument in your Hub method at the same time.
Recommended action
If you're broken by this change, you can disable the feature by setting DisableImplicitFromServicesParameters
to true:
Services.AddSignalR(options =>
{
options.DisableImplicitFromServicesParameters = true;
});
If you're broken by the change, but you want to use the feature without breaking clients, you can disable the feature as shown above and use an attribute that implements IFromServiceMetadata on new arguments/Hub methods:
Services.AddScoped<SomeCustomType>();
Services.AddScoped<SomeCustomType2>();
class MyHub : Hub
{
// old method with new feature (non-breaking), only SomeCustomType2 is resolved from DI
public Task MethodA(string arguments, SomeCustomType type, [FromServices] SomeCustomType2 type2);
// new method
public Task MethodB(string arguments, [FromServices] SomeCustomType type);
}
Affected APIs
Hub methods