【问题标题】:MVC controller post entire model to remote api actionMVC 控制器将整个模型发布到远程 api 操作
【发布时间】:2016-04-11 05:50:57
【问题描述】:

我想从我的前端 MVC 站点调用一个 API。这两个应用程序在同一网络上的不同服务器上运行。

API 控制器的功能类似于:

[AllowCrossSiteJson]
public class VerifyMyModelController : ApiController
{
    [HttpPost]
    public MyResponse Post(MyModel model)
    {
        return MyHelper.VerifyMyModel(model);
    }

    [HttpPost]
    public async Task<MyResponse> PostAsync(MyModel model)
    {
        return await MyHelper.VerifyMyModel(model);
    }
// ... Gets below as well
}

MyHelper 执行模型验证、数据库查找等...并返回带有响应代码、数据库 ID 等的公共响应对象

我的前端 MVC 站点有一个用户填写的表单,这些数据被发布到本地控制器,我想转发到 API。公众无法访问 API 应用程序,因此我无法使用 AJAX 等直接发布到它。它必须来自站点控制器。

我尝试了以下方法,但得到了500 internal server error 作为回复

[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
    var MyServer = ConfigurationManager.AppSettings["MyServer"];
    var json = Newtonsoft.Json.JsonConvert.SerializeObject(model);

    var requestUri = string.Format(@"http://{0}/api/VerifyMyModel/", MyServer);

    using (var c = new HttpClient())
    {
        var response = await c.PostAsJsonAsync(requestUri, json);
    }
    ...
}

var response 包含错误消息响应 500。

我也尝试过使用查询字符串:

public string GetQueryString(object obj)
{
    var properties = from p in obj.GetType().GetProperties()
                        where p.GetValue(obj, null) != null
                        select p.Name + "=" + HttpUtility.UrlEncode(p.GetValue(obj, null).ToString());

    return String.Join("&", properties.ToArray());
}

[HttpPost]
public async Task<MyResponse> VerifyAsync(MyModel model)
{
    var MyServer = ConfigurationManager.AppSettings["MyServer"];
    string queryString = GetQueryString(model);
    var requestUri = string.Format(@"http://{0}/api/VerifyMyModel/?{1}", MyServer, queryString);

    using (var c = new HttpClient()){
        var response = await c.GetAsync(requestUri); // API Also has GET methods
    }
}

但是querystring 方法返回一个405 method not allowed 响应。

MyModel 是共享类库的一部分,其中包含通用模型,并且包含在两个应用程序中。

有没有更好的方法将整个模型发布到远程 api 操作?

谢谢。

*编辑

API的RouteConfig:

public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}

我将以下内容添加到 API 的 MVC 站点的 HomeController 中,以对其进行测试,我收到了预期的结果,没有错误:

public async Task<ActionResult> TestVerifyMyModel(MyModel model)
{
        var api = new VerifyMyModelController();
        var res = await api.PostAsync(model);

        return Json(res, JsonRequestBehavior.AllowGet);
}

所以我知道控制器的PostAsync 操作有效.. 远程调用时我无法让它工作。

我还在服务器上启用了Failed Request Tracing 并拥有uploaded the generated XML file。这对我来说没有任何意义,但认为它可能会有所帮助。

【问题讨论】:

  • 显示远程web api的路由配置
  • 您提到它是一个远程 Web API,它是否托管在同一个域上?如果没有,则必须启用跨站点请求(如果您尚未启用)
  • 我已经添加了API的RouteConfig。 API Server 在同一个域上,使用http://ServerName/IISSiteName 访问我添加了一个AllowCrossSiteJsonAttribute,这是我通过google 找到的。

标签: c# asp.net-mvc api post


【解决方案1】:

发布的路由配置看起来更像您的 MVC 路由配置,而不是 Web Api 配置。但如果是 Web Api 配置,那么您不应该将 ActionName 添加到您的 url。

[HttpPost]
    public async Task<MyResponse> VerifyAsync(MyModel model)
    {
        var MyServer = ConfigurationManager.AppSettings["MyServer"];
        var json = Newtonsoft.Json.JsonConvert.SerializeObject(model);

        var requestUri = string.Format(@"http://{0}/api/VerifyMyModel/PostAsync", MyServer);

        using (var c = new HttpClient())
        {
            var response = await c.PostAsJsonAsync(requestUri, json);
        }
        ...
    }

更新:从 HttpClient 响应中检索模型的示例代码

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri(ConfigurationManager.AppSettings["MyServer"]);

    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    HttpResponseMessage response = await client.GetAsync("api/VerifyMyModel/PostAsync");
    if (response.IsSuccessStatusCode)
    {
        var myResponseModel = await response.Content.ReadAsAsync<MyResponseModel>();
    }
}

【讨论】:

  • 感谢您的回复。路由配置是 VS 创建的默认配置,我确定我选择了 MVC API 解决方案。我更新了代码以匹配您的答案,但我的 response500 internal server error: An error has occurred. 没有任何内容记录到我们的 elmah 日志中,所以我可以不知道是什么原因造成的。
  • 我在原始问题中添加了一个附加测试,API 在调用自身时有效,而不是来自其他任何地方。
  • 可能有些混乱。当您创建 ASP.net MVC 模板 + Web API 时,您应该获得 2 个配置文件:RouteConfig.cs (MVC)WebApiConfig.cs (Web API)。你应该有两种类型的控制器 MVC 和 API。所以你可能需要重新检查哪个调用哪个。
  • 啊,我确实有这两个文件。控制器的区别只是它继承的吗? :Controller:ApiController?谢谢你的帮助。最后一件事,response 现在有状态码200。如何使它具有 MyResponse 对象?这就是 API 调用应该返回的内容。谢谢
  • 我已经使用示例代码更新了答案以检索模型对象(假设您将其添加到 api 调用中的响应中)。希望对您有所帮助!
猜你喜欢
  • 1970-01-01
  • 2013-01-13
  • 1970-01-01
  • 2013-01-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多