2010-11-23 6 views
7

Supongamos que tengo la colección <httpErrors> siguiente en un web.config:Cómo revertir una httpError ConfigurationElement de nuevo a "heredada" por medio de IIS 7 API

<httpErrors> 
</httpErrors> 

Sí, Nice 'n vacía.

Y en IIS 7, mi página de errores HTTP tiene el siguiente aspecto:

httpErrors

hermoso! (He resaltado 404 simplemente porque ese es el ejemplo que usaré en un segundo).

Ahora, ejecute el siguiente código:

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

precioso. Ahora tengo, como se esperaba esto en mi web.config:

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

no podría estar más feliz. Ahora, en IIS 7 mi sección de errores HTTP se ve, como se esperaba, como a continuación: alt text

La vida no podría ser más dulce en este momento. Ahora, en el futuro, quiero volver a convertir mi error 404 programáticamente en el estado que se muestra en la captura de pantalla original. La lógica dicta que debería remove mi nuevo error:

httpErrorsCollection.Remove(errorElement); 

Pero, por desgracia, si hago esto, mi web.config se parece mucho a esto:

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

Y mi IIS se ve un poco como esto:

alt text

Esto se espera debido a mi web.config - pero ¿cómo, usando ServerManager y todo lo que es útil IIS 7 API, puedo eliminar el elemento httpError por completo y volver de nuevo a mi web.config:

<httpErrors> 
</httpErrors> 

¿Alguna idea?

Respuesta

4

Me he tropezado con esto antes. La única manera de que pudiera hacer este trabajo fue llamar RevertToParent() en la sección de system.webServer/httpErrors y confirmar los cambios antes de hacer cualquier cambio, por ejemplo .:

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

Usted tiene que comprometerse después RevertToParent() is called because the errors collection remains intact until CommitChanges() `se llama.

Luego, tiene que volver a agregar la copia guardada de la recopilación local de errores para eliminar o actualizar los errores personalizados a medida que se vuelven a agregar.

He pegado un ejemplo de trabajo completo a continuación.El código funciona en la raíz del sitio web.config pero con un poco de bricolaje se puede añadir soporte para web.config archivos de las subcarpetas:

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

Esa es la única manera que pude encontrar, también :(Creé mi propio método para hacerlo usando el método 'RevertToParent()', que también mantiene otros cambios, pero se siente tan horrible. Lo publicaré pronto. – joshcomley

16

En IIS7 y anteriormente en Gestión sección, podemos ver un icono llamado editor de configuración, doble clic y ampliar a

system.webserver-->webdav-->httpErrors

Haga clic derecho enruta defecto, bajo

section-->Click on Revert to Parent

Entonces reiniciar el sitio web

Los cambios se revirtieron

+0

Esto no responde a la pregunta: OP menciona específicamente ServerManager y la API de IIS 7, que es una solución .Net destinada a ayudar a los desarrolladores a administrar sus servidores IIS mediante código. Esta respuesta está específicamente orientada a la administración de la GUI del servidor. –

0

Bueno, esto es lo que he encontrado para este problema:

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

Obtengo una lista de elementos como normales, luego bucle para encontrar el que yo quiero, y luego llamar eliminar en el elemento. Eso es todo y funciona. No sé si esto existió cuando se hizo esta pregunta, pero ahora sí. Deberá asegurarse de conocer el código de estado y el código de subestación.

Cuestiones relacionadas