У меня есть проект ASP.NET, который включает отправку HTTP-запросов через Web-API Framework. Следующее исключение возникает только при отладке:
Сервер совершил нарушение протокола. Раздел = ResponseStatusLine
Проект работает отлично, если я начинаю без отладки.
Как мне устранить это исключение?
Любая помощь приветствуется!
Обновление
Проблема связана с ASP.NET MVC Identity Framework.
Чтобы получить доступ к другим методам Web-API, клиентское приложение должно сначала выполнить POST запрос login (запрос на вход еще не должен быть защищен, и поэтому я отправляю строки имени пользователя и пароля непосредственно к методу Web-API POST). Если я прошу прокомментировать запрос на вход, больше не будет сделано никаких исключений.
Ниже приведены соответствующие фрагменты кода:
Метод Post:
UserManager<ApplicationUser> UserManager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
AccountAccess ac = new AccountAccess();
public async Task<HttpResponseMessage> Post()
{
string result = await Request.Content.ReadAsStringAsync();
LoginMessage msg = JsonConvert.DeserializeObject<LoginMessage>(result);
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
var user = UserManager.Find(msg.username, msg.password);
if (user == null)
return response;
if (user.Roles == null)
return response;
var role = from r in user.Roles where (r.RoleId == "1" || r.RoleId == "2") select r;
if (role.Count() == 0)
{
return response;
}
bool task = await ac.LoginAsync(msg.username, msg.password);
response.Content = new StringContent(task.ToString());
return response;
}
Класс доступа к учетной записи (имитирующий шаблон AccountController по умолчанию в шаблоне MVC):
public class AccountAccess
{
public static bool success = false;
public AccountAccess()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountAccess(UserManager<ApplicationUser> userManager)
{
UserManager = userManager;
}
public UserManager<ApplicationUser> UserManager { get; private set; }
public async Task<bool> LoginAsync(string username, string password)
{
var user = await UserManager.FindAsync(username, password);
if (user != null)
{
await SignInAsync(user, isPersistent: false);
return true;
}
else
{
return false;
}
}
~AccountAccess()
{
if (UserManager != null)
{
UserManager.Dispose();
UserManager = null;
}
}
private IAuthenticationManager AuthenticationManager
{
get
{
return HttpContext.Current.GetOwinContext().Authentication;
}
}
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
}
Ниже приведены соответствующие фрагменты кода:
В клиентском приложении:
public static async Task<List<T>> getItemAsync<T>(string urlAction)
{
message = new HttpRequestMessage();
message.Method = HttpMethod.Get;
message.RequestUri = new Uri(urlBase + urlAction);
HttpResponseMessage response = await client.SendAsync(message);
string result = await response.Content.ReadAsStringAsync();
List<T> msgs = JsonConvert.DeserializeObject<List<T>>(result);
return msgs;
}
В контроллере Web-API:
public HttpResponseMessage Get(string id)
{
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
if (id == "ItemA")
{
List<ItemAMessage> msgs = new List<ItemAMessage>();
// some code...
response.Content = new StringContent(JsonConvert.SerializeObject(msgs));
}
else if (id == "ItemB")
{
List<ItemBMessage> msgs = new List<ItemBMessage>();
// some code...
response.Content = new StringContent(JsonConvert.SerializeObject(msgs));
}
return response;
}
Некоторые наблюдения, которые у меня есть:
- Я думал, что мне может потребоваться отправить запрос асинхронно (с синтаксисом
async-await
), но исключение все еще сохраняется. - Если я прохожу через код, запрос делает, введите метод HTTP, но код прерывается в случайной строке (почему?!), прежде чем возвращать ответ, поэтому я не предполагаю, что никакой ответ не отправляется назад.
- Я попробовал следующие решения, как это было предложено в ответах на подобные вопросы, ни одна из которых не работает для меня:
- Настройка
useUnsafeHeaderParsing
-true
- Добавление заголовка
Keep-Alive: false
- Изменение настроек порта Skype (у меня нет Skype, а порты 80 и 443 не заняты)
- Настройка
Дополнительная информация, если они имеют значение:
- Mac OS, работающая под управлением Windows 8.1 с помощью VMware Fusion
- Visual Studio 2013
- .NET Framework 4.5
- Сервер IIS Express
Обновление 2
Исключение разрешено, но я не уверен, какая модификация сделала трюк. AFAIK, либо один, либо оба из следующих зафиксировали его:
- У меня есть метод
checkConnection()
, который в основном отправляет запрос GET и возвращает true при успешном завершении. Я добавилawait
в методHttpClient.SendAsync()
и принудительно async до конца. - Я удалил весь код в конструкторе MainWindow, за исключением метода
InitializeComponent()
, в обработчик события Initial Initialized.
Любая идея?
Ниже приведены соответствующие коды к приведенным выше изменениям:
метод checkConnectionAsync:
public static async Task<bool> checkConnectionAsync()
{
message = new HttpRequestMessage();
message.Method = HttpMethod.Get;
message.RequestUri = new Uri(urlBase);
try
{
HttpResponseMessage response = await client.SendAsync(message);
return (response.IsSuccessStatusCode);
}
catch (AggregateException)
{
return false;
}
}
Обработчик события инициализированного окна (отведенный из конструктора MainWindow):
private async void Window_Initialized(object sender, EventArgs e)
{
if (await checkConnectionAsync())
{
await loggingIn();
getItemA();
getItemB();
}
else
{
logMsg.Content = "Connection Lost. Restart GUI and try again.";
}
}
Обновление 3
Хотя это может быть немного не по теме, я хотел бы добавить примечание на стороне, если кто-то еще попадает в это - Я использовал неправильный подход к аутентификации для веб-API для начала. Шаблон проекта Web-API уже имеет встроенную структуру Identity, и я как-то "заменил" ее довольно простым, но сломанным подходом...
Это видео - это хороший учебник для начала.
В этой статье содержится более подробное объяснение.