当使用异步调用获取模型时,MVC 中与 ASP.NET WebAPI 和 httpClient 一起使用的做法是什么

What is the practice in MVC used with ASP.NET WebAPI and httpClient when using async calls to get the Model

故事:

我做了一个WebAPI来获取各种信息。我被告知好的做法是作为前端开发人员,只需通过 services/API 向后端发送信息请求并使用 async 和 await 关键字等。

这就是我想要做的:

在我的 homeController 中我有这个:

namespace NHibernateMVC.Controllers
{
    public class HomeController : Controller
    {
        static HttpClient client = new HttpClient();

        static async Task RunAsync()
        {
            // New code:
            client.BaseAddress = new Uri("http://localhost:64498/");
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        }

        static async Task<IEnumerable<Article>> GetArticleAsync(string path)
        {
            IEnumerable<Article> art = null;
            HttpResponseMessage response = await client.GetAsync(path);
            if (response.IsSuccessStatusCode)
            {
                art = await response.Content.ReadAsAsync<IEnumerable<Article>>();
            }
            return art;
        }

        public ActionResult Index()
        {   
             // This is where I am supposed to make a call to get the Articles to return a View who's model is of type IEnumerable<Article>
        }

底线是我想用 IEnumerable<Article> 模型初始化索引页面,但使用 httpClient 获取文章,调用 WebAPI(这只是对 api/ArticleAPI 的 GET 请求, JSON 是响应)。 这在实践中通常是如何完成的?这是我第一次这样做,我确实需要帮助,搜索了一下,到目前为止没有找到任何可以帮助我的东西...

controller需要稍微重构一下才能正常调用

public class HomeController : Controller {
    const string ARTICLE_API_PATH = "api/ArticleAPI";
    static HttpClient client; = new HttpClient();
    static HomeController() {
        // New code:
        client.BaseAddress = new Uri("http://localhost:64498/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    async Task<IEnumerable<Article>> GetArticleAsync() {
        IEnumerable<Article> articles = new List<Article>();
        HttpResponseMessage response = await client.GetAsync(ARTICLE_API_PATH);
        if (response.IsSuccessStatusCode) {
            articles = await response.Content.ReadAsAsync<List<Article>>();
        }
        return articles;
    }

    public async Task<ActionResult> Index() {
        //call service method above.
        var articles = await GetArticleAsync();
        //pass the list as the model to the view
        return View(articles);
    }
}

以上内容只是一个开始,但还可以改进可维护性。

获取文章可以提取到服务抽象中

public interface IArticleService {
    Task<IEnumerable<Article>> GetArticleAsync();
}

public class ArticleService : IArticleService {
    const string ARTICLE_API_PATH = "api/ArticleAPI";
    static HttpClient client; = new HttpClient();

    static ArticleService() {
        client.BaseAddress = new Uri("http://localhost:64498/");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    }

    public async Task<IEnumerable<Article>> GetArticleAsync() {
        IEnumerable<Article> articles = new List<Article>();
        HttpResponseMessage response = await client.GetAsync(ARTICLE_API_PATH);
        if (response.IsSuccessStatusCode) {
            articles = await response.Content.ReadAsAsync<List<Article>>();
        }
        return articles;
    }
}

这样现在控制器可以简化为

public class HomeController : Controller {
    private readonly IArticleService articleService;

    public HomeController() {
       articleService = new ArticleService();
    }

    public async Task<ActionResult> Index() {
        //call service method above.
        var articles = await articleService.GetArticleAsync();
        //pass the list as the model to the view
        return View(articles);
    }
}

在更高级的场景中,您可以通过将服务注入控制器来反转服务的创建,但该主题不在本问题的讨论范围内。

看起来像这样。

public class HomeController : Controller {
    private readonly IArticleService articleService;

    public HomeController(IArticleService articleService) {
       this.articleService = articleService;
    }

    public async Task<ActionResult> Index() {
        //call service method above.
        var articles = await articleService.GetArticleAsync();
        //pass the list as the model to the view
        return View(articles);
    }
}