Domanda

E 'una buona pratica per limitare i verbi HTTP disponibili per ogni azione? Il mio codice è più pulito, senza [HttpGet], [HttpPost], [HttpPut], o [HttpDelete] decorare ogni azione, ma potrebbe anche essere meno robusta e sicura. Non vedo questo fatto in molti tutorial o codice di esempio, a meno che non sia esplicitamente richiesto il verbo, come avere due "Crea" le azioni in cui la versione GET restituisce un nuovo modulo e la versione inserti POST un nuovo record.

È stato utile?

Soluzione

Personalmente cerco di rispettare RESTful convenzioni e specificare il verbo HTTP ad eccezione del GET azioni che non modificano qualsiasi stato sul server consentendo loro di essere invocate con qualsiasi HTTP verbo.

Altri suggerimenti

Sì, io credo che sia una buona pratica di limitare le azioni solo per il metodo HTTP appropriata si suppone di manico, questo manterrà cattivi richieste dal vostro sistema, ridurre l'efficacia di possibili attacchi, migliorare la documentazione del codice, applicare un design RESTful, ecc.

Sì, utilizzando i [HttpGet], [HttpPost] .. attributi possono rendere il codice più difficile da leggere, specialmente se si utilizzano anche altri attributi, come [OutputCache], [Authorize], ecc.

Io uso un piccolo trucco con un IActionInvoker personalizzato, invece di utilizzare gli attributi che anteporre il metodo HTTP per il nome del metodo di azione, per esempio:.

public class AccountController : Controller {

   protected override IActionInvoker CreateActionInvoker() {
      return new HttpMethodPrefixedActionInvoker();
   }

   public ActionResult GetLogOn() {
      ...
   }

   public ActionResult PostLogOn(LogOnModel model, string returnUrl) {
      ...
   }

   public ActionResult GetLogOff() {
      ...
   }

   public ActionResult GetRegister() {
      ...
   }

   public ActionResult PostRegister(RegisterModel model) {
      ...
   }

   [Authorize]
   public ActionResult GetChangePassword() {
      ...
   }

   [Authorize]
   public ActionResult PostChangePassword(ChangePasswordModel model) {
      ...
   }

   public ActionResult GetChangePasswordSuccess() {
      ...
   }
}

Si noti che questo non cambia i nomi delle azioni, che sono ancora LogOn, LogOff, Register, ecc.

Ecco il codice:

using System;
using System.Collections.Generic;
using System.Web.Mvc;

public class HttpMethodPrefixedActionInvoker : ControllerActionInvoker {

   protected override ActionDescriptor FindAction(ControllerContext controllerContext, ControllerDescriptor controllerDescriptor, string actionName) {

      var request = controllerContext.HttpContext.Request;

      string httpMethod = request.GetHttpMethodOverride()
         ?? request.HttpMethod;

      // Implicit support for HEAD method. 
      // Decorate action with [HttpGet] if HEAD support is not wanted (e.g. action has side effects)

      if (String.Equals(httpMethod, "HEAD", StringComparison.OrdinalIgnoreCase))
         httpMethod = "GET";

      string httpMethodAndActionName = httpMethod + actionName;

      ActionDescriptor adescr = base.FindAction(controllerContext, controllerDescriptor, httpMethodAndActionName);

      if (adescr != null)
         adescr = new ActionDescriptorWrapper(adescr, actionName);

      return adescr;
   }

   class ActionDescriptorWrapper : ActionDescriptor {

      readonly ActionDescriptor wrapped;
      readonly string realActionName;

      public override string ActionName {
         get { return realActionName; }
      }

      public override ControllerDescriptor ControllerDescriptor {
         get { return wrapped.ControllerDescriptor; }
      }

      public override string UniqueId {
         get { return wrapped.UniqueId; }
      }

      public ActionDescriptorWrapper(ActionDescriptor wrapped, string realActionName) {

         this.wrapped = wrapped;
         this.realActionName = realActionName;
      }

      public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters) {
         return wrapped.Execute(controllerContext, parameters);
      }

      public override ParameterDescriptor[] GetParameters() {
         return wrapped.GetParameters();
      }

      public override object[] GetCustomAttributes(bool inherit) {
         return wrapped.GetCustomAttributes(inherit);
      }

      public override object[] GetCustomAttributes(Type attributeType, bool inherit) {
         return wrapped.GetCustomAttributes(attributeType, inherit);
      }

      public override bool Equals(object obj) {
         return wrapped.Equals(obj);
      }

      public override int GetHashCode() {
         return wrapped.GetHashCode();
      }

      public override ICollection<ActionSelector> GetSelectors() {
         return wrapped.GetSelectors();
      }

      public override bool IsDefined(Type attributeType, bool inherit) {
         return wrapped.IsDefined(attributeType, inherit);
      }

      public override string ToString() {
         return wrapped.ToString();
      }
   }
}

Non è necessario specificare i HttpGet, tutti gli altri si ha bisogno

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top