2009-02-19 5 views
13

Tôi có trang aspx nơi tôi cho phép người dùng tải lên tệp và tôi muốn giới hạn kích thước tải lên tệp tối đa là 10MB. IIS7, .NET 3.5. Tôi có cấu hình sau trong tệp web.config của mình:Tôi có thể nắm bắt và xử lý maxAllowedContentLength trong IIS7 ở đâu?

<location path="foo.aspx"> 
    <system.web> 
     <!-- maxRequestLength: kbytes, executionTimeout:seconds --> 
     <httpRuntime maxRequestLength="10240" executionTimeout="120" /> 
     <authorization> 
      <allow roles="customRole"/> 
      <!-- Deny everyone else --> 
      <deny users="*"/> 
     </authorization> 
    </system.web> 
    <system.webServer> 
     <security> 
      <requestFiltering> 
       <!-- maxAllowedContentLength: bytes --> 
       <requestLimits maxAllowedContentLength="10240000"/> 
      </requestFiltering> 
     </security> 
     <handlers accessPolicy="Read, Script"> 
      <add name="foo" path="foo.aspx" verb="POST" 
       type="System.Web.UI.PageHandlerFactory" 
       preCondition="integratedMode" /> 
     </handlers>  
    </system.webServer> 
</location> 

Tôi có mô-đun xử lý lỗi tùy chỉnh triển khai IHttpModule. Tôi đã nhận thấy rằng khi vượt quá maxRequestLength, HttpApplication.Error thực sự được tăng lên. Tuy nhiên, khi tôi chơi với maxAllowedContentLength, sự kiện HttpApplication.Error không được nâng lên và người dùng được chuyển hướng đến trang 404.13. Tôi đã gắn liền với Visual Studio với ngoại lệ cơ hội đầu tiên bật không có gì đang được ném.

Suy nghĩ đầu tiên của tôi là kiểm tra chiều dài nội dung tiêu đề trong một sự kiện trước đó - có đề xuất/phương pháp hay nhất nào về nơi tôi thực hiện việc này không? PostLogRequest? EndRequest?

Trả lời

14

Sau khi xem ASP.NET Application Life Cycle Overview for IIS 7.0 và thực hiện thử nghiệm của riêng mình, tôi giả định rằng xác thực yêu cầu được thực hiện nội bộ bởi IIS trước khi bất kỳ sự kiện nào được nâng lên.

Có vẻ như chỉ LogRequest, PostLogRequest, EndRequest, PreSendRequestContent và PreSendRequestHeaders được nâng lên sau khi xác thực nội bộ với lỗi này.

Tôi đã quyết định đính kèm một trình xử lý sự kiện vào sự kiện HttpApplication.EndRequest trong trình xử lý lỗi tùy chỉnh của mình và kiểm tra mã trạng thái 404.13 trên POST và xử lý khi tôi cần nó để xử lý, trong trường hợp của tôi là chuyển hướng đến trang gọi điện sẽ kiểm tra Server.GetLastError() và hiển thị lỗi thân thiện với người dùng cuối.

private void application_EndRequest(object sender, EventArgs e) 
{ 
    HttpRequest request = HttpContext.Current.Request; 
    HttpResponse response = HttpContext.Current.Response; 

    if ((request.HttpMethod == "POST") && 
     (response.StatusCode == 404 && response.SubStatusCode == 13)) 
    { 
     // Clear the response header but do not clear errors and 
     // transfer back to requesting page to handle error 
     response.ClearHeaders(); 
     HttpContext.Current.Server.Transfer(
      request.AppRelativeCurrentExecutionFilePath); 
    } 
} 

Tôi hoan nghênh phản hồi về cách tiếp cận này và các phương án thay thế.

+0

Không phải câu trả lời của hướng dương chỉ hoạt động nếu Chế độ đường ống được quản lý được đặt thành Tích hợp. Ít nhất đó là lý do tại sao tôi có kinh nghiệm – Marvin

+0

Tôi nhận thấy rằng giải pháp này không xử lý Xác thực đúng cách. Khi tôi gọi Server.Transfer, các thói quen kiểm tra xác thực của trang đích không thành công vì thuộc tính HttpContext.Current.User là NULL. Nó dường như không được gây ra bởi thanh toán bù trừ các tiêu đề, như lấy dòng đó ra vẫn còn kết quả trong vấn đề. Có cách nào để khắc phục điều này? Nó không phải là một giải pháp khác. – Triynko

+0

Tôi đặt mã lỗi của @Triynko trong trình xử lý sự kiện của bạn. Tôi đang sử dụng Umbraco - Tôi không chắc chắn nếu đó là đáng kể nhưng đây là nơi duy nhất tôi đã có thể bắt 'tối đa yêu cầu tối đa vượt quá' ngoại lệ như được nêu ra. Tôi cũng phải gọi 'Response.ClearContent();' để loại bỏ YSOD. 'Application_Error' không kích hoạt ngoại lệ này (mặc dù nó cho RequestValidation) và tôi không thể nhận được 'OnError' để kích hoạt trong UserControl hoặc Masterpage. Không thể tìm thấy trang thực. ;) –

3

Phương pháp đơn giản nhất là xử lý nó theo phương pháp OnError của chính trang đó.

Tôi nghĩ điều này chỉ hoạt động trong .NET 4.0, vì thuộc tính WebEventCode được ghi nhận là MỚI trong .NET 4.0.

protected override void OnError(EventArgs e) 
{ 
    Exception err = Server.GetLastError(); 
    if (err is HttpException) 
    { 
     if ((err as HttpException).WebEventCode == 3004) 
     { 
      Context.Items["error"] = "File exceeded maximum allowed length."; 
      Server.Transfer(Context.Request.Url.LocalPath); 
      return; 
     } 
    } 
    base.OnError(e); 
} 

protected override void OnLoad(EventArgs e) 
{ 
    base.OnLoad(e); 
    if (!IsPostBack) 
    { 
     string error = Context.Items["error"] as string; 
     if (!string.IsNullOrEmpty(error)) 
      showErrorMessage(error); 
    } 
} 

Những gì tôi đã làm là:

  • nhận được lỗi cuối cùng với Server.GetLastError
  • kiểm tra rằng đó là một "chiều dài yêu cầu tối đa vượt quá." lỗi (WebEventCode == 3004).
  • thêm một giá trị cho Context.Items bộ sưu tập để lá cờ yêu cầu như một lỗi
  • chuyển theo yêu cầu trở lại trang chính nó với Server.Transfer (Context.Request.Url.LocalPath)
  • của trang phương pháp onload kiểm tra cho cờ lỗi và hiển thị thông báo nếu có mặt

Điều này đảm bảo lỗi được xử lý hoàn toàn trên trang được yêu cầu và trang có khả năng báo cáo lỗi. Cũng lưu ý rằng trong khi trình duyệt cuối cùng sẽ nhận được phản hồi thích hợp, trình duyệt có thể mất thời gian tải lên toàn bộ yêu cầu trước khi nó xử lý phản hồi của máy chủ và hiển thị nó. Hành vi này có thể được định nghĩa là một phần của tương tác máy chủ/trình duyệt trong giao thức HTTP, vì vậy có lẽ không nhiều việc có thể được thực hiện về điều đó.

+0

Đôi khi nó trả về mã '0'. –

+0

Tôi đã sử dụng chức năng này để kiểm tra ... http://stackoverflow.com/a/665591/221683 –