Open danroth27 opened 4 years ago
@danroth27 can we leverage YARP for this?
Thanks for contacting us.
We're moving this issue to the Next sprint planning
milestone for future evaluation / consideration. We will evaluate the request when we are planning the work for the next milestone. To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
We have proxy middleware in the aspnet/asplabs repo: https://github.com/aspnet/AspLabs/tree/master/src/Proxy. I'm not sure if YARP is using that or not. @Tratcher?
We also have some proxying logic in SpaServices.Extensions that I believe @SteveSandersonMS wrote.
I believe the main things here are to rewrite/forward requests and rewrite things like cookies and things like that?
@danroth27 YARP was "inspired-by" that lab, but the code isn't very similar anymore. The relevant part is here: https://github.com/microsoft/reverse-proxy/blob/master/src/ReverseProxy/Service/Proxy/HttpProxy.cs
I believe the main things here are to rewrite/forward requests and rewrite things like cookies and things like that?
That sounds right. The goal is to emulate single origin as much as is possible/reasonable.
Just be aware of all the things proxies break. https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-3.1
Things used for url generation, redirects, cookies, etc.:
Rewriting response headers is one thing, trying to rewrite anything in the content is a very different problem.
A quick win could be to extend the DevServer
to use the SpaServices.Extensions
middleware as it already contains a proxy feature: https://github.com/dotnet/aspnetcore/tree/master/src/Middleware/SpaServices.Extensions/src/Proxying
To make it interoperable with the way many JavaScript projects work, it could leverage the BrowserSync config proxy structure - https://www.browsersync.io/docs/options#option-proxy
So have it that when the devserver starts up, if it finds a bs-config.json
file, then add the middleware and parse the proxy information out of it to setup the middleware.
I think that the spa services proxy works in combination with the different JS proxies. I think we would no take a dependency on node JS for something like that.
It doesn't appear that it uses anything from Node, the code for the proxy implementation is in https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/SpaServices.Extensions/src/Proxying/SpaProxy.cs and it added middleware to each request (https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/SpaServices.Extensions/src/Proxying/SpaProxyingExtensions.cs#L77-L82) and uses HttpClient
to forward the request (https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/SpaServices.Extensions/src/Proxying/SpaProxy.cs#L76-L94).
It looks like prior to .NET 5 the extensions depends on SpaServices, which in turn depends on NodeServices, but if I understand the csproj correctly it's being removed in 5 RTM: (https://github.com/dotnet/aspnetcore/blob/master/src/Middleware/SpaServices.Extensions/src/Microsoft.AspNetCore.SpaServices.Extensions.csproj#L18-L23)
@aaronpowell yes, but it is proxying that request to the angular/react/webpack proxy that is started by ng run and so on, which in turn are the ones that take care of proxying API requests and things like that.
Isn't it proxying any request that can't be handled by the ASP.Net server to an endpoint that's running whatever the endpoint runs?
Now I'm not sure we are talking about the same things. Proxying to a backend server in angular/react and other things like that are handled by nodejs middlware as Dan points out.
From what I've played with it, that middleware does more than what our current proxy middleware does (rewrites cookies, etc.) that's why I'm saying the SPA proxy is not enough, but I might be wrong.
@SteveSandersonMS will know better since he wrote the thing :).
My understanding is that the goal is to have it so that if you hit http://localhost:5000/api/product
and there isn't a Blazor route that matches that it should then pass through to whatever you've designated /api/product
to map to in the proxy config (it could be a local Azure Functions, it could be an asp.net core server, it could be something running on another machine), emulating single origin as Dan mentions.
@aaronpowell Makes sense!
I guess we would need to extend the framework's MapFallback
logic so that, if an incoming request does not have Accept: text/html
, then the "fallback" behavior switches over to doing a proxied request instead of returning the usual fallback response (e.g., the index.html
file).
Alternatively we'd create some other middleware the dev server plugs in before MapFallback
, which does this proxying for all requests that don't have Accept: text/html
, assuming that the static-files middleware or an MVC action etc. would already have handled the request if it matched a physical file or static web asset or known server-side endpoint.
As for the way the proxying is achieved, it's probably ideal to use YARP if we can, because that's the more modern and better maintained implementation. As per @Tratcher's comment, there are all kinds of caveats about what can actually be proxied and how it impacts behavior, but that's the same for all the other SPA tooling proxies too.
I'm not certain what aspects of request/response rewriting are involved (besides changing the Origin
and rewriting CORS headers). Most likely there are lots of details that aren't obvious up front. We would want to research exactly what the other SPA frameworks do to get an initial estimate of the required feature set. It might end up being a quick and cheap feature, or a hugely expensive long tail of issues.
Most of the FE frameworks use something along the lines of https://webpack.js.org/configuration/dev-server/#devserverproxy, which is why I suggested our SPA proxy wasn't enough. This is also based on my experimentation of switching the SPA proxy to use the native version.
Our SPA proxy, AFAIK just forwards the requests, but doesn't do any sort of transformation. Other FE frameworks allow you to specify things like "when hitting this url, this is the endpoint/url" you need to send the request to, and take care of the changes needed on the request and response to make that happen.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
Thanks for contacting us.
We're moving this issue to the .NET 8 Planning
milestone for future evaluation / consideration. We would like to keep this around to collect more feedback, which can help us with prioritizing this work. We will re-evaluate this issue, during our next planning meeting(s).
If we later determine, that the issue has no community involvement, or it's very rare and low-impact issue, we will close it - so that the team can focus on more important and high impact issues.
To learn more about what to expect next and how this issue will be handled you can read more about our triage process here.
We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.
What if you allowed a string of URLs as a configuration option to the DevServer and a flag to use CORs with that list of strings?
Add a DevServerOptions
class, and setup app.UseCors()
with those options from the configuration. That way users can just setup a list of allowed servers in a blazor-devserversettings.json
file in their project.
Add proxying support to the Blazor dev server similar to the functionality available from other frontend frameworks, particularly those based on webpack:
This functionality is useful when the Blazor WebAssembly app is being developed as a separate project from its backend API during development, but will be deployed to the same domain in production. A common example is a Blazor WebAssembly frontend with an Azure Functions backend.