2009-11-10 4 views
15

공유 호스트에 배포 한 ASP.NET MVC 응용 프로그램에서 사용자 정의 오류에 문제가 있습니다. ErrorController를 생성하고 처리되지 않은 예외를 잡아 내 로그에 기록한 다음 제어를 ErrorController에 전달하여 사용자 지정 오류를 표시하기 위해 Global.asax에 다음 코드를 추가했습니다. 로깅이 잘 작동하기 때문에ASP.NET MVC app 사용자 정의 오류 페이지가 공유 호스팅 환경에 표시되지 않습니다.

protected void Application_Error(object sender, EventArgs e) 
{ 
    Exception ex = Server.GetLastError(); 
    Response.Clear(); 

    HttpException httpEx = ex as HttpException; 
    RouteData routeData = new RouteData(); 
    routeData.Values.Add("controller", "Error"); 

    if (httpEx == null) 
    { 
     routeData.Values.Add("action", "Index"); 
    } 
    else 
    { 
     switch (httpEx.GetHttpCode()) 
     { 
      case 404: 
       routeData.Values.Add("action", "HttpError404"); 
       break; 
      case 500: 
       routeData.Values.Add("action", "HttpError500"); 
       break; 
      case 503: 
       routeData.Values.Add("action", "HttpError503"); 
       break; 
      default: 
       routeData.Values.Add("action", "Index"); 
       break; 
     } 
    } 

    ExceptionLogger.LogException(ex); // <- This is working. Errors get logged 

    routeData.Values.Add("error", ex); 
    Server.ClearError(); 
    IController controller = new ErrorController(); 
    // The next line doesn't seem to be working 
    controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData)); 
} 

함으로써 Application_Error 확실히 발사 않으며, 대신 내 사용자 지정 오류 페이지를 표시하는, 내가 가서 아빠 일반적인 것들을 얻을 :이 코드는 here에서 가져옵니다. 위의 코드는 블로그 게시물의 제목에서 가져온 것입니다. MVC 프레임 워크의 Release Candidate 2를 사용합니다. 1.0에서 코드의 마지막 줄이 작동하지 않는 변화가 있었습니까? 평소대로 works great on my machine.

모든 의견을 크게 기뻐할 것입니다.

편집 : Web.config (Off, On 및 RemoteOnly)의 customErrors 모드에 대해 3 가지 가능성을 모두 시도했음을 잊어 버렸습니다. 이 설정에 관계없이 같은 결과가 나타납니다.

편집 2 : 컨트롤러 클래스의 [HandleError] 데코레이션을 사용하거나 사용하지 않고 시도해 보았습니다.

업데이트 : 404를 알아 냈습니다. Go Daddy의 Hosting Control Center에는 404 동작을 제어 할 수있는 설정 패널 섹션이 있으며 기본값은 일반 페이지를 표시하는 것으로,이 설정은 Web.config 설정보다 우선합니다. 그래서 내 맞춤 404 페이지가 이제 의도 한대로 표시됩니다. 그러나 500s와 503s는 여전히 작동하지 않습니다.

public static HomeContent GetStaticContent() 
{ 
    HomeContent hc; 

    try 
    { 
     string path = Configuration.CcmConfigSection.Config.Content.PathToStaticContent; 
     string fileText = File.ReadAllText(path); 
     string regex = @"^[^#]([^\r\n]*)"; 
     MatchCollection matches = Regex.Matches(fileText, regex, RegexOptions.Multiline); 
     hc = new HomeContent 
      { 
       ID = Convert.ToInt32(matches[0].Value), 
       Title = matches[1].Value, 
       DateAdded = DateTime.Parse(matches[2].Value), 
       Body = matches[3].Value, 
       IsCurrent = true 
      }; 
    } 
    catch (Exception ex) 
    { 
     try 
     { 
      ExceptionLogger.LogException(ex); 
     } 
     catch 
     { 
      // couldn't log exception, continue without crashing 
     } 
     hc = null; 
    } 

    return hc; 
} 
: 여기
public ActionResult Index() 
{ 
    CcmDataClassesDataContext dc = new CcmDataClassesDataContext(); 

    // This might generate an exception which will be handled in the OnException override 
    HomeContent hc = dc.HomeContents.GetCurrentContent(); 

    ViewData["bodyId"] = "home"; 
    return View(hc); 
} 

protected override void OnException(ExceptionContext filterContext) 
{ 
    // Only concerned here with SqlExceptions so an HTTP 503 message can 
    // be displayed in the Home View. All others will bubble up to the 
    // Global.asax.cs and be handled/logged there. 
    System.Data.SqlClient.SqlException sqlEx = 
     filterContext.Exception as System.Data.SqlClient.SqlException; 
    if (sqlEx != null) 
    { 
     try 
     { 
      ExceptionLogger.LogException(sqlEx); 
     } 
     catch 
     { 
      // couldn't log exception, continue without crashing 
     } 

     ViewData["bodyId"] = "home"; 
     filterContext.ExceptionHandled = true; 
     HomeContent hc = ContentHelper.GetStaticContent(); 
     if (hc == null) 
     { 
      // Couldn't get static content. Display friendly message on Home View. 
      Response.StatusCode = 503; 
      this.View("ContentError").ExecuteResult(this.ControllerContext); 
     } 
     else 
     { 
      // Pass the static content to the regular Home View 
      this.View("Index", hc).ExecuteResult(this.ControllerContext); 
     } 
    } 
} 

가 정적 콘텐츠를 가져 오기 위해 시도하는 코드이다 : 나는 다음과 같이 SQL Server가 예외가 발생하면 콘텐츠의 정적 텍스트 버전을 잡기 위해 HomeController 코드를 가지고

SqlException을 생성하도록 연결 문자열을 변경하면 코드가 오류를 올바르게 기록한 다음 정적 콘텐츠를 잡고 표시한다는 것을 확인했습니다. 그러나 Web.config의 정적 텍스트 파일 경로를 변경하여 홈 뷰의 503 버전을 테스트하면 "서비스를 사용할 수 없음"이외의 다른 페이지가 표시됩니다. 그게 전부 야. 사이트의 모양과 느낌이있는 맞춤형 503 메시지가 없습니다.

누구든지 도움이 될만한 코드 개선에 대한 제안 사항이 있습니까? HttpResponse에 다른 헤더를 추가하는 것이 도움이 될까요? 아니면 아빠가 503을 무자비하게 납치 한 것입니까?

답변

29

나는 솔루션을 발견했으며 매우 간단합니다. IIS7에서 실제로 문제가 발생했습니다. 이뿐만 아니라 angrypets.comgreat blog post by Rick Strahl 다른 걷어 내 근처의 검색 엔진에 저를 이끌어

public bool TrySkipIisCustomErrors { get; set; } 

: Visual Studio에서이 문제를 디버깅하는 동안 나는 전에 내가 발견하지했던 HttpResponse에 개체의 속성을 보았다 this question here on SO. 이러한 링크는 내가 할 수있는 것보다 훨씬 더 피투성이의 세부 사항을 설명하지만, 릭의 게시물에서이 인용 꽤 잘 포착 :

진짜 혼란 오류가 ASP.NET에 의해 갇혀 있기 때문에 여기에 발생하지만 궁극적으로 여전히 처리 IIS는 500 상태 코드를보고 스톡 IIS 오류 페이지를 반환합니다.

또한이 동작은 통합 모드의 IIS7에만 해당됩니다. msdn에서 :

TrySkipIisCustomErrors 속성 기본값은 true입니다 IIS 7.0에서 클래식 모드에서 실행합니다. 통합 모드에서 실행할 때 TrySkipIisCustomErrors 속성 기본값은 false입니다.

그래서 기본적으로 내가 할 필요가 결국 모든 바로 설계로 지금 기능을 500 503-Response.StatusCode 모든 것을 설정하는 코드 후 Response.TrySkipIisCustomErrors = true;를 추가합니다.

+1

+1 감사합니다, Bryan. 2 시간 이상 검색하면 필요한 답을 나에게주었습니다. 매우 간단합니다. 나에게 보안 예외를주고 404 오류 코드를 설정하려고 "Response.TrySkipIisCustomErrors = true;" 고쳤다. –

+2

이것은 나를 미치게 만들었다. 정말 고맙습니다. 배치 "Response.TrySkipIisCustomErrors = true;" 내 오류 컨트롤러에서 응답 코드를 설정 한 직후에 저에게 효과가있었습니다. 내 로컬 IIS 7 인스턴스가 사용자 지정 오류보기를 렌더링했기 때문에 오해의 소지가 있었지만 원격 준비 서버는 그렇지 않았습니다. = P – NovaJoe

+0

나는이 답변에서 제공되는 것을 적용한 후에 같은 배에 있었다 : http://stackoverflow.com/a/7499406/114029. 'Response.TrySkipIisCustomErrors = true;는 천국에서옵니다! :) –

0

저는 GoDaddy에서 ASP.NET MVC 사이트를 호스팅하고 있으며 또한 사용자 정의 오류 페이지를 다루는 문제에 직면했습니다. 시행 착오를 통해 내가 발견 한 바는 GoDaddy가 HTTP 수준에서 오류를 가로 채는 것입니다.

예를 들어 HTTP 상태 코드 404를 반환 한 페이지는 GoDaddy의 사용자 지정 오류 페이지를 인계받습니다. 결국 200 개의 상태를 반환하는 사용자 정의 오류 페이지가 변경되었고 404 관련 문제가 사라졌습니다. 내 HTML은 동일했지만 HTTP 상태를 변경해야했습니다.

503 가지 상태 응답으로 동일한 작업을 시도한 적이 전혀 없지만 동일한 완화 조치가 적용될 수도 있습니다. 503 상태를 반환하는 상태에서 200 상태를 반환하는 것으로 변경하면 문제가 해결됩니까?

이 해결 방법을 사용하면 검색 엔진이 오류 페이지의 색인을 생성하지 못하게하는 것이 좋습니다. 그러면 검색 엔진의 관점에서 볼 때 일반 페이지에서 200 개의 상태를 구별 할 수 없게됩니다. 따라서 META ROBOTS 태그를 추가하여 오류 페이지의 색인 생성을 방지하십시오.

<META NAME="ROBOTS" CONTENT="NOINDEX"> 

이 접근법의 단점은 페이지가 Google에서 삭제 될 수 있다는 것일 수 있습니다. 이는 분명 좋지 않습니다.

UPDATE : 그래서,뿐만 아니라, 당신은 또한 사용자 에이전트가 크롤러인지 여부를 감지 할 수 있으며, 그것의 경우는 크롤러가 아니라면, 정보에 대한 200 페이지의 this blog post을 반환하면서 크롤러가 503을 반환 크롤러 감지 방법 예, 크롤러와 사용자가 서로 다른 콘텐츠를 반환하는 것은 SEO no-no입니다.하지만 여러 사이트에서 지금까지 아무런 부작용이 없었으므로 문제가 얼마나 많은지 잘 모르겠습니다.

귀찮은 크롤러가 봇 탐지기를 통과 할 경우 두 가지 방법 (META ROBOTS 및 봇 탐지)을 사용하는 것이 가장 좋습니다.

+0

감사합니다. 저스틴. 마침내 404s를 수정하는 방법을 알아 냈습니다. 위의 업데이트를 참조하십시오. 내 상황에서이 접근법의 문제점은 503 중 일부는 내용이 있었던 실제 페이지에 친숙한 메시지를 표시하는 것입니다. 503 대신 200을 반환하고 크롤러가 해당 일을 색인하기에 불충분하다면 올바른 내용 대신 내 친숙한 오류 메시지의 색인을 생성합니다. 그래서 이것은 내 특별한 경우에는 작동하지 않을 것입니다. 그래도 답장을 보내 주셔서 감사합니다. – Bryan

+0

크롤러를 조심해야합니다. 나는 원래의 게시물에서 이것을 해결하기 위해 ROBOTS META 태그를 사용할 수 있다고 언급했지만 더 많은 정보를 추가했습니다. 위 참조. –

+0

당신은 어떤 부작용도 보지 않았을 지 모르지만, 저와 제 고객에게 똑같이 적용될 수 있다는 것을 알 수있는 방법이 없습니다 :-).내 클라이언트 및 확장 기능으로 인해 검색 엔진 인덱스에서 제거 및/또는 금지 될 수 있으므로 귀하의 접근 방법을 고려하는 것을 주저합니다. – Bryan

관련 문제