在 ASP.NET Core 中启用跨域资源共享 (CORS)





5.00/5 (6投票s)
在本文中,我们将重点介绍如何在 ASP.NET Core 应用程序中启用 CORS,了解 CORS 策略,以及如何通过不同的源共享资源。
本文将讨论以下主题
- 什么是 CORS?
- 创建 .NET Core WebApi 应用程序
- 添加包
- 添加数据库连接
- 启用 CORS
- 发布到 IIS
- 通过 .NET Core 示例应用程序共享
引言
首先让我们了解一下 CORS,来自 Wikipedia,跨域资源共享 (CORS) 是一种机制,允许从源资源域之外的另一个域请求网页上受限制的资源(例如,字体)。从 docs.asp.net 获取更多详细信息。 好吧,让我们从一个示例应用程序开始我们的主题。
创建新应用程序
打开 Visual Studio 2015,然后转到顶部菜单并单击“文件” > “新建” > “项目”。
选择 Web API 模板。
最后,将出现 .NET Core 欢迎页面。 阅读有关 .NET Core 的更多信息。
首先,我们需要将所需的包添加到示例应用程序中,这里我们将下面列出的那些包添加到 project.json 文件中。 将所有这些包放入我们的项目配置文件后,它们将自动添加到我们的应用程序中。
project.json
//EntityFrameworkCore
"Microsoft.EntityFrameworkCore.SqlServer": "1.0.1",
"Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
"Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.1",
"Microsoft.EntityFrameworkCore": "1.0.1",
//Cross Origin Resource Sharing
"Microsoft.AspNetCore.Cors": "1.0.0"
现在让我们将数据库连接添加到我们的应用程序。 打开 appsettings.json 文件,我们已将数据库连接字符串放在此处,您可以从下面的代码部分看到。
appsettings.json
{
"ConnectionStrings": {
"dbConn": "Server=DESKTOP-JAKRV2S;Database=PhoneBook;Trusted_Connection=True;
MultipleActiveResultSets=true"
},
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}
之后,我们需要在 Startup.cs 的应用程序中间件中调用它。
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
//Add database services.
var connectionString = this.Configuration.GetConnectionString("dbConn");
services.AddDbContext<PhoneBookContext>
(options => options.UseSqlServer(connectionString));
}
现在,我们将向示例 API 应用程序添加并启用 CORS。 从解决方案资源管理器中打开 Startup.cs 文件,正如您所看到的,我已在 ConfigureServices
方法中添加了 CORS 服务,以通过在运行时调用来启用它。 在这里,我们还通过使用 CorsPolicyBuilder
指定了不同的 CORS 启用策略。 您可以使用此示例应用程序启用不同类型进行测试。
Startup.cs:ConfigureServices
services.AddCors(
options => options.AddPolicy("AllowCors",
builder =>
{
builder
//.WithOrigins("https://:4456") //AllowSpecificOrigins;
//.WithOrigins("https://:4456",
"https://:4457") //AllowMultipleOrigins;
.AllowAnyOrigin() //AllowAllOrigins;
//.WithMethods("GET") //AllowSpecificMethods;
//.WithMethods("GET", "PUT") //AllowSpecificMethods;
//.WithMethods("GET", "PUT", "POST") //AllowSpecificMethods;
.WithMethods("GET", "PUT",
"POST", "DELETE") //AllowSpecificMethods;
//.AllowAnyMethod() //AllowAllMethods;
//.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header");
//AllowSpecificHeaders;
.AllowAnyHeader(); //AllowAllHeaders;
})
);
让我们分离代码
通过 Origin:使用全部、多个或特定 Origin 启用 CORS
允许特定 Origin
builder.WithOrigins("https://:4456")
允许多个 Origin
builder.WithOrigins("https://:4456", "https://:4457")
允许所有 Origin
builder.AllowAnyOrigin()
通过 Methods:使用全部、多个或特定 Methods 启用 CORS
允许特定 Methods
builder.WithMethods("GET", "PUT", "POST", "DELETE")
允许所有 Methods
builder.AllowAnyMethod()
通过 Headers:使用全部或特定 Headers 启用 CORS
允许特定 Headers
builder.WithHeaders("Accept", "Content-type", "Origin", "X-Custom-Header")
允许所有 Headers
builder.AllowAnyHeader()
之后,我们使用扩展方法“UseCors
”为您的应用程序启用了 CORS。
Startup.cs:Configure
//Enable CORS policy "AllowCors"
app.UseCors("AllowCors");
最后是完整的 Startup.cs:
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
if (env.IsEnvironment("Development"))
{
// This will push telemetry data through Application Insights pipeline faster,
// allowing you to view results immediately.
builder.AddApplicationInsightsSettings(developerMode: true);
}
builder.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
//Add database services.
var connectionString = this.Configuration.GetConnectionString("dbConn");
services.AddDbContext<PhoneBookContext>
(options => options.UseSqlServer(connectionString));
// Add framework services.
services.AddApplicationInsightsTelemetry(Configuration);
services.AddMvc();
//Add CORS services.
//services.Configure<MvcOptions>(options =>
//{
// options.Filters.Add
// (new CorsAuthorizationFilterFactory("AllowSpecificOrigin"));
//});
services.AddCors(
options => options.AddPolicy("AllowCors",
builder =>
{
builder
//.WithOrigins("https://:4456") //AllowSpecificOrigins;
//.WithOrigins("https://:4456", "https://:4457")
//AllowMultipleOrigins;
.AllowAnyOrigin() //AllowAllOrigins;
//.WithMethods("GET") //AllowSpecificMethods;
//.WithMethods("GET", "PUT") //AllowSpecificMethods;
//.WithMethods("GET", "PUT", "POST")
//AllowSpecificMethods;
.WithMethods("GET", "PUT", "POST", "DELETE")
//AllowSpecificMethods;
//.AllowAnyMethod() //AllowAllMethods;
//.WithHeaders("Accept",
//"Content-type", "Origin", "X-Custom-Header");
//AllowSpecificHeaders;
.AllowAnyHeader(); //AllowAllHeaders;
})
);
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline
public void Configure
(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseApplicationInsightsRequestTelemetry();
app.UseApplicationInsightsExceptionTelemetry();
app.UseMvc();
//Enable CORS policy "AllowCors"
app.UseCors("AllowCors");
}
}
MVC WebApi:这是必需的命名空间列表。
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Cors;
using CrossOrigin.WebService.Models.DbEntities;
using Microsoft.EntityFrameworkCore;
API 控制器:在这里,我们在 APiController
上应用特定的 CORS 策略。 它也可以应用于基于每个操作,或全局应用于所有控制器。
[EnableCors("AllowCors"), Route("api/[controller]")]
public class ContactController : Controller
{
private PhoneBookContext _ctx = null;
public ContactController(PhoneBookContext context)
{
_ctx = context;
}
// GET: api/Contact/GetContact
[HttpGet("GetContact"), Produces("application/json")]
public async Task<object> GetContact()
{
List<Contacts> contacts = null;
object result = null;
try
{
using (_ctx)
{
contacts = await _ctx.Contacts.ToListAsync();
result = new
{
contacts
};
}
}
catch (Exception ex)
{
ex.ToString();
}
return contacts;
}
// GET api/Contact/GetContactByID/5
[HttpGet("GetContactByID/{id}"), Produces("application/json")]
public async Task<Contacts> GetContactByID(int id)
{
Contacts contact = null;
try
{
using (_ctx)
{
contact = await _ctx.Contacts.FirstOrDefaultAsync(x => x.ContactId == id);
}
}
catch (Exception ex)
{
ex.ToString();
}
return contact;
}
// POST api/Contact/PostContact
[HttpPost, Route("PostContact"), Produces("application/json")]
public async Task<object> PostContact([FromBody]Contacts model)
{
object result = null; string message = "";
if (model == null)
{
return BadRequest();
}
using (_ctx)
{
using (var _ctxTransaction = _ctx.Database.BeginTransaction())
{
try
{
_ctx.Contacts.Add(model);
await _ctx.SaveChangesAsync();
_ctxTransaction.Commit();
message = "Saved Successfully";
}
catch (Exception e)
{
_ctxTransaction.Rollback();
e.ToString();
message = "Saved Error";
}
result = new
{
message
};
}
}
return result;
}
// PUT api/Contact/PutContact/5
[DisableCors, HttpPut, Route("PutContact/{id}")]
public async Task<object> PutContact(int id, [FromBody]Contacts model)
{
object result = null; string message = "";
if (model == null)
{
return BadRequest();
}
using (_ctx)
{
using (var _ctxTransaction = _ctx.Database.BeginTransaction())
{
try
{
var entityUpdate = _ctx.Contacts.FirstOrDefault(x => x.ContactId == id);
if (entityUpdate != null)
{
entityUpdate.FirstName = model.FirstName;
entityUpdate.LastName = model.LastName;
entityUpdate.Phone = model.Phone;
entityUpdate.Email = model.Email;
await _ctx.SaveChangesAsync();
}
_ctxTransaction.Commit();
message = "Entry Updated";
}
catch (Exception e)
{
_ctxTransaction.Rollback(); e.ToString();
message = "Entry Update Failed!!";
}
result = new
{
message
};
}
}
return result;
}
// DELETE api/Contact/DeleteContactByID/5
[HttpDelete, Route("DeleteContactByID/{id}")]
public async Task<object> DeleteContactByID(int id)
{
object result = null; string message = "";
using (_ctx)
{
using (var _ctxTransaction = _ctx.Database.BeginTransaction())
{
try
{
var idToRemove = _ctx.Contacts.SingleOrDefault(x => x.ContactId == id);
if (idToRemove != null)
{
_ctx.Contacts.Remove(idToRemove);
await _ctx.SaveChangesAsync();
}
_ctxTransaction.Commit();
message = "Deleted Successfully";
}
catch (Exception e)
{
_ctxTransaction.Rollback(); e.ToString();
message = "Error on Deleting!!";
}
result = new
{
message
};
}
}
return result;
}
}
我们可以使用属性“DisableCors
”禁用 CORS。 在此控制器中,我们已将其应用于“PUT
”方法以禁用 CORS。
发布到 IIS
我们需要为 ASP.NET Core 应用程序准备服务器以进行托管。 获取有关 发布 .NET Core 应用程序 的更多详细信息。 我们使用了 localhost 并分配了端口 8081 以通过我们的共享应用程序进行访问。 https://:8081
让我们使用 https://:8081 url 浏览我们的应用程序,正如您所看到的,我们的 API 正在使用 JSON 数据响应。
现在,是时候访问共享资源了。 我已将 现有示例应用程序添加到此解决方案。 以下是我所做的简单更改,以通过来自不同源的 API 访问资源。
共享资源
public _saveUrl: string = 'https://:8081/api/Contact/PostContact';
public _updateUrl: string = 'https://:8081/api/Contact/PutContact';
public _getUrl: string = 'https://:8081/api/Contact/GetContact';
public _getByIdUrl: string = 'https://:8081/api/Contact/GetContactByID';
public _deleteByIdUrl: string = 'https://:8081/api/Contact/DeleteContactByID';
在这里,我们尝试通过 https://:8081 访问资源,但发生服务器错误,如下所示。
启用 CORS 后,我们成功地通过 Web API 访问了共享资源。
输出
源代码:我已将完整的源代码上传到 download/clone @github,希望这对您有所帮助。 :)