如何在 Asp.net MVC 中添加 Web Api,然后在同一个应用程序中使用 WebAPI

Posted

技术标签:

【中文标题】如何在 Asp.net MVC 中添加 Web Api,然后在同一个应用程序中使用 WebAPI【英文标题】:How to add WebApi in Asp.net MVC and then consume the WebAPI in the same application 【发布时间】:2014-02-12 21:09:13 【问题描述】:

我已经实现了创建 WebApi 本身,我可以从浏览器浏览它并获取输出。

对我不起作用的是,我正在尝试从 MVC 控制器使用 WebAPI,并且我已经在“cshtml”视图中编写了用于调用 WebAPI 的代码。

但这不起作用,因为我在加载页面时遇到错误,我知道我做错了什么。所以第一个问题是:我这样做是否正确,或者在 MVC 项目中创建 WebAPI 部分然后尝试从控制器在同一个 MVC 项目中使用它是完全错误的?

【问题讨论】:

发布您的错误。但是,您为什么要从同一个应用程序中使用 Web API,因为我假设该应用程序已经可以访问该服务所封装的所有代码?为什么要在不需要时花费额外的开销? 我完全同意你的看法,但是有什么技术原因我不能这样做,或者这只是一种错误的实现方式? @Maess、MVC 和 WebAPI 被设计为存在于同一个应用程序中。如果需要,您可以将特定的 API 控制器发送到单独的文件夹,例如根目录中的“API”以将它们分开。这就是为什么你有一个RouteConfig.cs 和一个WebApiConfig.cs 存在于同一个App_Start 文件夹中的原因——因为它预计会在同一个项目中利用这两者。不过,这不是必需的。 @user1570094,您不想从视图内部调用 WebAPI。您想从 MVC 前端控制器内部调用 WebAPI,如下所述。 【参考方案1】:

要回答您的问题,它实际上是“按设计”的,建议您将 WebAPI 和 MVC 客户端放在同一个项目中。这就是为什么在 MVC 项目中同时拥有 RouteConfig.csWebApiConfig.cs 的原因。 RouteConfig.cs 用于您的 MVC 控制器,WebApiConfig.cs 显然用于您的 Api 控制器。

将两者放在同一个项目中很容易。我所做的是在我的根目录中添加一个名为“API”的文件夹,并将我所有的 WebAPI 控制器放在那里。请记住,我相信您知道,WebAPI 控制器和 MVC 控制器之间的唯一区别是 WebAPI 控制器继承 ApiController,这是 System.Web.Http 的一部分(我相信),而 MVC 控制器继承 @ 987654328@ 是System.Web.MVC 的一部分。

以下是使 GET/PUT/DELETE/POST 请求TO您的 WebAPI FROM MVC 前端的正确方法。它是否在同一个项目中并不重要,因为您在控制器的构造函数中指定了 WebAPI URL。如果您的 WebAPI 与前端 MVC 应用程序位于不同的服务器上,则需要启用 CORS 支持,这是 WebAPI 版本 2 及更高版本中提供的功能。

这是从前端 MVC 客户端调用 WebAPI 的正确方法。

在您的控制器页面中,删除与 DbContext、Entity Framework 等有关的任何内容。原因是默认情况下,控制器将希望通过调用 DbContext 来执行 CRUD 操作,而我们不希望这样。我们想调用 WebAPI 来执行此操作。当我提到“控制器”时,我指的是 MVC 控制器,而不是 WebAPI 控制器。

首先,在 MVC 控制器中声明一些成员变量。您的 MVC 控制器的其余部分将使用这些:

    HttpClient client = new HttpClient();
    HttpResponseMessage response = new HttpResponseMessage();
    Uri contactUri = null;

    在您的 MVC 控制器中,为您的控制器创建一个构造函数,如下所示:

    public ContactController()
    
        // set base address of WebAPI depending on your current environment
        // the URL below, if the API is in the same project, will be something 
        // like "http://server/YourProjectName" - replace server with either
        // "localhost", etc.
        client.BaseAddress = new Uri("http://server/YourAPI/");
    
        // Add an Accept header for JSON format.
        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));
    
    

    将索引操作的代码替换为以下内容。请注意,唯一相关的部分是 client.GetAsync() 调用和 var contacts 分配。对于此问题的上下文,其他所有内容都不是必需的。 client.GetAsync() 中的值应该是您的控制器的名称,前面是您在 WebApiConfig.cs 中设置的任何自定义路由 - 就我而言,我在路由中添加了 api 部分以区分 API 调用和正常调用调用:

    public ActionResult Index()
    
        response = client.GetAsync("api/contact").Result;
        if (response.IsSuccessStatusCode)
        
            var contacts = response.Content.ReadAsAsync<IEnumerable<Contact>>().Result;
            return View(contacts);
        
        else
        
            // add something here to tell the user hey, something went wrong
            return RedirectToAction("Index");
        
    
    

    将 Create 操作(HttpPost 操作)替换为以下内容。同样,唯一重要的部分是 client.PostAsJsonAsync() 部分 - 这就是调用 WebAPI 的 POST 操作的部分,在我的例子中,它负责将新记录插入数据库:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Create(Contact contact)
    
        // Create a new product
        response = client.PostAsJsonAsync("api/contact", contact).Result;
        if (response.IsSuccessStatusCode)
        
            return RedirectToAction("Index");
        
        else
        
            // add something here to tell the user hey, something went wrong
            return RedirectToAction("Index");
        
    
    

    将 Edit 操作(非 HttpPost 操作)替换为以下内容。这有点棘手,因为为了进行编辑,您必须先检索记录,所以基本上,HttpPost 版本的 Edit 将包含一些类似的代码,还有一行代码执行编辑 POST (PUT)。下面,我们通过向 WebAPI 传递一个特定的记录 ID 来获取响应。因此,就像 Index (GET) 一样,我们只是在做同样的事情,只传递 ID,所以我们只取回一条记录。然后,我们将响应转换为可以在 View 中操作的实际对象:

    public ActionResult Edit(int id = 0)
    
        response = client.GetAsync(string.Format("api/contact/0", id)).Result;
        Contact contact = response.Content.ReadAsAsync<Contact>().Result;
        if (contact == null)
        
            return HttpNotFound();
        
        return View(contact);
    
    

    将 Edit 操作(HttpPost 操作)替换为以下内容。下面,我们通过调用client.GetAsync() 并将主键作为参数(contact_id)传递来获取要编辑的记录。然后,我们从该响应中获取 RequestUri 并将其保存。然后,我们调用 client.PutAsJsonAsync() 并传入 Uri.PathAndQuery(我们刚刚保存的内容)以及要编辑的对象。

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(Contact contact)
    
        response = client.GetAsync(string.Format("api/contact/0", contact.contact_id)).Result;
        contactUri = response.RequestMessage.RequestUri;
        response = client.PutAsJsonAsync(contactUri.PathAndQuery, contact).Result;
        if (response.IsSuccessStatusCode)
        
            return RedirectToAction("Index");
        
        else
        
            // add something here to tell the user hey, something went wrong
            return RedirectToAction("Index");
        
    
    

    将 Delete 操作(非 HttpPost 操作)替换为以下内容。同样,我们通过简单地调用 client.GetAsync() 并将其转换为我的应用知道的实际对象来从数据库中获取记录。

    public ActionResult Delete(int id = 0)
    
        response = client.GetAsync(string.Format("api/contact/0", id)).Result;
        Contact contact = response.Content.ReadAsAsync<Contact>().Result;
    
        if (contact == null)
        
            return HttpNotFound();
        
        return View(contact);
    
    

    最后,将 Delete 操作(HttpPost 操作)替换为以下内容。同样,我们正在执行类似于 Edit 操作的操作。我们正在获取要删除的记录,将其转换为一个对象,然后将该对象传递给client.DeleteAsync() 调用,如下所示。

    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
    public ActionResult DeleteConfirmed(int id)
    
        response = client.GetAsync(string.Format("api/contact/0", id)).Result;
        contactUri = response.RequestMessage.RequestUri;
        response = client.DeleteAsync(contactUri).Result;
        return RedirectToAction("Index");
    
    

【讨论】:

非常感谢您提供如此详细而精彩的解释,我完全同意了。但是在这个类似的场景中,我在同一个项目中有一个 WebApi 和 MVC 客户端,我可以通过在视图中编写 jquery 来访问 WebApi,并且该视图由 MVC 控制器作为 ActionResult 返回吗?也请给我一个答案,因为我认为它应该有效。我试过这个,但没有奏效。谢谢。 不错的答案,但登录呢?如果我们在 WebAPI 控制器上使用 [Authorize] 属性,我们如何更改代码?请澄清一下。谢谢! 我在使用 web-api-2 时遇到了问题,您的第 2 步添加了操作索引代码,例如 public ActionResult Index()。基于此question on why ... -ihttpactionresult-instead-of-httpresponsemessage,我假设对于 web-api-2,第 2 步的代码需要更改为public IHttpActionResult Index()。这是正确的吗?

以上是关于如何在 Asp.net MVC 中添加 Web Api,然后在同一个应用程序中使用 WebAPI的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Asp.net MVC 中添加 Web Api,然后在同一个应用程序中使用 WebAPI

Asp.net: WebForm基础上构建Mvc的方法

如何将 ID 属性添加到 asp.net MVC 链接元素

在 ASP.Net Web 表单/MVC 中动态加载和添加字段

如何将 Web API 控制器添加到现有的 ASP.NET Core MVC?

asp.net mvc web窗体文件中如何获取HttpContextBase对象