I created a simple api in .net core and trying to access that from react app, I get a CORS error. I enabled cors by following CORS with default policy and middleware section on
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1
still I get cors error in my react app. not exactly sure where I am getting it wrong.
.net core api
namespace React_NalONE_API
{
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
// options.AddPolicy(name: MyAllowSpecificOrigins,
// builder =>
// {
// builder.WithOrigins("http://localhost/*",
// "https://localhost/*");
// });
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("http://localhost/*",
"https://localhost/*");
});
});
services.AddControllers();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors(MyAllowSpecificOrigins);
});
}
}
}
React app
componentDidMount () {
console.log("The component is now mounted")
this.setState({loading : true})
fetch('https://localhost:44391/agency')
.then(data => data.json())
.then(data => this.setState({data, loading : false}))
}
error
Access to fetch at 'https://localhost:44391/agency' from origin 'http://localhost:3000' has been blocked by CORS policy: 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.
Your help is much appreciated
Thanks
R
From the document, you could know that:
Note: The specified URL must not contain a trailing slash (/). If the
URL terminates with /, the comparison returns false and no header is
returned.
For your requirement,it seems you want to allow CORS requests from all origins with any scheme (http or https),I suggest that you could use AllowAnyOrigin:
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.AllowAnyOrigin();
});
});
Reference:
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#cors-with-named-policy-and-middleware
https://learn.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1#set-the-allowed-origins
Another way is to change like below:
services.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.WithOrigins("https://localhost:44391",
"http://localhost:44391");
});
});
Related
I am doing this project, but I am having the issue of having a CORS error
Access to XMLHttpRequest at 'https://localhost:44309/api/auth/login' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
I am doing everything by the book and enabling CORS inside the startup.cs file
services.AddAutoMapper(typeof(GroupFourLibraryContext));
services.AddScoped<IUserService, UserService>();
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
builder =>
{
builder.SetIsOriginAllowed(isOriginAllowed: _ => true).AllowAnyHeader().AllowAnyMethod().AllowCredentials();
});
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "GroupFourLibrary v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors(MyAllowSpecificOrigins);
app.UseForwardedHeaders();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
Axios code.
Code returns a response and a token to login.
const response = await axios.post(authApiAddress + '/login',loginObject).then((res)=>{
}
);
if(response.status ===200){
localStorage.setItem(storageLocationConstant, response.data.message);
}
return response;
Controller code.
Controller handles the login. Calls a a ASP.Identity method to authenticate
[HttpPost]
[Route("login")]
[EnableCors("AllowOrigin")]
public async Task<IActionResult> login(LoginUserViewModel loginViewMdl)
{
if (!ModelState.IsValid)
{
return BadRequest("Login Model is not Valid or missing parameters");
}
var result = await this.usrService.LoginUser(loginViewMdl);
if (result.IsSuccess == false)
{
return BadRequest(result.Message);
}
return Ok(result);
}
Folks I'm developing a fullstack React.js - ASP.NET Core 5 application. The backend is done (fully tested). Of course it includes a CORS policy to allow request from the client side, but when I'm trying to send a request from react using axios, axios throws a network error:
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://localhost:5001/api/customers. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). Status code: 200.
I see the server sends correct responses (I can even debugged the server) but axios stills failing. I only tried to solved it by including a proxy in package.json:
"proxy": "https://localhost:5001"
I'm going to include my app.js request code and startup.cs code, since it contains the CORS Policy:
Client
const fetchCustomers = async () => {
const customers = await axios.get(customersApiUrl);
console.log(customers);
setCustomers(customers);
setIsLoading(false);
};
Server
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins("http://localhost:3000/");
builder.AllowAnyHeader();
builder.AllowAnyMethod();
});
});
services.AddControllers();
services.AddDbContextPool<TwinEnginesDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("Standard")));
services.AddScoped<ICustomerTypeRepository, CustomerTypeRepository>();
services.AddScoped<ICustomerTypeService, CustomerTypeService>();
services.AddScoped<ICustomerRepository, CustomerRepository>();
services.AddScoped<ICustomerService, CustomerService>();
services.AddAutoMapper(Assembly.GetExecutingAssembly());
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Edited: I'm including the CustomersController.cs code plus the details from the HTTP request.
CustomersController.cs
[Route("api/[controller]")]
[ApiController]
public class CustomersController : ControllerBase
{
private readonly ICustomerService _customerService;
private readonly ICustomerTypeService _typeService;
private readonly IMapper _mapper;
public CustomersController(ICustomerService customerService, ICustomerTypeService typeService, IMapper mapper)
{
this._customerService = customerService ?? throw new ArgumentNullException(nameof(customerService));
this._typeService = typeService ?? throw new ArgumentNullException(nameof(typeService));
this._mapper = mapper ?? throw new ArgumentNullException(nameof(mapper));
}
// [EnableCors("MyAllowSpecificOrigins")]
[HttpGet("")]
public async Task<ActionResult<IEnumerable<CustomerDTO>>> GetCustomers()
{
var customers = await _customerService.GetAllAsync();
var response = _mapper.Map<IEnumerable<CustomerDTO>>(customers);
return Ok(response);
}
}
Request image:
Any ideas, thoughts? I really need your help folks, this is a technical assignment for a dev job.
Try to use the setting without the
slash at the end: builder.WithOrigins("http://localhost:3000");
After the change please do a clean and rebuild the project, as it might be a thing.
Also, you don't need a proxy setting on the JS side.
P.S. A mode for the request might not be set properly on the Axios side. In case the solution above doesn't work try to use:
axios(requestURL, { mode: 'cors' })
Try to add this attribute to your controllers
[EnableCors(MyAllowSpecificOrigins)]
I am trying to send data from React App to .NET Core Web App using SignalR.
The .NET Core Web App has Windows Authentication enabled. With Windows Authentication enabled, I am getting the CORS error when my React App tries to send message to .NET Core App via SignalR.
It works fine if I disable windows authentication and enable anonymous authentication.
Can you please help me with your valuable inputs to make the connection work?
React JS app code looks like below:
const hubConnection = new HubConnectionBuilder()
.withUrl(window.config.APP_URL, options)
.withAutomaticReconnect()
.build();
this.setState({ hubConnection }, () => {
this.state.hubConnection
.start()
.then(() => console.log("SignalR Connection started!"))
.catch((err) =>
console.log("SignalR Error while establishing connection :(", err)
);
});
}
sendMessage = () => {
console.log("sendMessage() Properties: ", this.props);
const signalRMessage = {
UserName: this.props.userName,
};
this.state.hubConnection
.invoke("SendMessage", signalRMessage)
.catch((err) => console.error(err));
};
I tried to explicitly add the ‘Access-Control-Allow-Origin’ header as shown below. But still I see the CORS error.
componentDidMount() {
let options = {
httpClient: {
post: (url, httpOptions) => {
// httpOptions.headers = {
// ...httpOptions.headers,
// "Access-Control-Allow-Origin": window.config.CORS_ALLOW_ORIGIN_URL,
// //"Access-Control-Allow-Methods": "POST, GET, HEAD",
// };
// httpOptions.method = "POST";
// httpOptions.url = url;
// return httpOptions;
const headers = {
...httpOptions.headers,
"Access-Control-Allow-Origin": window.config.CORS_ALLOW_ORIGIN_URL,
"Access-Control-Allow-Methods": "POST, GET, HEAD",
};
let newResponse = {};
return axios.post(url, {}, { headers }).then(response => {
return (newResponse = {
statusCode: response.status,
statusText: response.statusText,
content: JSON.stringify(response.data)
});
});
}
}
};
Below is the CORS error that I see in console logs at React App side:
enter image description here
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddRazorPages();
services.AddCors(options =>
{
options.AddPolicy("ClientPermissionPolicy", policy =>
{
policy.WithOrigins("https://xxxx.com")
.AllowAnyHeader()
.AllowAnyMethod().AllowCredentials();
});
});
...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCors("ClientPermissionPolicy");
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapHub<TapHub>("/hubs/tap");
});
}
Went through many posts here in stackoverflow and tried below but in vain.
In Configure():
app.UseCors(builder => builder.WithOrigins("https://xxxx.com").AllowAnyMethod().AllowAnyHeader().AllowCredentials());
In ConfigureServices():
services.AddCors(options =>
{
options.AddPolicy("ClientPermissionPolicy", policy =>
{
policy.WithOrigins("https://xxxxx.com")
.AllowAnyHeader()
.AllowAnyMethod().AllowCredentials()
.SetIsOriginAllowed((host) => true);
});
});
Tried AllowAnyOrigin()
Tried removing AllowCredentials()
Like I said above, it works fine if I disable windows authentication and enable anonymous authentication. The React App successfully connects to the hub endpoint in case of anonymous authentication. The CORS error comes into picture only when I enable windows authentication. I need Windows Authentication enabled for my requirement. Requesting you to help fix the issue.
Thanks!
A bit late, however I faced similar problem right now. Even with enabled CORS, it still rejected me. In the end, I found out that problem is in the
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
When I included CORS into this part, it started to work ... finally
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors("ClientPermissionPolicy");
});
You have to place UseCors between UseRouting and UseAutorization
app.UseRouting();
app.UseCors("ClientPermissionPolicy");
app.UseAuthorization();
and maybe you can try to move AddCors to the top of ConfigureServices method
Just the test pourposes I would use this
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(o => o.AddPolicy("ClientPermissionPolicy", builder =>
{
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
}));
.....
}
only if it works, I would try to use specific origins.
For those using .NET Core 3.1, here is a COMPLETE solution (front-end to back-end):
My problem: When I enabled the windows authentication on my web API, I could not do fetch calls from my react app to my .NET Core 3.1 web API, CORS was freaking out. With Anonymous authentication it worked, but not when windows authentication is enabled.
1.launchSettings.json
this will be used only for your dev environnment, make sure windows auth is also enabled in IIS on your prod server.
{
"iisSettings": {
"windowsAuthentication": true,
"anonymousAuthentication": false,
"iisExpress": {
"applicationUrl": "http://localhost:58747",
"sslPort": 0
}
},
{... more settings if any}
}
2.Startup.cs:
CORS policy is enabled here. The order of methods is important here. Also, you don't need to set those in a web.config
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", //give it the name you want
builder =>
{
builder.WithOrigins( "http://localhost:3000", //dev site
"production web site"
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
//database services here
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
// global policy same name as in the ConfigureServices()
app.UseCors("CorsPolicy");
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
3.Controller(s):
using Microsoft.AspNetCore.Cors;
... your other usings
namespace ProjectTest.Controllers
{
[ApiController]
[EnableCors("CorsPolicy")] //THIS HERE needs to be the same name as set in your startup.cs
[Route("[controller]")]
public class FooController:Controller
{
[HttpGet("getTest")]
public JsonResult GetTest()
{
return Json("bar");
}
}
}
4.React Component fetch call example:
The "credential: 'include'" is the secret
await fetch('http://localhost:3000/Foo/getTest', {
method: 'GET',
credentials: 'include'
}).then(resp => resp.json());
As mentioned here, the problem takes place because:
IIS's Windows Auth happens before ASP.NET Core runs, the ASP.NET Core
CORS implementation isn't able to process the OPTIONS request (because
the browser won't send your Windows credentials with it). The only
real solution here is to use the IIS CORS module since it runs before
Windows Authentication and can process the unauthenticated CORS
request.
I'm trying to get my ReactJS app (on an AWS S3 machine) PUT request working with my Server API (on an AWS Windows EC2 machine). Seems I am being tripped up by the preflight message that is being sent out. I've been searching on how to handle this and came across these two stackoverflow posts:
Enable OPTIONS header for CORS on .NET Core Web API
How to handle OPTION header in dot net core web api
I've ensured IIS accepts the OPTIONS verb and have added the middleware described. I can see the OPTIONS preflight handling being called through the logging but for some reason I am still getting the CORS error. Listed the main sections of the code below, any help would be really appreciated.
ReactJS PUT request
var myHeaders = new Headers();
myHeaders.append('Accept', 'application/json');
myHeaders.append('Content-Type', 'application/json-patch+json');
var rawObject = {
Name: this.state.recipeEdit.name,
Type: this.state.recipeTypeEdit,
Description: this.state.recipeEdit.description,
Ingredients: this.state.recipeIngredients,
Steps: this.state.recipeSteps,
};
var requestOptions = {
method: 'PUT',
headers: myHeaders,
body: JSON.stringify(rawObject),
redirect: 'follow',
};
fetch(this.state.url, requestOptions)
.then((response) => response.json())
.then((data) => {
this.setState({ recipeDetail: data });
});
Middleware Class
public class OptionsMiddleware
{
private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
private readonly RequestDelegate _next;
public OptionsMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext context)
{
return BeginInvoke(context);
}
private Task BeginInvoke(HttpContext context)
{
if (context.Request.Method == "OPTIONS")
{
log.Error("Handling the OPTIONS preflight message");
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { (string)context.Request.Headers["Origin"] });
context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "Origin, X-Requested-With, Content-Type, Accept" });
context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "GET, POST, PUT, DELETE, OPTIONS" });
context.Response.Headers.Add("Access-Control-Allow-Credentials", new[] { "true" });
context.Response.StatusCode = 200;
return context.Response.WriteAsync("OK");
}
log.Error("Invoking message");
return _next.Invoke(context);
}
}
public static class OptionsMiddlewareExtentions
{
public static IApplicationBuilder UseOptions(this IApplicationBuilder builder)
{
return builder.UseMiddleware<OptionsMiddleware>();
}
}
CORS Configuration in Startup.cs
public void ConfigureServices(IServiceCollection services)
{
log.Error("Entered ConfigureServices");
try
{
#if DEBUG
services.AddCors();
#else
services.AddCors(o => o.AddPolicy("MyCorsPolicy", builder =>
{
builder.SetIsOriginAllowed((host) => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
}));
#endif
services.AddControllersWithViews().AddNewtonsoftJson();
services.AddControllersWithViews(options =>
{
options.InputFormatters.Insert(0, GetJsonPatchInputFormatter());
});
services.AddMvc(options => options.EnableEndpointRouting = false).SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddMvc(options => options.Filters.Add(typeof(homebakeExceptionFilter)));
#if USE_SQLITE
log.Error("Using SQLITE");
services.AddDbContext<SqliteDbContext>(options =>
{
options.UseSqlite("Data Source=./homebake.db");
});
#else
services.AddDbContext<AppDbContext>(options =>
{
options.UseInMemoryDatabase("homebakeapp-api-in-memory");
});
#endif
log.Error("Adding services");
services.AddScoped<IIngredientRepository, IngredientRepository>();
services.AddScoped<IRecipeStepRepository, RecipeStepRepository>();
services.AddScoped<IRecipeRepository, RecipeRepository>();
services.AddScoped<IIngredientService, IngredientService>();
services.AddScoped<IRecipeStepService, RecipeStepService>();
services.AddScoped<IRecipeService, RecipeService>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
log.Error("Adding auto mapper");
services.AddAutoMapper(typeof(Startup));
}
catch (System.Exception ex)
{
log.Error(ex.Message);
if (ex.InnerException != null )
log.Error(ex.InnerException);
}
}
private static NewtonsoftJsonPatchInputFormatter GetJsonPatchInputFormatter()
{
var builder = new ServiceCollection()
.AddLogging()
.AddMvc()
.AddNewtonsoftJson()
.Services.BuildServiceProvider();
return builder
.GetRequiredService<IOptions<MvcOptions>>()
.Value
.InputFormatters
.OfType<NewtonsoftJsonPatchInputFormatter>()
.First();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddLog4Net();
log.Error("Entered Configure");
app.UseOptions();
#if DEBUG
app.UseCors(options => options.WithOrigins("http://localhost:3000").AllowAnyMethod().AllowAnyHeader());
#else
log.Error("Using cors policy");
app.UseCors("MyCorsPolicy");
#endif
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
//app.use
app.UseHttpsRedirection();
log.Error("Using MVC");
app.UseMvc();
}
I have seen this error when the server-side CORS settings are set using both the web.config and in the code, like in your middleware, which at runtime results in duplicates and cause this type of behavior. Also, you may want to add the following to your web.config and see if it helps. This will ensure your CORS settings are only set by the code.
<httpProtocol>
<customHeaders>
<remove name="Access-Control-Allow-Headers" />
<remove name="Access-Control-Allow-Methods" />
<remove name="Access-Control-Allow-Origin" />
</customHeaders>
</httpProtocol>
In the end the issue was to do with IIS configuration. After more searching I found the solution here:
How do I enable HTTP PUT and DELETE for ASP.NET MVC in IIS?
Essentially I had to update the ExtensionlessUrlHandler-Integrated-4.0 setting to accept the PUT and DELETE verbs (access it from the Handler Mappings option in IIS) and also disable both the WebDav module and handler. After that the requests went through and were processed correctly. I'm also still running the Middleware code as detailed above in case anyone else ever comes across this issue.
What made me look at the IIS configuration was that I got the multiple entries for Access-Control-Allow-Origin if I added it to my web.config file, if so, how could it be missing when not included there. Big thanks to #Masoud Safi for al the help he gave on this too.
I am using React with Signal R
I have a standard web application that hosts my hub.
When I send messages all works perfectly in the web page for the web application
I also have a react application that is hosted on port 3000
I changed IIS Express settings as per below
<httpProtocol>
<customHeaders>
<clear />
<add name="X-Powered-By" value="ASP.NET" />
<add name="Access-Control-Allow-Origin" value="*" />
<add name="Access-Control-Allow-Headers" value="Content-Type" />
</customHeaders>
<redirectHeaders>
<clear />
</redirectHeaders>
</httpProtocol>
and my server side Startup for cors etc is below
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddCors(options =>
{
options.AddPolicy("cors",
builder =>
{
builder
.AllowAnyHeader()
.AllowAnyMethod()
.WithOrigins("http://localhost:3000");
});
});
services.AddSignalR();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseCors("cors");
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chatHub");
endpoints.MapRazorPages();
});
}
On the React side I have implemented as below
import React, { Component } from 'react';
import * as signalR from '#aspnet/signalr';
class Chat extends Component {
constructor(props) {
super(props);
this.state = {
nick: '',
message: '',
messages: [],
hubConnection: null,
};
}
componentDidMount = () => {
const protocol = new signalR.JsonHubProtocol();
const transport = signalR.HttpTransportType.WebSockets;
const options = {
transport,
logMessageContent: true,
logger: signalR.LogLevel.Trace,
};
// create the connection instance
var hubConnection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:44360/chatHub", options)
.withHubProtocol(protocol)
.build();
this.setState({ hubConnection }, () => {
this.state.hubConnection
.start()
.then(() => console.log('Connection started!'))
.catch(err => console.log('Error while establishing connection :('));
this.state.hubConnection.on('SendMessage', (user, message) => {
const text = `${user}: ${message}`;
const messages = this.state.messages.concat([text]);
console.log('ssss');
this.setState({ messages });
});
});
}
render() {
return (
<div>
<br />
<div>
{this.state.messages.map((message, index) => (
<span style={{display: 'block'}} key={index}> {message} </span>
))}
</div>
</div>
);
}
}
export default Chat;
As you can see I have connected to the exact port where my server application is
I get an entry in the log to say I am connected
However, I never actually get any messages?
My hub in the web application is shown below
"use strict";
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build();
//Disable send button until connection is established
document.getElementById("sendButton").disabled = true;
connection.on("ReceiveMessage", function (user, message) {
var msg = message.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
var encodedMsg = user + " says " + msg;
var li = document.createElement("li");
li.textContent = encodedMsg;
document.getElementById("messagesList").appendChild(li);
});
connection.start().then(function () {
document.getElementById("sendButton").disabled = false;
}).catch(function (err) {
return console.error(err.toString());
});
document.getElementById("sendButton").addEventListener("click", function (event) {
var user = document.getElementById("userInput").value;
var message = document.getElementById("messageInput").value;
connection.invoke("SendMessage", user, message).catch(function (err) {
return console.error(err.toString());
});
event.preventDefault();
});
I thought I had resolved the Cors issues but when I left the web page open for a while I got the error
Access to XMLHttpRequest at 'http://localhost:44360/chatHub/negotiate' from origin 'http://localhost:3000' 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.
Can anyone see what I have done wrong?
After hours of trying I finally got this to work
I am going to keep this question here along with my solution to help others
First - In ConfigureServices:
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddCors();
services.AddSignalR();
}
Ensuring Cors is before Signal R
Then in Configure
// Make sure the CORS middleware is ahead of SignalR.
app.UseCors(builder =>
{
builder.WithOrigins("http://localhost:3000") //Source
.AllowAnyHeader()
.WithMethods("GET", "POST")
.AllowCredentials();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<MYHubClass>("/myHub");
});
Ensuring that UseCors is before UseEndpoints
The problem is that you've defined origins both in IIS config and in code. You should only specify origins in IIS config if (1) you only trust a single origin for all applications on the server, or (2) you trust all origins for all applications on the server.
When specified in the config at server level, every http context in the pipeline has the Access-Control-Allow-Origin header added. Then, the WithOrigins(<origin>) method appends another value to it.
https://www.w3.org/TR/cors/
6.4 Implementation Considerations This section is non-normative.
Resources that wish to enable themselves to be shared with multiple
Origins but do not respond uniformly with "*" must in practice
generate the Access-Control-Allow-Origin header dynamically in
response to every request they wish to allow. As a consequence,
authors of such resources should send a Vary: Origin HTTP header or
provide other appropriate control directives to prevent caching of
such responses, which may be inaccurate if re-used across-origins.
Try to set Cors like this:
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy", builder => builder.WithOrigins("http://localhost:3000")
.SetIsOriginAllowed((host) => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
Try enabling the Access-Control-Allow-Credentials in CORS setting in your Azure Web app.
I included a screenshot