Могу ли я получить тип возврата действия из фильтра действий? - PullRequest
11 голосов
/ 19 мая 2010

У меня есть приложение ASP.NET MVC 2, в котором я создаю фильтр пользовательских действий. Этот фильтр находится на контроллерах в приложении и проверяет из базы данных, доступна ли эта функция в настоящее время.

Public Overrides Sub OnActionExecuting(ByVal filterContext As System.Web.Mvc.ActionExecutingContext)
  Try
    ' Check controller name against database.
    Dim controllerName = filterContext.Controller.GetType().Name
    controllerName = controllerName.Remove(controllerName.Length - 10)
    ' Look up availability.
    Dim available As Boolean = _coreService.GetControllerAvailability(controllerName)
    If Not available Then
      ' Redirect to unavailable notice.
      filterContext.Result = New RedirectResult("/Home/Unavailable/")
    End If
  Catch ex As Exception
    _eventLogger.LogWarning(ex, EventLogEntryType.Error)
    Throw
  End Try
End Sub

Моя проблема в том, что в зависимости от запрошенного действия мне нужно перенаправить пользователя к действию, которое возвращает либо представление, частичное представление, либо JSON.

Учитывая ActionExecutingContext, могу ли я узнать, какой тип возврата изначально запрошенного действия?

EDIT:

Хорошо, я подхожу ближе, но у меня другая проблема.

Public Overrides Sub OnActionExecuting(ByVal filterContext As System.Web.Mvc.ActionExecutingContext)
  Try
    ' Check controller name against database.
    Dim controllerName = filterContext.Controller.GetType().Name
    Dim shortName = controllerName.Remove(controllerName.Length - 10)
    ' Look up availability.
    Dim available As Boolean = _coreService.GetControllerAvailability(shortName)
    If Not available Then
      ' find out what type is expected to be returned
      Dim actionName As String = filterContext.ActionDescriptor.ActionName
      Dim controllerType = Type.GetType("Attenda.Stargate.Web." & controllerName)
      Dim actionMethodInfo = controllerType.GetMethod(actionName)
      Dim actionReturnType = actionMethodInfo.ReturnType.Name

      Select Case actionReturnType
        Case "PartialViewResult"
          filterContext.Result = New RedirectResult("/Home/UnavailablePartial/")
        Case "JsonResult"
          filterContext.Result = New RedirectResult("/Home/UnavailableJson/")
        Case Else
          filterContext.Result = New RedirectResult("/Home/Unavailable/")
      End Select

    End If
  Catch ex As Exception
    _eventLogger.LogWarning(ex, EventLogEntryType.Error)
    Throw
  End Try
End Sub

Я могу использовать отражение, чтобы найти тип возврата метода действия. Моя проблема, если у меня есть следующие методы на контроллере:

Public Function Create() As ViewResult
  Return View()
End Function

<AcceptVerbs(HttpVerbs.Post)>
Public Function Create(values as FormCollection) As ViewResult
  ' Do stuff here
End Function

Я получаю исключение AmbiguousMatchException.

Имея информацию, которую я имею в методе OnActionExecuting, есть ли в любом случае более точное определение вызываемой перегрузки?

Ответы [ 3 ]

9 голосов
/ 15 февраля 2013

Я создал AuthenticationFilterAttribute на основе этого, который возвращает разные результаты в зависимости от типа:

    /// <summary>
    /// Access to the action will be blocked if the user is not logged in. 
    ///  Apply this to the controller level or individual actions as an attribute.
    /// </summary>
    public class AuthenticationFilterAttribute : ActionFilterAttribute
    {
        protected const string InvalidAccess = "Invalid access";

        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            // Find out if the user is logged in: 
            Controller controller = (Controller)filterContext.Controller;
            if (!controller.User.Identity.IsAuthenticated)
            {
                switch (GetExpectedReturnType(filterContext).Name)
                {
                    case "JsonResult":
                        var jsonResult = new JsonResult();
                        jsonResult.Data = new { Error = true, ErrorMessage = InvalidAccess };
                        jsonResult.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
                        filterContext.Result = jsonResult;
                        break;

                    // Assume same behaviour as ActionResult
                    default: 
                        var actionResult = new ContentResult();
                        actionResult.Content = InvalidAccess;
                        filterContext.Result = actionResult;
                        break;
                }
            }
        }

        private Type GetExpectedReturnType(ActionExecutingContext filterContext)
        {
            // Find out what type is expected to be returned
            string actionName = filterContext.ActionDescriptor.ActionName;
            Type controllerType = filterContext.Controller.GetType();
            MethodInfo actionMethodInfo = default(MethodInfo);
            try
            {
                actionMethodInfo = controllerType.GetMethod(actionName);
            }
            catch (AmbiguousMatchException ex)
            {
                // Try to find a match using the parameters passed through
                var actionParams = filterContext.ActionParameters;
                List<Type> paramTypes = new List<Type>();
                foreach (var p in actionParams)
                {
                    paramTypes.Add(p.Value.GetType());
                }

                actionMethodInfo = controllerType.GetMethod(actionName, paramTypes.ToArray());
            }

            return actionMethodInfo.ReturnType;
        }
    }
2 голосов
/ 19 мая 2010

Хорошо, это решение, которое я придумала.

Public Overrides Sub OnActionExecuting(ByVal filterContext As System.Web.Mvc.ActionExecutingContext)
  Try
    ' Check controller name against database.
    Dim controllerName = filterContext.Controller.GetType().Name
    Dim shortName = controllerName.Remove(controllerName.Length - 10)
    ' Look up availability.
    Dim available As Boolean = _coreService.GetControllerAvailability(shortName)
    If Not available Then
      ' find out what type is expected to be returned
      Dim actionName As String = filterContext.ActionDescriptor.ActionName
      Dim controllerType = Type.GetType("Attenda.Stargate.Web." & controllerName)
      Dim actionMethodInfo As MethodInfo
      Try
        actionMethodInfo = controllerType.GetMethod(actionName)
      Catch ex As AmbiguousMatchException
        ' Try to find a match using the parameters passed through
        Dim actionParams = filterContext.ActionParameters
        Dim paramTypes As New List(Of Type)
        For Each p In actionParams
          paramTypes.Add(p.Value.GetType())
        Next
        actionMethodInfo = controllerType.GetMethod(actionName, paramTypes.ToArray)
      End Try
      Dim actionReturnType = actionMethodInfo.ReturnType.Name

      Select Case actionReturnType
        Case "PartialViewResult"
          filterContext.Result = New RedirectResult("/Home/UnavailablePartial/")
        Case "JsonResult"
          filterContext.Result = New RedirectResult("/Home/UnavailableJson/")
        Case Else
          filterContext.Result = New RedirectResult("/Home/Unavailable/")
      End Select

    End If
  Catch ex As Exception
    _eventLogger.LogWarning(ex, EventLogEntryType.Error)
    Throw
  End Try
End Sub

Если вызов Type.GetMethod (string) не может определить запрошенный метод, я извлекаю коллекцию параметров из коллекции ActionExecutingContext.ActionParameters и создаю массив типов параметров, переданных в запросе. Затем я могу использовать перегрузку Type.GetMethod (string, type ()), чтобы быть более точным в моем запросе.

0 голосов
/ 19 мая 2010

К тому моменту, когда вызывается OnActionExecuting, метод действия еще не был выполнен, поэтому вы не знаете, будет ли этот метод действия возвращать какой подкласс ActionResult. Так что, если вы не можете приступить к реализации анализа CIL (что, я думаю, может очень быстро стать уродливым), я не думаю, что то, что вы хотите сделать, возможно.

Тем не менее, разве вы не перенаправляете пользователей в представление, когда контроллер недостаточно доступен? Я имею в виду, я не понимаю, почему вы хотите перенаправить пользователей в результат JSON или частичное представление.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...