SignalR negotiate succesfully but fail at start request - c#

I am developing a chat application for our internal application using SignalR in a javascript angularJS client with a (self hosted for the moment) webAPI. This is in a cross domain connection.
using SignalR 2.2.1
using Owin 3.0.1
using Angular 1.5.7 if that's relevant
My problem is whenever I try to establish a connexion with my hub,
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Auto detected cross domain url.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Client subscribed to hub 'chathub'.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Negotiating with 'https: localhost:44361/signalr/negotiateclientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D'.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: webSockets transport starting.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Connecting to websocket endpoint 'wss: localhost:44361/signalr/connect?transport=webSockets&clientProtocol=1…kAIY9w9Q%3D%3D&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&tid=4'.jquery.signalR.js:82
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: Websocket opened.
the start request fails
[08:26:38 GMT-0400 (Est (heure d’été))] SignalR: webSockets transport connected. Initiating start request.
Failed to load resource: the server responded with a status of 500 ()
XMLHttpRequest cannot load https: localhost:44361/signalr/start?transport=webSockets&clientProtocol=1…D%3D&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=1471436795468. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'https: localhost:3000' is therefore not allowed access. The response had HTTP status code 500.
I've tried to pin point this problem for a couple of days now and what've noticed is that in the start request call, the response is missing the 'Access-Control-Allow-Origin' header. What bugs me most is that the negotiate request and the abort request both contains the header
Negotiate Request
Request URL:https: localhost:44361/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=14714 39245326
Request Method:GET
Status Code:200 OK
Remote Address:[::1]:44361
Response Headers
Access-Control-Allow-Credentials:true
Access-Control-Allow-Origin:https: localhost:3000
Cache-Control:no-cache
Content-Type:application/json; charset=UTF-8
Date:Wed, 17 Aug 2016 13:07:29 GMT
Expires:-1
Pragma:no-cache
Server:Microsoft-IIS/10.0
Transfer-Encoding:chunked
X-AspNet-Version:4.0.30319
X-Content-Type-Options:nosniff
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcVXNlcnNccmFwaGFlbC5tb3JpblxTb3VyY2VcUmVwb3NcVGVhbXdvcmtTb2x1dGlvblxUZWFtd29yay5BcGlcc2lnbmFsclxuZWdvdGlhdGU=?=
but not my start request
Start Request
Request URL:https: localhost:44361/signalr/start?transport=webSockets&clientProtocol=1.5&connectionToken=tR9V6HAxpgmW7r5Ro%2BzJzhUoJdMUcmv7eDv1ZDM%2Fq6yur21LXCZ2Dg1rrNrDGc5VBXQzfanyisyZKOcWNP7SKOl3TsTkBl3luS4I2UnYtdw8biviZ5NtcE1caoXPi3lVHaHs%2FjQnicwGVDlmJdvRzA%3D%3D&connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&_=1471439245327
Request Method:GET
Status Code:500 Internal Server Error
Remote Address:[::1]:44361
Response Headers
Cache-Control:private
Content-Type:text/html; charset=utf-8
Date:Wed, 17 Aug 2016 13:08:05 GMT
Server:Microsoft-IIS/10.0
Transfer-Encoding:chunked
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
X-SourceFiles:=?UTF-8?B?QzpcVXNlcnNccmFwaGFlbC5tb3JpblxTb3VyY2VcUmVwb3NcVGVhbXdvcmtTb2x1dGlvblxUZWFtd29yay5BcGlcc2lnbmFsclxzdGFydA==?=
Here is my Startup class
[assembly: OwinStartup(typeof(Teamwork.Api.Startup))]
namespace Teamwork.Api
{
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration {
EnableJavaScriptProxies = false,
EnableDetailedErrors = true};
map.RunSignalR(hubConfiguration);
});
}
}
}
My hub
namespace Teamwork.Api.Hubs
{
public class ChatHub : Hub
{
public void TransferMessage(string receiver, string message)
{
var name = this.Context.User.Identity.Name;
var context = GlobalHost.ConnectionManager.GetHubContext<ChatHub>();
context.Clients.Group(name).AddMessage(name, message);
context.Clients.Group(receiver).AddMessage(receiver, message);
}
public override Task OnDisconnected(bool stopCalled)
{
var name = this.Context.User.Identity.Name;
Clients.All.changeStatus(name, 4);
return base.OnDisconnected(stopCalled);
}
public override Task OnConnected()
{
var name = this.Context.User.Identity.Name;
Clients.All.changeStatus(name, 0);
return Groups.Add(name, name);
}
}
}
I access it using an angularJS service provider that didn't have any problem with until i tried to subscribe to my hub
Service Provider
class ChatServiceProvider implements IChatServiceProvider {
baseUrl: string;
chatHub: HubProxy;
public setBaseUrl(url: string) {
this.baseUrl = url;
}
public $get(
$rootScope: fuse.interfaces.IRootScope
): IChatService {
var self = this;
var connection = $.hubConnection(self.baseUrl);
var chatHub = connection.createHubProxy("chatHub");
function initialize(): JQueryPromise<any> {
connection.logging = true;
return connection.start();
};
return {
chatHub: undefined,
initialize: () => {
return initialize()
},
on: function (eventName, callback) {
chatHub.on(eventName, function (result: any) {
$rootScope.$apply(function () {
if (callback) {
callback(result);
}
});
});
}
}
}
Controller
self.chatService.on("addMessage", function (name: string, message: string) {
this.addMessage(name, message);
})
this.$scope.reply = function (id: string, message: string) {
this.chatService.chatHub.invoke("transferMessage", id, message);
}
this.chatService.initialize()
.done(function (data: HubProxy) {
self.chatService.chatHub = data;
console.log("Connected");
})
.fail(function () { console.log("Failed") });
I tried to add this code to my Global.asax file without any success:
Context.Response.AppendHeader("Access-Control-Allow-Credentials", "true");
var referrer = Request.UrlReferrer;
if (Context.Request.Path.Contains("/signalr") && referrer != null){
Context.Response.AppendHeader("Access-Control-Allow-Origin", referrer.Scheme + ": " + referrer.Authority);
}
I've been looking for 4 days now for a similar issue and i can find none. As i am not proficient with webAPI and HtmlRequest, i may have miss something obvious. If not then any tips/ideas/answers would be greatly appreciated. If anything is missing, tell me and I'll add it as soon as possible.

Thanks to Holly which had a similar problem but I was too dumb to search correctly

Related

Issue with configuring and Sending RPC queries using KubeMQ

I'm working on a learning project in which I developed 2 APIs Buyer and Seller and containerized it using Docker. To setup communication between these 2 APIs, I wanted to use KubeMQ RPC. I referred their cookbook and wrote a simple SendRequestAsync and SubscribeRequest.
public async Task<Response> SendRequest()
{
Channel = new Channel(new ChannelParameters
{
RequestsType = RequestType.Query,
Timeout = 10000,
ChannelName = "SampleChannel",
ClientID = "MyAPI",
KubeMQAddress = "localhost:50000"
});
var result = await Channel.SendRequestAsync(new KubeMQ.SDK.csharp.CommandQuery.Request
{
Metadata = "MyMetadata",
Body = Converter.ToByteArray("A Simple Request from Buyer.")
});
//Async
if (result.Executed)
return result;
return null;
}
private void SubscribeToChannel()
{
SubscribeRequest subscribeRequest = new SubscribeRequest(SubscribeType.Queries, "MyAPI", "SampleChannel", EventsStoreType.Undefined, 0);
_responder.SubscribeToRequests(subscribeRequest, HandleIncomingRequests, HandleIncomingError);
}
private Response HandleIncomingRequests(RequestReceive request)
{
// Convert the request Body to a string
string strBody = Converter.FromByteArray(request.Body).ToString();
_logger.LogDebug($"Respond to Request. ID:'{request.RequestID}', Channel:'{request.Channel}', Body:'{strBody}'");
// Create the Response object
Response response = new Response(request)
{
Body = Converter.ToByteArray("OK"),
Error = "None",
ClientID = this.ClientID,
Executed = true,
Metadata = "OK",
};
return response;
}
private void HandleIncomingError(Exception ex)
{
_logger.LogWarning($"Received Exception :{ex}");
}
My docker.yaml reads as below
services:
kubemq:
image: kubemq/kubemq:latest
container_name: kubemq
ports:
- "8080:8080"
- "9090:9090"
- "50000:50000"
environment:
- KUBEMQ_HOST=kubemq
- KUBEMQ_TOKEN=<<MyToken>>
networks:
- backend
volumes:
- kubemq_vol:/store
networks:
backend:
volumes:
kubemq_vol:
I am simply trying to send a message and get a response. But I'm getting the below error:
Grpc.Core.RpcException: Status(StatusCode="Unavailable", Detail="failed to connect to all addresses", DebugException="Grpc.Core.Internal.CoreErrorDetailException: {"created":"#1654251803.063997885","description":"Failed to pick subchannel","file":"/var/local/git/grpc/src/core/ext/filters/client_channel/client_channel.cc","file_line":5420,"referenced_errors":[{"created":"#1654251803.063991635","description":"failed to connect to all addresses","file":"/var/local/git/grpc/src/core/ext/filters/client_channel/lb_policy/pick_first/pick_first.cc","file_line":398,"grpc_status":14}]}")
at Grpc.Core.Internal.AsyncCall`2.UnaryCall(TRequest msg)
at Grpc.Core.Calls.BlockingUnaryCall[TRequest,TResponse](CallInvocationDetails`2 call, TRequest req)
at Grpc.Core.DefaultCallInvoker.BlockingUnaryCall[TRequest,TResponse](Method`2 method, String host, CallOptions options, TRequest request)
at Grpc.Core.Interceptors.InterceptingCallInvoker.<BlockingUnaryCall>b__3_0[TRequest,TResponse](TRequest req, ClientInterceptorContext`2 ctx)
at Grpc.Core.ClientBase.ClientBaseConfiguration.ClientBaseConfigurationInterceptor.BlockingUnaryCall[TRequest,TResponse](TRequest request, ClientInterceptorContext`2 context, BlockingUnaryCallContinuation`2 continuation)
I'm new to docker, KubeMQ and Microservices. So I'm maybe doing something wrong here. Any inputs is appreciated.
I didn't find a lot of articles/questions on KubeMQ when compared to Kafka or RabbitMQ. I have to continue using KubeMQ since I can't change the requirement now.

How to use webSocketOptions.AllowedOrigins?

I have an ASP web app.
The app opens a websocket communication server. The websocket server works properly.
var webSocketOptions = new WebSocketOptions()
{
KeepAliveInterval = TimeSpan.FromSeconds(120),
};
app.UseWebSockets(webSocketOptions);
app.Use(async (context, next) =>
{
if (context.Request.Path == "/ws")
{
if (context.WebSockets.IsWebSocketRequest)
{
using (WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync())
{
//do some stuff
}
}
else
{
context.Response.StatusCode = 400;
}
}
else
{
await next();
}
});
When I open my domain example.com and go to Chrome Web Console, the following code works :
var socket = new WebSocket("wss://www.example.com/ws");
However when I add the security constraint :
webSocketOptions.AllowedOrigins.Add("https://www.example.com");
The websocket connection doesn't work anymore. I'm getting the error
VM376:1 WebSocket connection to 'wss://www.example.com/ws' failed: Error during WebSocket handshake: Unexpected response code: 403
Can anyone help please on how to use webSocketOptions.AllowedOrigins ?
I want the Websocket access be allowed only when a request is made from my website www.example.com
Thanks
You have to configure "webSocketOptions.AllowedOrigins" inside your startup middleWare
here a microsoft websocket doc:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/websockets?view=aspnetcore-3.1

How to fix "err connection refused" in angular

I am building an web application with webApi and angular 7 .
The webApi part works because when I run dotnet watch run it brings my data from the database in the browser but when I connect it with angular I get err connection refused.
I checked the url. It is correct
This is my service.ts :
const httpOptions = {
headers: new HttpHeaders({ 'Content-Type': 'application/json' })
};
const apiUrl = 'http://localhost:5000/api';
#Injectable({
providedIn: 'root'
})
export class ApiService {
constructor(private http: HttpClient) { }
private handleError<T>(operation = 'operation', result?: T) {
return (error: any): Observable<T> => {
// TODO: send the error to remote logging infrastructure
console.error("emptyyyyyy"); // log to console instead
// Let the app keep running by returning an empty result.
return of(result as T);
};
}
getEmployees(): Observable<Employee[]> {
return this.http.get<Employee[]>(apiUrl)
.pipe(
catchError(this.handleError('getSuppliers', []))
);
}
}
In the console it sayss : emptyyy and err connection refused

Signal R Server Client "Access-Control-Allow-Origin" missing error

I'm trying out the Signal R and built a server dll (windows service library/c#) that runs as a Windows Services. I have build also a client application (asp.net web application) to communicate with the server.
But i'm getting always the error(Firefox) "Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:8080/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%5D&_=1482829095207. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing)."
Chrome error "
Failed to load resource: the server responded with a status of 400 (Bad Request)"
XMLHttpRequest cannot load http://localhost:8080/signalr/negotiate?clientProtocol=1.5&connectionData=%5B%5D&_=1482830200155. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:50259' is therefore not allowed access. The response had HTTP status code 400.
Note: Edge and also IE gives me errors
I have read almost every post about this subject on Stackoverflow, but non of these solutions seems to work.
The code i'm using for the server side:
namespace SignalRService
{
public class StartupConfiguration
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
EnableDetailedErrors = true,
EnableJSONP = true,
};
map.RunSignalR(hubConfiguration);
});
}
}
}
Services.cs
public void StartService()
{
LogMessage("SignalRService started", true);
Running = true;
WebApp.Start<StartupConfiguration>(ConfigurationManager.AppSettings["SignalRServerUrl"]);
}
EnvironmentSettings.config:
<add key="SignalRServerUrl" value="http://localhost:8080"/>
Hubs.cs
namespace SignalRService.Hubs
{
[HubName("TestHub")]
public class TestHub: Hub
{
public static Dictionary<string, List<HubClient>> clients = new Dictionary<string, List<HubClient>>();
[HubMethodName("Subscribe")]
public async Task Subscribe(string Id)
{...... }}
ClientSide (Javascript/Jquery)
var signalrHubConnection;
var signalrHubConnectionProxy;
var signalRServerUrl = "http://localhost:8080";
var currentTimeout;
var count = 0;
var startSignalRConnection = function () {
console.log("Start");
signalrHubConnection = $.hubConnection(signalRServerUrl);
console.log("Running");
signalrHubConnection.logging = true;
signalrHubConnectionProxy = signalrHubConnection.createHubProxy('TestHub');
console.log("--Subscribe starting");
signalrHubConnection.start()
.done(function () {
signalrHubConnectionProxy.invoke('Subscribe', Id.toString());
console.log("Subscribe ending");
})
.fail(function (test) {
if (count < 5) {
console.log(test.toString());
clearTimeout(currentTimeout);
currentTimeout = setTimeout(function () {
count++;
startSignalRConnection();
}, 300000); // retry after 5 minutes
}
}
);
signalrHubConnectionProxy.on('IncomingMessage',
function (message) {
console.log("Message = " + message.toString());
}
);
};
Test.aspx
<script src="https://code.jquery.com/jquery-3.1.1.min.js" type="text/javascript"></script>
<script src="http://ajax.aspnetcdn.com/ajax/signalr/jquery.signalr-2.2.1.min.js"></script>
Did I something wrong?
The error implied that the SignalR url is different from the requesting url (origin). So, SignalR is on localhost, but your main website (the site that holds the client side example) obviously is accessed using "localhost".
Maybe you're accessing it using an IP (eg http://127.0.0.1/) or your PC name (eg http://badassPC/), whereas they must match under the default SignalR setting. I am pretty certain it doesn't matter if the port is different, and also doesn't matter if they are on the same domain (eg www.mysite.com and signalr.mysite.com)
Note there is a workaround that I wouldn't recommend unless you really really know what you're doing as there is a quite serious security risk otherwise: https://www.asp.net/signalr/overview/guide-to-the-api/hubs-api-guide-javascript-client#crossdomain

SignalR not working since migrating to server

I built a webservice that processes notification requests and a website that receives the push notifications using SignalR. This all worked fine when running both the webservice and Website on my box using Visual Studio and whatever webserver VS uses to run projects.
However since moving to a test server which runs IIS 7, the signalR no longer works. Both the webservice and website are on the same server, website on port 8088 and webservice on port 8089.
This is the error I get
10-12-2015 14:56:26,864 [UK\!kerslaj1][35] ERROR Centrica.CE.SEFlex.Common.Logging.ConsoleLogger - There was an error opening the connection 'http://localhost:8088/'
Microsoft.AspNet.SignalR.Client.HttpClientException: StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
Connection: close
Date: Thu, 10 Dec 2015 14:56:26 GMT
Server: Microsoft-HTTPAPI/2.0
Content-Length: 334
Content-Type: text/html; charset=us-ascii
}
at Microsoft.AspNet.SignalR.Client.Http.DefaultHttpClient.<>c__DisplayClass2.<Get>b__1(HttpResponseMessage responseMessage)
at Microsoft.AspNet.SignalR.TaskAsyncHelper.TaskRunners`2.<>c__DisplayClass42.<RunTask>b__41(Task`1 t)
10-12-2015 14:56:26,866 [UK\!kerslaj1][41] DEBUG Centrica.CE.SEFlex.Common.Logging.ConsoleLogger - Connection started
10-12-2015 14:56:26,866 [UK\!kerslaj1][41] DEBUG Centrica.CE.SEFlex.Common.Logging.ConsoleLogger - User: kerslaj1
10-12-2015 14:56:26,866 [UK\!kerslaj1][41] DEBUG Centrica.CE.SEFlex.Common.Logging.ConsoleLogger - Added username: UK\!kerslaj1
10-12-2015 14:56:26,867 [UK\!kerslaj1][41] ERROR Centrica.CE.SEFlex.Common.Logging.ConsoleLogger - There was an error notifying using the connection http://localhost:8088/
System.InvalidOperationException: Data cannot be sent because the connection is in the disconnected state. Call start before sending any data.
at Microsoft.AspNet.SignalR.Client.Connection.Send(String data)
at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke[TResult,TProgress](String method, Action`1 onProgress, Object[] args)
at Microsoft.AspNet.SignalR.Client.Hubs.HubProxy.Invoke[T](String method, Object[] args)
at Centrica.CE.SEFlex.Common.Notification.SignalRHandler.Notify(EventNotification notification, IEnumerable`1 subscribers, String hubConnection) in c:\Development\TFS\Atlas\SE\DEV\SEFLEX\Build\Common\Centrica.CE.SEFlex.Common\Notification\SignalRHandler.cs:line 66
10-12-2015 14:56:26,868 [UK\!kerslaj1][41] DEBUG SEFlex - Subscriber notified
On my website the SignalR is configured as so
public class OwinStartup
{
public void Configuration(IAppBuilder app)
{
var container = new UnityContainer();
container.RegisterType<NotificationHub, NotificationHub>(new ContainerControlledLifetimeManager());
GlobalHost.DependencyResolver.Register(typeof(IHubActivator), () => new UnityHubActivator(container));
var idProvider = new PrincipalUserIdProvider();
GlobalHost.DependencyResolver.Register(typeof(IUserIdProvider), () => idProvider);
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
And my layout html page
#Scripts.Render("~/bundles/signalr")
<script src="/signalr/hubs"></script>
<script>
var notifyProxy = $.connection.notification, // the generated client-side hub proxy
$notificationTable = $('#NotificationTable'),
$notificationTableBody = $notificationTable.find('tbody'),
rowTemplate = '<tr data-symbol="{EventNotificationId}"><td style="text-align:left;width:115px;vertical-align:text-top;"><nobr>{EventDate} : </nobr></td><td><span class="{Class}"><small class="text-uppercase">{ClassLabel}</small></span></td><td style="text-align:left;">{Description}</td></tr>';
function formatNotification(notification) {
return $.extend(notification, {
EventDate: notification.EventTime.substr(0, 10).concat(' ').concat(notification.EventTime.substr(11, 8)),
Description: notification.FriendlyText,
Class: notification.Class
});
}
function init() {
notifyProxy.server.getCurrentNotifications().done(function (notifications) {
$notificationTableBody.empty();
$.each(notifications, function () {
var notification = formatNotification(this);
$notificationTableBody.prepend(rowTemplate.supplant(notification));
});
});
}
// Add a client-side hub method that the server will call
notifyProxy.client.addNotification = function (notification) {
$notificationTableBody.prepend(rowTemplate.supplant(formatNotification(notification)));
};
// Start the connection
$.connection.hub.start().done(init);
</script>
This is a bit of a stab in the dark, but could it be that it expects SignalR to be listening by default on port 80, and you're running your site on port 8088. Or that SignalR is still listening on port 80 and your site is on 8088?
Maybe setting the connection URL might do the trick?
$.connection.hub.url = "http://[HOST URL HERE]:8080/signalr";

Categories