Can't access a dotnet API due to an SPA Proxy - c#

I'm serving a React app through dotnet's UseStaticFiles. this allows the front-end to communicate with the front-end by simply fetching to localhost. Now I would like to deploy a 2nd front-end outside this close-loop, problem is, I can't access the underlying backend since all requests are being handled by its front-end.
Say I would like to access /users, then the front-end would try to match that route, if it doesn't find it, then it will display a 404 error page.
I tried mapping the controller routes under api like so.
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "api/{controller}/{action=Index}/{id?}"
);
});
BUt I am still unable to access the API under the /api base path.

Related

Consume third party API with Blazor WebAssembly [duplicate]

I have a blazor web assembly which fetches from an external API built on ASP.NET Core which I do not have access to. I can perform get requests, but cannot perform post requests. I get the following error when I do.
Access to fetch at 'http://external:9000/User/Create' from origin 'http://localhost:56138' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
The author of the api confirms he enabled cors to allow any header in his startup and also suggested I do the same but this did not fix the issue. I confirmed from the debugger I am sending the right data format the endpoint requires and I am also running on http scheme same as the web service.
This is the client configuration in program.cs
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri("http://external:9000/") });
builder.Services.AddCors(policy =>
{
policy.AddPolicy("_myAllowSpecificOrigins", builder => builder.WithOrigins("http://external:9000/")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
This is how I post
var dataJson = JsonConvert.SerializeObject(application);
var stringContent = new StringContent(dataJson, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync($"User/Create", stringContent);
I have read this is a common problem with blazor assembly, I'm not entirely sure of what I read. I am currently trying to move the project to blazor server to see if it would work, but I would prefer it on web assembly.
builder.Services.AddCors(policy =>
{
policy.AddPolicy("_myAllowSpecificOrigins", builder => builder.WithOrigins("http://external:9000/")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
This configuration should be done on a Server, and not yours but the server of the external API. You do nothing in that regard, except call end points on that Web Api.
The author of the api confirms they enabled cors to allow any header in his startup
If so, ask them for the code for confirmation...
and also suggested I do the same but this did not fix the issue.
You do nothing of the sort.
Workaround solution:
AS CORS is a security feature of JavaScript enforced by the browser, you can circumvent it by calling your Server code from which you perform the call to this Web Api end point, and then returns it back to your WebAssembly front-end. Use asynchronous code as much as you can.
Update as per comment
Are you saying I should have two projects, the server and the client under one solution? The server calls the calls the external api, then passes it to the client. Is this what your last suggestion is?
If you're using WebAssembly Blazor App hosted wherein the hosting server contains Web Api controllers, then you should expose end points that can be called from your WebAssembly front-end. The code in these end points should perform the HTTP calls to the external Web Api, and pass back to the WebAssembly calling methods the data received from the external Web Api.
Note: If you don't have such controllers ( they are created by default by Visual Studio), you may add them yourself to the server project.
If you already have created a Web Api project instead of those controllers, then expose the necessary end points from your Web Api project. Note that it makes no difference whether your Web Api project resides in the same solution of the WebAssembly front-end, as long as you provide the correct Url.
If you're using WebAssembly Blazor App stand alone; that is, the default installation does not create a Server project, you'll need to create a Web Api project and use it, unless you've already created one.
You are working with localhost so you should use this configuration to your Server:
builder.Services.AddCors(policy =>
{
policy.AddPolicy("_myAllowSpecificOrigins", builder =>
builder.WithOrigins("http://localhost:56138/")
.SetIsOriginAllowed((host) => true) // this for using localhost address
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
//
app.UseCors("_myAllowSpecificOrigins");

Launching a WebApi application from a Windows App

I have a simple WebApi2 app that handles various REST requests. It's essentially a front end for various CRUD operations on an SQL Server Database. Up until now, I've never run it from outside of Visual Studio yet though and I usually don't do Windows specific stuff, but here I am.
My goal is to build this webapp's functionality into a Windows Desktop application (or at least be able to control the webapp from the windows program), mostly so the user can start the Webapp, stop it, see who is connecting to it, etc, but I've got no idea how to go about connecting this particular set of dots. It's actually a pretty tough thing to google.
The WebApp part also needs to be told some things at startup (just strings, so if the answer(s) involve executing various system command lines to tell the WebApp to start/stop/etc and I can pass in what I need on a command line somehow, that's fine).
Ultimately, the goal is to hand the user an install program and he doesn't have to know there is a webserver involved unless he really wants to.
So how would I go about accomplishing this part? (If this question is too vague, tell me why and I'll modify it as necessary).
One of the good things about Web API is the ability to be hosted outside of a web server such as IIS. For example you could host it inside your Windows Forms application. Here's an article with detailed instructions on how to achieve this.
You would have a Startup class that will be used for bootstrapping:
public class Startup
{
// This code configures Web API. The Startup class is specified as a type
// parameter in the WebApp.Start method.
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
HttpConfiguration config = new HttpConfiguration();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
appBuilder.UseWebApi(config);
}
}
and then its just a matter of starting the listener:
using (WebApp.Start<Startup>("http://localhost:8080"))
{
Console.WriteLine("Web Server is running.");
Console.WriteLine("Press any key to quit.");
Console.ReadLine();
}
This will make available your Web API on port 8080 locally and your application can send HTTP requests to it.
So basically the keywords that you are looking for are: self hosting asp.net web api.

How to add a Web API service to a non-MVC Asp site?

With the help of several online tutorials, like this one, I am still struggling to add a Web API service to an existing Asp site, that is not MVC.
I added to the project a new item of type Web API Controller Class(v2.1), named it something like AbcController.cs, and VS2015 asked me to put it in the App_Code directory. The default code has handlers for Get, Put etc. Sounded to me like I am on the right track.
I added a default route in Global.asax.cs like in the tutorial:
RouteTable.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
This got built after adding a reference to System.Web.Http.Webhost which was not mentioned in the tutorial. Sounded like I was still on the right track.
However, it doesn't work. I run the site in debug and this gives me a 404 Not Found:
http://localhost:54905/api/abc
I tried to run this on the production server with IIS7, of course as a second test web site to not interfere with the version that is in production. However, I ran into the error that the Microsoft.Web.Infrastructure dll could not be found. To fix this, I should install MVC packages, which I don't like for just an experiment.
My questions are:
do I get it right that the URL is in lower case, i.e., not .../api/Abc ?
does this kind of routing work in the debugger?
am I essentially turning the web site into an MVC web site?
is this really the simplest way to add a "REST" service to an existing web site? I only need to implement the POST, read and return some JSON data, and do not need arguments in the URL

How do I create pages in a web api project?

I want to display a default status page for my web api project (where instead some IIS message is displayed when I start the project). However it seems like I cannot create views in web api (there is no support for ActionResult).
In addition to a status page I will also use this information to create an api documentation page.
How can I achieve displaying html pages in this situation ?
If your default status page is static html, you don't have to use MVC. Just tell WebApi in your Startup.cs that you want to support static resources:
app.UseFileServer();
For creating an API documentation, maybe you could write that file on startup dynamically?
You can create regular controllers and views in a webAPI project the same as any MVC project. Just create a normal controller that does not inherit from ApiController. In your startup.cs make sure to configure at least a default route.
configuration.Routes.MapHttpRoute(
name: "someName",
routeTemplate: "{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
Right click and select Add, then you should see controller at the top. Select one of the mvc controllers.

Are ASP.NET MVC routes cached?

I added a route to my asp.net mvc application to handle some json requests I need to do. This works great on my development pc, however when I installed in QA, the route isn't working at all. I tried to physically type in the address and get a "Bad Request". Can anyone assist with this? I have restarted IIS to try to clear any cache but still no luck. First time, I've seen this as I've made several changes to routes before.
routes.MapRoute(
"FsrProblemTypesByEquipment",
"Fsr/ProblemTypesByEquipment/{equipmentID}",
new {controller = "Fsr", action = "ProblemTypesByEquipment", equipmentID = ""});
Do you still get a "bad request" if you take out the new route entry, but use the same test URL? If it is really a problem with your routing table, then your catchall route should get the request.
My guess is that the request is never getting to your routing table; IIS is catching the request before it gets passed to your application. If that is true, then it is a configuration problem in IIS, or IIS is unhappy with the construction of the URL for some reason.
See this forum post for more information:
http://forums.asp.net/p/1458130/3343674.aspx

Categories