从MVC控制器调用Web API

29

我在我的MVC5项目解决方案中有一个WebAPI控制器。

该WebAPI具有一种方法,返回特定文件夹中的所有文件作为Json列表:

[{"name":"file1.zip", "path":"c:\\"}, {...}]

从我的HomeController中,我想调用此方法,将Json响应转换为List<QDocument>,并将此列表返回到Razor视图。如果文件夹中没有文件,这个列表可能是空的:[]

这是APIController:

public class DocumentsController : ApiController
{
    #region Methods
    /// <summary>
    /// Get all files in the repository as Json.
    /// </summary>
    /// <returns>Json representation of QDocumentRecord.</returns>
    public HttpResponseMessage GetAllRecords()
    {
      // All code to find the files are here and is working perfectly...

         return new HttpResponseMessage()
         {
             Content = new StringContent(JsonConvert.SerializeObject(listOfFiles), Encoding.UTF8, "application/json")
         };
    }               
}

这是我的HomeController:

public class HomeController : Controller
{
     public Index()
     {
      // I want to call APi GetAllFiles and put the result to variable:
      var files = JsonConvert.DeserializeObject<List<QDocumentRecord>>(API return Json);
      }
 }

最后,如果你需要的话,这就是模型:

public class QDocumentRecord
{
      public string id {get; set;}
      public string path {get; set;}
   .....
}

那我该如何进行这个调用呢?


1
为什么不把它称为其他任何方法呢?添加引用,初始化并调用该方法... - Kaf
1
仅提醒一下,在您的ApiController中使用JsonConvert时要注意... 这是WebAPI的旗舰功能之一,可以自动完成此操作。 - spender
5个回答

24
从我的HomeController中,我想调用这个方法并将Json响应转换为列表。
不,你不需要。当代码可以轻松实现时,你确实不需要增加HTTP调用和(反)序列化的开销。它甚至在同一个程序集中!
你的ApiController无论如何都违反了(我喜欢的)约定。让它返回一个具体类型:
public IEnumerable<QDocumentRecord> GetAllRecords()
{
    listOfFiles = ...
    return listOfFiles;
}

如果您不想这样做,并且您绝对确定需要返回HttpResponseMessage,那么仍然完全没有必要自己调用JsonConvert.SerializeObject()
return Request.CreateResponse<List<QDocumentRecord>>(HttpStatusCode.OK, listOfFiles);

然而,您不希望在控制器中使用业务逻辑,因此您需要将其提取到一个类中,该类为您执行工作:

public class FileListGetter
{
    public IEnumerable<QDocumentRecord> GetAllRecords()
    {
        listOfFiles = ...
        return listOfFiles;
    }
}

无论哪种方式,您都可以从MVC控制器直接调用此类或ApiController:

public class HomeController : Controller
{
    public ActionResult Index()
    {
        var listOfFiles = new DocumentsController().GetAllRecords();
        // OR
        var listOfFiles = new FileListGetter().GetAllRecords();

        return View(listOfFiles);
    }
}

但如果你真的非常需要进行HTTP请求,你可以使用HttpWebRequestWebClientHttpClientRestSharp,这些都有很多教程可供参考。


在你的例子中,你会把 FileListGetter 放在哪里?把这个逻辑放在模型里面可以吗? - Alonso Urbano

23

这里已经很晚了,但是我想分享下面的代码。 如果我们的WebApi是在同一解决方案中不同的项目中,则可以像下面这样从MVC控制器调用相同的API:

很晚了,但是想分享以下代码。如果我们的WebApi和MVC控制器不在一个项目中,我们可以像下面这样从MVC控制器中调用WebApi:

public class ProductsController : Controller
    {
        // GET: Products
        public async Task<ActionResult> Index()
        {
            string apiUrl = "http://localhost:58764/api/values";

            using (HttpClient client=new HttpClient())
            {
                client.BaseAddress = new Uri(apiUrl);
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

                HttpResponseMessage response = await client.GetAsync(apiUrl);
                if (response.IsSuccessStatusCode)
                {
                    var data = await response.Content.ReadAsStringAsync();
                    var table = Newtonsoft.Json.JsonConvert.DeserializeObject<System.Data.DataTable>(data);

                }


            }
            return View();

        }
    }

8
为什么不把你在ApiController调用DocumentsController中的代码移动到一个类中,然后可以从HomeController和DocumentController中调用该类。将其提取到一个类中,然后从两个控制器中调用该类。你问题中的这些内容:
// 找文件的所有代码都在这里,并且正常工作...
在同一网站的另一个控制器中调用API Controller没有意义。
这也会简化代码,在未来回顾时,你将有一个通用的类来查找文件并在那里执行该逻辑...

2
在同一网站上从另一个控制器调用API控制器是没有意义的。 - spender
我必须以那种方式设计API。该API正在被其他移动应用程序使用。我想将结果作为列表发送到Razor视图以进行过滤等操作。 - A-Sharabiani
将生成文件列表的内部逻辑移动到公共类中不应影响移动应用程序使用的实际控制器接口。对于他们来说,控制器中发生的事情是一个黑盒子。只需将查找文件的通用逻辑提取到两者都使用的公共类中即可。 - kmcnamee
1
我以前也像这样想。直到最近,我发现自己处于这样一种情况:在某些情况下,从控制器实际调用 Web API 控制器是必需的:卡支付行业的安全标准不允许 Web 直接访问数据库,但必须通过 Web 服务(部署在私有 LAN 上)进行访问。这样做的想法是,即使公共 Web 被劫持了,攻击者仍然不能直接访问您的数据库。他只能自己调用内部 Web 服务,这样就会更安全。 - Hoàng Long
1
简而言之:该问题是一个有效的使用案例。 如果安全性不是主要问题,您的答案仍然是一个有效的考虑因素。 - Hoàng Long

1

好的,您可以用多种方式来实现...其中一种是创建HttpRequest。我建议您不要从自己的MVC中调用自己的WebAPI(这个想法是多余的...),但是这里有一个端到端教程


1

控制器:

    public JsonResult GetProductsData()
    {
        using (var client = new HttpClient())
        {
            client.BaseAddress = new Uri("http://localhost:5136/api/");
            //HTTP GET
            var responseTask = client.GetAsync("product");
            responseTask.Wait();

            var result = responseTask.Result;
            if (result.IsSuccessStatusCode)
            {
                var readTask = result.Content.ReadAsAsync<IList<product>>();
                readTask.Wait();

                var alldata = readTask.Result;

                var rsproduct = from x in alldata
                             select new[]
                             {
                             Convert.ToString(x.pid),
                             Convert.ToString(x.pname),
                             Convert.ToString(x.pprice),
                      };

                return Json(new
                {
                    aaData = rsproduct
                },
    JsonRequestBehavior.AllowGet);


            }
            else //web api sent error response 
            {
                //log response status here..

               var pro = Enumerable.Empty<product>();


                return Json(new
                {
                    aaData = pro
                },
    JsonRequestBehavior.AllowGet);


            }
        }
    }

    public JsonResult InupProduct(string id,string pname, string pprice)
    {
        try
        {

            product obj = new product
            {
                pid = Convert.ToInt32(id),
                pname = pname,
                pprice = Convert.ToDecimal(pprice)
            };



            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:5136/api/product");


                if(id=="0")
                {
                    //insert........
                    //HTTP POST
                    var postTask = client.PostAsJsonAsync<product>("product", obj);
                    postTask.Wait();

                    var result = postTask.Result;

                    if (result.IsSuccessStatusCode)
                    {
                        return Json(1, JsonRequestBehavior.AllowGet);
                    }
                    else
                    {
                        return Json(0, JsonRequestBehavior.AllowGet);
                    }
                }
                else
                {
                    //update........
                    //HTTP POST
                    var postTask = client.PutAsJsonAsync<product>("product", obj);
                    postTask.Wait();
                    var result = postTask.Result;
                    if (result.IsSuccessStatusCode)
                    {
                        return Json(1, JsonRequestBehavior.AllowGet);
                    }
                    else
                    {
                        return Json(0, JsonRequestBehavior.AllowGet);
                    }

                }




            }


            /*context.InUPProduct(Convert.ToInt32(id),pname,Convert.ToDecimal(pprice));

            return Json(1, JsonRequestBehavior.AllowGet);*/
        }
        catch (Exception ex)
        {
            return Json(0, JsonRequestBehavior.AllowGet);
        }

    }

    public JsonResult deleteRecord(int ID)
    {
        try
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = new Uri("http://localhost:5136/api/product");

                //HTTP DELETE
                var deleteTask = client.DeleteAsync("product/" + ID);
                deleteTask.Wait();

                var result = deleteTask.Result;
                if (result.IsSuccessStatusCode)
                {

                    return Json(1, JsonRequestBehavior.AllowGet);
                }
                else
                {
                    return Json(0, JsonRequestBehavior.AllowGet);
                }
            }



           /* var data = context.products.Where(x => x.pid == ID).FirstOrDefault();
            context.products.Remove(data);
            context.SaveChanges();
            return Json(1, JsonRequestBehavior.AllowGet);*/
        }
        catch (Exception ex)
        {
            return Json(0, JsonRequestBehavior.AllowGet);
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接