Search code examples
c#azureazure-functionsnegotiateazure-signalr

Azure Function SignalR | negotiate function | Fails with 500 error code


I have installed Microsoft.Azure.WebJobs.Extensions.SignalRService using extensions.csproj.

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>netstandard2.0</TargetFramework>
    <WarningsAsErrors />
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.CosmosDB" Version="3.0.1" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Script.ExtensionsMetadataGenerator" Version="1.0.*" />
    <PackageReference Include="Microsoft.Azure.WebJobs.Extensions.SignalRService" Version="1.0.0" />
  </ItemGroup>
</Project>

I was able to post messages thru Azure SignalR Service using following Azure Function. Function is triggered when there is any AddOrUpdate() operations at CosmosDB Collections and it send signals by the name 'fruitUpdated' in a hub.

#r "Microsoft.Azure.DocumentDB.Core"
#r "Microsoft.Azure.WebJobs.Extensions.SignalRService"
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Azure.Documents;
using Microsoft.Azure.WebJobs.Extensions.SignalRService;

public static void Run(IReadOnlyList<Document> input, ILogger log, ICollector<SignalRMessage> signalRMessages)
{
    if (input != null && input.Count > 0)
    {
        log.LogInformation("Documents modified " + input.Count);
        foreach (var fruit in input)
        {
            signalRMessages.Add( 
                new SignalRMessage 
                {
                    Target = "fruitUpdated",
                    Arguments = new [] { fruit } 
                });
        }
    }
}

But negotiate function does not seem to work now. It throws 500 error code without any clue. Following are samples,

run.csx

#r "Newtonsoft.Json"

using System;
using System.Net;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Newtonsoft.Json;

public static IActionResult Run(HttpRequest req, ILogger log, object connectionInfo)
{
    return (ActionResult)new OkObjectResult(connectionInfo);
}

function.json

{
  "bindings": [
    {
      "authLevel": "anonymous",
      "name": "req",
      "type": "httpTrigger",
      "direction": "in",
      "methods": [
        "get",
        "post"
      ]
    },
    {
      "type": "signalRConnectionInfo",
      "name": "connectionInfo",
      "hubName": "flights",
      "direction": "in",
      "connectionStringSetting": "AzureSignalRConnectionString"
    }
  ]
}

I tried all combinations. Azure documentation is tiresome for some cases! No input\ output schema It is supposed to be frowned upon. Azure Product team should take it seriously

SignalR versions are not compatible to each other. They just dismiss messages passively without throwing error if we use different versions of SignalR dll in server & client.

I think I need the JSON Payload of connectionInfo object. Could you please assist me here?


Solution

  • I found an answer here at Serverless360. It turned out type issue and method-parameter decoration. After referring SignalService library and decorator, it started working. In my opinion, object being a base type, it is supposed to have received or been injected with the connectionInfo.

    #r "Newtonsoft.Json"
    #r "Microsoft.Azure.WebJobs.Extensions.SignalRService"
    
    using System;
    using System.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Newtonsoft.Json;
    using Microsoft.Azure.WebJobs.Extensions.SignalRService;
    
    public static IActionResult Run(HttpRequest req, ILogger log, [SignalRConnectionInfo(HubName = "flights")]SignalRConnectionInfo connectionInfo)
    {
        return (ActionResult)new OkObjectResult(connectionInfo);
    }
    

    Now, negotiate function is working as expected. Hope it helps to people with similar problems!

    Sample output payload for negotiate function

    {"url":"https://myazuresignalrservice.service.signalr.net/client/?hub=myhubname","accessToken":"mybeareraccesstoken"}
    

    UPDATE

    Issue was with, not using, *[SignalRConnectionInfo(HubName = "fruits")]SignalRConnectionInfo* in the method signature.

    public static IActionResult Run(HttpRequest req, ILogger log, [SignalRConnectionInfo(HubName = "fruits")]SignalRConnectionInfo connectionInfo) { }
    

    Expected payload was also posted for your reference. If you have any questions, let me know in comments.