2015-08-27 19 views
21

Tôi có một dự án ASP.NET liên quan đến việc gửi yêu cầu HTTP qua khung Web-API. Ngoại lệ sau chỉ được nâng lên khi gỡ lỗi:WebException về yêu cầu HTTP trong khi gỡ lỗi

Máy chủ đã vi phạm giao thức. Section = ResponseStatusLine

Dự án chạy hoàn hảo nếu tôi "Bắt đầu không gỡ lỗi".

Tôi nên giải quyết ngoại lệ này như thế nào?

Mọi trợ giúp đều được đánh giá cao!


Cập nhật

Vấn đề dường như có liên quan đến ASP.NET MVC nhận dạng khung.

Để truy cập các phương pháp Web-API khác, ứng dụng khách phải POST lần đầu tiên yêu cầu đăng nhập (Yêu cầu đăng nhập không cần bảo mật và vì vậy tôi gửi chuỗi tên người dùng và mật khẩu trực tiếp tới Web -API POST method). Nếu tôi nhận xét yêu cầu đăng nhập, không có ngoại lệ nào được nêu ra.

Dưới đây là các đoạn mã liên quan:

Phương pháp mới gởi:

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; 
} 

Lớp Tài khoản Access (mô phỏng AccountController mặc định trong MVC mẫu):

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); 
    } 
} 

Dưới đây là những đoạn có liên quan mã:

Trong ứng dụng client:

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; 
} 

Trong điều khiển 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; 
} 

Một số quan sát tôi có:

  1. Tôi tôi nghĩ rằng tôi có thể cần phải gửi yêu cầu không đồng bộ (với cú pháp async-await), nhưng ngoại lệ vẫn tồn tại theo cách đó.
  2. Nếu tôi bước qua mã, yêu cầu làm nhập phương thức HTTP, nhưng mã ngắt ở dòng ngẫu nhiên (Tại sao ?!) trước khi trả lời, vì vậy tôi cho rằng không có phản hồi nào được gửi lại.
  3. Tôi đã thử các giải pháp sau đây, như đề xuất trong câu trả lời cho câu hỏi tương tự, không ai trong số đó làm việc cho tôi:
    • Thiết useUnsafeHeaderParsing để true
    • Thêm tiêu đề Keep-Alive: false
    • Thay đổi cài đặt cổng của Skype (Tôi không có Skype và cổng 80 và 443 không bị chiếm đóng)

Thông tin bổ sung rmation, trong trường hợp họ có vấn đề:

  • Mac OS chạy Windows 8.1 với VMware Fusion
  • Visual Studio 2013
  • .NET Framework 4.5
  • IIS tốc máy chủ

Cập nhật 2

Trường hợp ngoại lệ được giải quyết, nhưng tôi không chắc chắn về việc sửa đổi nào đã thực hiện thủ thuật. AFAIK, một trong hai hoặc cả hai điều sau đây đã sửa lỗi:

  • Tôi có phương thức checkConnection(), về cơ bản gửi yêu cầu GET và trả về thành công. Tôi đã thêm await vào phương pháp HttpClient.SendAsync() và được thực thi không đồng bộ tất cả các cách thức lên.
  • Tôi đã rút lại tất cả mã trong hàm tạo MainWindow, ngoại trừ phương thức InitializeComponent(), vào trình xử lý sự kiện Windows Initializedized.

Bất kỳ ý tưởng nào?

Dưới đây là mã có liên quan đến những sửa đổi được minh họa ở trên:

phương pháp 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; 
    } 
} 

Window xử lý sự kiện khởi tạo (rút từ các nhà xây dựng 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."; 
    } 
} 

Cập nhật 3

Mặc dù đây có thể là một chút off-topic, tôi muốn thêm một mặt lưu ý trong trường hợp bất cứ ai khác rơi vào này - Tôi đã sử dụng phương pháp xác thực sai cho Web-API để bắt đầu. Mẫu dự án Web-API đã có sẵn một khuôn khổ Identity tích hợp, và bằng cách nào đó tôi đã "thay thế" nó bằng một cách tiếp cận khá đơn giản nhưng bị hỏng ...

This video là một hướng dẫn tốt để bắt đầu.

This article cung cấp giải thích toàn diện hơn.

+1

Điều gì sẽ xảy ra nếu bạn xóa cuộc gọi ngủ trong LoginAsync? –

+0

@Brianfromstatefarm Tôi thực sự đã thêm dòng đó để kiểm tra nội dung khác và quên xóa nó khi đăng mã. Cảm ơn bạn đã chỉ ra! –

+0

Có thể VM đang thêm vào vấn đề này không? –

Trả lời

6

Trong ứng dụng khách hàng bạn đang chờ đợi task. Truy cập Kết quả mà không cần chờ đợi có thể gây ra lỗi không thể đoán trước. Nếu nó chỉ thất bại trong chế độ Debug, tôi không thể nói chắc chắn, nhưng nó chắc chắn không phải là cùng một chương trình (kiểm tra thêm được thêm vào, tối ưu hóa thường không được kích hoạt). Bất kể khi nào Debugging đang hoạt động, nếu bạn gặp lỗi mã, bạn nên sửa lỗi đó và nó sẽ hoạt động ở cả hai chế độ.

Vì vậy, hãy làm cho chức năng đó không đồng bộ và gọi nhiệm vụ với công cụ sửa đổi await hoặc gọi task.WaitAndUnwrapException() về nhiệm vụ sao cho nó sẽ chặn đồng bộ cho đến khi kết quả được trả về từ máy chủ.

+0

Tôi thực sự có cả hai phiên bản (có và không có chờ đợi) của phương pháp getItem, nếu đó là một trong những bạn đang đề cập đến. Thật không may, chờ đợi và đảm bảo "không đồng bộ tất cả các cách xuống/lên" không giải quyết ngoại lệ tôi nhận được. Cảm ơn bạn đã chỉ ra! Tôi đã chỉnh sửa mã để tránh nhầm lẫn. –

+0

Tôi đã trao phần thưởng cho câu trả lời này vì nó chỉ ra nguyên nhân có thể xảy ra nhất trong vấn đề của tôi. –

1

Đảm bảo URL có chuỗi truy vấn ID có giá trị là Mục A hoặc Mục B. Nếu không, bạn sẽ không trả về nội dung có mã trạng thái Http 200 có thể dẫn đến vi phạm giao thức.

1

Khi bạn sử dụng SendAsync, bạn được yêu cầu tự cung cấp tất cả tiêu đề thư có liên quan, bao gồm message.Headers.Authorization = new AuthenticationHeaderValue("Basic", token);.
Bạn có thể muốn sử dụng GetAsync thay thế (và gọi một phương thức nhận cụ thể trên máy chủ).
Ngoài ra, bạn có chắc là ngoại lệ được giải quyết không? Nếu bạn có phương thức async mức cao trả về Task và không làm trống, ngoại lệ đó có thể bị bỏ qua âm thầm.

+0

Bạn có thể xây dựng trên tuyên bố cuối cùng của mình không? Như đã nêu trong bản cập nhật thứ hai, tôi đã sửa đổi mã thành "không đồng bộ tất cả các con đường lên", với mức cao nhất (trình xử lý sự kiện) trả về 'void'. Mọi phương thức không đồng bộ khác trả về 'Tác vụ'. –

+0

Về điểm khác, tôi có nên sử dụng GetAsync với các yêu cầu GET (hoặc HEAD) và SendAsync cho phần còn lại không? –

+0

Tôi muốn đảm bảo rằng thực sự không có trình xử lý sự kiện nào trả về ´Task´ hoặc các tác vụ khác không được chờ đợi. –

Các vấn đề liên quan