What version of .NET does your existing project use?
.NET 6
What version of .NET are you attempting to target?
.NET 8
Description
Hi,
I wanted to bring up an issue with the SignalRTrigger solution. My team and I are using this approach in .NET6 for our project to trigger some asynchronous operations. In response, we are returning a custom object indicating whether the operation was successful. However, in .NET8, our SignalRTrigger functions consistently return a null result in the server response, regardless of our efforts to fix it. It is worth mentioning that during the .NET8 upgrade, we are migrating our functions to isolated mode.
Here is our server-side code in .NET6:
[SignalRHub(path: "")]
public partial class MainHub : ServerlessHub<IMainHub>
{
...
[FunctionName(nameof(Echo))]
public async Task<SignalRHubActionRequest> Echo([SignalRTrigger()] InvocationContext invocationContext, string name, string message)
{
await Clients.Client(invocationContext.ConnectionId).Echo(name, message);
return new SignalRHubActionRequest { SignalRHubActionStatus = SignalRHubActionStatus.Accepted };
}
...
}
public class SignalRHubActionRequest
{
public string Id { get; set; }
public Status Status { get; set; }
}
public enum Status
{
Success,
Failure
}
The only change in .NET8 solution for this code snippet is the Echo function (in the SignalRTrigger attribute):
[Function(nameof(Echo))]
public async Task<SignalRHubActionRequest> Echo([SignalRTrigger(nameof(MainHub), CATEGORY, nameof(Echo), "name", "message")] SignalRInvocationContext invocationContext, string name, string message)
{
await Clients.Client(invocationContext.ConnectionId).Echo(name, $"async : {message}");
return new SignalRHubActionRequest { SignalRHubActionStatus = SignalRHubActionStatus.Accepted };
}
This is how we registered SignalR in .NET6:
builder.Services.Configure<SignalROptions>(o => {
var settings = new JsonSerializerSettings()
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
settings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
o.JsonObjectSerializer = new NewtonsoftJsonObjectSerializer(settings);
});
This is our registration in .NET8:
services.AddSignalR()
.AddNewtonsoftJsonProtocol(options =>
{
options.PayloadSerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
options.PayloadSerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
});
services.AddSignalR()
.AddNewtonsoftJsonProtocol(options =>
{
options.PayloadSerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
options.PayloadSerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
});
And this is our C# SignalR client code:
await using var connection = new HubConnectionBuilder()
.WithAutomaticReconnect()
.WithUrl(uriTime, options =>
{
options.AccessTokenProvider = () => Task.FromResult(accessToken);
})
.AddNewtonsoftJsonProtocol(options =>
{
options.PayloadSerializerSettings = new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
options.PayloadSerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
});
await connection.StartAsync();
var result01 = await connection.InvokeAsync<SignalRHubActionRequest>("Echo", name, message);
We inspected the request and observed that the server side is returning null in the result property, regardless of what we attempt to send (e.g., a string instead of SignalRHubActionRequest or changing serializer to default or json one). We confirmed this by using tools like NGROK and Fiddler:
https://i.sstatic.net/v8Wfm4Ao.png
https://i.sstatic.net/IblboCWk.png
This resulted in a server-side error. When we changed the return type to string while using this SignalROutput attribute, we encountered a different error.
https://i.sstatic.net/2vYdrjM6.png
Ultimately, we downloaded the latest codebase from your repository and used your samples, specifically the Extensions solution, and experienced the same null result issue.
This indicates that the problem lies within your library. We are unsure of the cause of these varying errors, but based on these examples, it appears you can return error objects. This implies you should be able to return an object in the result property as well. We initially thought this functionality was removed, but the errors suggest otherwise. Additionally, your documentation does not indicate that the feature to return objects from a SignalRTrigger function was removed. Therefore, we are requesting your assistance and investigation into this issue.
Thanks
Project configuration and dependencies
Azure function app
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<AzureFunctionsVersion>v4</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
<_FunctionsSkipCleanOutput>true</_FunctionsSkipCleanOutput>
<GenerateDocumentationFile>True</GenerateDocumentationFile>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.7" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.22.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.DurableTask" Version="1.1.4" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.2.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore" Version="1.3.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http.AspNetCore.Analyzers" Version="1.0.2" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Rpc" Version="1.0.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.ServiceBus" Version="5.20.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.SignalRService" Version="1.14.0" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Timer" Version="4.3.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.4" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk.Analyzers" Version="1.2.1" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk.Generators" Version="1.3.2" />
<PackageReference Include="SignalRSwaggerGen" Version="4.7.0" />
</ItemGroup>
<ItemGroup>
<Using Include="System.Threading.ExecutionContext" Alias="ExcutionContext" />
</ItemGroup>
</Project>
Client app:
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="8.0.7" />
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="8.0.7" />
</ItemGroup>
</Project>
Link to a repository that reproduces the issue
https://github.com/Azure/azure-functions-dotnet-worker/tree/main/samples/Extensions/SignalR
viki83 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.