signalr.client.httpclientexception statuscode 404 exception when passing through hubConnection.Start().Wait() - c#

We are unable to connect to a signalR hub deployed on server (Windows Server 2008 Enterprise SP2 and IIS 6) through a console application, we tested everything locally on a PC and it was working fine, but deployed on a server (IIS 6) we became unable to connect remotely or even locally on the server itself.
No experience in SignalR but the same client is working fine on a normal PC. (client and hub in the same pc).
We tested the connectivity and the permissions to the server and it's all fine.
We are able to reach the hub url (http://hr1/HRNotificationHub) when we call it remotely via a web browser , but when we add signalR/hubs we get 404 error in the browser also.
static void Main(string[] args) //Client
{
try
{
IHubProxy _hub;
string url = #"http://localhost/HRNotificationHub/";
var connection = new HubConnection(url);
_hub = connection.CreateHubProxy("HRHub");
connection.Start().Wait();
_hub.On("ReceiveMessage", x => Console.WriteLine(x));
string line = null;
while ((line = System.Console.ReadLine()) != null)
{
_hub.Invoke("BroadcastMessageToAll", line).Wait();
}
Console.Read();
}
catch (Exception ex)
{
Console.WriteLine(ex.InnerException.ToString());
Console.Read();
}
}
public class Startup //Server
{
public void Configuration(IAppBuilder app)
{
app.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration()
{
EnableDetailedErrors = true,
EnableJSONP = true,
EnableJavaScriptProxies = true
};
app.MapSignalR(hubConfiguration);
}
}
[HubName("HRHub")]
public class HRHub : Hub //Hub Class
{
public void BroadcastMessageToAll(string message)
{
Clients.All.newMessageReceived(message);
var newMessage = message + "-newmessage";
Clients.All.ReceiveMessage(newMessage);
}
public void JoinAGroup(string group)
{
Groups.Add(Context.ConnectionId, group);
}
public void RemoveFromAGroup(string group)
{
Groups.Remove(Context.ConnectionId, group);
}
public void BroadcastToGroup(string message, string group)
{
Clients.Group(group).newMessageReceived(message);
}
}

Locally, it is working under IIS Express, which is normal.
On the server though, you are running IIS 6 which is not a supported version. Please check the documentation. You need at minimum IIS 7, but IIS 8 if you expect to use web sockets.

All what I have done to solve this issue was adding the line in the webconfig of the project deployed on the server:
<modules runAllManagedModulesForAllRequests="true" />

Related

Signalr connection is closing on web garden with 404 code

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?

Blazor Server, Sharepoint upload proxy settings

i have a problem uploading an xlsx file to sharepoint on the deployed version. In my IIS Express in the local pc i can upload the document without any problem. When i deploy the application the server gives me an exception "No connection could be made because the target machine actively refused it. [::ffff:127.0.0.1]:9000 (127.0.0.1:9000)". The Server uses a proxy server in order to execute the web request. I tried many solutions on the internet but nothing worked. I also developed a console application, which was able to upload the file without any further configuration.
This brings me to the conclusion, that the blazor server for some reason doesn't use the systems default proxy when it does the web request.
Here is my code:
public Task<bool> UploadDocument(byte[] fileBinaryArray, string fileName, string sharePointLink)
{
try
{
Debug.WriteLine("-----------------------------------" + sharePointLink);
var preparedLink = PrepareSharePointLink(sharePointLink);
Debug.WriteLine("-----------------------------------" + preparedLink);
ClientContext ctx = new PnP.Framework.AuthenticationManager().GetACSAppOnlyContext(_siteUrl, _clientId, _clientSecret);
/*ctx.ExecutingWebRequest += (sen, args) =>
{
System.Net.WebProxy myProxy = new System.Net.WebProxy("proxyIp", 8080);
args.WebRequestExecutor.WebRequest.Proxy.Credentials = System.Net.CredentialCache.DefaultCredentials;
args.WebRequestExecutor.WebRequest.Proxy = myProxy;
};*/
var folder = ctx.Web.GetFolderByServerRelativeUrl(preparedLink);
ctx.Load(folder);
ctx.ExecuteQuery();
folder.Files.Add(new FileCreationInformation
{
Overwrite = true,
Content = fileBinaryArray,
Url = fileName
});
ctx.ExecuteQuery();
return Task.FromResult(true);
}
catch(Exception e)
{
_eventlogService.LogError(e, _authenticationService?.UserName);
return Task.FromResult(false);
}
}

Can't connect secured Asp.Net Core Web Socket hosted on Azure Web App (using TLS)

I spent a whole day searching for a solution but I didn't solve my problem. As you can see from the title, I implemented a basic Web Socket using Asp.Net Core (3.1) framework and I deployed it on Azure (on a Web App service). I successfully make it works without the TLS protocol (so I think the ws has been configured in a good manner) but when I try to connect using wss I receive this errors on the client side:
System.Net.WebSockets.WebSocketException : Unable to connect to the remote server
System.Net.WebException: The underlying connection was closed: An unexpected error occurred on a send.
System.IO.IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.
System.Net.Sockets.SocketException: An existing connection was forcibly closed by the remote host
I tried to switch the "HTTPS Only" trigger on azure portal but it keep refusing any client to connect.
Do you have any idea how to let wss works with Azure Web App? Do I need to configure a certificate? I read that azure provide a certificate if the user didn't have one. Thanks and regards
UPDATE: the code has been "copied" from this great Les Jackson's tutorial and is available on git hub at this precise address. The important part of the code is here:
/* THIS IS THE SERVER PART WHERE THE CONNECTION IS ACCEPTED */
namespace WebSocketServer.Middleware
{
public class WebSocketServerMiddleware
{
private readonly RequestDelegate _next;
private WebSocketServerConnectionManager _manager;
public WebSocketServerMiddleware(RequestDelegate next, WebSocketServerConnectionManager manager)
{
_next = next;
_manager = manager;
}
public async Task InvokeAsync(HttpContext context)
{
if (context.WebSockets.IsWebSocketRequest)
{
WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
await Receive(webSocket, async (result, buffer) =>
{
if (result.MessageType == WebSocketMessageType.Text)
{
Console.WriteLine($"Receive->Text");
return;
}
else if (result.MessageType == WebSocketMessageType.Close)
{
await sock.CloseAsync(result.CloseStatus.Value, result.CloseStatusDescription, CancellationToken.None);
return;
}
});
}
else
{
await _next(context);
}
}
}
}
/* THIS IS THE STARTUP FILE*/
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddWebSocketServerConnectionManager();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseWebSockets();
app.UseWebSocketServer();
}
}
/* THIS IS THE CLIENT (WRITTEN IN NET FULLFRAMEWORK) */
Console.Write("Connecting....");
var cts = new CancellationTokenSource();
var socket = new ClientWebSocket();
string wsUri = "wss://testingwebsocket123123.azurewebsites.net";
await socket.ConnectAsync(new Uri(wsUri), cts.Token);
Console.WriteLine(socket.State);
await Task.Factory.StartNew(
async () =>
{
var rcvBytes = new byte[1024 * 1024];
var rcvBuffer = new ArraySegment<byte>(rcvBytes);
while (true)
{
WebSocketReceiveResult rcvResult = await socket.ReceiveAsync(rcvBuffer, cts.Token);
byte[] msgBytes = rcvBuffer.Skip(rcvBuffer.Offset).Take(rcvResult.Count).ToArray();
string rcvMsg = Encoding.UTF8.GetString(msgBytes);
Console.WriteLine("Received: {0}", rcvMsg);
}
}, cts.Token, TaskCreationOptions.LongRunning, TaskScheduler.Default);
Thank you for reading
As disussed over the comments, it works fine with the provided javascript client in the sample. The error in .net client happens because of TLS version when you connect from c# client with full framework. The screenshot of your Azure web app enforces min TLS 1.2. Set that in the .net client like below:
System.Net.ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12;

Self hosted windows service (Console App is running fine) on Windows Server 2016 RSTful api is not accessible

My main question is:
What is the difference between self hosted service inside a console app and a windows service?
I wrote a Self-Host Web API Console application which provides a simple api. For that I used basically the MSDN exemple:
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
var config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
public class HeartbeatController : ApiController
{
public HttpResponseMessage Get()
{
var jsonToSend = GetJsonHeartbeatStatus();
if (!string.IsNullOrEmpty(jsonToSend))
{
var response = this.Request.CreateResponse(HttpStatusCode.OK);
response.Content = new StringContent(jsonToSend, Encoding.UTF8, "application/json");
return response;
}
throw new HttpResponseException(HttpStatusCode.NotFound);
}
private string GetJsonHeartbeatStatus()
{
var hs = new HeartbeatStatus();
hs.Toolname = "html Scraper";
hs.Heartbeat = DateTime.Now.ToString();
hs.Plant = "plant1";
hs.Department = "departmentA";
hs.Servername = Environment.MachineName;
return JsonConvert.SerializeObject(hs);
}
}
protected override void OnStart(string[] args)
{
base.OnStart(args);
logger.Info("In OnStart");
var UserDomain = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName;
var Port = "8377";
string baseAddress = string.Format("http://{0}.{1}:{2}", Environment.MachineName, UserDomain, Port);
var completeAddress = baseAddress + "/api/heartbeat";
try
{
host = WebApp.Start<Startup>(baseAddress);
HttpClient client = new HttpClient();
var response = client.GetAsync(completeAddress).Result;
logger.Info("Api address: {0}", completeAddress);
logger.Info("Service Host started #{0}", DateTime.Now.ToString());
}
catch (Exception ex)
{
logger.Info("{0}", ex.ToString());
}
finally
{
if (host != null)
{
host.Dispose();
}
}
}
Next Step was to write a Firewall inbound role to get access to the port.
Then I tested it on our Windows Server 2016 Standard.
-> Test passed in Postman on another machine!
Now as you already saw (in the code) I took the code to a Windows Service Application (user= Local System). I am logging in Windows Event and I have no error in starting the host (that's why I used the try catch).
-> Test with the browser on the server failed and also with Postman on a different machine.
I figured out that I have to reserve the path with netsh
I tried:
netsh http add urlacl url=http://+:8377/api/heartbeat user=everyone
netsh http add urlacl url=http://machineName.corp:8377/api/heartbeat/ user=everyone
Installed the Service application with my user (admin) and set up the urls
netsh http add urlacl url=http://+:8377/api/heartbeat user=myUser
netsh http add urlacl url=http://machineName.corp:8377/api/heartbeat/ user=myUser
-> Test with the browser on the server failed and also with Postman on a different machine.
At this point I could not find any solution why my api is not working.
Does anybody have any ideas?
-edit-
Console appöication:
C:\Windows\system32>netstat -na | find "8378"
TCP 0.0.0.0:8378 0.0.0.0:0 LISTENING
TCP [::]:8378 [::]:0 LISTENING
TCP [fe80::5505:852c:952e:74f%6]:8378 [fe80::5505:852c:952e:74f%6]:62555 ESTABLISHED
TCP [fe80::5505:852c:952e:74f%6]:62555 [fe80::5505:852c:952e:74f%6]:8378 ESTABLISHED
Windows Service application:
C:\Windows\system32>netstat -na | find "8377"
no response!

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

Categories