11

假设我在 a 中有以下<httpErrors>集合web.config

<httpErrors>
</httpErrors>

是的,很好,很空。

在 IIS 7 中,我的 HTTP 错误页面如下所示:

httpErrors

美丽的!(我突出显示 404 只是因为这是我稍后将使用的示例)。

现在,我运行以下代码:

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

迷人的。正如预期的那样,我现在在我的web.config

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

再高兴不过了。现在,在 IIS 7 中,我的 HTTP 错误部分看起来像预期的那样,如下所示: 替代文字

此时的生活再美好不过了。现在,我想以编程方式将我的 404 错误恢复到原始屏幕截图中显示的状态。逻辑表明我应该remove新​​的错误:

httpErrorsCollection.Remove(errorElement);

但是,唉,如果我这样做,我的web.config看起来很像这样:

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

我的 IIS 看起来有点像这样:

替代文字

这是因为我的预期web.config- 但是如何,使用ServerManager和所有有用的 IIS 7 API,我是否httpError完全删除该元素并恢复web.config到:

<httpErrors>
</httpErrors>

有任何想法吗?

4

3 回答 3

21

在 IIS7 及以上的Management部分,我们可以看到一个名为Configuration Editor的图标, 双击展开

system.webserver-->webdav-->httpErrors

右键单击默认路径,在

部分->单击恢复为父级

然后重启网站

更改将被还原

于 2012-12-17T09:30:27.853 回答
5

我以前碰到过这个。我可以完成这项工作的唯一方法是在进行任何更改之前调用RevertToParent()该部分并提交更改,例如:system.webServer/httpErrors

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

RevertToParent() is called because the errors collection remains intact until您必须在调用 CommitChanges()`后提交。

然后,您必须重新添加本地错误集合的已保存副本,以在重新添加自定义错误时删除或更新它们。

我在下面粘贴了一个完整的工作示例。该代码适用于站点根目录web.config,但稍作修改,您可以添加对子web.config文件夹中文件的支持:

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; }
    }  
  }
}
于 2010-11-24T22:15:35.813 回答
0

好吧,这就是我发现的这个问题:

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

我像往常一样得到一个元素列表,然后循环查找我想要的元素,然后在元素上调用 delete。就是这样,它的工作原理。我不知道问这个问题时是否存在,但现在确实存在。您必须确保您知道该状态代码和子状态代码。

于 2016-06-13T22:28:53.527 回答