CORS using asp.net web api 2 odata and breeze - c#

I have problem consuming my OData with Breeze. My api is hosted on another server, and I'm using asp.net web api 2.0 (which comes with VS 2013 preview). I know web api is properly configured for CORS, because I've tested it without breeze, and it worked fine.
Here is web api 2.0 code which enables CORS:
var cors = new EnableCorsAttribute("http://localhost:7122/", "*", "*");
config.EnableCors(cors);
Here is my IEdmModel
private static IEdmModel CreateModel()
{
var modelBuilder = new ODataConventionModelBuilder {Namespace = "Test.Domain.Model"};
modelBuilder.EntitySet<MuscleGroup>("MuscleGroup");
modelBuilder.EntitySet<Exercise>("Exercises");
modelBuilder.EntitySet<ExerciseCategory>("ExerciseCategories");
modelBuilder.EntitySet<Muscle>("Muscle");
return modelBuilder.GetEdmModel();
}
Here is controller:
[EnableCors(origins: "http://localhost:7122", headers: "*", methods: "*")] //this enables CORS for controller
public class MuscleGroupController : EntitySetController<MuscleGroup, int>
{
private readonly DatabaseContext _databaseContext = new DatabaseContext();
[Queryable]
public override IQueryable<MuscleGroup> Get()
{
return _databaseContext.MuscleGroups;
}
protected override MuscleGroup GetEntityByKey(int key)
{
return _databaseContext.MuscleGroups.Find(key);
}
}
Here is how I consume OData using breeze:
app.adminMuscleGroup.dataService = ( function(breeze, logger) {
breeze.config.initializeAdapterInstances({ dataService: "OData" });
var servicename = "http://localhost:23758/odata/";
var manager = new breeze.EntityManager(servicename);
manager.enableSaveQueuing(true);
var dataService = {
getAll: getAll,
};
return dataService;
function getAll() {
var query = breeze.EntityQuery.from("MuscleGroup").orderBy("Name");
return manager.executeQuery(query);
}
And here is error I get:
Failed to load resource: the server responded with a status of 400 (Bad Request) http://localhost:23758/odata/$metadata
Failed to load resource: Origin http://localhost:7122 is not allowed by Access-Control-Allow-Origin. http://localhost:23758/odata/$metadata
XMLHttpRequest cannot load http://localhost:23758/odata/$metadata. Origin http://localhost:7122 is not allowed by Access-Control-Allow-Origin. MuscleGroup:1
[Q] Unhandled rejection reasons (should be empty):
Array[0]
q.js:891
Error: Metadata query failed for: http://localhost:23758/odata/$metadata; Logger.js:52
What I don't get is why url for query is: http://localhost:23758/odata/$metadata instead of http://localhost:23758/odata/$metadata#MuscleGroup
I know this answer explains how to use breeze with CORS, but I believe this was prior web api 2 and that I don't need to write class for CORS handling as I can do it now with:
var cors = new EnableCorsAttribute("http://localhost:7122/", "*", "*");
Long story short, my api handles CORS well (I've tested it) but for some reason it doesn't work with breeze.
EDIT
I've deleted this line [EnableCors(origins: "http://localhost:7122", headers: "*", methods: "*")] from controller, and just enabled CROS globbaly, but now I get this error:
[Q] Unhandled rejection reasons (should be empty):
Array[0]
q.js:891
Error: Metadata query failed for http://localhost:23758/odata/$metadata; Unable to process returned metadata: Cannot read property 'end' of null Logger.js:52
And I don't know what this property end is, as it isn't defined in my entities

var cors = new EnableCorsAttribute(
"http://localhost:7122/",
"*",
"*",
"DataServiceVersion, MaxDataServiceVersion"
);
config.EnableCors(cors);
Try adding DataServiceVersion and MaxDataServiceVersion to your EnableCorsAttribute.
This worked for me. I found it here.

Related

Why is localhost next js GetStaticProps returning 500 error against localhost C# ASP.NET Core API route

I have a C# / ASP.NET Core Web API project running on https://localhost:7001 and a next js app running on http://localhost:3000.
I can run the C# API from swagger and directly in the browser (https://localhost:7001/api/SourceSystems), but when I try to call it from the next js page using GetStaticProps, I get a 500 error.
Next.js code:
export default function Sourcesystem({systems}) {
return (
<ul>
{systems.map((system) => (
<li key={system.systemName}>{system.systemName} </li>
))}
</ul>
)
};
// This function gets called at build time
export async function getStaticProps() {
// Call an external API endpoint to get posts
const res = await fetch(
'https://localhost:7001/api/Schedules',
{
method:'GET',
}
)
const systems = await res.json()
console.log(systems);
return {
props: {
systems
},
}
}
I have added CORS to the c# code (I think) in
program.cs
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
builder =>
{
builder.WithOrigins(
"http://example.com",
"http://www.contoso.com",
"http://localhost:3000"
);
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
// add dbContext
builder.Services.AddDbContext<GdqcDevContext>(options => options.UseSqlServer("Data Source = RAZERPRO17; Initial Catalog = GDQC_dev; Integrated Security = True; Connect Timeout = 30; Encrypt = False; TrustServerCertificate = False; ApplicationIntent = ReadWrite; MultiSubnetFailover = False"));
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Next is saying the the fetch failed:
I am suspecting something still not set correctly for CORS but I have copied the CORS configuration and the middleware assignment order from documentation and other stackoverflow answers. NOTE: I am running the c# API code using the debug browser rather than directly from IIS. I have read somewhere about the OPTIONS but this is only for the full blown IIS
I have also added a CORS guard annotation to the c# controller with no success
namespace Overwatch_API.Controllers
{
[EnableCors("MyAllowSpecificOrigins")]
[Route("api/[controller]")]
[ApiController]
public class SourceSystemsController : ControllerBase
{
private readonly GdqcDevContext _context;
public SourceSystemsController(GdqcDevContext context)
{
_context = context;
}
// GET: api/SourceSystems
[HttpGet]
public async Task<ActionResult<IEnumerable<SourceSystem>>> GetSourceSystems()
...
UPDATE: It looks like Next is returning the following error message in the logging:
cause: Error: self-signed certificate
at TLSSocket.onConnectSecure (node:_tls_wrap:1538:34)
at TLSSocket.emit (node:events:513:28)
at TLSSocket._finishInit (node:_tls_wrap:952:8)
at ssl.onhandshakedone (node:_tls_wrap:733:12) {
code: 'DEPTH_ZERO_SELF_SIGNED_CERT'
I presume this is related to the SSL cert on the .net core 6 api code, as this is being called with https. How do I get next to accept a self signed cert, or build a propertly signed cert for the dev environment
This issue is common in nextjs.
I found two ways to fixed it.
1. If the issue occurs in dev environment. we can use NODE_TLS_REJECT_UNAUTHORIZED=0 to solve it.
① Overcome the DEPTH_ZERO_SELF_SIGNED_CERT on Node.js
② Self Signed SSL Certificate in NextJS
2. We also can use NODE_EXTRA_CA_CERTS to solve it. It can be used in Dev or Prod Environment.
Node TLS socket : DEPTH_ZERO_SELF_SIGNED_CERT error

What am I missing regarding the simple CORS policy?

Making a post call to the API controller and no matter how to set things up, I get this response in the browser console.
Access to XMLHttpRequest at 'http://192.168.68.107:8090/api/Files/submitfile' from origin 'http://192.168.68.100:5173' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
I have a .Net 6 Core API that I want to use in my local network. I have local IIS setup on a small server that I publish the API to. It deploys and mostly functions correctly. I have the CORS policy setup according to the docs.
var _policyName = "CorsPolicy";
builder.Services.AddCors(opt =>
{
opt.AddPolicy(name: _policyName, builder =>
{
builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod();
});
}
);
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(_policyName);
app.UseAuthorization();
app.MapControllers();
app.Run();
API functions correctly when I launch Localhost and have my front end axios post call submit to it, but it will not work when I publish to the in house web server I have.
I've setup the axios call correctly. I believe I've setup the CORS policy correctly.
Only thing I can think of is the way I have the controller setup.
I have a controller that takes a FromBody parameter and it works perfectly Cross origin. It's here
[HttpPost, Route("new-category")]
public async Task<IActionResult> AddNewCategory([FromBody] CategoryDto category)
{
try
{
await _uploadService.SaveNewCategory(category.Category);
return Ok();
}
catch (Exception)
{
throw;
}
}
This controller is the culprit. No matter what I try CORS blocks this ..
[HttpPost, Route("submitfile")]
public async Task<IActionResult> SubmitFile([FromForm] FileUploadModel file)
{
try
{
if (file.File.Length <= 0)
return BadRequest("Empty File");
//save file
var fileLocation = await _uploadService.FileUpload(file.File, file.Category);
return Ok();
}
catch (Exception ex)
{
throw;
}
}
Here's the axios method that calls this controller.. which works when running localhost
await axios.post(API + "Files/submitfile", formData, {
headers: {
"Content-Type": "multipart/form-data",
},
The above CORS response is what I get. What am I missing here? How can I resolve this error?
Thank you for taking a look. Greatly appreciate the help
I don't know why that doesn't work, but I had a similar issue until I bypassed the named policy and applied the requirements in the UseCors() method:
app.UseCors(policy => {
policy.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin();
});

React .NET Enable CORS - No 'Access-Control-Allow-Origin' header is present on the requested resource

Been attempting to integrate a React front-end with a .NET Framework backend and I am constantly coming into contact with CORS errors. The request I am sending to the server works on Postman. I extracted the code from Postman and put it into my react app (Fetch) and I receive the following error:
Access to fetch at 'http://localhost:33333/Token' 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.
However, on my .NET backend I added the following filter:
using System;
using System.Web.Mvc;
namespace TheFifth.Cors
{
public class AllowCrossSiteAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin",
"*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Headers",
"*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Credentials",
"true");
base.OnActionExecuting(filterContext);
}
}
}
Then referenced the Filter at the top of my Controller
[AllowCrossSite]
public class DA_Object
{
//some code
}
Does anyone know why my .NET backend or my React Frontend is preventing me from communicating across different ports - even though it works on Postman?
Additional Details
var myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");
var urlencoded = new URLSearchParams();
urlencoded.append("type", "x");
urlencoded.append("username", "x#x.com");
urlencoded.append("password", "x#");
var requestOptions = {
method: 'POST',
headers: myHeaders,
body: urlencoded,
redirect: 'follow'
};
fetch("http://localhost:33333/api/Token", requestOptions)
.then(response => response.text())
.then(result => console.log(result))
.catch(error => console.log('error', error));
In your startup.cs
in the ConfigureServices method you should have something like this, if you don't have then add it:
services.AddCors(options =>
{
options.AddPolicy(DefaultCorsPolicyName, builder =>
{
//App:CorsOrigins in appsettings.json can contain more than one address with splitted by comma.
builder
.AllowAnyOrigin()
.SetIsOriginAllowedToAllowWildcardSubdomains()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
And in your appsettings.json add http://0.0.0.0:80 like this:
"App": {
...
"CorsOrigins": "http://*.mycompany.com,http://0.0.0.0:80",
...}
Another solution is to add a CORS extention in your browser and enable it, but it's not recommended

CORS not working in ASP.NET Web API 2 app

You know, the usual: CORS isn't working. Chrome serves me up with this:
Fetch API cannot load https://url-to-my-api-thing. No
'Access-Control-Allow-Origin' header is present on the requested
resource. Origin 'https://url-to-the-origin-thing' is therefore not
allowed access. If an opaque response serves your needs, set the
request's mode to 'no-cors' to fetch the resource with CORS disabled.
I have an ASP.NET Web API 2 application which uses the OWIN pipeline and is hosted in IIS.
Here's how I (try to) set up CORS in my Configuration method:
// ... container setup above, CORS is the first middleware ...
var corsPolicyProvider = new CorsPolicyProvider(_corsOrigins, container.GetInstance<ILogger>);
app.UseCors(new CorsOptions
{
PolicyProvider = corsPolicyProvider
});
app.UseStageMarker(PipelineStage.Authenticate);
configuration.Services.Replace(typeof(IExceptionHandler), new PassThroughExceptionHandler());
configuration.MapHttpAttributeRoutes();
app.UseWebApi(configuration);
And here's what my CorsPolicyProvider class looks like:
public class CorsPolicyProvider : ICorsPolicyProvider
{
private readonly Regex _corsOriginsRegex;
private readonly string _defaultCorsOrigin;
private readonly Func<ILogger> _scopedLoggerCreator;
public CorsPolicyProvider(string corsOrigins, Func<ILogger> scopedLoggerCreator)
{
_corsOriginsRegex = new Regex($"({corsOrigins})", RegexOptions.IgnoreCase);
_defaultCorsOrigin = corsOrigins?.Split('|').FirstOrDefault();
_scopedLoggerCreator = scopedLoggerCreator;
}
public Task<CorsPolicy> GetCorsPolicyAsync(IOwinRequest request)
{
var logger = _scopedLoggerCreator();
var allowedOrigin = _defaultCorsOrigin;
string[] origins;
request.Headers.TryGetValue("Origin", out origins);
var origin = origins?.FirstOrDefault();
if (origin != null && Uri.IsWellFormedUriString(origin, UriKind.Absolute) && _corsOriginsRegex.IsMatch(new Uri(origin).Host))
allowedOrigin = origins.FirstOrDefault();
var policy = new CorsPolicy
{
Origins = { allowedOrigin },
Methods = { HttpMethod.Get.Method, HttpMethod.Post.Method, HttpMethod.Put.Method, HttpMethod.Delete.Method },
Headers = { "accept", "content-type" },
SupportsCredentials = true,
PreflightMaxAge = 1728000
};
logger?.Verbose("Resolving CORS policy: {#CorsPolicy}", policy);
return Task.FromResult(policy);
}
}
Why is this policy never triggered, or at best malfunctioning? If I set a breakpoint and explicitly send an OPTIONS request when testing locally, it enters the GetCorsPolicyAsync method, and also logs the request as expected. But when the API is on the server and I try to call it from a website in Chrome, it never logs the request and it just tells me there's no CORS header.
... and like clockwork, the moment I post something on SO I find the answer. There was a CORS header, and the request was being logged, but the environment had the wrong configuration, so the origin (which was then invalid since it was a different environment) was correctly being blocked, and the logs end up on the wrong server. Fixed the configuration, and it works as expected again.

Cors requests and MVC5

So I have a view on a controller ...
[AllowAnonymous]
[Route("MyView")]
public ActionResult MyView()
{
// first attempt at solving problem
Response.AddHeader("Access-Control-Allow-Origin", "*");
Response.AddHeader("Access-Control-Allow-Headers", "*");
Response.AddHeader("Access-Control-Allow-Methods", "*");
return PartialView();
}
I tried adding this attribute (2nd attempt) ...
public class AllowCors : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Origin", "*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Headers", "*");
filterContext.RequestContext.HttpContext.Response.AddHeader("Access-Control-Allow-Methods", "*");
base.OnActionExecuting(filterContext);
}
}
As im using owin to initialise my app I figured this might work (3rd attempt) ...
app.Use((context, next) =>
{
if (context.Request.Method == "OPTIONS")
{
context.Response.StatusCode = 200;
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
context.Response.Headers.Add("Access-Control-Allow-Headers", new[] { "*" });
context.Response.Headers.Add("Access-Control-Allow-Methods", new[] { "*" });
return context.Response.WriteAsync("handled");
}
return next.Invoke();
}).UseStageMarker(PipelineStage.PreHandlerExecute);
The problem is that if I just straight up ask for it by putting the url in the browser I get the right headers ...
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:*
Access-Control-Allow-Origin:*
... moving over in to postman to test this, when I issue an OPTIONS call to the same URL I get this in the headers ...
Allow: OPTIONS, TRACE, GET, HEAD, POST
... so how do I get MVC to respond correctly to the OPTIONS http verb so that I can use this view outside the domain of the site?
EDIT
it's worth noting that I have looked around already and found all these and many more ...
The requested resource does not support http method 'OPTIONS'.?
jQuery $.ajax(), $.post sending "OPTIONS" as REQUEST_METHOD in Firefox
AJAX in Chrome sending OPTIONS instead of GET/POST/PUT/DELETE?
Why does this jQuery AJAX PUT work in Chrome but not FF
How to support HTTP OPTIONS verb in ASP.NET MVC/WebAPI application
... i'm also very familiar with using CORS and making CORS requests in to WebAPI, but for some reason I can't seem to make a CORS request in to MVC without getting this seemingly "dummy" response back.
I think what I need is a means to override / replace the MVC default behaviour to this HttpVerb based request to allow me to embed views in a remote site.
Install these two nuget packages:
Microsoft.AspNet.Cors
Microsoft.Owin.Cors
Then in your Startup.cs add this line inside the Configuration function:
public partial class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureAuth(app);
app.UseCors(CorsOptions.AllowAll);
}
}
In my demo setup I'm sending a post request from the domain http://example.local (Apache) to the domain http://localhost:6569/ (IIS Express).
Without app.UseCors(CorsOptions.AllowAll); (notice the warning in the console and no CORS headers):
And after adding the packages and adding the line to the Configuration method:
As you can see in the screenshot, the access-control-allow-origin was added in the response headers as expected/

Categories

Resources