I've created a WSS chat app using the sample that comes with the AWS dotnet lambda templates. My web front end can connect ok and it creates a record in dynamo but when I try to broadcast a message to all connections I get the following error:
`Name or service not known (execute-api.ap-southeast-2.amazonaws.com:443) `
I'm using the following code to set it:
var protocol = "https";
//var protocol = "wss";
var domainName = request.RequestContext.DomainName;
//var domainName = "ID HERE.execute-api.ap-southeast-2.amazonaws.com";
var stage = request.RequestContext.Stage;
// var stage = "";
//var stage = "test";
//var stage = "test/@connections";
var endpoint = $"{protocol}://{domainName}/{stage}";
and it logs the following:
API Gateway management endpoint: https://ID HERE.execute-api.ap-southeast-2.amazonaws.com/test
Ive tried all the combinations and a custom domain.
Im thinking that ap-southeast-2 does not support wss ? Or ... ??
Been stuck on this for a while now. About ready to give up. Anyone got any ideas??
Update: Heres the code for sending the message - it just an updated version of the sample. From the startup:
public Functions()
{
DDBClient = new AmazonDynamoDBClient();
// Grab the name of the DynamoDB from the environment variable setup in the CloudFormation template serverless.template
if (Environment.GetEnvironmentVariable(TABLE_NAME_ENV) == null)
{
throw new ArgumentException($"Missing required environment variable {TABLE_NAME_ENV}");
}
ConnectionMappingTable = Environment.GetEnvironmentVariable(TABLE_NAME_ENV) ?? "";
this.ApiGatewayManagementApiClientFactory = (Func<string, AmazonApiGatewayManagementApiClient>)((endpoint) =>
{
return new AmazonApiGatewayManagementApiClient(new AmazonApiGatewayManagementApiConfig
{
ServiceURL = endpoint,
RegionEndpoint = RegionEndpoint.APSoutheast2, // without this I get Credential errors
LogResponse = true, // dont see anything extra with these
LogMetrics = true,
DisableLogging = false
});
});
}
And the SendMessageFunction:
try
{
// Construct the API Gateway endpoint that incoming message will be broadcasted to.
var protocol = "https";
//var protocol = "wss";
var domainName = request.RequestContext.DomainName;
//var domainName = "?????.execute-api.ap-southeast-2.amazonaws.com";
var stage = request.RequestContext.Stage;
// var stage = "";
//var stage = "test";
//var stage = "test/@connections";
var endpoint = $"{protocol}://{domainName}/{stage}";
context.Logger.LogInformation($"API Gateway management endpoint: {endpoint}");
JObject message = JObject.Parse(request.Body);
context.Logger.LogInformation(request.Body);
if (!GetRecipient(message, context, out WSMessageRecipient? recipient))
{
context.Logger.LogError($"Invalid or empty WSMessageRecipient");
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.BadRequest, Body = "Nothing to do or invalid request"
};
}
if (!GetData(message, context, out string? data))
{
context.Logger.LogError($"Invalid or empty WSSendMessage");
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.BadRequest, Body = "Nothing to do or invalid request"
};
}
var stream = new MemoryStream(UTF8Encoding.UTF8.GetBytes(data!));
if (stream.Length == 0)
{
context.Logger.LogError($"Empty Stream");
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.BadRequest, Body = "Empty data stream"
};
}
// List all of the current connections. In a more advanced use case the table could be used to grab a group of connection ids for a chat group.
ScanResponse scanResponse = await GetConnectionItems(recipient);
// Construct the IAmazonApiGatewayManagementApi which will be used to send the message to.
var apiClient = ApiGatewayManagementApiClientFactory(endpoint);
context.Logger.LogInformation($"Table scan of {ConnectionMappingTable} got {scanResponse.Items.Count} records.");
// Loop through all of the connections and broadcast the message out to the connections.
var count = 0;
foreach (var item in scanResponse.Items)
{
var connectionId = item[ConnectionIdField].S;
context.Logger.LogInformation($"Posting to connection {count}: {connectionId}");
var postConnectionRequest = new PostToConnectionRequest
{
ConnectionId = connectionId, Data = stream
};
try
{
stream.Position = 0;
await apiClient.PostToConnectionAsync(postConnectionRequest);
context.Logger.LogInformation($"Posted to connection {count}: {connectionId}");
count++;
}
catch (AmazonServiceException e)
{
// API Gateway returns a status of 410 GONE then the connection is no
// longer available. If this happens, delete the identifier
// from our DynamoDB table.
if (e.StatusCode == HttpStatusCode.Gone)
{
context.Logger.LogInformation($"Deleting gone connection: {connectionId}");
var ddbDeleteRequest = new DeleteItemRequest
{
TableName = ConnectionMappingTable,
Key = new Dictionary<string, AttributeValue>
{
{ConnectionIdField, new AttributeValue {S = connectionId}}
}
};
await DDBClient.DeleteItemAsync(ddbDeleteRequest);
}
else
{
context.Logger.LogError(
$"Error posting message to {connectionId}: {e.Message}");
context.Logger.LogInformation(e.StackTrace);
}
}
catch (Exception ex)
{
context.Logger.LogError($"Bugger, something fecked up: {ex.Message}");
context.Logger.LogInformation(ex.StackTrace);
}
}
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.OK, Body = "Data sent to " + count + " connection" + (count == 1 ? "" : "s")
};
}
catch (Exception e)
{
context.Logger.LogInformation("Error Sending Message: " + e.Message);
context.Logger.LogInformation(e.StackTrace);
return new APIGatewayProxyResponse
{
StatusCode = (int)HttpStatusCode.InternalServerError, Body = $"Failed to send message: {e.Message}"
};
}
I'll try that again but pretty sure I did already. If I use a custom domain then I dont need /stage/ ??
Confirmed, that doesnt work either.
How does your sending code looks like?
Updated. Thanks for helping!!!