为什么此 AJAX.Helper Post 调用会出现实体框架错误,而 "Get" 不会?

Why Does This AJAX.Helper Post call get a Enity Framework Error, but the "Get" doesn't?

作为一个学习项目,我有一个 MVC & Typescript 项目和一个 Web 2.0 & entity framework 项目,MVC 项目试图与 Web 2.0 项目对话,但我遇到了一个奇怪的错误。

这是我的网站API 2.0 播放器控制器:

 public class PlayerController : ApiController
{

    // GET api/<controller>/5
    public Player Get(int? id)
    {
        if (id == null || id == -1)
        {

            var player = new Player();
            LeaderBoardContext.Current.Players.Add(player);
            LeaderBoardContext.Current.SaveChanges();
            return player;
        }
        return LeaderBoardContext.Current.Players.FirstOrDefault(x => x.PlayerId == id);
    }


    // PUT: api/Scores/5
    [ResponseType(typeof(void))]
    public IHttpActionResult PostPlayer(LearningCancerAPICalls.Models.Player player)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        var model = LeaderBoardContext.Current.Players.FirstOrDefault(x => x.PlayerId == player.PlayerId);
        LeaderBoardContext.Current.Entry<Player>(player).State = EntityState.Modified;

        try
        {
            LeaderBoardContext.Current.SaveChanges();
        }
        catch (DbUpdateConcurrencyException)
        {

        }
        return StatusCode(HttpStatusCode.NoContent);
    }
}

此时它经历了几次迭代,有一次它在文件顶部初始化自己的数据库上下文,但在 post 期间它神秘地为空。所以现在我正在使用我们在其他项目中使用的样式,如下所示:

public static LeaderBoardContext Current
    {
        get
        {
            try
            {
                //added because 'HttpContext.Current.Items["_EntityContext"] ' was mysteriously comming back null....
                if (HttpContext.Current.Items["_EntityContext"] == null)
                {
                    HttpContext.Current.Items["_EntityContext"] = new LeaderBoardContext();
                }

                var obj = HttpContext.Current?.Items["_EntityContext"] as LeaderBoardContext;
                return obj;
            }
            catch (Exception) //should only get here if using background task
            {
                return null;
            }
        }
    }

所以第一个奇怪的是在post上下文中坚持为null,但是通过上面的复杂方法强制它不为null并没有太大改善这种情况。请注意我现在放入的第一个 EF 调用基本上与 GET:

相同
var model = LeaderBoardContext.Current.Players.FirstOrDefault(x => x.PlayerId == player.PlayerId);

我在两种样式中都调用了 GET(使用 -1,具有有效 ID)并且工作正常,但是 POST 到目前为止导致了这个错误:

我通常会将其与初始化不当的 EF 项目相关联,但 GET 有效!它做的正是它应该做的。我什至尝试 post 使用不同型号的 EF 脚手架控制器,但遇到了同样的问题!

两者之间的主要区别(GET/POST除外)是我调用它们的方式,这就是我使用 GET 的方式:

    var playerId = -1;
var activeUser:Player;
function initPlayerOnGameStart() {
    if (host === undefined) {
        host = 'http://localhost:52316';
    }
    if (playerId === undefined) {
        playerId = -1;
    }
    var uri = host + '/api/Player/' + playerId;
    jQuery.getJSON(uri).done(data => {
        activeUser = data;
        playerId = activeUser.PlayerId;
    });

}

在纯 Typescript Json 调用中。做 POST 我正在试验 AJAX.Helper:

    @model LearningCancerAPICalls.Models.Player

<a id="contact-us">Share Score!</a>
<div id="contact-form" class="hidden" title="Online Request Form">
    @using (Ajax.BeginForm("", "", null, new AjaxOptions
    {
        HttpMethod = "POST", Url = "/api/Player",
        OnSuccess ="OnSuccess",
        OnFailure ="OnFailure" 
    }, new { id = "formId", name = "frmStandingAdd" }))
    {
        @Html.LabelFor(m => m.PlayerName);
        @Html.TextBoxFor(m => m.PlayerName);
        @Html.LabelFor(m => m.Email);
        @Html.TextBoxFor(m => m.Email);
        @Html.HiddenFor(m => m.PlayerId);
        @Html.Hidden( "PlayerId");
         <input type="submit" name="submit" value="Ok" />

    }
</div>

<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script>
    function OnSuccess() {
        alert('Success');
    }
    function OnFailure(ajaxContext) {

        alert('Failure');
    }

</script>

我从打字稿中设置 PlayerID 的地方。这成功调用了 post 但在首次使用 EF 时崩溃。另一个奇怪的事情是,如果我在 post 上进行调试。该模型似乎不正确,因为当我将鼠标悬停在它上面时,它显示为一个 Player 模型,没有铸造错误,但它不允许我扩展它的属性。如果我使用变量或立即 window 来检查变量,那么它们都很好。但我认为值得一提。

稍后我将尝试纯 ajax 调用,看看它是否解决了问题,但我不明白为什么 Ajax.helper 会在这里出错,它在技术上完成了它的工作错误与我看到的模型无关。

更新 1 所以我尝试了纯 ajax 调用:

Html:

 Name: <input type="text" name="fname" id="userName"><br />
        <button onclick="postJustPlayer()"> Ok </button>

打字稿

function postJustPlayer() {
    let level = jQuery("#chooseGridLevel").val();
    let name = jQuery("#userName").val();
    let uri = host + '/api/Player';
    let player: Player = <Player>{};


    player.Email = "Testing";
    player.PlayerName = name;
    jQuery.post(uri, player);
}

可行!??我不知道为什么纯 jQuery 有效,就 EF 而言,它肯定会做同样的事情吗?为什么 AJAX.helper post 会有所不同...

解决了!这是一个真正的难题,只有当我深入研究网络数据(工具 ftw)时才解决。

对于其他网络新手,我将解释我是如何找到这个问题的路径的。在 Chrome Dev Tools 中有一个 Network 选项卡,可以显示您的 Web 请求和响应。因此,通过在单击我的确定按钮后打开它,我可以看到我的纯 AJAX 调用:

然后我可以将其与我在 ajax 表单上单击 "Submit" 时进行比较:

我将这些都复制并粘贴到 KDiff3 中,这突出了一个非常重要的区别 本地主机地址

你会注意到我在纯 ajax 请求中指定了主机,这是因为正如我提到的,我的 web api 项目和我的网站项目是分开的,因此它们在不同的主机上!

所以,实际上,AJAX 助手调用永远不会起作用,但就在我决定在我的网站项目中需要一个来自 API 项目的模型的前一天,当时想"I probably shouldn't include my API project as a reference in my main website, but just for now...."。所以这导致 API 调用错误的主机有效!当然,根本区别在于 EF 未在 THAT 主机上设置。

可怜的 ajax 老帮手因为一个只有特殊类型的白痴设置才会导致的错误而受到我的大量诅咒。更改 ajax 助手以使用完整路径:

    @model LearningCancerAPICalls.Models.Player

<a id="contact-us">Share Score!</a>
<div id="contact-form" class="hidden" title="Online Request Form">
    @using (Ajax.BeginForm("", "", null, new AjaxOptions
    {
        HttpMethod = "POST", Url = "http://localhost:52316/api/Player",
        OnSuccess ="OnSuccess",
        OnFailure ="OnFailure" 
    }, new { id = "formId", name = "frmStandingAdd" }))
    {
        @Html.LabelFor(m => m.PlayerName);
        @Html.TextBoxFor(m => m.PlayerName);
        @Html.LabelFor(m => m.Email);
        @Html.TextBoxFor(m => m.Email);
        @Html.HiddenFor(m => m.PlayerId);
        @Html.Hidden( "PlayerId");
         <input type="submit" name="submit" value="Ok" />

    }
</div>

<script src="@Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script>
    function OnSuccess() {
        alert('Success');
    }
    function OnFailure(ajaxContext) {

        alert('Failure');
    }

</script>

问题解决了!感谢任何为这个问题挠头的人,希望这个奇怪错误的分解对某些人有用。