【问题标题】:Using ModelState to return errors from WebAPI 2使用 ModelState 从 WebAPI 2 返回错误
【发布时间】:2014-03-09 22:59:05
【问题描述】:

我正在尝试使用 ModelState 对象向客户端发送错误;我正在为服务使用 asp.net Web API。

在 Web 服务方面,我正在这样做。

    public HttpResponseMessage VerifyData(Cobject data)
    {
        string[] errors;
        if (!VerifyAllRequiredData(data, out errors))
        {
            foreach(string error in errors)
                ModelState.AddModelError("", error);
            return Request.CreateErrorResponse(HttpStatusCode.ExpectationFailed, ModelState);
        }

        return Request.CreateResponse(HttpStatusCode.OK, data);
    }

我正在为该服务创建一个 .NET 客户端库,以便我们可以将其用于现有的 Windows 应用程序。

在客户端:

    public bool VerifyData(Cobject data)
    {
        try
        {  
            HttpClient c = new HttpClient();
            c.BaseAddress = BaseAddress;
            c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(JsonHeader));
            c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(HTMLHeader));
            c.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(TextHeader));
            var asyncResponse = this.PostAsJsonAsync(url, data);
            asyncResponse.Wait();
            asyncResponse.Result.EnsureSuccessStatusCode();
            return true;
        }
        catch (HttpRequestException hre)
        {
            Console.WriteLine(hre.Message);
            return false;
        }
        catch (Exception e)
        {
            Console.WriteLine(e.Message);
            return false;
        }
    }

这里的问题是我没有看到任何消息添加到响应的 ModelState 中。我看到状态(ExpectionFailed)但没有消息。如何在客户端检索这些消息?

【问题讨论】:

  • ModelState 在 HTTP 内容中返回。您可以使用 Fiddler 来查看它的外观。不幸的是,我知道没有用于反序列化 ModelState 的 Web API 客户端支持,但自己定义兼容模型很容易。

标签: c# rest asp.net-web-api .net-4.5 dotnet-httpclient


【解决方案1】:

我使用“类似”代码发布帖子并访问我的网络 API。让我复制一些代码,以便您可以从 ModelState 中获取信息

var responseTask = await client.SendAsync(request);
var result = responseTask.ContinueWith(async r =>
               {
                   var response = r.Result;

                   var value = await response.Content.ReadAsStringAsync();
                   if (!response.IsSuccessStatusCode)
                   {
                       var obj = new { message = "", ModelState = new Dictionary<string,string[]>() };
                       var x = JsonConvert.DeserializeAnonymousType(value, obj);
                       throw new AggregateException(x.ModelState.Select(kvp => new Exception(string.Format("{0}: {1}", kvp.Key, string.Join(". ", kvp.Value)))));
                   }

               }).Result;

我希望这对你有用:)

【讨论】:

    【解决方案2】:

    我创建了一个强类型对象,如下所示:

    public class BadRequestResponse
    {
    
        public string Message { get; set; }
        public Dictionary<string, string[]> ModelState { get; set; }
    }
    

    并使用它来反序列化 JSON,如下例所示:

        public async Task DoStuff()
        {
            using (var client = new HttpClient())
            {
                client.BaseAddress = "http://localhost/";
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    
                RegisterUserRequest content = new RegisterUserRequest { ConfirmPassword = "foo", Password = "foo", Email = "foo@bar" };
    
                HttpResponseMessage response = await client.PostAsJsonAsync("api/Account/Register", content).ConfigureAwait(false);
                if (response.StatusCode == System.Net.HttpStatusCode.BadRequest)
                {
                    BadRequestResponse message = await response.Content.ReadAsAsync<BadRequestResponse>().ConfigureAwait(false);
                    // do something with "message.ModelState.Values"
                }
            }
        }
    

    您可以检查HttpStatusCode.ExpectationFailed 而不是HttpStatusCode.BadRequest

    我还安装了 WebApi 客户端包(因为这个 ReadAsAsync 重载是这个库的扩展):

    Install-Package Microsoft.AspNet.WebApi.Client
    

    【讨论】:

    • 谢谢。 BadRequestResponse 定义帮助了我
    • 为什么在读取响应时不使用已经存在的 ModelState 类?
    • @EfeZaladin 我不确定 ModelState 类是否适用于所有场景。例如,这里的问题是创建一个在 Windows 桌面应用程序中使用的 .NET 类库,因此 ModelState 类不可用。
    【解决方案3】:

    实际上,您可以使用“CreateErrorResponse”解决问题。这个方法有一个重载,让你有机会发回 ModelState

     [HttpGet]
            public HttpResponseMessage Get([FromUri]InputFilterModel filter)
            {
                try
                {
                    if (filter == null || ModelState.IsValid == false)
                    {
                       return (filter == null)? Request.CreateErrorResponse(HttpStatusCode.BadRequest,"Input parameter can not be null")
                                              : Request.CreateErrorResponse(HttpStatusCode.BadRequest, ModelState);
                }
    

    模型状态返回一个 Json,其中包含验证问题的模型中的每个字段。您可以看到它直接在浏览器中或使用 fiddler 进行查询。

    【讨论】:

      猜你喜欢
      • 2017-11-01
      • 1970-01-01
      • 2014-06-20
      • 2019-08-05
      • 2010-10-27
      • 2015-06-15
      • 1970-01-01
      • 2020-11-19
      • 2018-06-29
      相关资源
      最近更新 更多