2013-04-23 18 views
5

Abbiamo un'applicazione ASP.NET di lunga durata nata nei giorni .NET 1.1/IIS6. Ora siamo su .NET4.5/IIS7 ma non abbiamo fatto nulla con MVC.Riscrittura URL in ASP.NET 4.5 e API Web

Noi forniamo un catalogo per i clienti e dare loro un URL che possono utilizzare:

www.ourhost.com/customername 

Utilizzando un personalizzato IHttpModule abbiamo sviluppato noi tiriamo 'CustomerName' fuori l'URL per trovare il cliente nel database. L'ID di quel cliente viene quindi memorizzato nel contesto * della pagina e utilizzato praticamente da tutte le pagine del sito per personalizzare i contenuti per quel cliente. Dopo questo processo, quanto sopra URL verrebbe riscritta e trattati come

www.ourhost.com/index.aspx 

con index.aspx avere accesso al ID del cliente tramite il suo contesto e che può fare la sua cosa.

Questo funziona perfettamente e supportiamo diverse migliaia di clienti. la logica di riscrittura è abbastanza complessa perché convalida gli account dei clienti, reindirizza a una pagina 'uh oh' se il cliente non è valido e a un'altra pagina 'Trova un rivenditore' se il cliente non ha pagato, ecc. ecc.

Ora mi piacerebbe costruire alcuni controller API Web e la riscrittura in stile MVC mi preoccupa. Vedo molti esempi in cui la riscrittura accade per rendere l'URL di come questo lavoro:

www.ourhost.com/api/{controller} 

ma ho ancora bisogno di questi API Web 'chiama' per accadere nel contesto di un cliente. Le nostre pagine sono sempre più sofisticate con le chiamate asincrone JSON/AJAX, ma nel rispondere a queste chiamate ho ancora bisogno del contesto del cliente. Vorrei che l'URL di essere

www.ourhost.com/customername/api/{controller} 

ma sono perplesso su come configurare il routing per fare questo e farlo giocare bene con la nostra IHttpModule.

È possibile?

* AGGIORNAMENTO: Quando dico "memorizzato nel contesto della pagina", intendo il HttpContext associato a ogni richiesta web che include un dizionario in cui posso memorizzare alcuni dati specifici per pagina/richiesta.

+0

Quando dici "memorizzato nel contesto della pagina", ti riferisci ad un oggetto 'Session', o stai scrivendo direttamente su un' Cookie' di qualche tipo? Dato che hai taggato questo 'web-api', fa un po 'di differenza. –

+0

@Troy: Grazie per il commento - Ho aggiornato la mia domanda con chiarimenti. – n8wrl

+0

Capito - stai usando 'HttpContext.Current.User' per tenere traccia di chi è l'utente che ha effettuato l'accesso? Come stai persistendo nelle chiamate successive che non includono il nome utente dell'utente nell'URL? –

risposta

2

Ci sono due parti della risposta al tuo problema che posso vedere.

mantenendo l'User Informazioni attraverso più richieste Generalmente un'applicazione API MVC sarà senza stato, cioè l'utente non conservi l'attuale stato della sessione tra le richieste degli utenti. Bene, questo è quello che ho imparato o che ho predicato molte volte durante la scrittura di API RESTFul.

Ciò premesso, è possibile attivare lo stato della sessione in MVC Web API aggiungendo quanto segue al tuo global.asax.cs

protected void Application_PostAuthorizeRequest() 
    { 
     // To enable session state in the WebAPI. 
     System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required); 
    } 

autorizzazione di un cliente nella Richiesta Come avete mostrato nel Richiedi URL puoi aggiungere il nome del cliente, quindi acquisirlo e passarlo alla stessa routine che il tuo attuale modulo http chiama per autorizzare su richiesta. Puoi farlo con un filtro MVC.

Prima eseguire un pattern URL simile per acquisire il nome del cliente in WebApiConfig.cs, qualcosa del genere;

 config.Routes.MapHttpRoute(
      name: "WithCustomerApi", 
      routeTemplate: "api/{customername}/{controller}/{id}", 
      defaults: new { id = RouteParameter.Optional } 
     ); 

quindi aggiungere un ActionFilter per il Controller API che elabora ogni richiesta, controlla attuali informazioni di sessione e, se necessario, chiamate il vostro codice di ricerca autorizzare/cliente e quindi salva per lo stato della sessione per un uso successivo. O se nessuna buona informazione da parte del cliente può inviare ad una nuova rotta MVC

Così si aggiungerà un attributo qualcosa del genere;

[WebApiAuthentication] 
public class BaseApiController : ApiController 
{ 
} 

Poi creare un filtro di un'azione che potrebbe essere simile a questo (notare non ho ancora testato questo, appena fatto per un modello di come).

public class WebApiAuthenticationAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuting(HttpActionContext actionContext) 
    { 
     var routeData = actionContext.ControllerContext.Request.GetRouteData(); 
     var currentContext = HttpContext.Current; 

     if (routeData.Route.RouteTemplate.Contains("customername")) 
     { 
      try 
      { 
       var authenticated = currentContext.Request.IsAuthenticated; 
       if (!authenticated) 
       { 
        var customer = routeData.Values["customername"]; 
        // do something with customer here and then put into session or cache 
        currentContext.Session.Add("CustomerName", customer); 
       } 
      } 
      catch (Exception exception) 
      { 
       var error = exception.Message; 
       // We dont like the request 
       actionContext.Response = new HttpResponseMessage(HttpStatusCode.BadRequest); 
      } 
     } 
     else 
     { 
      // No customer name specified, send bad request, not found, what have you ... you *could* potentially redirect but we are in API so it probably a service request rather than a user 
      actionContext.Response = new HttpResponseMessage(HttpStatusCode.NotFound); 
     } 

    } 
} 

Se si crea un nuovo MVC 5 API Web Application e aggiungere a questi extra e mettere il filtro sul controller valori di default in questo modo si dovrebbe essere in grado di vedere questo correre come demo di una possibile soluzione.

Questo ripeterà il nome del cliente se tutto funziona correttamente.

[WebApiAuthentication] 
public class ValuesController : ApiController 
{ 
    // GET api/values 
    public IEnumerable<string> Get() 
    { 
     var session = HttpContext.Current.Session; 

     if (session != null) 
     { 
      return new string[] {"session is present", "customer is", session["CustomerName"].ToString()}; 
     } 

     return new string[] { "value1", "value2" }; 
    } 

} 

Offro questo come una possibile soluzione come ho detto, ci sono argomenti religiosi su come memorizzare sessione e che autorizza in un'API, ma quelli non sono il problema. Spero che ti sia d'aiuto, Steve