SignalR v2 with load balancer - asp.net-mvc

I am pretty new to SignalR and have been going through some tutorials as I've been tasked with upgrading our current implementation.
We've got an ASP.NET MVC application which uses SignalR (version 1.x). The application is in our F5 load-balanced cloud environment. So we have multiple sites (for different customers) using the same load balancer. To make the SignalR calls servers-side, we use the HubConnection from the Microsoft.ASPNET.SignalR.Client namespace and create a proxy like this (full example here):
var hubConnection = new HubConnection("http://www.contoso.com/");
IHubProxy stockTickerHubProxy = hubConnection.CreateHubProxy("StockTickerHub");
stockTickerHubProxy.On<Stock>("UpdateStockPrice", stock => Console.WriteLine("Stock update for {0} new price {1}", stock.Symbol, stock.Price));
await hubConnection.Start();
Where http://contoso.com/ is the current customer's site URL.
We are looking to upgrade to the latest SignalR (version 2.x) and I am wondering if it is necessary to even use the HubConnection. Even though the article above specifies version 2, it does mention:
This document provides an introduction to using the Hubs API for SignalR version 2 in .NET clients, such as Windows Store (WinRT), WPF, Silverlight, and console applications.
This is a web application with a regular class library back-end for data access. Taking a look at this tutorial, I don't see anything about HubConnection (it also doesn't mention load balancing). Consider the following, from the Chat tutorial:
public class ChatHub : Hub
{
public void Send(string name, string message)
{
// Call the addNewMessageToPage method to update clients.
Clients.All.addNewMessageToPage(name, message);
}
}
Then, in Statup.cs:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
app.MapSignalR();
}
}
So my question is, are we using SignalR properly? If not, what considerations/modifications need to be made when running a load-balanced application which uses SignalR (v2.x)? I haven't been able to find much regarding load balancing, etc.
Or is this a job for Groups?

You don't need to change anything structural. Have a look at the signalr redis scaleout, or any other scaleout option. Basically you need to install an additional package and ms opentech redis to do load balancing. So the scaleout will make sure that each request is sent over a message bus, making multiple servers possible.

Related

Integrate Open Policy Agent with ASP.Net Core web API

I was going through some videos and tutorials on OPA (Open Policy Agent) and found it really cool to use it for implementing Authentication and Authorization across multiple services / APIs. However I am not able to get any insights on how to install it on windows and integrate it with an ASP.Net core Web API to implement Authentication and Authorization. Can anyone help me in this ?
Thanks,
Amit Anand
Without knowing more about your use case or the platform you're running on, here's some general advice.
Architecture. Decide whether you want to run OPA as a sidecar or as a standalone service. That's an architectural question that will depend on latency, performance, and the data you need for your policies. OPA is a building-block designed as a sidecar, but you can build a service around OPA by spinning up multiple copies, load-balancing across them, adding a persistence layer, etc.
Administration. Decide how to load/update policies and log decisions to OPA and if applicable, decide how to load data into OPA.
Service Integration. If you are using a network proxy that intercepts all network traffic going to your services (e.g. Envoy, Linkerd, Kong, ...) you can configure your network proxy to call out to OPA without modifying your .Net service. If you're not using a network proxy, modify your .Net services to make HTTP callouts when your services need policy decisions, using a library where possible to minimize the impact on individual services. The integration page shows how for Java Spring and PHP.
Tim Hinrichs' answer above is on point. However, to add to it here are some specific solutions. Out of the 2 solutions below, I would recommend using the REST API and ASP.NET middleware. Also, while OPA can theoretically be used as an Authentication tool, I would advise against it. It's purpose is Authorization.
Use ASP.NET Authorization Middleware
Firstly, OPA would be running either as it's own service, as a sidecar in k8's, or in a Docker container. OPA's documentation does a good job showing examples on how to implement that so I won't go into specifics.
Here you would create a .NET service that queries OPA's Rest API.
Here is a a complete example here
Here is Microsoft's documentation on using middleware
This is what the middleware would look like.
using System.Net;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
namespace Authz.Opa
{
public class OpaAuthzMiddleware
{
private const string ForbiddenMessage = "Forbidden";
private readonly RequestDelegate _next;
private readonly IOpaService _opaService;
public OpaAuthzMiddleware(RequestDelegate next, IOpaService service)
{
_next = next;
_opaService= service;
}
public async Task InvokeAsync(HttpContext context)
{
var enforceResult = await _opaService.RunAuthorizationAsync(context);
if (!enforceResult)
{
context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
await context.Response.WriteAsync(ForbiddenMessage);
return;
}
await _next(context);
}
}
}
and you would implement it in your startup like this
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
namespace Sample
{
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddRouting();
services.AddSingleton<IOpaService, OpaService>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseMiddleware<OpaAuthzMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Use OPA's Wasm compilation
OPA has tooling that can compile Rego policies into executable Wasm modules. They provide documentation here.
It's currently under development, but there is an example on using this in .NET here. Looking at the discussions under that repo's Issues section, it looks like they're still working out some things.
You would need to use one of the available .NET libraries to read the compiled Wasm files, but this is considered to be the fastest evaluation method that OPA offers.

Sharing connections between two SignalR Hubs on different domains

I currently have a live chat website set up that hits a subdomain responsible for handling SignalR interactions:
www.domain1.com > chat.domain1.com
I'm wanting to introduce a second, duplicate, largely identical site using the same structure:
www.domain2.com > chat.domain2.com
Both sites will use the same database, which stores all persistent SignalR related things like connections, chat rooms, chat messages, etc.
Is it possible for both SignalR chat subdomains to communicate with clients connected to the other subdomain? While the shared database means that persistent resources are shared, I need to make it so that when I publish an event on chat.domain1.com clients connected to both chat.domain1.com and chat.domain2.com receive them.
It appears that it is common to handle this by sharing the same domain and using CORS to handle cross-domain interactions like so:
www.domain1.com
> chat.domain1.com
www.domain2.com
I can't do this as the SignalR chat endpoints authenticate using cookies set on the main www domain. Those cookies can't be shared cross-domain and even if they could, it's a requirement that a user has the ability to be logged in simultaneously to different accounts on domain1.com and domain2.com on the same machine.
So, are there any approaches I can use to share connections between these two hubs? Both chat subdomains are hosted on the same server?
Typically a backplane is used when your app is being scaled out across multiple servers however it also appeared to work in this situation. I used SQL Server for the backplane but there are also packages to get this working with Redis and Azure Service Bus.
Introduction to Scaleout in SignalR
SignalR Scaleout with SQL Server
First install the package for SQL Server:
Install-Package Microsoft.AspNet.SignalR.SqlServer
Then configure the backplane:
public class Startup
{
public void Configuration(IAppBuilder app)
{
// Any connection or hub wire up and configuration should go here
string sqlConnectionString = "Connecton string to your SQL DB";
GlobalHost.DependencyResolver.UseSqlServer(sqlConnectionString);
app.MapSignalR();
}
}
This allows SignalR to use SQL Server to persist any messages it needs to distribute. The first time it starts up it creates a few tables in the database and you're good to go:
Because both apps share the same database, this works perfectly.

Create in memory test with system.Web.Http.HttpServer

I would like to ask if it possible to wire up a full mvc/api (v5.2.3) site with the in memory HttpServer.
I am using owin and need to wire it up.
If it going to work I need to call static Startup() and Configuration(IAppBuilder app) in class Startup.cs in my integration test.
I read the article ASP.NET Web API integration testing with in-memory hosting it gave me a deeper understanding of the HttpServer, - but as always close but no cigar.
Can it be done?

.Net Web Api multiple requests at once

I want to enable making several concurrent requests to server from a single client. How can this be done with .Net WebApi? In ASP.Net MVC 3 it could be enabled with adding the follow attribute to the controller:
[SessionState(SessionStateBehavior.ReadOnly)]
public class SomeController : AsyncController
{
//.....
}
Information about MVC Session was found here:
The Downsides of ASP.NET Session State
But in Web Api application it doesn't work. I've also accessing session data like in this question:
Accessing Session Using ASP.NET Web API
So, I think thats why I can't make multiple requests at once from client. What should I do enable that feature?
Resolved by adding:
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
HttpContext.Current.SetSessionStateBehavior(
SessionStateBehavior.ReadOnly);
}
and
public override void Init()
{
PostAuthenticateRequest += MvcApplication_PostAuthenticateRequest;
base.Init();
}
to Global.asax
Yes, there are a lot of problems with using session in your ASP.NET applications. Moreover, by default, HTTP (and by extension, REST- like/style application) is stateless – and as a result each HTTP request should carry enough information by itself for its recipient to process it to be in complete harmony with the stateless nature of HTTP.
Web Api was not design to support Asp.net Session ; you have nothing else to do.
So, If you need some information in a Web Api, do not rely on Seesion State but add them into your request
What is very funny, is that some people want to support Session in Web Api ...

Asp.Net MVC Consuming a web api from a Class Library

I am wondering if there is a way to create a class library that contains web API, so I can use the dll as a plug-in, to inject into the MVC application.
Thank you in advance for your help.
Web API methods are called over HTTP, so calling a Web API service requires it to be hosted somewhere and called using a suitable client as detailed in #David's link. You can self-host Web API, so in theory you could have an assembly local to an MVC application which contained a class which set up and then called a self-hosted Web API service.
You would inject the Web API service behind an interface, something like this:
public interface IProductsService
{
IEnumerable<Product> GetAllProducts();
}
...implemented something like this:
public class SelfHostedWebApiProductsService
{
public SelfHostedWebApiProductsService()
{
// Set up a self-hosted Web API service
}
public IEnumerable<Product> GetAllProducts()
{
// Call your self-hosted WebApi to get the products
}
}
Configure your DI container to use SelfHostedWebApiProductsService for the IProductsService interface, and away you go. This article details how to set up and call a self-hosted Web API.
As the SelfHostedWebApiProductsService sets up the self-hosted Web API in its constructor - a relatively expensive operation - you might want to consider giving this class a singleton lifetime in your DI container.
You could Self-Host a Web API:
http://www.asp.net/web-api/overview/hosting-aspnet-web-api/self-host-a-web-api
You can put all your controllers in a Class Library project.
Then use Autofac to resolve the dependencies in your host project:
https://code.google.com/p/autofac/wiki/WebApiIntegration

Resources