我在使用Breeze消费OData服务时出现问题,我通过跟随this guide设置了一个Web API OData服务,来自Fiddler,它按预期工作得很好,但是当我尝试使用它时很轻松它失败并给出错误消息“OK”:
[Q] Unhandled rejection reasons (should be empty):Error: OK
使用fiddler我看到它去查询元数据然后查询正确返回的实体,这可能是什么问题?
breeze.config.initializeAdapterInstances({ dataService: "OData" });
var manager = new breeze.EntityManager(serverAddress);
var query = new breeze.EntityQuery.from("Laboratories");
manager.executeQuery(query).then(function (data) {
ko.applyBindings(data);
}).fail(function (e) {
alert(e);
});
我通过使用ASP.NET Web API CORS support的每晚构建来启用CORS,它一切正常,我可以检索实体,因为我可以在提琴手中看到它们被返回...这只是它不会去然后承诺失败了。
更新
为了回应新创建项目的@Ward测试,我做了以下工作:
PROJECT 1
创建了一个Web API项目。
从Nuget添加了Microsoft ASP.MET Web API跨源资源共享(CORS)参考。
添加了以下控制器:
namespace CORSBreezeTest1.Controllers
{
public class ValuesController : EntitySetController<Value, int>
{
ValuesDbContext _context = new ValuesDbContext();
[Queryable]
public override IQueryable<Value> Get()
{
return _context.Values;
}
protected override Value GetEntityByKey(int key)
{
return _context.Values.Find(key);
}
protected override Value CreateEntity(Value entity)
{
Value value = _context.Values.Find(entity.Id);
if (value != null)
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.Conflict));
}
_context.Values.Add(entity);
_context.SaveChanges();
return entity;
}
protected override int GetKey(Value entity)
{
return entity.Id;
}
protected override void Dispose(bool disposing)
{
_context.Dispose();
base.Dispose(disposing);
}
}
}
以下Code First数据库:
namespace CORSBreezeTest1
{
public class ValuesDbContext : DbContext
{
public ValuesDbContext()
: base("DefaultConnection")
{
}
public DbSet<Value> Values { get; set; }
}
public class Value
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public int Quantity { get; set; }
}
}
在WebApiConfig.cs
public static void Register(HttpConfiguration config)
{
// Default code left out here ...
config.Routes.MapODataRoute("Values", "odata", GetEdmModel());
config.EnableQuerySupport();
config.EnableCors(new EnableCorsAttribute("*", "*", "*"));
}
private static IEdmModel GetEdmModel()
{
ODataModelBuilder builder = new ODataConventionModelBuilder();
builder.Namespace = "CORSBreezeTest1";
builder.EntitySet<Value>("Values");
return builder.GetEdmModel();
}
PROJECT 2 然后创建了另一个Web API项目。
为ASP.NET Web API项目Nuget包添加了Breeze
添加了datajs Nuget Package。
将以下代码行添加到Index.cshtml
:
<p data-bind="visible: !results">Fetching data ... </p>
<ul data-bind="foreach: results, visible: results" style="display: none">
<li>
<span data-bind="text: Name"></span>
<span data-bind="text: Quantity"></span>
</li>
</ul>
@section Scripts {
<script src="~/Scripts/knockout-2.2.0.debug.js"></script>
<script src="~/Scripts/q.js"></script>
<script src="~/Scripts/datajs-1.1.0.js"></script>
<script src="~/Scripts/breeze.min.js"></script>
<script type="text/javascript">
$(function () {
breeze.config.initializeAdapterInstances({ dataService: "OData" });
var manager = new breeze.EntityManager("http://serverAddress/odata")
var query = new breeze.EntityQuery.from("Values");
manager.executeQuery(query).then(function (data) {
ko.applyBindings(data);
}).fail(function (e) {
alert(e);
});
});
</script>
}
按原样测试,因为两个网站都在localhost上,所以它有效。
将PROJECT 1发布到Web服务器,以便测试实际上会看到不同的来源并进行测试。
这就是Nugget所看到的:
第一个请求标题是OPTIONS
OPTIONS /odata/Values HTTP/1.1
第二个请求标题是GET
GET /odata/Values HTTP/1.1
如果我将fail
代码更改为:
fail(function (e) {
ko.applyBindings(e.body.value);
});
我的淘汰代码:
<p data-bind="visible: !$data">Fetching data ... </p>
<ul data-bind="foreach: $data, visible: $data" style="display: none">
<li>
<span data-bind="text: Name"></span>
<span data-bind="text: Quantity"></span>
</li>
</ul>
瞧!它来自数据:
这就是控制台所看到的:
SEC7118: XMLHttpRequest for http://serverAddress/odata/$metadata required Cross Origin Resource Sharing (CORS).
localhost:53317
SEC7119: XMLHttpRequest for http://serverAddress/odata/$metadata required CORS preflight.
localhost:53317
SEC7118: XMLHttpRequest for http://serverAddress/odata/Values required Cross Origin Resource Sharing (CORS).
localhost:53317
SEC7119: XMLHttpRequest for http://serverAddress/odata/Values required CORS preflight.
localhost:53317
[Q] Unhandled rejection reasons (should be empty):Error: OK
PROJECTS 1&amp; 2 使用BreezeControllerAttribute
如果我在另一个测试中添加Breeze Nuget example之后的新控制器并添加Breeze for ASP.NET Web API项目Nuget包并添加以下控制器:
namespace CORSBreezeTest1.Controllers
{
[BreezeController]
public class BreezeValuesController : ApiController
{
readonly EFContextProvider<ValuesDbContext> _context =
new EFContextProvider<ValuesDbContext>();
[HttpGet]
public string Metadata()
{
return _context.Metadata();
}
[HttpGet]
public IQueryable<Value> Values()
{
return _context.Context.Values;
}
[HttpPost]
public SaveResult SaveChanges(JObject saveBundle)
{
return _context.SaveChanges(saveBundle);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
}
}
}
然后按如下方式修改客户端:
//breeze.config.initializeAdapterInstances({ dataService: "OData" });
var manager = new breeze.EntityManager("http://serverAddress/breeze/BreezeValues")
然后请求发生变化:
一切正常......我不确定EntitySetController
部分处理请求的方式是不是,或者在更改dataService
时Breeze会发出不同的请求。
答案 0 :(得分:0)
我还不知道答案。但是你的问题中存在一些误解。首先,CORS是一种浏览器约定。这是一种(相对)安全的方法来解决浏览器“同源”政策。
这是浏览器政策。 Fiddler不是浏览器。它不受“同源”策略的约束,可以愉快地跨域读写。因此,根据Fiddler中的情况,您无法判断服务器是否针对CORS正确配置。
当然“托管Web API的同一站点中的相同代码可以完美地运行”;您没有违反“同源”政策,因此不涉及CORS。
您需要编写一个浏览器客户端应用程序来测试您的服务器配置,该应用程序从Web API主机以外的站点启动。它不一定是一个轻而易举的客户端。对端点的简单AJAX调用就可以了。您也可以编写另一个简单的非Breeze Web API控制器。保持两个控制器非常简单。保持测试客户端非常简单。
我敢打赌,使用breeze-enabled和vanilla Web API控制器会遇到同样的问题。你可以通过它。当你这样做时,它应该适用于微风和香草控制器。如果您可以证明您的客户使用其中一个而不是另一个,请返回并向我们提供代码。
抱歉你的痛苦。
答案 1 :(得分:0)
让它发挥作用的唯一方法是使用来自Breeze.WebApi的BreezeControllerAttribute
,遵循使用api的微风。不使用EntitySetController
并返回常规ApiController
。问题本身的详细解释。
[BreezeController]
public class BreezeValuesController : ApiController
{
// Methods here
}
答案 2 :(得分:0)
您只需添加此额外参数DataServiceVersion
,MaxDataServiceVersion
配置enableCors。
config.EnableCors(new EnableCorsAttribute("*", "*", "*", "DataServiceVersion, MaxDataServiceVersion"));