2010-11-23 10 views
7

Angenommen, ich habe folgende <httpErrors> Sammlung in einem web.config zurückzukehren:Wie eine httperror Configuration zurück zu „geerbt“ mit IIS 7 API

<httpErrors> 
</httpErrors> 

Ja, schön ‚n leer.

Und in IIS 7, sieht meine HTTP-Fehler-Seite wie folgt aus:

httpErrors

Beautiful! (Ich habe 404 einfach hervorgehoben, weil das das Beispiel ist, das ich in einer Sekunde verwenden werde).

Nun betreibe ich den folgenden Code:

errorElement["statusCode"] = 404; 
errorElement["subStatusCode"] = -1; 
errorElement["path"] = "/404.html"; 
httpErrorsCollection.Add(errorElement); 

Schöne. Ich habe jetzt, wie erwartet dies in meinem web.config:

<httpErrors> 
    <remove statusCode="404" subStatusCode="-1" /> 
    <error statusCode="404" subStatusCode="-1" prefixLanguageFilePath="" path="/404.html" /> 
</httpErrors> 

könnte nicht glücklicher sein. Jetzt, in IIS 7 sieht meine HTTP-Fehler Abschnitt, wie erwartet, wie unten: alt text

Das Leben könnte nicht süßer an dieser Stelle sein. Jetzt möchte ich meinen 404-Fehler programmatisch auf den ursprünglichen Screenshot zurücksetzen. Die Logik diktiert, dass ich meine neue Fehler remove:

httpErrorsCollection.Remove(errorElement); 

Aber ach, wenn ich das tue, mein web.config sieht viel wie folgt aus:

<httpErrors> 
     <remove statusCode="404" subStatusCode="-1" /> 
    </httpErrors> 

Und mein IIS sieht ein bisschen wie folgt aus:

wegen meiner web.config

alt text

Dies ist zu erwarten - aber wie, mit ServerManager und alle ist es nützlich IIS 7 API, entferne ich das httpError Element vollständig und kehrt mein web.config zurück zur Seite:

<httpErrors> 
</httpErrors> 

Irgendwelche Ideen?

Antwort

4

Ich bin hier schon einmal gestoßen. Die einzige Art, wie ich diese Arbeit machen konnte, war RevertToParent() auf dem system.webServer/httpErrors Abschnitt aufzurufen und die Änderungen zu übernehmen, bevor Sie Änderungen vornehmen, z.B .:

ConfigurationSection httpErrorsSection = 
      config.GetSection("system.webServer/httpErrors"); 

// Save a copy of the errors collection first (see pastebin example) 
httpErrorsCollectionLocal = 
      CopyLocalErrorCollection(httpErrorsSection.GetCollection() 
      .Where(e => e.IsLocallyStored) 
      .ToList<ConfigurationElement>()); 

httpErrorsSection.RevertToParent(); 
serverManager.CommitChanges(); 

Sie haben nach RevertToParent() is called because the errors collection remains intact until CommitChanges zu begehen() `genannt wird.

Anschließend müssen Sie die gespeicherte Kopie der lokalen Fehlersammlung erneut hinzufügen, indem Sie die benutzerdefinierten Fehler entfernen oder aktualisieren, wenn sie erneut hinzugefügt werden.

Ich habe unten ein vollständiges Arbeitsbeispiel eingefügt.Der Code funktioniert auf der Website root web.config aber mit ein wenig Bastelei Sie die Unterstützung für web.config Dateien in Unterordner hinzufügen könnte:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using Microsoft.Web.Administration; 

namespace IIS7_HttpErrorSectionClearing 
{ 
    class Program 
    { 
    static void Main(string[] args) 
    { 
     long siteId = 60001; 

     // Add some local custom errors 
     CustomErrorManager.SetCustomError(siteId, 404, -1, ResponseMode.File, @"D:\websites\60001\www\404.html"); 
     CustomErrorManager.SetCustomError(siteId, 404, 1, ResponseMode.File, @"D:\websites\60001\www\404-1.html"); 
     CustomErrorManager.SetCustomError(siteId, 404, 5, ResponseMode.File, @"D:\websites\60001\www\404-5.html"); 

     // Change existing local custom error 
     CustomErrorManager.SetCustomError(siteId, 404, 1, ResponseMode.ExecuteURL, "/404-5.aspx"); 

     // Revert to inherited 
     CustomErrorManager.RevertCustomError(siteId, 404, 5); 
     CustomErrorManager.RevertCustomError(siteId, 404, -1); 
     CustomErrorManager.RevertCustomError(siteId, 404, 1); 
    } 
    } 

    public enum ResponseMode 
    { 
    File, 
    ExecuteURL, 
    Redirect 
    } 

    public static class CustomErrorManager 
    { 
    public static void RevertCustomError(long siteId, int statusCode, int subStatusCode) 
    { 
     List<Error> httpErrorsCollectionLocal = CopyLocalsAndRevertToInherited(siteId); 
     int index = httpErrorsCollectionLocal.FindIndex(e => e.StatusCode == statusCode && e.SubStatusCode == subStatusCode); 
     if(index > -1) 
     { 
     httpErrorsCollectionLocal.RemoveAt(index); 
     } 
     PersistLocalCustomErrors(siteId, httpErrorsCollectionLocal); 
    } 

    public static void SetCustomError(long siteId, long statusCode, int subStatusCode, 
              ResponseMode responseMode, string path) 
    { 
     SetCustomError(siteId, statusCode, subStatusCode, responseMode, path, null); 
    } 

    public static void SetCustomError(long siteId, long statusCode, int subStatusCode, 
              ResponseMode responseMode, string path, string prefixLanguageFilePath) 
    { 
     List<Error> httpErrorsCollectionLocal = CopyLocalsAndRevertToInherited(siteId); 
     AddOrUpdateError(httpErrorsCollectionLocal, statusCode, subStatusCode, responseMode, path, prefixLanguageFilePath); 
     PersistLocalCustomErrors(siteId, httpErrorsCollectionLocal); 
    } 

    private static void PersistLocalCustomErrors(long siteId, List<Error> httpErrorsCollectionLocal) 
    { 
     using (ServerManager serverManager = new ServerManager()) 
     { 
     Site site = serverManager.Sites.Where(s => s.Id == siteId).FirstOrDefault(); 
     Configuration config = serverManager.GetWebConfiguration(site.Name); 
     ConfigurationSection httpErrorsSection = config.GetSection("system.webServer/httpErrors"); 
     ConfigurationElementCollection httpErrorsCollection = httpErrorsSection.GetCollection(); 

     foreach (var localError in httpErrorsCollectionLocal) 
     { 
      ConfigurationElement remove = httpErrorsCollection.CreateElement("remove"); 
      remove["statusCode"] = localError.StatusCode; 
      remove["subStatusCode"] = localError.SubStatusCode; 
      httpErrorsCollection.Add(remove); 

      ConfigurationElement add = httpErrorsCollection.CreateElement("error"); 
      add["statusCode"] = localError.StatusCode; 
      add["subStatusCode"] = localError.SubStatusCode; 
      add["responseMode"] = localError.ResponseMode; 
      add["path"] = localError.Path; 
      add["prefixLanguageFilePath"] = localError.prefixLanguageFilePath; 
      httpErrorsCollection.Add(add); 
     } 
     serverManager.CommitChanges(); 
     } 
    } 

    private static List<Error> CopyLocalsAndRevertToInherited(long siteId) 
    { 
     List<Error> httpErrorsCollectionLocal; 
     using (ServerManager serverManager = new ServerManager()) 
     { 
     Site site = serverManager.Sites.Where(s => s.Id == siteId).FirstOrDefault(); 
     Configuration config = serverManager.GetWebConfiguration(site.Name); 
     ConfigurationSection httpErrorsSection = config.GetSection("system.webServer/httpErrors"); 
     ConfigurationElementCollection httpErrorsCollection = httpErrorsSection.GetCollection(); 

     // Take a copy because existing elements can't be modified. 
     httpErrorsCollectionLocal = CopyLocalErrorCollection(httpErrorsSection.GetCollection() 
             .Where(e => e.IsLocallyStored).ToList<ConfigurationElement>()); 

     httpErrorsSection.RevertToParent(); 

     // Have to commit here because RevertToParent won't clear the collection until called. 
     serverManager.CommitChanges(); 
     return httpErrorsCollectionLocal; 
     } 
    } 

    private static List<Error> CopyLocalErrorCollection(List<ConfigurationElement> collection) 
    { 
     List<Error> errors = new List<Error>(); 
     foreach (var error in collection) 
     { 
     errors.Add(new Error() 
     { 
      StatusCode = (long)error["statusCode"], 
      SubStatusCode = (int)error["subStatusCode"], 
      ResponseMode = (ResponseMode)error["responseMode"], 
      Path = (string)error["path"], 
      prefixLanguageFilePath = (string)error["prefixLanguageFilePath"] 
     }); 
     } 
     return errors; 
    } 

    private static void AddOrUpdateError(List<Error> collection, long statusCode, int subStatusCode, 
              ResponseMode responseMode, string path, string prefixLanguageFilePath) 
    { 
     // Add or update error 
     Error error = collection.Find(ce => ce.StatusCode == statusCode && ce.SubStatusCode == subStatusCode); 
     if (error == null) 
     { 
     collection.Add(new Error() 
     { 
      StatusCode = statusCode, 
      SubStatusCode = subStatusCode, 
      ResponseMode = responseMode, 
      Path = path, 
      prefixLanguageFilePath = prefixLanguageFilePath 
     }); 
     } 
     else 
     { 
     error.ResponseMode = responseMode; 
     error.Path = path; 
     error.prefixLanguageFilePath = prefixLanguageFilePath; 
     } 
    } 

    private class Error 
    { 
     public long StatusCode { get; set; } 
     public int SubStatusCode { get; set; } 
     public ResponseMode ResponseMode { get; set; } 
     public string Path { get; set; } 
     public string prefixLanguageFilePath { get; set; } 
    } 
    } 
} 
+0

Das ist der einzige Weg, den ich auch finden könnte :(Ich habe meine eigene Methode mit der 'RevertToParent()' Methode erstellt, die auch alle anderen Änderungen behält, aber es fühlt sich so schrecklich an – joshcomley

16

In IIS7 und oben unter Verwaltung Abschnitt können wir ein Symbol namens Configuration Editor sehen, Doppelklick auf und erweitern zu

system.webserver-->webdav-->httpErrors

Rechtsklick aufStandardpfad unter

section-->Click on Revert to Parent

Dann Neustart der Website

Die Änderungen rückgängig gemacht werden wird zurück

+0

Dies beantwortet die Frage nicht - das OP erwähnt speziell den ServerManager und die IIS 7 API, eine .Net-Lösung, die den Entwicklern helfen soll, ihre IIS-Server über Code zu verwalten Diese Antwort ist speziell auf das GUI-Management des Servers ausgerichtet. –

0

Gut, das ist, was ich für dieses Problem gefunden habe:

ServerManager serverManager = new ServerManager(); 
Configuration config = serverManager.GetWebConfiguration(siteName); 
ConfigurationSection httpErrorsSection = config.GetSection("system.webServer/httpErrors"); 
ConfigurationElementCollection httpErrorsCollection = httpErrorsSection.GetCollection(); 
foreach (ConfigurationElement errorEle in httpErrorsCollection) { 
    if (errorEle("statusCode") == statusCode && errorEle("subStatusCode") == subStatusCode) { 
     errorEle.Delete(); 
     serverManager.CommitChanges(); 
     return; 
    } 
} 

Ich bekomme eine Liste von Elemente als normal, dann Schleife, um die eine, die ich will, und dann löschen auf dem Element zu finden. Das ist es und es funktioniert. Ich weiß nicht, ob es das gab, als diese Frage gestellt wurde, aber jetzt. Sie müssen sicherstellen, dass Sie den Statuscode und den Substatuscode kennen.