Вы можете написать быстрый скрипт, который удаляет единственную директиву #include, компилирует проекты и записывает имя в #include и файл, из которого он был удален, в случае, если ошибки компиляции не были.
Пусть он работает ночью, а на следующий день у вас будет 100% правильный список включенных файлов, которые вы можете удалить.
Иногда грубая сила работает: -)
edit: а иногда это не так :-). Вот немного информации из комментариев:
Код взят от http://blogs.microsoft.co.il/blogs/shay/archive/2009/03/06/real-world-error-hadnling-in-asp-net-mvc-rc2.aspx и работает в ASP.net MVC 1.0 также
, Вот то, как я обрабатываю http исключения:
protected void Application_Error(object sender, EventArgs e)
{
Exception exception = Server.GetLastError();
// Log the exception.
ILogger logger = Container.Resolve<ILogger>();
logger.Error(exception);
Response.Clear();
HttpException httpException = exception as HttpException;
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Error");
if (httpException == null)
{
routeData.Values.Add("action", "Index");
}
else //It's an Http Exception, Let's handle it.
{
switch (httpException.GetHttpCode())
{
case 404:
// Page not found.
routeData.Values.Add("action", "HttpError404");
break;
case 500:
// Server error.
routeData.Values.Add("action", "HttpError500");
break;
// Here you can handle Views to other error codes.
// I choose a General error template
default:
routeData.Values.Add("action", "General");
break;
}
}
// Pass exception details to the target error View.
routeData.Values.Add("error", exception);
// Clear the error on server.
Server.ClearError();
// Avoid IIS7 getting in the middle
Response.TrySkipIisCustomErrors = true;
// Call target Controller and pass the routeData.
IController errorController = new ErrorController();
errorController.Execute(new RequestContext(
new HttpContextWrapper(Context), routeData));
}
Ниже приведены мои требования для решения 404 и ниже Я показываю, как я это реализую:
Я думаю, вам следует сохранить Application_Error
в Global.asax для более высоких таких как необработанные исключения и ведение журнала (например, ответ Шэя Якоби показывает), но не обработку 404. Вот почему я предлагаю убрать 404 из файла Global.asax.
Это хорошая идея для удобства сопровождения. Используйте ErrorController , чтобы можно было легко адаптировать будущие улучшения вашей хорошо продуманной страницы 404 . Кроме того, убедитесь, что ваш ответ содержит код 404 !
public class ErrorController : MyController
{
#region Http404
public ActionResult Http404(string url)
{
Response.StatusCode = (int)HttpStatusCode.NotFound;
var model = new NotFoundViewModel();
// If the url is relative ('NotFound' route) then replace with Requested path
model.RequestedUrl = Request.Url.OriginalString.Contains(url) & Request.Url.OriginalString != url ?
Request.Url.OriginalString : url;
// Dont get the user stuck in a 'retry loop' by
// allowing the Referrer to be the same as the Request
model.ReferrerUrl = Request.UrlReferrer != null &&
Request.UrlReferrer.OriginalString != model.RequestedUrl ?
Request.UrlReferrer.OriginalString : null;
// TODO: insert ILogger here
return View("NotFound", model);
}
public class NotFoundViewModel
{
public string RequestedUrl { get; set; }
public string ReferrerUrl { get; set; }
}
#endregion
}
HandleUnknownAction
404 в ASP.NET MVC нужно перехватывать в нескольких местах. Первый - HandleUnknownAction
.
Метод InvokeHttp404
создает обычное место для перенаправления на ErrorController
и наше новое действие Http404
. Подумайте DRY !
public abstract class MyController : Controller
{
#region Http404 handling
protected override void HandleUnknownAction(string actionName)
{
// If controller is ErrorController dont 'nest' exceptions
if (this.GetType() != typeof(ErrorController))
this.InvokeHttp404(HttpContext);
}
public ActionResult InvokeHttp404(HttpContextBase httpContext)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
var errorRoute = new RouteData();
errorRoute.Values.Add("controller", "Error");
errorRoute.Values.Add("action", "Http404");
errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
errorController.Execute(new RequestContext(
httpContext, errorRoute));
return new EmptyResult();
}
#endregion
}
Примерно так (это не обязательно должно быть StructureMap):
Пример MVC1.0:
public class StructureMapControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(Type controllerType)
{
try
{
if (controllerType == null)
return base.GetControllerInstance(controllerType);
}
catch (HttpException ex)
{
if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
((ErrorController)errorController).InvokeHttp404(RequestContext.HttpContext);
return errorController;
}
else
throw ex;
}
return ObjectFactory.GetInstance(controllerType) as Controller;
}
}
Пример MVC2.0:
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
return base.GetControllerInstance(requestContext, controllerType);
}
catch (HttpException ex)
{
if (ex.GetHttpCode() == 404)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
((ErrorController)errorController).InvokeHttp404(requestContext.HttpContext);
return errorController;
}
else
throw ex;
}
return ObjectFactory.GetInstance(controllerType) as Controller;
}
Я думаю, что лучше выявлять ошибки ближе к тому месту, где они возникают. Вот почему я предпочитаю описанное выше обработчику Application_Error
.
Это второе место, где можно поймать ошибку 404.
Этот маршрут должен указывать на наше действие Http404
. Обратите внимание, что параметр url
будет относительным URL-адресом, потому что механизм маршрутизации отсекает здесь часть домена? Вот почему у нас есть вся эта логика условного URL-адреса на шаге 1.
routes.MapRoute("NotFound", "{*url}",
new { controller = "Error", action = "Http404" });
Это третье и последнее место, где можно поймать 404 в приложении MVC, которое вы не вызываете сами.Если вы не поймаете здесь несовпадающие маршруты, тогда MVC передаст проблему ASP.NET (Global.asax), и вам это не нужно в этой ситуации.
Например, когда в мой контроллер ссуд (получен из MyController
) отправляется неверный идентификатор:
//
// GET: /Detail/ID
public ActionResult Detail(int ID)
{
Loan loan = this._svc.GetLoans().WithID(ID);
if (loan == null)
return this.InvokeHttp404(HttpContext);
else
return View(loan);
}
Было бы неплохо, если бы все это можно было подключить в меньшем количестве мест с меньшим количеством кода, но я думаю, что это решение более удобное в обслуживании, более тестируемое и довольно прагматичное.
Спасибо за обратную связь. Я бы хотел получить больше.
ПРИМЕЧАНИЕ: это было значительно отредактировано по сравнению с моим исходным ответом, но цель / требования те же - вот почему я не добавил новый ответ
Мне очень нравится решение Коттсакса, и я думаю, что оно очень четко объяснено. Мое единственное дополнение - изменить шаг 2 следующим образом
public abstract class MyController : Controller
{
#region Http404 handling
protected override void HandleUnknownAction(string actionName)
{
//if controller is ErrorController dont 'nest' exceptions
if(this.GetType() != typeof(ErrorController))
this.InvokeHttp404(HttpContext);
}
public ActionResult InvokeHttp404(HttpContextBase httpContext)
{
IController errorController = ObjectFactory.GetInstance<ErrorController>();
var errorRoute = new RouteData();
errorRoute.Values.Add("controller", "Error");
errorRoute.Values.Add("action", "Http404");
errorRoute.Values.Add("url", httpContext.Request.Url.OriginalString);
errorController.Execute(new RequestContext(
httpContext, errorRoute));
return new EmptyResult();
}
#endregion
}
В основном это останавливает URL, содержащие некорректные действия И контроллеры, от запуска процедуры исключения дважды. Например, для таких URL, как asdfsdf/dfgdfgd
Единственный способ заставить метод @cottsak работать с недопустимыми контроллерами - это изменить существующий запрос маршрута в CustomControllerFactory, например:
public class CustomControllerFactory : DefaultControllerFactory
{
protected override IController GetControllerInstance(RequestContext requestContext, Type controllerType)
{
try
{
if (controllerType == null)
return base.GetControllerInstance(requestContext, controllerType);
else
return ObjectFactory.GetInstance(controllerType) as Controller;
}
catch (HttpException ex)
{
if (ex.GetHttpCode() == (int)HttpStatusCode.NotFound)
{
requestContext.RouteData.Values["controller"] = "Error";
requestContext.RouteData.Values["action"] = "Http404";
requestContext.RouteData.Values.Add("url", requestContext.HttpContext.Request.Url.OriginalString);
return ObjectFactory.GetInstance<ErrorController>();
}
else
throw ex;
}
}
}
Я должен упомянуть, что использую MVC 2.0.