signalR change default site in startup - c#

I have an application where i have 2 instances of it running on the same IIS server.
/Site1
/Site2
same source code in both, just different settings. I have signalR code on both sites, but i would like Site2 to use the signalR server from Site1.
I have this working so that if changes are made on Site1, Site2 knows to refresh, and that works fine. THE PROBLEM is that if server changes (not javascript) are made on Site2, Site1 doesn't get them. Below is my code:
Startup.cs
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
var hubConfiguration = new HubConfiguration
{
#if DEBUG
EnableDetailedErrors = true
#endif
};
map.RunSignalR(hubConfiguration);
});
javascript code:
$.connection.hub.url = "http://servername/Site1/signalr";
...$.connection.start etc
All of that seems to work fine, but what i can't find anywhere is how to push settings in the C# code from Site2 to Site1.
random c# code:
var hub = GlobalHost.ConnectionManager.GetHubContext<myHub>();
this globalhost.connectionmanager.gethubcontext is always pointing to itself. How can i get Site2 to point to Site1 in the last section? I've tried looking into editing Startup.cs to use MapSignalR(..path,...), but the path doesn't take absolute URLs, it has to start with '/', so it won't go up a level.
Any ideas or am i missing something basic?

Apparently what i'm looking for is a backplane. https://learn.microsoft.com/en-us/aspnet/signalr/overview/performance/scaleout-in-signalr . super easy to set up, and fixed my problem immediately (without any of the javascript changes above needed).

Related

Changing the base URL of a Blazor WASM app

I have a Blazor WebAssembly app which is server hosted.
When I deploy it on an internal work network, the address is just the IP address, e.g. http://192.168.1.23. That works, but it's not so user friendly. I want it to be http://192.168.1.23/myapp.
I've done some reading on this here (Microsoft), and also here (Stackoverflow). They suggest a couple of things:
In Client side code, index.html, change <base href="/" /> to <base href="/myapp/" />.
In Server side code, Startup.cs, add app.UsePathBase("player"); early on in the Configure() method.
Microsoft also says how to edit the launch settings so that debug still works normally, and they include adding the following to the launchSettings.json file:
"commandLineArgs": "--pathbase=/myapp",
"launchUrl": "myapp"
They don't say if this is in the Client or Server launchSettings.json file, and I can't get it to work anyway. Even if I add "launchUrl": "https://www.google.com" everywhere, nothing different happens when I run it.
Ignoring number 3 above though, the app will start, and I can get to the correct place by manually adding /myapp to the address. So far so good.
I am using cookie authentication though, and when I try to retrieve the user details from the user details from the HttpContext using this method on a hub:
public static User GetAuthenticatedUser(this HttpContext context)
{
var idClaim = context.User.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.NameIdentifier));
var nameClaim = context.User.Claims.FirstOrDefault(c => c.Type.Equals(ClaimTypes.Name));
return new User
{
Id = int.Parse(idClaim.Value),
Name = nameClaim.Value
};
}
It fails, with each claim being null. It did not before I set the base path. How can I overcome this issue?
Note: It works on a regular controller, it's specifically a hub it is failing on, so it's as if the hub is not receiving the same HttpContext as before. The hub was also setup in Startup.cs, with the following in the Configure() method:
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<MyHub>("/myhub1");
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
Any advice is much appreciated.

SignalR not working after deploy on azure.Works on localhost

so if got this error after deploying. The chat page thats located on localhost/Home/Chat opens fine when i run it in local host but i get status code 500 when i try to open it azurewebsites.net
app.UseEndpoints(
endpoints =>
{
endpoints.MapHub<SignalRChatHub>("/chat");
endpoints.MapControllerRoute("areaRoute", "{area:exists}/{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllerRoute("default", "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
Those are my endpoints in startup.
Thats the JS in the view
<script>
var connection =
new signalR.HubConnectionBuilder()
.withUrl("https://myurl.azurewebsites.net/Home/Chat")
.build();
connection.on("NewMessage",
function (message) {
var chatInfo = `<div style="color:black;text-align:center;font-size: 25px">${message.user} says : ${escapeHtml(message.text)}</div>`;
$("#messagesList").append(chatInfo);
});
i replaced the WithUrl with my url(i didnt post it here because its not ready :D) but still nothing
Thats my home controller
public IActionResult Chat()
{
return this.View();
}
i suspect it got something to do with Connection string and that is getting the dafault connection from the db and not the one from the Azure db. But dont know how to fix that...
Okay got it going ! The first problem was that Environmental Variable in azure was set to Production and thats why the error looked like that changed the ASPNETCORE_ENVIRONMENT in Azure,AppService,Configuration,Application Settings. From Production to Development and got the more convinient error.The error was that it couldnt find the View.I have the view in the folder it searched but it didnt work. The fix was right click on the view and changing the Build Action to Content.This fixed my issue.

Enable CORS from a specific origin on Topshelf hosted service

I'm sure this is a duplicate but none of the answers I've found appears to be working.
I have a web.api hosted as a windows service and I need to allow CORS to two specific origins.
I have this in my startup.cs
config.EnableCors(
new EnableCorsAttribute("http://customer.mydomain.com,
http://admin.mydomain.com", "*", "*")
);
var policy = new CorsPolicy()
{
AllowAnyHeader = true,
AllowAnyMethod = true,
SupportsCredentials = true
};
policy.Origins.Add("*http://customer.mydomain.com");
policy.Origins.Add("*http://admin.mydomain.com");
app.UseCors(new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context => Task.FromResult(policy)
}
});
So my understanding here is that I'll only allow access to my service from admin and customer subdomains?
and then on top of my controller I have
[EnableCors("*.mydomain.com","*","*")]
public class MasterDataController
everything builds and is happy but when I run my service and call a method in the controller directly from the browser URL it responds fine, shouldn't it be blocking me as I'm not calling it from mydomain.com ?
I've seen answers saying I need to send my origin in my call but surely that's not the answer as I specifically want to stop calls unless they are from my allowed origins? I feel like I'm going in circles here
[Update]
I've also added
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*.bizcash.co.za" />
</customHeaders>
to my IIS proxy and if I check the response headers when I call the method directly I see the following
*.redacted obviously being my domain. However, I can still call it directly from my browser and it shouldn't allow that should it? It should only allow the calls if made from my domain?
okay, so two problems with the question.
adding specific CORS origins doesn't stop you calling the service directly in the browser, it stops other web applications calling it. So I was testing it wrong.
So you need to make your changes, deploy it to your server and then test it via your normal applications.
to make it work this is what I have in the end
var policy = new CorsPolicy()
{
AllowAnyHeader = true,
AllowAnyMethod = true
};
policy.Origins.Add("https://customer.mydomain.com");
policy.Origins.Add("https://admin.mydomain.com");
app.UseCors(new CorsOptions
{
PolicyProvider = new CorsPolicyProvider
{
PolicyResolver = context => Task.FromResult(policy)
}
});
That's it, just that in the startup.cs and it works. Hopefully I save someone else two wasted days of life

SignalR 404 error when trying to negotiate

So I am very new to SignalR, in fact I've only been using it for a couple of days now. Anyway, I am getting the error below when my application first starts up:
The code for the application in question is located in two projects, a Web API and a Single Page Application (SPA). The first one has my backend code (C#) and the second one my client-side code (AngularJS). I think the problem might be due to the fact that the projects in question run on different ports. The Web API, where my SignalR hub lives, is on port 60161 and the SPA is on 60813. My hub is declared like so:
public class ReportHub : Hub
{
public void SendReportProgress(IList<ReportProgress> reportProgress)
{
this.Clients.All.broadcastReportProgress(reportProgress);
}
public override Task OnConnected()
{
this.Clients.All.newConnection();
return base.OnConnected();
}
}
and then in my Startup.cs file for my Web API I initialize SignalR like this:
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.Services.Replace(typeof(IHttpControllerActivator), new NinjectFactory());
config.MessageHandlers.Add(new MessageHandler());
//set up OAuth and Cors
this.ConfigureOAuth(app);
config.EnableCors();
config.IncludeErrorDetailPolicy = IncludeErrorDetailPolicy.Always;
// Setting up SignalR
app.Map("/signalr", map =>
{
map.UseCors(CorsOptions.AllowAll);
map.RunSignalR(new HubConfiguration { EnableJSONP = true });
});
//set up json formatters
FormatterConfig.RegisterFormatters(config.Formatters);
WebApiConfig.Register(config);
app.UseWebApi(config);
}
For my client-side code I use an Angular SignalR API called angular-signalr-hub (Angular-signalr-hub). The client-side follows:
angular
.module("mainApp")
.factory("reportHubService", ["$rootScope", "Hub", reportHubService]);
/// The factory function
function reportHubService($rootScope, Hub) {
var vm = this;
vm.reportName = "None";
// Setting up the SignalR hub
var hub = new Hub("reportHub", {
listeners: {
'newConnection': function(id) {
vm.reportName = "SignalR connected!";
$rootScope.$apply();
},
'broadcastReportProgress': function (reportProgress) {
vm.reportName = reportProgress.reportName;
$rootScope.$apply();
}
},
errorHandler: function(error) {
},
hubDisconnected: function () {
if (hub.connection.lastError) {
hub.connection.start();
}
},
transport: 'webSockets',
logging: true
//rootPath: 'http://localhost:60161/signalr'
});
I did some googling yesterday and one of the suggestions I came upon was to set the SignalR URL to the one of my Web API, which I did (the commented out line above). When I uncomment the line in question, that does seem to do something because if I now go to http://localhost:60161/signalr/hubs in my browser, it does show me the dynamically generated proxy file:
and when I run my application I no longer get the error above, but now it doesn't seem to connect. It gets to the negotiate line and it stops there:
I think it should look like this (this is from a SignalR tutorial I found):
In addition, none of my listeners (declared in my Angular code above) get called, so something is still now working quite right. There should be more lines in the log to the effect that connection was successfully established, etc. What could be the problem here?
UPDATE: upon further debugging i found out the problem is most likely being caused by the ProtocolVersion property being different between the client and the result here:
Because of that it seems it just exists and fails to establish connection.
I figured out what the problem was. My SignalR dependencies were out of date and because of that my client and server versions differed. All I had to do was update (via NuGet Package Manager) all SignalR dependencies to the latest version and now it works.
As a side note, SignalR was not very good at telling me what was wrong. In fact, no error message was displayed, unless of course there was some additional logging somewhere that had to be found or turned on, in addition to the logging I already had (turned on). Either way, it's either not logging certain errors or it makes it difficult to figure out how to turn on all logging. I had to go and debug the JQuery SignalR api to figure out what the problem was, which was a time consuming endeavour.

Why Request.Url.Authority is returning the internal path and not my domain

I'm working through the final issues of an application set to go live this week. I need help to either modify my code or explain to our hosters what they need to fix in the IIS/DNS configurations to make this code work as expected.
Here is the code:
public string BaseSiteUrl
{
get
{
var c = this.ControllerContext.RequestContext.HttpContext;
string baseUrl = c.Request.Url.Scheme + "://" + c.Request.Url.Authority
+ c.Request.ApplicationPath.TrimEnd('/') + '/';
return baseUrl;
}
}
I make a call to this in my Controller, to generate a url that gets persisted to a database.
It works fine when I run on my local machine. However, it does not work when it is run on the beta server.
Expected results on beta. On the beta server this is an application named dr405
https://beta.sc-pa.com/dr405/
The actual result on beta. (I changed the server/domain names to what you see in CAPS for security's sake)
http://SERVERNAME1.GROUP1.SUBGROUP.local/dr405/
I don't think you need the method you wrote. There is a UrlHelper class that adds extension methods. To get the base URL for your site you should be using the Content() method like this:
var baseUrl = Url.Content("~/");
In your example, it looks like the http://SERVERNAME1.GROUP1.SUBGROUP.local/dr405/ result is an internal host name. On your development machine the internal host matches your public facing one. Your hosting provider is unlikely to be able to modify this for you, especially if it's a shared hosting solution.
If you're behind a load balancer or similar, it might be worth checking server variables. In our case we do something like this:
string hostName = Request.Headers["x-forwarded-host"];
hostName = string.IsNullOrEmpty(hostName) ? Request.Url.Host : hostName;
This question I asked a while ago might be of interest:
Asp.net mvc 301 redirect from www.domain.com to domain.com
Due to time constraints, and the need to get this project out the door, I had to resort to hardcoding the main part of the url into the application. After I made the change I felt stupid for trying to make it dynamic in the first place. I mean how often should our domain name change?

Categories

Resources