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";
Related
have followed the steps mentioned in the Push code lab Push Notifications site to integrated Push notification in my dot net ``site
1.register Service worker and also was able to see the Subscription on the page.
Subscription:
Step: have down Loaded the C# Library to send the Push Notifications and have added Test Program to test this C#code. i am able to run the code and no Error were shown but i am not seeing any Push Notification in the Chrome Browser( Kept the same Browser tab opened where i have my Site Running / Also closed the browser and Relaunched to see any Notification).In Either case i am not seeing any Notifications
I am not seeing any Error from the Code an
below is the Response from Web pushClient.
{StatusCode: 201, ReasonPhrase: 'Created', Version: 1.1, Content: System.Net.Http.StreamContent, Headers: { X-Content-Type-Options: nosniff X-Frame-Options: SAMEORIGIN X-XSS-Protection: 1; mode=block Alt-Svc: quic=":443"; ma=2592000; v="39,38,37,36,35" Cache-Control: max-age=0, private Date: Wed, 05 Jul 2017 15:59:43 GMT Location: https://fcm.googleapis.com/fcm/0:1499270383802342%e609af1cf9fd7ecd Server: GSE Content-Length: 0 Content-Type: text/plain Expires: Wed, 05 Jul 2017 15:59:43 GMT }}
var pushEndpoint = #"https://fcm.googleapis.com/fcm/send/dKUDjOvvyjg:APA91bF3jr2gsX--KjonylSL_25TfCGG5mVsFZoYgnESYLep2rlWOI6KK1T9Dghr9E8o1e7a0wtOCH2LqmcCV0pjW7ZuDW7wPptJnnXy3XBu4Eo_CX0fLYGqsqy8voU9pFg6eZyaDFab";
var p256dh = #"BMEI2Zz1LPeFBeBtEZlTV_St0PHb6v_OlldbUoE6wrnnx8ychyz4o7tMt_S_Z0bKQj3vOAS0lMuZRRrgO7-LEGo=";
var auth = #"hwrfOP0UUevO5UdB6WRIQw==";
var subject = #"mailto:megan#gmail.com";
var publicKey = #"BK4ITwwSPZpxelX-oaycWnPuRSnRetbu3QBY4hSm5f1Up24PTrktIrJxRXR9bUIqrGx2YFcDCv48sDwFW50jdmI";
var privateKey = #"PEW_j759M2Q218O9le3GS8OnejmwlWYI1-LtNAP31bg";
var subscription = new PushSubscription(pushEndpoint, p256dh, auth);
var vapidDetails = new VapidDetails(subject, publicKey, privateKey);
//var gcmAPIKey = #"[your key here]";
var webPushClient = new WebPushClient();
try
{
webPushClient.SendNotification(subscription, "payload", vapidDetails);
//webPushClient.SendNotification(subscription, "payload", gcmAPIKey);
}
catch (WebPushException exception)
{
Console.WriteLine("Http STATUS code" + exception.StatusCode);
}
After looking at your service worker source, I think you need to move the showNotification call inside the event.waitUntil call. So something like this:
event.waitUntil(self.registration.showNotification(title, options));
However if you're getting notifications on your home network and not your work network, that leads me to believe something on your work network is blocking it.
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
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
I have a Single Page Application (SPA) with AngularJS as my front-end and .NET Web API as my backend. Everything works fine on my development machine, i.e. when I run it from Visual Studio (2015) under localhost. However, once published to our testing server, when sending POST requests to the Web API I get a "400 Bad Request" error. GET requests work fine. I am debugging it with Fiddler and when I look in the TextView tab it says "The underlying provider failed to Open". Here are some screenshots from Fiddler:
This is how the request and response look on my local machine:
This is the response headers on the the test server:
And the TextView on the test server:
The data being sent through the POST request is the same for both the localhost and the test server. Also, for both of them an authorization header is present. Other than the values for "Referer" and "Host", the only other difference I am noticing between them is that localhost is running on IIS/10.0 while the test server is on IIS/8.0.
The code for the AngularJS resource which calls the WebAPI is the following:
(function () {
"use strict";
angular
.module("mainApp")
.factory("incidentResource", ["$resource", "baseApiUrl", incidentResource]);
/// The factory function. The Angular $resource service and the appSettings
/// constant are injected as parameters.
function incidentResource($resource, baseApiUrl) {
return {
generateFile: $resource(baseApiUrl + "/api/Imports/PreviewOverlay", null,
{
'generate': { method: 'POST' }
})
};
}
})();
This is called from Angular code like so:
vm.generate = function () {
incidentResource.generateFile.generate(vm.divisionImports,
function (data) {
vm.successMessage.show = true;
},
function (response) {
vm.message = response.statusText + "\r\n";
if (response.data.exceptionMessage) {
vm.message += response.data.exceptionMessage;
}
});
}
And finally, my Web API controller looks like this:
[RoutePrefix("api/Imports")]
public class ImportController : BaseController
{
[Authorize]
[HttpPost]
[Route("PreviewOverlay")]
public IHttpActionResult GenerateFile(DivisionImport[] chargedIncidents)
{
try
{
// Get the name of the user currently logged in
string UserName = this.GetCurrentUserIdFromRequest();
List<DivisionImport> incidentsList = new List<DivisionImport>();
incidentsList.AddRange(chargedIncidents);
this.incidentFileBuilder.GenerateFile(FileType.Delimited, incidentsList);
return this.Ok();
}
catch (Exception ex)
{
return this.BadRequest(ex.Message);
}
}
}
[EnableCors(origins: "*", headers: "*", methods: "*")]
public class BaseController : ApiController
{
}
What could be causing this error?
As #Dan Jul pointed out, the error was caused by a faulty database connection string. While deploying my code to our test server, we changed the connection configuration file to a different one (for the test server) and it contained a connection string with a syntax error.
Things are working now.
I have a WebApi application with the following controllor:
public class ContentController : ApiController
{
[HttpPost]
public HttpResponseMessage Post(string contentType)
{
//do stuff
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
The route looks like this
routes.MapHttpRoute("content",
"api/content/{contentType}",
new { controller = "Content", contentType = RouteParameter.Optional });
When I host the service in IIS / cassini, if I POST to api/content/whatever then as expected, my controller action is hit.
However,
I've got a test project, that SelfHosts this api
using (var client = new HttpClient(Server))
{
var result = client.PostAsync(BaseAddress + "api/content/whatever"
var message = result.Content.ReadAsStringAsync().Result;
}
If I debug the unit test, and step into it, result is:
{StatusCode: 500, ReasonPhrase: 'Internal Server Error', Version: 1.1, Content: System.Net.Http.ObjectContent`1[[System.Web.Http.HttpError, System.Web.Http, Version=5.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35]], Headers:
{
Content-Type: application/json; charset=utf-8
}}
Unhelpfully, message is literally just
An error has occurred
Is there a way I can debug my self hosted WebApi to find out what is causing this error?
Set up
Server is just an HttpServer from a base class, that holds my self hosted server, new'd up like so:
var httpConfig = new HttpSelfHostConfiguration(BaseAddress);
new ApiServiceConfiguration(httpConfig).Configure();
var server = new HttpSelfHostServer(httpConfig);
server.OpenAsync().Wait();
Server = server;
If you enable tracing and add a Trace.Listeners.Add(new ConsoleTraceListener()) then you will get more detailed error messages. However, your problem is most likely related to the fact that the object that you are trying to serialize is failing to serialize.
Added to Startup
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
where config is of HttpConfiguration type.
This single line of code solved the same issue for me - now I can see all the inner exception's details.