从MVC控制器调用Web API
从MVC控制器调用Web API
我在我的MVC5项目解决方案中有一个WebAPI控制器。\nWebAPI有一个方法,它以Json列表的形式返回特定文件夹中的所有文件:\n[{\"name\":\"file1.zip\", \"path\":\"c:\\\\\"}, {...}]
\n我想从HomeController中调用这个方法,将Json响应转换为List
并将这个列表返回给一个Razor视图。如果文件夹中没有文件,这个列表可能是空的:[]
。\n这是APIController:\n
public class DocumentsController : ApiController { #region Methods ////// 以Json形式获取存储库中的所有文件。 /// ///QDocumentRecord的Json表示。 public HttpResponseMessage GetAllRecords() { // 找到文件的所有代码都在这里,并且完全正常运行... return new HttpResponseMessage() { Content = new StringContent(JsonConvert.SerializeObject(listOfFiles), Encoding.UTF8, "application/json") }; } }
\n这是我的HomeController:\n
public class HomeController : Controller { public Index() { // 我想调用API的GetAllFiles方法,并将结果放入变量中: var files = JsonConvert.DeserializeObject>(API返回的Json); } }
\n最后这是模型,如果你需要的话:\n
public class QDocumentRecord { public string id {get; set;} public string path {get; set;} ..... }
\n那么我该如何进行这个调用?
问题出现的原因:
- 希望在不同的控制器中调用相同的逻辑代码
- 希望将文件查找的逻辑放入一个公共类中,以便在未来的代码维护中更加简化
解决方法:
- 将原本在ApiController中的代码移动到一个可以同时被HomeController和DocumentController调用的类中
- 将文件查找的逻辑提取到一个公共类中,这样在未来的代码维护中可以更加方便
- 调用API Controller可以在安全性要求较高的场景下使用,例如在支付行业中,安全标准要求网站不能直接访问数据库,而是通过内部的Web服务来访问,以减少数据库被攻击的风险
代码示例:
// 公共类 CommonClass.cs public class CommonClass { public ListGetFiles() { // 文件查找逻辑 // ... return files; } } // HomeController.cs public class HomeController : Controller { public ActionResult Index() { CommonClass common = new CommonClass(); List files = common.GetFiles(); // 其他处理逻辑 // ... return View(files); } } // DocumentController.cs public class DocumentController : ApiController { public IHttpActionResult GetFiles() { CommonClass common = new CommonClass(); List files = common.GetFiles(); // 返回文件列表 return Ok(files); } }
以上是解决这个问题的方法和示例代码。如果安全性不是首要考虑因素,那么将逻辑代码提取到公共类中的方法仍然是一个有效的思考点。
问题原因:这段代码中出现了一个问题,即在MVC控制器中调用Web API。问题的根源是在MVC控制器中使用HttpClient来调用Web API时没有正确设置相关参数。
解决方法:为了解决这个问题,我们需要在MVC控制器中对HttpClient进行正确的配置。具体来说,我们需要设置Web API的基本地址、请求头和接受的数据格式。下面是正确的代码示例:
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(); } }
通过以上代码,我们可以正确地在MVC控制器中调用Web API,并且获取到返回的数据。通过设置正确的参数,我们可以确保请求能够成功,并且能够正确解析返回的数据。
问题的出现原因:
该问题出现的原因是因为在HomeController中想要调用某个方法并将Json响应转换为List,但是不希望增加HTTP调用和(反)序列化的开销,因为这些代码在同一个程序集中。
解决方法:
1. 从ApiController返回一个具体类型的对象:
public IEnumerableGetAllRecords() { listOfFiles = ... return listOfFiles; }
2. 如果一定要返回HttpResponseMessage类型,仍然不需要手动调用JsonConvert.SerializeObject()方法:
return Request.CreateResponse>(HttpStatusCode.OK, listOfFiles);
3. 将业务逻辑提取到一个专门处理工作的类中:
public class FileListGetter { public IEnumerableGetAllRecords() { listOfFiles = ... return listOfFiles; } }
然后从MVC controller中直接调用这个类或者ApiController:
public class HomeController : Controller { public ActionResult Index() { var listOfFiles = new DocumentsController().GetAllRecords(); // 或者 var listOfFiles = new FileListGetter().GetAllRecords(); return View(listOfFiles); } }
4. 如果确实需要进行HTTP请求,可以使用HttpWebRequest、WebClient、HttpClient或RestSharp等工具库。
在这个例子中,将FileListGetter类放在哪里?在模型中放置这个逻辑是否可行?
FileListGetter类可以放在控制器内部,也可以作为一个单独的类放在控制器外部。将这个逻辑放在模型中是可行的。