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
Related
A signalr API (.NET 6) is hosted on IIS with "web garden" mode. Client frequently closes a connection with the following message: "System.Net.Http.HttpRequestException: Response status code does not indicate success: 404 (Not Found)."
When IIS config is changed not to use webgarden (max worker processes is set to 1) - error does not occur.
I have read that redis backplane would be a solution in such case (webgarden) but inlcuding it in my project did not help - the same error message occurs in same scenarios.
Here is my sample code from the Startup:
services.AddSignalR(options =>
{
options.EnableDetailedErrors = true;
})
.AddHubOptions<MyHub>(options =>
{
options.AddFilter<MyFilter>();
})
.AddNewtonsoftJsonProtocol()
.AddStackExchangeRedis(o =>
{
o.ConnectionFactory = async writer =>
{
var config = new ConfigurationOptions
{
AbortOnConnectFail = false
};
config.EndPoints.Add(IP_ADDR, PORT_NO);
config.DefaultDatabase = DEFAULT_DB;
var connection = await ConnectionMultiplexer.ConnectAsync(config, writer);
connection.ConnectionFailed += (_, e) =>
{
Console.WriteLine("Connection to Redis failed.");
};
if (!connection.IsConnected)
{
Console.WriteLine("Did not connect to Redis.");
}
else
{
Console.WriteLine("Connected to Redis.");
}
return connection;
};
});
Did I miss somethig in my code? Or maybe it is about IIS configuration?
Background/Problem: I am running an Angular app (with C#/.NET WebApi/DataAccess) and am getting the following errors when attempting to login (happens in DEV environment, not in REL):
Chrome Dev Tools Console errors:
POST http://localhost:1789/api/token 400 (Bad Request)
Backend
returned code 400, body was [object Object]
Error is only happening in DEV. Does not happen in REL or PROD. This was working in DEV previously.
What I've tried so far:
I am able to make calls to other classes and methods in the WebApi,
but not sure where this error came from.
I don't see any extra discernible information in "Network" tab of
Chrome Dev Tools (it just mentions the status code again)
I used the debugger in the Sources tab of Chrome dev tools and also
did not see any extra discernible information
There have not been any changes in the C# code that I can see from
source control. The Angular component and service are the same as
well.
I have tested other parts of the API as mentioned above
I have checked my config files multiple times and they seem to have
the appropriate values they used to have
I have looked up information about token authorization such as:
https://learn.microsoft.com/en-us/aspnet/aspnet/overview/owin-and-katana/owin-oauth-20-authorization-server
Spotify API bad request on api/token authorization Error: 400
(as well as all the other SO articles on 400 error for api token I
could find)
Debugged in Visual Studio: For OAuthAuthorizationServerOptions:
AccessTokenFormat is null. AuthorizeEndpointPath is {}. But
TokenEndpointPath is {/api/token}
Code:
login.component.ts:
cmdLogin_click()
{
if (this._authForm.value.username != null && this._authForm.value.password != "")
{
if (this._authForm.valid)
{
this.securityService.loginEndpoint(this._authForm.value.username,this._authForm.value.password)
.subscribe(response => {
this.setUser(response);
this.routerService.navigate(['/home']);
},
}
}
}
security.service.ts:
public loginEndpoint(email: string, password: string): Observable<any> {
let url = API_URL + '/api/token';
let ip = "";
const headers = new HttpHeaders().set('Content-Type', 'text/plain; charset=utf-8');
let content: string = "grant_type=password&username=" + email + "&password=" + password + "&ip=" + ip
return this.http.post(url, content, { headers: headers }).pipe(
catchError(this.handleError)
)
}
private handleError(error: HttpErrorResponse) {
if (error.error instanceof ErrorEvent) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', error.error.message);
} else {
// The backend returned an unsuccessful response code. // The response body may contain clues as to what went wrong,
console.error(
`Backend returned code ${error.status}, ` +
`body was: ${error.error}`);
}
// return an observable with a user-facing error message
return throwError(
'Something bad happened; please try again later.');
};
Startup.cs:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
}
}
Startup.Auth.cs:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Configure the application for OAuth based flow
PublicClientId = "self";
OAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromHours(25),
Provider = new EmdOAuthProvider(),
RefreshTokenProvider = new SimpleRefreshTokenProvider()
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
My expected result is to be able to login without the error. My actual result is the errors listed above.
Been stuck on this for hours. Where should I be focusing at this point?
I want to show custom message when my web application is failed to connect to internet.
Currently when my internet connectivity fails then the browser shows "unable to connect" or "server not found". so I want to show my custom message on my page.
I have written this :
bool bb = System.Net.NetworkInformation.NetworkInterface.GetIsNetworkAvailable();
if (bb == true)
{
//custom message
}
else
//meesage
But still it is not working.
How can I show that?
I think you are expecting internet connectivity from browser, if so use navigator.onLine;
<script type="text/javascript">
var isOnline = navigator.onLine;
if (!isOnline)
alert("Your custom message for no internet connectivity!!!");
</script>
Periodically call from client to server, and if there is no answer or not expecting answer - show error message.
for web forms:
create handler with implemetation of ProcessRequest like this:
public void ProcessRequest(HttpContext context)
{
context.Response.ContentType = "text/plain";
context.Response.Write("Ok");
}
for mvc:
create action with simple result like this:
public ActionResult CheckInternetConnection()
{
return Json("Ok");
}
of course, this request handlers should not require any authorization or another pretreatment
then create js timer and method for request
var maxTime = <your interval time>;
var timer;
//write own method for check request
function performRequest() {
var xhr = new XMLHttpRequest();
// reserve 1 sec for timeout function execution
// if we didn't - you can get a situation when
// simultaneously performing more than 1 request
xhr.timeout = maxTime - 1000;
xhr.ontimeout = function {
//waiting to long
alert('<your message>');
window.clearInterval(timer);
};
xhr.open('GET', '<url of your check connection handler>', true);
xhr.send();
xhr.onreadystatechange = function () {
if (xhr.readyState != 4)
return;
if (xhr.responseText !== 'OK') {
//Can't access to handler
alert('<your message>');
window.clearInterval(timer);
}
}
}
//after page load start request timer
document.onload += function () {
timer = window.setInterval(performRequest, maxTime);
}
I haven't debug this code.
I'm been doing some stress testing on nodejs express server and noticed that it includes a "Connection: Keep-Alive" header by default. My application will be a web api exposed to the client, so I don't need the connection to remain open after the client has posted it's data and received it's response.
Unfortunately due to client limitations this needs to be a synchronous operation. We already have a C# Web API that we intend to replace by a nodejs server and this API don't a append a Keep Alive header on the HTTP response.
I can't find a way to override this behavior. I've tried using app.disable and also removing the header on the middleware, but it doesn't work (it works for other HTTP headers though).
var express = require('express'),
app = express(),
port = 58458;
app.configure(function(){
app.use(express.bodyParser());
app.use(app.router);
});
app.use(function (req, res, next) {
res.removeHeader('Connection','Close');
next();
});
app.disable('Connection');
var counter = 0;
app.listen(port, function() { console.log('escutando') } );
app.post("/api/order", function(req, res) {
counter = counter + 1;
var r = req.body;
if (counter%100 === 0)
console.log(counter);
res.json(1);
res.end();
});
You have to set the header instead of remove Header
app.use(function(req, res, next) {
res.setHeader('Connection', 'close');
next();
});
I recently upgraded a project from SignalR 2.0.0-beta1 to 2.0.0-rc1. I understand that in RC1, configuration of support for cross domain requests changed. I've updated my project to use the new syntax however I'm now getting the following error when attempting to communicate with my hub:
XMLHttpRequest cannot load
=1377623738064">http://localhost:8080/negotiate?connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&clientProtocol=1.3&=1377623738064.
Origin http://localhost:7176 is not allowed by
Access-Control-Allow-Origin.
The client site is running at http://localhost:7176 and the hub is listening via a console application at http://localhost:8080. Am I missing something here? Cross domain requests were working before I upgraded to RC1.
CONSOLE APP ENTRY POINT
static void Main(string[] args)
{
var chatServer = new ChatServer();
string endpoint = "http://localhost:8080";
chatServer.Start(endpoint);
Console.WriteLine("Chat server listening at {0}...", endpoint);
Console.ReadLine();
}
CHATSERVER CLASS
public class ChatServer
{
public IDisposable Start(string url)
{
return WebApp.Start<Startup>(url);
}
}
STARTUP CONFIGURATION
public class Startup
{
public void Configuration(IAppBuilder app)
{
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.RunSignalR(new HubConfiguration { EnableJSONP = true });
});
}
}
Something is wrong with your client configuration.
XMLHttpRequest cannot load =1377623738064">http://localhost:8080/negotiate?connectionData=%5B%7B%22name%22%3A%22chathub%22%7D%5D&clientProtocol=1.3&=1377623738064. Origin http://localhost:7176 is not allowed by Access-Control-Allow-Origin.
The negotiate request should be made to http://localhost:8080/signalr/negotiate?... not http://localhost:8080/negotiate?.... To fix this you can try the following before you call $.connection.hub.start:
$.connection.hub.url = http://localhost:8080/signalr;
Not sure if this question has been adequately answered, but I made the following changes to the sample provided by Microsoft:
public void Configuration(IAppBuilder app)
{
var config = new HubConfiguration();
config.EnableJSONP = true;
app.MapSignalR(config);
}
And I added the following to the JS sample:
$.connection.hub.start({ jsonp: true }).done(function () {
$('#sendmessage').click(function () {
// Call the Send method on the hub.
chat.server.send($('#displayname').val(), $('#message').val());
// Clear text box and reset focus for next comment.
$('#message').val('').focus();
});
});
And now the Cross domain scripting is enabled. Hope this helps someone else, I was really puzzling with it for a while.
For Microsoft.Owin 2.x and above:
Add Microsoft.Owin.Cors package via NuGet by this command in Package Manager console:
PM> Install-Package Microsoft.Owin.Cors
and then using this package in Startup class file:
using Microsoft.Owin;
using Microsoft.Owin.Cors;
then change your source code like this:
// app.MapHubs(new HubConfiguration { EnableCrossDomain = true });
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
I think the best way to handle Cross Domain is documented here
CrossDomain Signal R