Каков правильный способ вызова ASP.NET веб-API из мобильного приложения Xamarin, используя C #, особенно для метода post

#c# #android #asp.net-web-api #xamarin.forms #httpclient

#c# #Android #asp.net-web-api #xamarin.формы #httpclient #xamarin.forms

Вопрос:

Я создал ASP.NET Проект веб-API, в котором я создал два контроллера api, один предназначен для получения всех зарегистрированных пользователей, а второй — для входа в приложение с помощью имени пользователя и пароля. В то время как я тестирую оба метода с postman, они работают нормально. Я использую свойство BaseAddress для ввода URI и помещаю «api / controllername / action» в метод PostAsJsonAsync (). Когда я отлаживаю свой код приложения xamarin, в PostAsJasonAsync() методе он показывает-

 {StatusCode: 400, ReasonPhrase: 'Bad Request', Version: 1.1, Content: System.Net.Http.StreamContent, Headers:
{
  Connection: close
  Date: Sun, 23 Aug 2020 11:13:44 GMT
  Forwarded: host=192.168.20.176:45459; proto=http
  Server: Microsoft-HTTPAPI/2.0
  X-Android-Received-Millis: 1598181223781
  X-Android-Response-Source: NETWORK 400
  X-Android-Selected-Protocol: http/1.1
  X-Android-Sent-Millis: 1598181223764
  Content-Length: 374
  Content-Type: text/html; charset=us-ascii}.
  

код контроллера веб-API является:

     public class LoginController : ApiController
    {
        SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["SPCon"].ToString());
        SqlCommand cmd = new SqlCommand();

        [HttpPost]
        public int Login([FromBody] Login user)
        {
            int ret = 0;
            try
            {
                cmd.CommandType = CommandType.Text;
                cmd.CommandText = "SELECT count(*) FROM Login WHERE UserNames = '"   user.UserName.Trim()   "' and PassWord="   user.PassWord.Trim();
                cmd.Connection = con;
                if (con.State == ConnectionState.Open)
                {
                    con.Close();
                }
                con.Open();
                ret = Convert.ToInt32(cmd.ExecuteScalar());
                con.Close();
            }
            catch
            {

            }
            return ret;
        }

    }

  

Код мобильного приложения выглядит следующим образом:

 public void LoginBtnClicked()
        {
            if (Username.Trim() != "" amp;amp; Password.Trim() != "")
            {
                using(var client=new HttpClient())
                {
                    client.BaseAddress = new Uri("http://ipaddress:45459/"); //I'm using conveyor to get this address and I'm running mobile app in android emulator
                    client.DefaultRequestHeaders.Accept.Clear();
                    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

                    UserLogin user = new UserLogin
                    {
                        UserName = Username,
                        PassWord = Password
                    };
                    var response = client.PostAsJsonAsync("api/Login/Login", user).Resu<
                    if (response.IsSuccessStatusCode)
                    {
                        var a = response.Content.ReadAsStringAsync();
                        if (a.Result.ToString().Trim() == "0")
                        {
                            Application.Current.MainPage.DisplayAlert("Error", "Invalid Login Credentials", "Cancel");
                        }
                        else
                        {
                            Application.Current.MainPage.Navigation.PushAsync(new Home());
                        }
                    }
                    else
                    {
                        Application.Current.MainPage.DisplayAlert("Error", "Internal Server Error", "Ok");
                    }
                    
                }
            }
        }
  

Комментарии:

1. имеют ли класс Login на сервере и класс UserLogin на клиенте одинаковое определение?

2. да, оба имеют одинаковое определение

3. Лучший способ решить проблему — использовать сниффер, такой как wireshark или fiddler. Сравните заголовки в первом запросе с использованием Postman с заголовками c #. Сделайте код c # похожим в точности на Postman. Заголовки по умолчанию в c # не совпадают с заголовками Postman, и у вас либо неправильный, либо отсутствующий заголовок.

4. Точно так же, как сказал @jdweng, вы должны проверить, какие заголовки вы добавляете. Postman обычно добавляет некоторые общие заголовки, особенно не включенные language , которые вызывали у меня проблемы в прошлом. Но в нынешнем виде невозможно точно узнать, в чем проблема

5. Возможно, вам потребуется указать TLS версии 1.2: HttpClient HttpClient = new HttpClient(); //укажите, чтобы использовать TLS 1.2 в качестве соединения по умолчанию System.Net.ServicePointManager. SecurityProtocol = SecurityProtocolType.Tls12;

Ответ №1:

Спасибо, что приложили свои усилия к моему вопросу. Я нашел решение, изменив процедуру вызова веб-API на стороне клиента. Я использовал методы HttpContent и PostAsync () вместо методов BaseAddress и PostAsJsonAsync (). код, приведенный ниже:

 using(HttpClient client=new HttpClient())
                {
                    UserLogin user = new UserLogin
                    {
                        UserName = Username,
                        PassWord = Password
                    };
                    var json = JsonConvert.SerializeObject(user);
                    HttpContent content = new StringContent(json);
                    content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
                    var uri = new Uri("http://ipaddress/api/UserLogin");
                    var response = await client.PostAsync(uri, content);

                    //more conditions and code....
                }