2015-02-17 4 views
6

Chcę wybrać Akcja mojego kontrolera na podstawie żądanego typu nośnika w nagłówku Accept.Czy jest możliwe wybranie akcji z atrybutem AttributeRouting w .NET MVC na podstawie typu nośnika nagłówka Accept?

Na przykład mam zasób o nazwie podmiot. Jej trasa jest przypisana:

GET/przedmiotów/{subjectId: int}

Normalnie przeglądarka żąda text/html, co jest w porządku. Domyślnie Media Formatter radzi sobie z tym świetnie.

Mam teraz niestandardową logikę, którą chcę wykonać, gdy ta sama trasa jest dostępna z nagłówkiem akceptującym, określającym application/pdf jako akceptowany typ nośnika.

Mogłem utworzyć niestandardowy formater mediów, ale, jak rozumiem, oznaczałoby to, że każda trasa, która jest żądana z nagłówkiem Accept pod numerem application/pdf, również byłaby uruchamiana przez ten format formatowania mediów. To jest niedopuszczalne.

W Javie istnieje adnotacja o nazwie @Produces:

@Produces adnotacja jest używana do określenia typów MIME lub medialne reprezentacje zasobu mogą produkować i wysyłać z powrotem do klienta. Jeśli zostanie zastosowana klasa @Produces, wszystkie metody w zasobie mogą domyślnie generować określone typy MIME. W przypadku zastosowania na poziomie metody adnotacja zastępuje wszelkie adnotacje @Produces zastosowane na poziomie klasy.

Pozwoliłoby mi wykonać następujące czynności:

namespace MyNamespace 
{ 
    [RoutePrefix("subjects")] 
    public class SubjectsController : Controller 
    { 
     [Route("{subjectId:int}")] 
     [HttpGet] 
     public ActionResult GetSubject(int subjectId) 
     { 
     } 

     [Route("{subjectId:int}")] 
     [HttpGet] 
     [Produces("application/pdf")] 
     public ActionResult GetSubjectAsPdf(int subjectId) 
     { 
      //Run my custom logic here to generate a PDF. 
     } 
    } 
} 

Nie ma Produkuje atrybut .NET, że mogę znaleźć, oczywiście, tak to nie działa. Nie byłem też w stanie znaleźć podobnego atrybutu.

Mogę oczywiście ręcznie sprawdzić nagłówek w treści akcji i przekierować go do innej akcji, ale w najlepszym przypadku wydaje się to być hackowe.

Czy istnieje mechanizm .NET 4.5, który mogę użyć, aby wyciągnąć to, że przegadam lub brakuje?

(używam MVC 5.2.2 z Nuget repozytorium)

+0

Wydaje się być możliwe za pomocą niestandardowego selektora kontrolera: http: // stackoverflow.com/questions/25941590/asp-net-mvc-przechwytywanie-routing-i-przekierowywanie-do-różnych-działań-tras – mostruash

+0

@mostruash Nie wygląda na to, że wybieram kontroler, ale chcę, żeby zacząłem szukać do selektorów akcji, które są podobne. Zajrzę i zobaczę, czy uda mi się to rozgryźć. – crush

+0

Teraz myślę, że mogę potencjalnie użyć ograniczenia trasy, ale nie jestem jeszcze pewien. – crush

Odpowiedz

5

Po przeszukaniu całego internetu na chwilę, wpadłem na pomysł, że byłoby to najlepiej osiągnąć poprzez stworzenie ActionMethodSelectorAttribute.

Poniżej znajduje się bardzo naiwne, realizacja pierwszego przejścia z ProducesAttribute że pisałem z ewentualnym zamiarem naśladując Java produkuje adnotacja:

namespace YourNamespace 
{ 
    using System; 
    using System.Collections.Generic; 
    using System.Net; 
    using System.Net.Mime; 
    using System.Web.Mvc; 

    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] 
    public sealed class ProducesAttribute : ActionMethodSelectorAttribute 
    { 
     private readonly ISet<ContentType> acceptableMimeTypes; 

     public ProducesAttribute(params string[] acceptableMimeTypes) 
     { 
      this.acceptableMimeTypes = new HashSet<ContentType>(); 

      foreach (string acceptableMimeType in acceptableMimeTypes) 
       this.acceptableMimeTypes.Add(new ContentType(acceptableMimeType)); 
     } 

     public override bool IsValidForRequest(ControllerContext controllerContext, System.Reflection.MethodInfo methodInfo) 
     { 
      string acceptHeader = controllerContext.RequestContext.HttpContext.Request.Headers[HttpRequestHeader.Accept.ToString()]; 
      string[] headerMimeTypes = acceptHeader.Split(new char[] {','}, StringSplitOptions.RemoveEmptyEntries); 

      foreach (var headerMimeType in headerMimeTypes) 
      { 
       if (this.acceptableMimeTypes.Contains(new ContentType(headerMimeType))) 
        return true; 
      } 

      return false; 
     } 
    } 
} 

To ma być używany z atrybutem Routing i może można zastosować w następujący sposób:

public sealed class MyController : Controller 
{ 
    [Route("subjects/{subjectId:int}")] //My route 
    [Produces("application/pdf")] 
    public ActionResult GetSubjectAsPdf(int subjectId) 
    { 
     //Here you would return the PDF representation. 
    } 

    [Route("subjects/{subjectId:int}")] 
    public ActionResult GetSubject(int subjectId) 
    { 
     //Would handle all other routes. 
    } 
} 
Powiązane problemy