TL; DR
blockquote>
__proto__
является свойствомobject
, которое позволяет вам искать в цепочке прототипов. В то время какprototype
является свойствомFunction
, которое позволяет вам добавлять общие функции в функцию конструктора.Длинный ответ
blockquote>Поймите это на примере, скажем, вы создаете функцию конструктора.
function A() {}
, а затем создать его экземпляр,var a = new A()
.Затем добавьте функцию следующим образом:
A.prototype.getA = function () { return 'A'; }
.Теперь, если вы попытаетесь получить доступ к
a.getA()
, вы получите результат, то естьgetA
будет выполнено.Но как он узнает о функции
getA
, хотяgetA
был добавлен после создания экземпляраa
. Именно из-за использования__proto__
вы можете перемещаться вверх по цепочке (вы, наверное, слышали о цепочке прототипов).Технически,
__proto__
является свойством объекта, тогда какprototype
является свойствомfunction
. Но какfunctions
мог иметь собственность? Потому что все в JavaScript неявно преобразуется в объект. Вы никогда не задумывались, как вы могли что-то вроде этого:'test'.toUpperCase()
? Разве строковые литералы не являются «объектами» и являются ли они примитивами?Прочитайте это для справки: http://jayendra.co.in/objects-in-javascript/ [1143 ]
Теперь ответим на ваш вопрос:
Что означает
blockquote>Function.prototype.__proto__
?Вы пытаетесь получить доступ к свойству
prototype
вFunction
функция конструктора. Помните, чтоprototype
сам по себе являетсяobject
, поэтому вы можете получить доступ к таким свойствам, какconstructor
и__proto__
.blockquote>
Function.prototype.__proto__ === Object.prototype
Чтобы включить сцепление, при доступе к свойству
__proto__
вы ищите!Любая функция может получить доступ ко всем свойства объекта. Как?
blockquote>Свойство
Object
, скажем,toString
. Вы можете сделать,A.toString() // A created at the start
. Но мы никогда не создавали функциюtoString
для функции конструктораA
!
Как насчет класса TransferResult? (на основе ответа Станса )
/// <summary>
/// Transfers execution to the supplied url.
/// </summary>
public class TransferResult : ActionResult
{
public string Url { get; private set; }
public TransferResult(string url)
{
this.Url = url;
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var httpContext = HttpContext.Current;
// MVC 3 running on IIS 7+
if (HttpRuntime.UsingIntegratedPipeline)
{
httpContext.Server.TransferRequest(this.Url, true);
}
else
{
// Pre MVC 3
httpContext.RewritePath(this.Url, false);
IHttpHandler httpHandler = new MvcHttpHandler();
httpHandler.ProcessRequest(httpContext);
}
}
}
Обновлено: Теперь работает с MVC3 (с использованием кода из сообщения Саймона ). Он должен (не удалось его протестировать) также работать в MVC2, проверяя, работает ли он в интегрированном конвейере IIS7 +.
Для полной прозрачности; В нашей производственной среде мы никогда не используем TransferResult напрямую. Мы используем TransferToRouteResult, который, в свою очередь, вызывает TransferResult. Вот что на самом деле работает на моих производственных серверах.
public class TransferToRouteResult : ActionResult
{
public string RouteName { get;set; }
public RouteValueDictionary RouteValues { get; set; }
public TransferToRouteResult(RouteValueDictionary routeValues)
: this(null, routeValues)
{
}
public TransferToRouteResult(string routeName, RouteValueDictionary routeValues)
{
this.RouteName = routeName ?? string.Empty;
this.RouteValues = routeValues ?? new RouteValueDictionary();
}
public override void ExecuteResult(ControllerContext context)
{
if (context == null)
throw new ArgumentNullException("context");
var urlHelper = new UrlHelper(context.RequestContext);
var url = urlHelper.RouteUrl(this.RouteName, this.RouteValues);
var actualResult = new TransferResult(url);
actualResult.ExecuteResult(context);
}
}
И если вы используете T4MVC (если нет ... сделайте!), это расширение может пригодиться.
public static class ControllerExtensions
{
public static TransferToRouteResult TransferToAction(this Controller controller, ActionResult result)
{
return new TransferToRouteResult(result.GetRouteValueDictionary());
}
}
Используя этот маленький драгоценный камень, вы можете сделать
// in an action method
TransferToAction(MVC.Error.Index());
Не могли бы вы просто создать экземпляр контроллера, на который вы хотели бы перенаправить, вызвать нужный метод действия, а затем вернуть результат этого? Примерно так:
HomeController controller = new HomeController();
return controller.Index();
Просто создайте экземпляр другого контроллера и выполните его метод действия.
Вы можете обновить другой контроллер и вызвать метод действия, возвращающий результат. Однако это потребует от вас размещения вашего представления в общей папке.
Я не уверен, что вы имели в виду дубликат, но:
return new HomeController().Index();
Редактировать
Другой вариант может заключаться в создании вашей собственной ControllerFactory, это Таким образом, вы можете определить, какой контроллер создать.
Разве маршрутизация не позаботится об этом сценарии для вас? то есть для сценария, описанного выше, вы можете просто создать обработчик маршрута, который реализует эту логику.
Недавно я узнал, что ASP.NET MVC не поддерживает Server.Transfer (), поэтому я создал метод-заглушку (вдохновленный Default.aspx.cs).
private void Transfer(string url)
{
// Create URI builder
var uriBuilder = new UriBuilder(Request.Url.Scheme, Request.Url.Host, Request.Url.Port, Request.ApplicationPath);
// Add destination URI
uriBuilder.Path += url;
// Because UriBuilder escapes URI decode before passing as an argument
string path = Server.UrlDecode(uriBuilder.Uri.PathAndQuery);
// Rewrite path
HttpContext.Current.RewritePath(path, false);
IHttpHandler httpHandler = new MvcHttpHandler();
// Process request
httpHandler.ProcessRequest(HttpContext.Current);
}
Бесстыдное воровство форматирования Генри ...
Редактировать 4/11/2011: TempData прерывается с Server.TransferRequest, начиная с MVC 3 RTM
Изменен приведенный ниже код, чтобы генерировать исключение, но на данный момент нет другого решения.
Вот моя модификация, основанная на предложении Маркуса измененная версия оригинального сообщения Стэна. Я добавил дополнительный конструктор, чтобы взять словарь значений маршрута - и переименовал его в MVCTransferResult, чтобы избежать путаницы, что это может быть просто перенаправление.
Теперь я могу сделать следующее для перенаправления:
return new MVCTransferResult(new {controller = "home", action = "something" });
Мой измененный класс:
public class MVCTransferResult : RedirectResult
{
public MVCTransferResult(string url)
: base(url)
{
}
public MVCTransferResult(object routeValues):base(GetRouteURL(routeValues))
{
}
private static string GetRouteURL(object routeValues)
{
UrlHelper url = new UrlHelper(new RequestContext(new HttpContextWrapper(HttpContext.Current), new RouteData()), RouteTable.Routes);
return url.RouteUrl(routeValues);
}
public override void ExecuteResult(ControllerContext context)
{
var httpContext = HttpContext.Current;
// ASP.NET MVC 3.0
if (context.Controller.TempData != null &&
context.Controller.TempData.Count() > 0)
{
throw new ApplicationException("TempData won't work with Server.TransferRequest!");
}
httpContext.Server.TransferRequest(Url, true); // change to false to pass query string parameters if you have already processed them
// ASP.NET MVC 2.0
//httpContext.RewritePath(Url, false);
//IHttpHandler httpHandler = new MvcHttpHandler();
//httpHandler.ProcessRequest(HttpContext.Current);
}
}
Я хотел перенаправить текущий запрос на другой контроллер / действие, сохраняя при этом путь выполнения точно таким же, как если бы был запрошен этот второй контроллер / действие. В моем случае Server.Request не работал, потому что я хотел добавить больше данных. Фактически это эквивалентно тому, что текущий обработчик выполняет другой HTTP GET / POST, а затем передает результаты клиенту. Я уверен, что найдутся более эффективные способы достижения этой цели, но вот что работает для меня:
RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Public");
routeData.Values.Add("action", "ErrorInternal");
routeData.Values.Add("Exception", filterContext.Exception);
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
var request = new RequestContext(context, routeData);
IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(filterContext.RequestContext, "Public");
controller.Execute(request);
Ваше предположение верно: я помещаю этот код в
public class RedirectOnErrorAttribute : ActionFilterAttribute, IExceptionFilter
и использую его для отображения ошибок разработчикам, пока он в продакшене буду использовать обычный редирект. Обратите внимание, что я не хотел использовать сеанс ASP.NET, базу данных или другие способы передачи данных исключения между запросами.
сохраняя путь выполнения точно таким же, как если бы был запрошен этот второй контроллер / действие. В моем случае Server.Request не работал, потому что я хотел добавить больше данных. Фактически это эквивалентно тому, что текущий обработчик выполняет другой HTTP GET / POST, а затем передает результаты клиенту. Я уверен, что найдутся более эффективные способы достижения этой цели, но вот что мне подходит:RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Public");
routeData.Values.Add("action", "ErrorInternal");
routeData.Values.Add("Exception", filterContext.Exception);
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
var request = new RequestContext(context, routeData);
IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(filterContext.RequestContext, "Public");
controller.Execute(request);
Ваше предположение верно: я поместил этот код в
public class RedirectOnErrorAttribute : ActionFilterAttribute, IExceptionFilter
и использую его для отображения ошибок разработчикам, пока он в продакшене буду использовать обычный редирект. Обратите внимание, что я не хотел использовать сеанс ASP.NET, базу данных или другие способы передачи данных исключения между запросами.
сохраняя путь выполнения точно таким же, как если бы был запрошен этот второй контроллер / действие. В моем случае Server.Request не работал, потому что я хотел добавить больше данных. Фактически это эквивалентно тому, что текущий обработчик выполняет другой HTTP GET / POST, а затем передает результаты клиенту. Я уверен, что найдутся более эффективные способы достижения этой цели, но вот что мне подходит:RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Public");
routeData.Values.Add("action", "ErrorInternal");
routeData.Values.Add("Exception", filterContext.Exception);
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
var request = new RequestContext(context, routeData);
IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(filterContext.RequestContext, "Public");
controller.Execute(request);
Ваше предположение верно: я поместил этот код в
public class RedirectOnErrorAttribute : ActionFilterAttribute, IExceptionFilter
и использую его для отображения ошибок разработчикам, пока он в продакшене буду использовать обычный редирект. Обратите внимание, что я не хотел использовать сеанс ASP.NET, базу данных или другие способы передачи данных исключения между запросами.
Фактически это эквивалентно тому, что текущий обработчик выполняет другой HTTP GET / POST, а затем передает результаты клиенту. Я уверен, что найдутся более эффективные способы достижения этой цели, но вот что работает для меня:RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Public");
routeData.Values.Add("action", "ErrorInternal");
routeData.Values.Add("Exception", filterContext.Exception);
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
var request = new RequestContext(context, routeData);
IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(filterContext.RequestContext, "Public");
controller.Execute(request);
Ваше предположение верно: я помещаю этот код в
public class RedirectOnErrorAttribute : ActionFilterAttribute, IExceptionFilter
и использую его для отображения ошибок разработчикам, пока он в продакшене буду использовать обычный редирект. Обратите внимание, что я не хотел использовать сеанс ASP.NET, базу данных или другие способы передачи данных исключения между запросами.
Фактически это эквивалентно тому, что текущий обработчик выполняет другой HTTP GET / POST, а затем передает результаты клиенту. Я уверен, что найдутся более эффективные способы достижения этой цели, но вот что работает для меня:RouteData routeData = new RouteData();
routeData.Values.Add("controller", "Public");
routeData.Values.Add("action", "ErrorInternal");
routeData.Values.Add("Exception", filterContext.Exception);
var context = new HttpContextWrapper(System.Web.HttpContext.Current);
var request = new RequestContext(context, routeData);
IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(filterContext.RequestContext, "Public");
controller.Execute(request);
Ваше предположение верно: я помещаю этот код в
public class RedirectOnErrorAttribute : ActionFilterAttribute, IExceptionFilter
и использую его для отображения ошибок разработчикам, пока он в продакшене буду использовать обычный редирект. Обратите внимание, что я не хотел использовать сеанс ASP.NET, базу данных или другие способы передачи данных исключения между запросами.
в продакшене буду использовать обычное перенаправление. Обратите внимание, что я не хотел использовать сеанс ASP.NET, базу данных или другие способы передачи данных исключения между запросами. в продакшене буду использовать обычное перенаправление. Обратите внимание, что я не хотел использовать сеанс ASP.NET, базу данных или другие способы передачи данных исключения между запросами.Не ответ сам по себе, но очевидно, что требование заключается не только в том, чтобы фактическая навигация "делала" эквивалентную функциональность Webforms Server.Transfer(), но и в том, чтобы все это было полностью поддержано в рамках юнит-тестирования. Поэтому ServerTransferResult должен "выглядеть" как RedirectToRouteResult и быть как можно более похожим на иерархию классов.
Я думаю сделать это, посмотрев на рефлектор и сделав все, что делает класс RedirectToRouteResult, а также различные методы базового класса контроллера, а затем "добавив" последний в контроллер с помощью методов расширения. Может быть, это могут быть статические методы внутри одного класса, для простоты/безмятежности загрузки?
Если я обойду это, то выложу, иначе, может быть, кто-то другой меня опередит!
.