【问题标题】:ASP.NET MVC 4 Application Calling Remote WebAPIASP.NET MVC 4 应用程序调用远程 WebAPI
【发布时间】:2012-10-23 09:59:11
【问题描述】:

我过去创建了几个 ASP.NET MVC 应用程序,但我以前从未使用过 WebAPI。我想知道如何创建一个简单的 MVC 4 应用程序,该应用程序通过 WebAPI 而不是通过普通的 MVC 控制器执行简单的 CRUD 操作。诀窍是 WebAPI 应该是一个单独的解决方案(事实上,很可能在不同的服务器/域上)。

我该怎么做?我错过了什么?是否只是设置指向 WebAPI 服务器的路由的问题?我发现的所有显示如何使用 MVC 应用程序使用 WebAPI 的示例似乎都假定 WebAPI 已“嵌入”到 MVC 应用程序中,或者至少位于同一台服务器上。

哦,澄清一下,我不是在谈论使用 jQuery 的 Ajax 调用...我的意思是 MVC 应用程序的控制器应该使用 WebAPI 来获取/放置数据。

【问题讨论】:

    标签: asp.net-mvc asp.net-mvc-4 asp.net-web-api


    【解决方案1】:

    您应该使用新的 HttpClient 来使用您的 HTTP API。我还可以建议您使您的呼叫完全异步。由于 ASP.NET MVC 控制器动作支持基于任务的异步编程模型,它非常强大和简单。

    这是一个过于简化的例子。以下代码是示例请求的帮助类:

    public class CarRESTService {
    
        readonly string uri = "http://localhost:2236/api/cars";
    
        public async Task<List<Car>> GetCarsAsync() {
    
            using (HttpClient httpClient = new HttpClient()) {
    
                return JsonConvert.DeserializeObject<List<Car>>(
                    await httpClient.GetStringAsync(uri)    
                );
            }
        }
    }
    

    然后,我可以通过我的 MVC 控制器异步使用它,如下所示:

    public class HomeController : Controller {
    
        private CarRESTService service = new CarRESTService();
    
        public async Task<ActionResult> Index() {
    
            return View("index",
                await service.GetCarsAsync()
            );
        }
    }
    

    您可以查看以下帖子,了解使用 ASP.NET MVC 进行异步 I/O 操作的效果:

    My Take on Task-based Asynchronous Programming in C# 5.0 and ASP.NET MVC Web Applications

    【讨论】:

    • 这看起来很棒,但我根本无法让异步/等待的东西工作。 IDE 不喜欢这些关键字。我正在使用 .NET 4.0 并使用 NuGet 安装了 Web API 客户端库。
    • @GlennArndt 除非您采取更多措施,否则您不能在 .NET 4.0 中使用 async/await。请参阅此博客文章:blogs.msdn.com/b/bclteam/archive/2012/10/22/… 您可以利用不带 async 和 await 关键字的异步控制器操作,但随后会变得混乱。
    • 我知道这是一篇旧帖子,但我无法找到答案。问题在上面的解决方案代码中,您将如何使用带有 json 数据的 Request Body 进行 httppost?
    • @tugberk 如果我想在 mvc 中自动获取 url:localhost:2236 怎么办,有没有办法得到它?
    • 这可能是迄今为止我发现的从 .NET 使用自定义 Web API 的最佳方法。我喜欢。干得好,@tugberk
    【解决方案2】:

    感谢大家的回复。我认为@tugberk 让我走上了正确的道路。这对我有用...

    对于我的 CarsRESTService 助手:

    public class CarsRESTService
    {
        readonly string baseUri = "http://localhost:9661/api/cars/";
    
        public List<Car> GetCars()
        {
            string uri = baseUri;
            using (HttpClient httpClient = new HttpClient())
            {
                Task<String> response = httpClient.GetStringAsync(uri);
                return JsonConvert.DeserializeObjectAsync<List<Car>>(response.Result).Result;
            }
        }
    
        public Car GetCarById(int id)
        {
            string uri = baseUri + id;
            using (HttpClient httpClient = new HttpClient())
            {
                Task<String> response = httpClient.GetStringAsync(uri);
                return JsonConvert.DeserializeObjectAsync<Car>(response.Result).Result;
            }
        }
    }
    

    然后是 CarsController.cs:

    public class CarsController : Controller
    {
        private CarsRESTService carsService = new CarsRESTService();
    
        //
        // GET: /Cars/
    
        public ActionResult Index()
        {
            return View(carsService.GetCars());
        }
    
        //
        // GET: /Cars/Details/5
    
        public ActionResult Details(int id = 0)
        {
            Car car = carsService.GetCarById(id);
    
            if (car == null)
            {
                return HttpNotFound();
            }
            return View(car);
        }
    }
    

    【讨论】:

    • 使用字符串插值(自从提出这个问题以来添加了新的 c# 6 功能)或 string.builder 而不是“string uri = baseUri + id;”,将使事情更容易阅读并且稍微少一些资源密集型:)
    【解决方案3】:

    您可以使用 WCF 来使用该服务。像这样:

    [ServiceContract]
    public interface IDogService
    {
        [OperationContract]
        [WebGet(UriTemplate = "/api/dog")]
        IEnumerable<Dog> List();
    }
    
    public class DogServiceClient : ClientBase<IDogService>, IDogService
    {
        public DogServiceClient(string endpointConfigurationName) : base(endpointConfigurationName)
        {
        }
    
        public IEnumerable<Dog> List()
        {
            return Channel.List();
        }
    }
    

    然后你可以在你的控制器中使用它:

    public class HomeController : Controller
    {
        public HomeController()
        {
        }
    
        public ActionResult List()
        {
            var service = new DogServiceClient("YourEndpoint");
            var dogs = service.List();
            return View(dogs);
        }
    }
    

    然后在您的 web.config 中放置端点的配置:

    <system.serviceModel>
      <client>
        <endpoint address="http://localhost/DogService" binding="webHttpBinding"
        bindingConfiguration="" behaviorConfiguration="DogServiceConfig" 
        contract="IDogService" name="YourEndpoint" />
      </client>
      <behaviors>
        <endpointBehaviors>
          <behavior name="DogServiceConfig">
            <webHttp/>
          </behavior>
        </endpointBehaviors>
      </behaviors>
    </system.serviceModel>
    

    【讨论】:

    • 我真的很喜欢使用 wcf 来隐藏在接口后面调用服务的实现细节。非常好的提示。
    • 我有一个 ASP.net 外部站点和一个 MVC 仅内部 Web API。我该怎么做?从外部站点调用内部唯一的 Web API? stackoverflow.com/questions/43002283/…
    【解决方案4】:

    http://restsharp.org/ 是您问题的答案。我目前在具有类似结构的应用程序中使用它。

    但更一般地说,使用 WebAPI 只是发布和请求数据,如何处理取决于您。您甚至可以使用标准的 WebRequest 和 JavascriptSerializer。

    干杯。

    【讨论】:

    • WebRequestJavascriptSerializer 现在是堆栈中的老式 API。新的HttpClient 是要走的路。如果您安装Microsoft.AspNet.WebApi.Client NuGet 包,它也提供 OOTB 格式支持,它将使用 Json.NET 执行 JSON 序列化和反序列化。
    【解决方案5】:

    在这种情况下,您可以使用 HttpClient 从您的控制器使用 Web API。

    【讨论】:

      猜你喜欢
      • 2014-05-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-16
      • 1970-01-01
      • 2015-08-31
      • 2017-04-19
      • 1970-01-01
      相关资源
      最近更新 更多