HttpClient 传递多个简单参数

Posted

技术标签:

【中文标题】HttpClient 传递多个简单参数【英文标题】:HttpClient pass multiple simple parameters 【发布时间】:2014-10-16 11:46:52 【问题描述】:

我正在尝试从一个controller 到另一个controller 执行POST。两个controller 都来自不同的项目。一个项目用于模拟表示层(我将这里称为测试项目)。

从测试项目中,我尝试将 2 个简单的 string 参数传递给另一个我将调用该过程的控制器。

var values = new List<KeyValuePair<string, string>>();
values.Add(new KeyValuePair<string, string>("id", param.Id.Value));
values.Add(new KeyValuePair<string, string>("type", param.Type.Value));
var content = new FormUrlEncodedContent(values);
using (var client = new HttpClient())

       client.BaseAddress = new Uri(url);
       client.DefaultRequestHeaders.Clear();
       client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("nl-NL"));

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

       string token = param.token.Value;
       client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

       var response = client.PostAsync("/api/Process/Product", content).Result;

       if (response.IsSuccessStatusCode)
       
           var result = response.Content.ReadAsStringAsync().Result;
           return Request.CreateResponse(HttpStatusCode.OK, result);
       

       return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "fail");

在进程控制器中,我试图像这样接收它:

[HttpPost]
public HttpResponseMessage Product(string id, string type)

    return null;

但它永远不会到达这个controller。我总是收到“未找到状态码”。

那么如何使用HttpClient() 传递两个简单的参数?

【问题讨论】:

为什么不使用 GetAsync?意味着将您的动词从 Post 更改为 Get。 因为我只能通过GET传递1个参数。虽然我尝试了你的解决方案,但没有奏效。进程中没有出现controller 【参考方案1】:

对简单类型参数使用 Get 而不是 Post。

    using (var client = new HttpClient())
    
        BaseAddress = new Uri(url);
        client.BaseAddress = new Uri(url);
   client.DefaultRequestHeaders.Clear();
   client.DefaultRequestHeaders.AcceptLanguage.Add(new StringWithQualityHeaderValue("nl-NL"));

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

   string token = param.token.Value;
   client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

        // New code:
        var response = await client.GetAsync( string.format("api/products/id=0&type=1",param.Id.Value,param.Id.Type) );
 if (response.IsSuccessStatusCode)
   
       var result = response.Content.ReadAsStringAsync().Result;
       return Request.CreateResponse(HttpStatusCode.OK, result);
   

   return Request.CreateErrorResponse(HttpStatusCode.BadRequest, "fail");

    

在 API 端你可以这样做。

[HttpGet]
public HttpResponseMessage Product(string id, string type)

  return null;

【讨论】:

我需要对属性中的路由做一些事情吗?就像他们在这篇文章中描述的那样:asp.net/web-api/overview/web-api-routing-and-actions/… 是的,你使用属性路由或者你可以更新你的路由配置来适应这个。 或者你可以试试product/id=value&type=value 你最后的评论成功了,请更新你的答案,以便我标记它。 很好的答案@NMK。太疯狂了,它没有内置的构建参数,它们让你自己格式化,但不管怎样,这都是关键!【参考方案2】:

接收帖子时,必须在参数中指定 [FromBody] 以调用方法

[HttpPost]
public HttpResponseMessage Product([FromBody]string id, [FromBody]string type)

    return null;

【讨论】:

这行不通...您不能拥有多个 [FromBody] 属性 docs.microsoft.com/en-us/aspnet/web-api/overview/…【参考方案3】:

我不确定我是否完全爱上了它,但我过去使用匿名类型和动态来处理这个......(注意使用 PostAsJsonAsync() 的配置差异。我最初忘记了这些。)

client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));    
client.PostAsJsonAsync("api/User/UpdateLastLogin", new  UserId = userId, ApplicationId = applicationId );

接收控制器:

    [HttpPost]
    public void UpdateLastLogin([FromBody]dynamic model)
    
        _userRepository.UpdateLastLogin((int)model.UserId, (int)model.ApplicationId);
    

在 WebApiConfig.Register() 中:

var json = config.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
config.Formatters.Remove(config.Formatters.XmlFormatter);

我传递的另一种方法是为每个调用创建一组全新的强类型模型。我不想这样做,因为我有很多东西要用于 WebAPI。

【讨论】:

也尝试了您的解决方案,但也没有用。它永远不会在进程controller中遇到断点。 你在调试这两个应用程序吗? 是的。在进程controller 中带有断点的所有其他方法都会被命中。只是这个没有。 Fiddler 也将 url 标记为红色。但是在检查它时,它没有显示任何可以告诉我问题可能是什么的东西。 如果你还没有听说过,这是一个在调试这种情况下非常有用的工具。 getpostman.com 这样,您应该能够使用两个参数(id、类型)进行发布以验证路由等。但是,您将无法使用两个参数离开该控制器。您将需要使用单个强类型对象或动态对象。【参考方案4】:

这是另一个可用于WinFormsWPFConsole 应用的示例

客户端代码

async Task<CalendarView> GetData(int month, int year, int deviceTypeID)
        
            var result = new MSOCommon.CalendarView();
            try
            
                HttpClient client = new HttpClient();

                var calendarRequest = new CalendarRequest()
                
                    Month = month,
                    Year = year,
                     DeviceTypeID = deviceTypeID,
                    UserInfo = Program.UserInfo
                ;

                var url = Properties.Settings.Default.ServerBaseUrl + string.Format("/api/calendar/Calendar");

                HttpResponseMessage response = await client.PostAsync(url, calendarRequest.AsJson());
                if (response.IsSuccessStatusCode)    // Check the response StatusCode
                
                    var serSettings = new JsonSerializerSettings()
                    
                        TypeNameHandling = TypeNameHandling.All
                    ;    

                    string responseBody = await response.Content.ReadAsStringAsync();

                    result = JsonConvert.DeserializeObject<MSOCommon.CalendarView>(responseBody, serSettings);
                
                else
                
                    logger.Error(Properties.Resources.DATACannotGetCalendar);
                
            
            catch (Exception ex)
            
                logger.Error(Properties.Resources.DATACannotGetCalendar + " " + ex.Message);
                logger.Error(ex);
            

            return result;
        

控制器服务器端代码

 [HttpPost()]
        public CalendarView Calendar(CalendarRequest calendarRequest)
        
            logger.Info(string.Format("Get calendar for month 0 and year 1 ", calendarRequest.Month, calendarRequest.Year));
            // TODO Check username
            var result = new CalendarView();

            using (var db = new MSOnlineEntities())
            
                result =   db.Calendars.Include("CalendarDetails")
                     .Where(x => x.CMonth == calendarRequest.Month && x.CYear == calendarRequest.Year && x.CDeviceTypeID == calendarRequest.DeviceTypeID).ToList()
                     .ConvertAll(x => new CalendarView
                     
                         ID = x.ID,
                         CMonth = x.CMonth,
                         CYear = x.CYear,
                         CDays = x.CDays,
                         CDeviceTypeID = x.CDeviceTypeID,
                         ClosedAtTime = x.ClosedAtTime,
                         ClosedByUser = x.ClosedByUser,
                         IsClosed = x.IsClosed,
                         CalendarDetails = x.CalendarDetails.ToList().ConvertAll(d => new CalendarDetailView
                         
                             ID = d.ID,
                             CalendarID = d.CalendarID,
                             MachineID = d.MachineID,
                             MachineName = d.DATA_MACHINE.Name,
                             D1 = d.D1 ?? -1,
                             D2 = d.D2 ?? -1,
                             D3 = d.D3 ?? -1,
                             D4 = d.D4 ?? -1,
                             D5 = d.D5 ?? -1,
                             D6 = d.D6 ?? -1,
                             D7 = d.D7 ?? -1,
                             D8 = d.D8 ?? -1,
                             D9 = d.D9 ?? -1,
                             D10 = d.D10 ?? -1,
                             D11 = d.D11 ?? -1,
                             D12 = d.D12 ?? -1,
                             D13 = d.D13 ?? -1,
                             D14 = d.D14 ?? -1,
                             D15 = d.D15 ?? -1,
                             D16 = d.D16 ?? -1,
                             D17 = d.D17 ?? -1,
                             D18 = d.D18 ?? -1,
                             D19 = d.D19 ?? -1,
                             D20 = d.D20 ?? -1,
                             D21 = d.D21 ?? -1,
                             D22 = d.D22 ?? -1,
                             D23 = d.D23 ?? -1,
                             D24 = d.D24 ?? -1,
                             D25 = d.D25 ?? -1,
                             D26 = d.D26 ?? -1,
                             D27 = d.D27 ?? -1,
                             D28 = d.D28 ?? -1,
                             D29 = d.D29 ?? -1,
                             D30 = d.D30 ?? -1,
                             D31 = d.D31 ?? -1
                         )
                     ).FirstOrDefault();

                return result;
            
        

【讨论】:

【参考方案5】:

在服务器上使用[HttpGet] 而不是[HttpPost]

 HttpResponseMessage response = 
 await client.GetAsync(string.format("api/product?id=0&type=1",param.Id.Value,param.Id.Type);

我的答案和 NMK 接受的答案之间的区别是 ? 而不是 / 这对我有用

【讨论】:

以上是关于HttpClient 传递多个简单参数的主要内容,如果未能解决你的问题,请参考以下文章

httpclient简介说明

httpClient 配置与测试

httpclient如何传递数组参数

HTTPClient模块的HttpGet和HttpPost

HttpClient 如何在一个地方捕获每个响应

在查询参数Angular HttpClient中传递数组