【问题标题】:Unable to render the response from the Joke API server to the view ASP.NET Core 5.0 MVC无法将来自 Joke API 服务器的响应呈现给视图 ASP.NET Core 5.0 MVC
【发布时间】:2021-05-14 16:35:30
【问题描述】:

这是我之前的问题Controlling a Checkbox group input type with a Radio button input type in ASP.NET Core 的后续问题,我接受了解决方案。

我无法让视图呈现来自 Joke API 服务器的响应,即使我可以看到在视图代码上设置断点的响应。

型号:

public class Joke
{
    public string type { get; set; }
    public string joke { get; set; }
    public string setup { get; set; }
    public string delivery { get; set; }
    public int id { get; set; }
    public Flags flags { get; set; }
}

控制器:

 public class JokesController: Controller
    {

        [HttpGet]
        public IActionResult GetRequestURL()
        {
            return View();
        }
        

        [HttpPost]
        public  async Task<IActionResult> GetRequestURL(string newData)
        {
            string receivedData = newData;
            List<Joke> randomJoke = new List<Joke>();

           
            using (var httpClient = new HttpClient())
            {
                using (var response = await httpClient.GetAsync(receivedData))
                {
                    string apiResponse = await response.Content.ReadAsStringAsync();
                    randomJoke = JsonConvert.DeserializeObject<List<Joke>>(apiResponse);
                }
            }
            return View(randomJoke);

           
        }
}

查看:

@model IEnumerable<Joke>
<!DOCTYPE html>
<html lang="en">
<head>
    <script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
    <script>
        var settings = {

            baseURL: "https://v2.jokeapi.dev",
            Endpoint: "joke",
            anyCategoryName: "Any",
        };
        var tryItURL = "";
        window.onload = function () { reRender(); };

        function reRender() {

            var isValid = false;
            document.getElementsByName("category").forEach(function (el) {
                if (!el.checked)
                    return;

                if (el.value == "Any") {
                    isValid = true;
                    ["cat-cb1", "cat-cb2", "cat-cb3", "cat-cb4", "cat-cb5", "cat-cb6"].forEach(function (cat) {
                        document.getElementById(cat).disabled = true;
                    });
                }
                else {
                    var isChecked = false;
                    ["cat-cb1", "cat-cb2", "cat-cb3", "cat-cb4", "cat-cb5", "cat-cb6"].forEach(function (cat) {
                        var cel = document.getElementById(cat);
                        cel.disabled = false;

                        if (cel.checked)
                            isChecked = true;
                    });

                    if (isChecked)
                        isValid = true;
                }
            });


            buildURL();

        }

        //#MARKER build URL
        function buildURL() {
            var queryParams = [];

            //#SECTION categories
            var selectedCategories = [settings.anyCategoryName];
            if (document.getElementById("Custom").checked) {
                selectedCategories = [];
                if (document.getElementById("cat-cb1").checked) {
                    selectedCategories.push("Programming");
                }
                if (document.getElementById("cat-cb2").checked) {
                    selectedCategories.push("Miscellaneous");
                }
                if (document.getElementById("cat-cb3").checked) {
                    selectedCategories.push("Dark");
                }
                if (document.getElementById("cat-cb4").checked) {
                    selectedCategories.push("Pun");
                }
                if (document.getElementById("cat-cb5").checked) {
                    selectedCategories.push("Spooky");
                }
                if (document.getElementById("cat-cb6").checked) {
                    selectedCategories.push("Christmas");
                }

                if (selectedCategories.length == 0) {
                    selectedCategories.push(settings.anyCategoryName);
                }
            }

            tryItURL = settings.baseURL + "/" + settings.Endpoint + "/" + selectedCategories.join(",");
           // tryItURL =  selectedCategories.join(",");
            if (queryParams.length > 0) {
                tryItURL += "?" + queryParams.join("&");
            }


            document.getElementById("urlBuilderUrl").innerText = tryItURL;

              $.ajax({

            type: "POST",
            url: "@Url.Action("GetRequestURL")",


                  data: { newData: tryItURL },
                  dataType: "text",
            success: function (data) {
                console.log("Success");
            },
            failure: function (errMsg) {
                console.log("Failed");
            }
        });
        }
       // var testString = settings.baseURL + "/" + settings.Endpoint + "/" + selectedCategories.join(",");


    </script>
</head>
<body>
    <form method="post" enctype="multipart/form-data" asp-action="GetRequestURL" asp-controller="Jokes">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>

        <div class="form-group">
            <label for="category" class="control-label"> Select category/categories</label>
            @*<input type="radio" value="Any" /> Any
        <input type="radio" value="Custom" name="Custom" /> Custom:*@

            <div><input type="radio" name="category" value="Any" checked="checked" id="Any" class="control-label" checked="checked" onchange="reRender()" /> Any</div>
            <div>
                <input type="radio" name="category" value="Custom" class="control-label" id="Custom" onchange="reRender()" /> Custom:
                <input type="checkbox" name="customcategory" id="cat-cb1" value="Programming" class="control-label" onchange="reRender()" /> Programming
                <input type="checkbox" name="customcategory" id="cat-cb2" value="Misc" class="control-label" onchange="reRender()" /> Misc
                <input type="checkbox" name="customcategory" id="cat-cb3" value="Dark" class="control-label" onchange="reRender()" /> Dark
                <input type="checkbox" name="customcategory" id="cat-cb4" value="Pun" class="control-label" onchange="reRender()" /> Pun
                <input type="checkbox" name="customcategory" id="cat-cb5" value="Spooky" class="control-label" onchange="reRender()" /> Spooky
                <input type="checkbox" name="customcategory" id="cat-cb6" value="Christmas" class="control-label" onchange="reRender()" /> Christmas
            </div>
            <div class="form-group">
               @* <span id="urlBuilderUrl">/Jokes/GetRequestURL</span>*@
                <button id="urlBuilderUrl" type="submit" class="btn btn-sm btn-primary">/Jokes/GetRequestURL</button>
            </div>
           
        </div>
        </form>
           
    <table class="table table-sm table-striped table-bordered m-2">
        @if(Model != null)
        {
        <tbody>
            @foreach (var joke in Model)
            {
    <tr>
        <td>@joke.id</td>
        <td>@joke.type</td>
        <td>@joke.delivery</td>
        <td>@joke.flags</td>
        <td>@joke.joke</td>
       
    </tr>
    }
        </tbody>
        }
    </table>

   
</body>
</html>

【问题讨论】:

    标签: javascript jquery asp.net-core model-view-controller asp.net-core-webapi


    【解决方案1】:

    使用 Ajax submit 请求数据。

    @model Joke
    @{
        Layout = null;
    }
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <script src="https://code.jquery.com/jquery-3.5.1.js" integrity="sha256-QWo7LDvxbWT2tbbQ97B53yJnYU3WhH/C8ycbRAkjPDc=" crossorigin="anonymous"></script>
        <script>
            var settings = {
    
                baseURL: "https://v2.jokeapi.dev",
                Endpoint: "joke",
                anyCategoryName: "Any",
            };
            var tryItURL = "";
            window.onload = function () { reRender(); };
    
            function reRender() {
    
                var isValid = false;
                document.getElementsByName("category").forEach(function (el) {
                    if (!el.checked)
                        return;
    
                    if (el.value == "Any") {
                        isValid = true;
                        ["cat-cb1", "cat-cb2", "cat-cb3", "cat-cb4", "cat-cb5", "cat-cb6"].forEach(function (cat) {
                            document.getElementById(cat).disabled = true;
                        });
                    }
                    else {
                        var isChecked = false;
                        ["cat-cb1", "cat-cb2", "cat-cb3", "cat-cb4", "cat-cb5", "cat-cb6"].forEach(function (cat) {
                            var cel = document.getElementById(cat);
                            cel.disabled = false;
    
                            if (cel.checked)
                                isChecked = true;
                        });
    
                        if (isChecked)
                            isValid = true;
                    }
                });
    
    
                buildURL();
    
            }
    
            //#MARKER build URL
            function buildURL() {
                var queryParams = [];
    
                //#SECTION categories
                var selectedCategories = [settings.anyCategoryName];
                if (document.getElementById("Custom").checked) {
                    selectedCategories = [];
                    if (document.getElementById("cat-cb1").checked) {
                        selectedCategories.push("Programming");
                    }
                    if (document.getElementById("cat-cb2").checked) {
                        selectedCategories.push("Miscellaneous");
                    }
                    if (document.getElementById("cat-cb3").checked) {
                        selectedCategories.push("Dark");
                    }
                    if (document.getElementById("cat-cb4").checked) {
                        selectedCategories.push("Pun");
                    }
                    if (document.getElementById("cat-cb5").checked) {
                        selectedCategories.push("Spooky");
                    }
                    if (document.getElementById("cat-cb6").checked) {
                        selectedCategories.push("Christmas");
                    }
    
                    if (selectedCategories.length == 0) {
                        selectedCategories.push(settings.anyCategoryName);
                    }
                }
    
                tryItURL = settings.baseURL + "/" + settings.Endpoint + "/" + selectedCategories.join(",");
               // tryItURL =  selectedCategories.join(",");
                if (queryParams.length > 0) {
                    tryItURL += "?" + queryParams.join("&");
                }
    
                document.getElementById("urlBuilderUrl").innerText = tryItURL;
            }
    
    
            $(document).ready(function () {
    
                // process the form
                $('form').submit(function (event) {
                    // process the form
                    $.ajax({
                        type: "POST", // define the type of HTTP verb we want to use (POST for our form)
                        url: "@Url.Action("GetRequestURL")", // the url where we want to POST
                        data: { newData: tryItURL }, // our data object
                        dataType: 'json' // what type of data do we expect back from the server
                    })
                    // using the done promise callback
                    .done(function (data) {
    
                         // log data to the console so we can see
                        console.log(data);
                        document.getElementById('id').innerHTML = data.id;
                        document.getElementById('joke').innerHTML = data.joke;
                        document.getElementById('safe').innerHTML = data.safe;
                        document.getElementById('category').innerHTML = data.category;
                        document.getElementById('type').innerHTML = data.type;
                        document.getElementById('lang').innerHTML = data.lang;
    
                         // here we will handle errors and validation messages
                     });
    
                    // stop the form from submitting the normal way and refreshing the page
                    event.preventDefault();
                });
    
            });
    
    
        </script>
    </head>
    <body>
        <form id="form" method="post" enctype="multipart/form-data">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    
            <div class="form-group">
                <label for="category" class="control-label"> Select category/categories</label>
                @*<input type="radio" value="Any" /> Any
                    <input type="radio" value="Custom" name="Custom" /> Custom:*@
    
                <div><input type="radio" name="category" value="Any" checked="checked" id="Any" class="control-label" checked="checked" onchange="reRender()" /> Any</div>
                <div>
                    <input type="radio" name="category" value="Custom" class="control-label" id="Custom" onchange="reRender()" /> Custom:
                    <input type="checkbox" name="customcategory" id="cat-cb1" value="Programming" class="control-label" onchange="reRender()" /> Programming
                    <input type="checkbox" name="customcategory" id="cat-cb2" value="Misc" class="control-label" onchange="reRender()" /> Misc
                    <input type="checkbox" name="customcategory" id="cat-cb3" value="Dark" class="control-label" onchange="reRender()" /> Dark
                    <input type="checkbox" name="customcategory" id="cat-cb4" value="Pun" class="control-label" onchange="reRender()" /> Pun
                    <input type="checkbox" name="customcategory" id="cat-cb5" value="Spooky" class="control-label" onchange="reRender()" /> Spooky
                    <input type="checkbox" name="customcategory" id="cat-cb6" value="Christmas" class="control-label" onchange="reRender()" /> Christmas
                </div>
                <div class="form-group">
                    @* <span id="urlBuilderUrl">/Jokes/GetRequestURL</span>*@
                    <button id="urlBuilderUrl" type="submit" class="btn btn-sm btn-primary">/Jokes/GetRequestURL</button>
                </div>
    
            </div>
        </form>
    
        <table class="table table-sm table-striped table-bordered m-2">
            <tbody>
                <tr>
                    <td>id</td>
                    <td id="id"></td>
                </tr>
                <tr>
                    <td>joke</td>
                    <td id="joke"></td>
                </tr>
                <tr>
                    <td>safe</td>
                    <td id="safe"></td>
                </tr>
                <tr>
                    <td>category</td>
                    <td id="category"></td>
                </tr>
                <tr>
                    <td>type</td>
                    <td id="type"></td>
                </tr>
                <tr>
                    <td>lang</td>
                    <td id="lang"></td>
                </tr>
            </tbody>
        </table>
    
    
    </body>
    </html>
    

    测试结果

    Json 反序列化

    https://v2.jokeapi.dev/joke/Miscellaneous,Dark 的链接中,我们可以看到它返回的笑话对象不是你编码的列表。

    所以像下面这样定义笑话:

    public class Joke
    {
        public bool error { get; set; }
        public string category { get; set; }
        public string type { get; set; }
        public string joke { get; set; }
        public Flags flags { get; set; }
        public int id { get; set; }
        public string safe { get; set; }
        public string lang { get; set; }
    }
    
    public class Flags
    {
        public bool nsfw { get; set; }
        public bool religious { get; set; }
        public bool political { get; set; }
        public bool racist { get; set; }
        public bool sexist { get; set; }
        [JsonProperty("explicit")]
        public bool Explicit { get; set; }
    }
    

    那么就可以反序列化成功了。

    Cors

    浏览器安全性可防止网页向与该网页提供服务的域不同的域发出请求。这种限制称为同源策略。同源策略可防止恶意站点从另一个站点读取敏感数据。有时,您可能希望允许其他网站向您的应用发出跨域请求。

    当我测试你的代码时,我需要添加Cors来启用不同的域请求。

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllersWithViews();
        }
    
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            ...
            app.UseCors(builder => builder
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());
    
            app.UseRouting();
            ...
        }
    

    查看

    当一个操作返回一个view 时,一个名为view discovery 的过程就会发生。此过程根据视图名称确定使用哪个视图文件。

    View 方法(返回View();)的默认行为是返回一个与调用它的操作方法同名的视图。例如,控制器的 About ActionResult 方法名称用于搜索名为 About.cshtml 的视图文件。首先,运行时在 Views/[ControllerName] 文件夹中查找视图。如果在那里找不到匹配的视图,它会在共享文件夹中搜索该视图。

    如果隐式返回 ViewResult 并返回 View() 并不重要;或者使用 return View("&lt;ViewName&gt;"); 显式地将视图名称传递给 View 方法; 在这两种情况下,视图发现都会按以下顺序搜索匹配的视图文件:

    • 视图/[ControllerName]/[ViewName].cshtml
    • Views/Shared/[ViewName].cshtml

    在你的情况下,你可以返回一个视图和一个模型:

    return View("Views/Joke/Index.cshtml", randomJoke);
    

    如果将搜索Views/Jokes/Index.cshtml

    测试结果:

    【讨论】:

    • 嗨@Michael Wang 我不认为视图发现是这里的问题,因为我使用的视图与操作方法 GetRequestURL() 同名,视图名称为 GetRequestURL.cshtml 和该视图位于 Views/Jokes 文件夹中(Jokes 是控制器名称。现在请您在 GitHub 上分享您的 VS 解决方案,或者像以前一样编写完整的操作方法/视图。您在 POSTMAN 上显示响应没有帮助。提前致谢
    • 嗨,@krchome,您应该首先在您的操作中找到错误所在的行。在我的代码中,我没有在您编写代码时使用来自 HttpClient 的列表进行重定向。我用静态列表对其进行了测试,这就是我看到数据的原因。
    • 1.您是否通过 Ajax 成功发送了 post 请求? 2.如果是,action方法是否接收到newData字符串? 3. 如果是,是否从newData Url 中获取列表? 4.如果是,反序列化对象是否成功?
    • 是的,我已经完成了您在最新评论中要求的所有内容 1。我已通过 Ajax 成功发送了发布请求。 2. 是的,action 方法接收到包含 URL 的字符串(这就是我通过在 action 方法上附加断点来知道步骤 1 成功的方式,对) 3. 是的,它确实从发送的 URL 中获得了序列化的 json 响应 4. 是,它确实成功地反序列化了对象(如在断点被击中时鼠标悬停所示)。代码在:github.com/krchome/JokeAPIClient.git(唯一重要的文件夹是 WebAPI Consume 和解决方案文件)
    • 太好了,我已经更新了如何从v2.jokeapi.dev/joke/Any的返回数据中反序列化
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 1970-01-01
    • 2019-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-28
    相关资源
    最近更新 更多