【问题标题】:ASP.NET - API Url to List of Model ObjectsASP.NET - 模型对象列表的 API Url
【发布时间】:2020-01-01 01:00:45
【问题描述】:

目前我正在通过 jQuery 进行 API 调用,我的问题是,是否可以在 C# 中进行此调用,或者是否可以将 API 调用的结果转换为 ASP.NET 模型对象列表?

这是我的模型

public class TeamStatsClass
{
        public int id { get; set; }
        public string name { get; set; }
        public string league { get; set; }
        public string division { get; set; }
}

这是我当前的 ajax 调用

$.ajax({
        url: "https://statsapi.web.nhl.com/api/v1/teams?sportId=1",
        success: function (data) {

            for (var team of data.teams) {

                console.log(team.name);

            }

        }
    });

更新

我把我的课程改成这样:

public class StatsTeamsClass
    {
        public IEnumerable<Teams> teams { get; set; }
        public string copyright { get; set; }
    }
    public class Division
    {
        public int id { get; set; }
        public string name { get; set; }
        public string link { get; set; }
    }

    public class Teams
    {
        public int id { get; set; }
        public string name { get; set; }
        public string link { get; set; }
        public League league { get; set; }
        public Division division { get; set; }
    }

并创建了这个确实将结果放入模型对象的方法:

public async System.Threading.Tasks.Task<StatsTeamsClass> GetTeams()
{

            HttpClient Http = new HttpClient();
            var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
            StatsTeamsClass teams = JsonConvert.DeserializeObject<StatsTeamsClass>(json);

            return teams;
}

但是当我尝试在另一个控制器中调用此方法时,它只是挂在那里,没有错误,没有任何东西,我假设它会在一段时间后超时

public class HomeController : Controller
{

        APIController webService = new APIController();

        public ActionResult Index()
        {

            var item = webService.GetTeams().Result.teams;

            return View();
        }
}

(GetTeams() 在控制器 APIController 中)

那么 A. 在对象模型中获取 API 的结果然后调用这些结果的正确方法是什么?

【问题讨论】:

标签: c# jquery asp.net ajax curl


【解决方案1】:

是的,C# 中的等价物是使用HttpClient。您最好创建一个类的静态实例,以便重复调用特定类型的重复调用:

private static readonly HttpClient Http = new HttpClient(); 

然后通过async 方法使用它,使用Newtonsoft.Json,如下所示:

var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");

然后你可以将这个 JSON 字符串解析成这样的模型类:

var model = JsonConvert.DeserializeObject<TeamStatsClass>(json);

【讨论】:

    【解决方案2】:

    由于上面的@Daniel 回答了这个问题,只是想在此处添加更多点您获得的 json 不能直接转换为 TeamStatsClass 您可能必须引入另一个基类,因为团队是您所在的 json 中的集合得到。

    我把它贴在这里以获得更清晰的视图

        public class ResponseBaseClass
        {
            public IEnumerable<TeamStatsClass> teams { get; set; }
            public string copyright { get; set; }
        }
        public class TeamStatsClass
        {
            public int id { get; set; }
            public string name { get; set; }
            public Division division { get; set; }
        }
        public class Division
        {
            public int id { get; set; }
            public string name { get; set; }
            public string nameShort { get; set; }
            public string link { get; set; }
    
        }
    
     HttpClient Http = new HttpClient();
     var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
     var model = JsonConvert.DeserializeObject<ResponseBaseClass>(json);
     var yourTeamModelObj = model.teams;
    

    【讨论】:

    • @user979331 HttpClient 基本上是为异步进程设计的,您必须使用 WebClient 类进行同步工作WebClient webpage = new WebClient(); string json = webpage.DownloadString("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
    • 如何在另一个控制器中调用这个方法?
    • 简单的方法是创建一个新类,比如 Teams,并将上面的代码作为静态函数写在一个返回类型为 ResponseBaseClass 的新类中,并在每个控制器上调用它。
    • @user979331 我唯一注意到错误的是控制器方法索引也应该是异步的。因为对于 aysn/await 架构,所有前面和后面的方法都应该是异步的,否则可能会导致死锁。有很多可以完美编写此代码的方式取决于您的应用程序范围和架构。但我认为您所做的基本工作还不错。
    【解决方案3】:

    控制器操作也需要异步,以避免混合异步等待和阻塞调用,如 .Result.Wait(),这可能会导致死锁。

    参考Async/Await - Best Practices in Asynchronous Programming

    public class HomeController : Controller {    
        APIController webService = new APIController();
    
        public async Task<ActionResult> Index() {    
            var model = await webService.GetTeams();
            var teams = model.teams;
            return View();
        }
    }
    

    假设APIController 是一个实际的ApiContoller

    public class APIController : ApiController {
    
        //Your original code
        public async Task<StatsTeamsClass> GetTeams() {        
            HttpClient Http = new HttpClient();
            var json = await Http.GetStringAsync("https://statsapi.web.nhl.com/api/v1/teams?sportId=1");
            StatsTeamsClass teams = JsonConvert.DeserializeObject<StatsTeamsClass>(json);
            return teams;
        }
    
        //...
    }
    

    我建议不要像从HomeController 那样直接调用APIController,而是将GetTeams() 方法提取到可重用的服务中

    public class WebService {
        static Lazy<HttpClient> http = new Lazy<HttpClient>();
    
        public async Task<T> GetAsync<T>(string url) {        
            var json = await http.Value.GetStringAsync(url);
            return JsonConvert.DeserializeObject<T>(json);
        }
    
        public Task<StatsTeamsClass> GetTeamsAsync() {        
            var url = "https://statsapi.web.nhl.com/api/v1/teams?sportId=1";
            return GetAsync<StatsTeamsClass>(url);
        }
    }
    

    参考You're using HttpClient wrong

    可以在HomeController中正确使用

    public class HomeController : Controller {        
        public async Task<ActionResult> Index() {
            // Ideally web service should be injected but that topic
            // is outside of the scope of the question at the moment.
            var webService = new WebService();
    
            var model = await webService.GetTeamsAsync();
            var teams = model.teams;
    
            //...
    
            return View(teams);
        }
    }
    

    这里假设项目是一个混合的Asp.Net MVC和Web Api 2+

    Index.cshtml

    @model IEnumerable<Teams>
    @{
        ViewBag.Title = "Teams";
    }
    @if(Model != null && Model.Count() > 0) {
        @foreach (var @team in Model) {
            <p>@team.name</p>
        }
    }
    

    【讨论】:

    • @Nkosi 你能不能引用你在开头提到的这个“最新更新”,迫使人们在这种情况下使用异步,以确保代码的正确执行?
    • @SpiritBob 我指的是他们的问题/帖子的最新更新。它们最初并未包含有关异步控制器操作的相关信息。检查revision history
    • @SpiritBob 我现在已经编辑了该声明以避免任何进一步的混淆
    猜你喜欢
    • 2013-07-08
    • 2020-03-14
    • 2021-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多