1

我在使用 Breeze 使用 OData 服务时遇到问题,我按照本指南设置了一个 Web API OData 服务,从 Fiddler 中它按预期工作得很好,但是当我尝试使用它时,它会失败并给出错误消息“好的”:

[Q] Unhandled rejection reasons (should be empty):Error: OK

使用提琴手,我看到它会查询元数据,然后查询正确返回的实体,这可能是什么问题?

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 支持启用了 CORS ,一切正常,我可以检索实体,因为我可以在提琴手中看到它们被返回......只是它没有转到然后承诺它会失败。

更新:

为了响应来自新创建项目的@Ward 测试,我执行了以下操作:

项目 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);
        }
    }
}

以及以下代码优先数据库:

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();
}

项目 2 然后创建了另一个 Web API 项目。

为 ASP.NET Web API 项目 Nuget 包添加了微风

添加了 datajs Nuget 包。

将以下代码行添加到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>
}

按原样进行测试,并且由于两个网站都在本地主机上,因此它可以正常工作。

将 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 

项目 1 和 2使用BreezeControllerAttribute

如果我在另一个测试中按照Breeze Nuget 示例添加一个新控制器,并添加 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处理请求的方式不同,还是 Breeze 在更改dataService.

4

3 回答 3

0

我还不知道答案。但是你的问题有几个误解。首先,CORS 是一种浏览器约定。这是一种(相对)安全的解决浏览器“同源”策略的方法。

这是浏览器策略。Fiddler 不是浏览器。它不受“同源”策略的限制,可以愉快地跨域读写。因此,您无法根据 Fiddler 中发生的情况判断服务器是否为 CORS 正确配置。

当然,“托管 Web API 的同一站点中的相同代码可以完美运行”;您没有违反“同源”政策,因此不涉及 CORS。

您需要通过编写一个从 Web API 主机以外的站点启动的浏览器客户端应用程序来测试您的服务器配置。它不一定是轻而易举的客户。对端点的简单 AJAX 调用就可以了。您不妨在使用时编写另一个简单的非 Breeze Web API 控制器。保持两个控制器非常简单。让您的测试客户端非常简单。

我敢打赌,你会在使用启用微风的 Web API 控制器和普通 Web API 控制器时遇到同样的问题。你会通过它的力量。当你这样做时,它应该适用于微风控制器和香草控制器。如果您可以证明您的客户可以使用其中一个但不能使用另一个,请返回并将代码提供给我们。

对不起你的痛苦。

于 2013-07-01T22:34:16.390 回答
0

让它工作的唯一方法是使用BreezeControllerAttributeBreeze.WebApi遵循使用 api 的微风精确方式。不使用EntitySetController并回到常规的ApiController. 问题本身的详细解释。

[BreezeController]
public class BreezeValuesController : ApiController
{
    // Methods here
}
于 2013-08-04T16:34:20.527 回答
0

你只需要添加这个额外的参数DataServiceVersionMaxDataServiceVersion配置 enableCors。

config.EnableCors(new EnableCorsAttribute("*", "*", "*", "DataServiceVersion, MaxDataServiceVersion"));
于 2014-05-31T17:58:37.717 回答