MVC控制器向远程API操作传递完整模型数据

3
我是一名有用的助手,我可以为您翻译文本。

我希望你能够从我的前端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内部服务器错误作为响应。

[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方法不允许的响应。

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,并上传了生成的XML文件。虽然对我来说没有什么意义,但我认为这可能会有所帮助。


显示远程 Web API 的路由配置 - Joel R Michaliszen
你提到它是一个远程Web API,它是否托管在同一域上?如果不是,您必须启用跨站点请求(如果您尚未这样做)。 - Camilo Terevinto
我已经添加了API的RouteConfig。API服务器位于同一域上,使用http://ServerName/IISSiteName进行访问。我添加了一个通过谷歌找到的AllowCrossSiteJsonAttribute - Jake
1个回答

2
发布的路由配置看起来更像是MVC路由配置,而不是Web API的配置。但如果这是Web API的配置,那么你不应该在URL中添加ActionName
[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解决方案。我已经更新了我的代码以匹配您的答案,但我的“response”是“500内部服务器错误:发生错误。”没有任何日志记录到我们的elmah日志中,所以我无法找出原因。 - Jake
我在原问题的基础上添加了一个额外的测试,API 在调用自身时可以工作,但似乎从其他任何地方都无法工作。 - Jake
可能会有一些混淆。当你创建一个ASP.net MVC模板+Web API时,应该会得到2个配置文件:RouteConfig.cs(MVC)和WebApiConfig.cs(Web API)。而且你应该有2种类型的控制器,即MVC和API。所以你可能需要重新检查哪一个调用了哪一个。 - Amanvir Mundra
啊,我确实有那两个文件。控制器的区别只是它继承的东西吗?:Controller:ApiController?谢谢你的帮助。最后一个小问题,response现在包含状态码200。我如何使其包含MyResponse对象?这应该是API调用返回的内容。谢谢。 - Jake
我已经更新了答案,并附上了一个示例代码来检索模型对象(假设您将其添加到api调用的响应中)。希望能对您有所帮助! - Amanvir Mundra
非常好,谢谢。现在我遇到了服务器无法看到POST数据的问题。如果你有时间,能否帮忙看一下 - Jake

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