Comment puis-je utiliser un objet de session ASP.NET standard au sein de la mise en œuvre de services ServiceStack

StackOverflow https://stackoverflow.com/questions/8339584

  •  26-10-2019
  •  | 
  •  

Question

Je viens juste de commencer avec ServiceStack et, en cas de test, je suis à la recherche de retravailler un service existant qui est construit en utilisant les gestionnaires standards ASP.Net. J'ai réussi à tout travail comme je le veux, mais ont certains aspects qui font usage de l'objet session ASP.Net.

Je l'ai essayé d'ajouter IRequiresSessionState dans l'interface de service:

public class SessionTestService : RestServiceBase<SessionTest>, IRequiresSessionState {
    public override object OnPost(SessionTest request) {
        // Here I want to use System.Web.HttpContext.Current.Session
    }
}

Le problème est que je ne peux pas l'air de le faire fonctionner comme objet session est toujours nulle.

Je l'ai fait beaucoup de recherches sur Google et ont perplexe sur https://github.com/mythz/ServiceStack/blob/master/tests/ServiceStack.WebHost.IntegrationTests/Services/Secure.cs et similaire, mais je ne peux pas trouver un exemple de code qui fait cela (ce qui me surprend). Quelqu'un peut-il expliquer pourquoi le travail ci-dessus et pas conseiller ce que je dois faire pour le faire fonctionner?

Remarque: En fin de compte, je vais probablement chercher à le remplacer par Redis ou vais essayer de supprimer toute exigence de la session de Serverside, mais je pensais que j'utiliser la mise en œuvre ASP.Net pour l'instant , de faire fonctionner les choses et d'éviter le retravaillant plus que nécessaire à ce stade.

Était-ce utile?

La solution

Utilisation ServiceStack ISession

ServiceStack a une nouvelle interface ISession soutenu par ICacheClient qui vous permet de partager même ISession entre contrôleurs MVC, pages de base ASP.NET et des services Web de ServiceStack qui partagent le même Cookie Id vous permettant de partager des données librement entre ces frameworks Web.

Note: ISession est mise en œuvre propre qui a complètement court-circuite la session ASP.NET existant avec les composants propres de ServiceStack comme décrit dans MVC PowerPack de ServiceStack et expliqué en détail dans la section page Sessions .

Pour utiliser facilement la session de ServiceStack (Cache & JSON sérialiseur) ont vos contrôleurs héritent ServiceStackController (dans MVC) ou PageBase (dans ASP.NET)

Il y a aussi une nouvelle fonctionnalité d'authentification / validation ajoutée ServiceStack que vous pouvez lire sur le wiki:

Utiliser ASP.NET session

Pour l'essentiel ServiceStack est juste un ensemble de matériaux légers IHttpHandler de en cours d'exécution soit sur une ASP.NET hôte ou HttpListener. Si hébergé dans IIS / ASP.NET (le plus courant), il fonctionne comme une demande de ASP.NET normale.

Rien dans ServiceStack accès ou affecte les fournisseurs de caching et en session configurés dans l'application ASP.NET sous-jacente. Si vous voulez l'activer, vous devrez le configurer selon la normale dans ASP.NET (à savoir en dehors de ServiceStack) voir:

http://msdn.microsoft.com/en-us/library /ms178581.aspx

Une fois configuré, vous pouvez accéder à la session ASP.NET dans un service Web ServiceStack via le singleton:

HttpContext.Current.Session

Ou bien via le sous-jacent ASP.NET HttpRequest avec:

var req = (HttpRequest)base.RequestContext.Get<IHttpRequest>().OriginalRequest;
var session = req.RequestContext.HttpContext.Session;

Bien en raison de la dépendance obligatoire configuration XML et performances dégradées par défaut , je préfère éviter l'utilisation de la session de ASP.NET, optant plutôt pour utiliser le nettoyant Clients cache inclus avec ServiceStack.

En gros la façon dont le travail Sessions (ASP.NET inclus) est un cookie contenant un identifiant uniques est ajouté à la réponse identifiant de façon unique la session du navigateur. Cette id pointe vers un correspondant Dictionnaire / Collection sur le serveur qui représente session des navigateurs.

IRequiresSession Interface vous liez à ne faire rien par défaut, il est tout simplement un moyen de signal, soit un filtre de demande personnalisée ou un service Web de base que ce besoin de demander à être authentifiées (c.-à- deux endroits où vous devez mettre la logique de validation / authentification dans ServiceStack).

Voici une la mise en œuvre de base Auth qui regarde pour voir si un service Web est sécurisé et si oui, assurez-vous qu'ils ont authentifié.

Voici une autre implémentation d'authentification qui valident au lieu de tous les services marqués d'un [Authentifier] attribut, et comment activer l'authentification pour votre service en ajoutant l'attribut sur votre demande DTO.

Nouvelle authentification modèle dans ServiceStack

La mise en œuvre ci-dessus est en dehors du modèle de fournisseur multi-auth inclus dans la prochaine version de ServiceStack. Voici l'exemple de référence montrant comment pour enregistrer et configurer le nouveau modèle Auth dans votre application.

Stratégies d'authentification

Le nouveau modèle Auth est tout à fait un opt-in commodité que vous ne pouvez pas l'utiliser et mettre en œuvre un comportement similaire vous en utilisant Demande Filtres ou classes de base (en remplaçant OnBeforeExecute ). En fait, les nouveaux services de Auth ne sont pas réellement intégrés en ServiceStack per se. La vie entière de mise en œuvre en option ServiceStack.ServiceInterfaces projet mis en œuvre en utilisant des filtres de demande personnalisés.

Voici les différentes stratégies d'authentification que j'ai utilisé au fil des ans:

  • services que l'authentification Mark besoin d'un [Attributs] . Probablement la façon la plus idiomatiques C #, idéal lorsque la session id est passé par un cookie.

  • En particulier en dehors d'un contexte Web, en utilisant parfois plus explicite IRequiresAuthentication interface est mieux car il offre un accès fortement typé à l'utilisateur et SessionId requis pour l'authentification.

  • Vous pouvez juste avoir un 1-liner pour authentifier sur chaque service qui en a besoin - sur une base ad hoc. Une approche appropriée lorsque vous avez très peu de services nécessitant une authentification.

Autres conseils

C'est une réponse grande et complète par @mythz. Cependant, lorsque vous essayez d'accéder à la session ASP.NET par HttpContext.Current.Session au sein d'un service Web ServiceStack, il retourne toujours null pour moi. En effet, aucun des HttpHandlers au sein ServiceStack sont ornés de l'interface IRequiresSessionState, de sorte que le .NET Framework ne nous fournit pas l'objet de la session.

Pour contourner ce problème, je l'ai mis en place deux nouvelles classes, toutes deux utilisent le modèle de décorateur pour nous fournir ce dont nous avons besoin.

Tout d'abord, une nouvelle IHttpHandler qui nécessite l'état de session. Il enveloppe le IHttpHandler fourni par ServiceStack et passe des appels par lui ...

public class SessionHandlerDecorator : IHttpHandler, IRequiresSessionState {
    private IHttpHandler Handler { get; set; }

    internal SessionHandlerDecorator(IHttpHandler handler) {
        this.Handler = handler;
    }

    public bool IsReusable {
        get { return Handler.IsReusable; }
    }

    public void ProcessRequest(HttpContext context) {
        Handler.ProcessRequest(context);
    }
}

Ensuite, une nouvelle IHttpHandlerFactory qui délègue la responsabilité de générer le IHttpHandler à ServiceStack, avant d'envelopper le gestionnaire de retour dans notre nouveau SessionHandlerDecorator ...

public class SessionHttpHandlerFactory : IHttpHandlerFactory {
    private readonly static ServiceStackHttpHandlerFactory factory = new ServiceStackHttpHandlerFactory();

    public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) {
        var handler = factory.GetHandler(context, requestType, url, pathTranslated);
        return handler == null ? null : new SessionHandlerDecorator(handler);
    }

    public void ReleaseHandler(IHttpHandler handler) {
        factory.ReleaseHandler(handler);
    }

}

Ensuite, il est juste une question de changer les attributs type dans les gestionnaires dans Web.config à SessionHttpHandlerFactory au lieu de ServiceStack.WebHost.Endpoints.ServiceStackHttpHandlerFactory, ServiceStack et vos services Web devrait maintenant avoir la session ASP.NET disponnible pour eux.

En dépit de ce qui précède, je souscris pleinement à la nouvelle mise en œuvre de ISession fournies par ServiceStack. Cependant, dans certains cas, sur un produit mature, il semble tout simplement trop grand un travail pour remplacer toutes les utilisations de la session ASP.NET avec la nouvelle implémentation, donc cette solution de contournement!

Merci @Richard pour votre réponse ci-dessus. Je dirigeais une nouvelle version de la pile de service et ils ont enlevé le ServiceStackHttpFactory avec HttpFactory. Au lieu d'avoir

private readonly static ServiceStackHttpHandlerFactory factory = new ServiceStackHttpHandlerFactory();

Vous devez avoir

private static readonly HttpHandlerFactory Factory = new HttpHandlerFactory();

Voici le code mis à jour pour ce service

using ServiceStack;
using System.Web;
using System.Web.SessionState;

namespace MaryKay.eCommerce.Mappers.AMR.Host
{
public class SessionHttpHandlerFactory : IHttpHandlerFactory
{
    private static readonly HttpHandlerFactory Factory = new HttpHandlerFactory();
    public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
    {
        var handler = Factory.GetHandler(context, requestType, url, pathTranslated);
        return handler == null ? null : new SessionHandlerDecorator(handler);
    }

    public void ReleaseHandler(IHttpHandler handler)
    {
        Factory.ReleaseHandler(handler);
    }
}

public class SessionHandlerDecorator : IHttpHandler, IRequiresSessionState
{
    private IHttpHandler Handler { get; set; }

    internal SessionHandlerDecorator(IHttpHandler handler)
    {
        Handler = handler;
    }

    public bool IsReusable
    {
        get { return Handler.IsReusable; }
    }

    public void ProcessRequest(HttpContext context)
    {
        Handler.ProcessRequest(context);
    }
}
}

Au ServiceStack 4.5+ le HttpHandler peut également prendre en charge Async. Comme ceci:

namespace FboOne.Services.Host
{
  public class SessionHttpHandlerFactory : IHttpHandlerFactory
  {
    private static readonly HttpHandlerFactory Factory = new HttpHandlerFactory();

    public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
    {
      var handler = Factory.GetHandler(context, requestType, url, pathTranslated);
      return handler == null ? null : new SessionHandlerDecorator((IHttpAsyncHandler)handler);
    }

    public void ReleaseHandler(IHttpHandler handler)
    {
      Factory.ReleaseHandler(handler);
    }
  }

  public class SessionHandlerDecorator : IHttpAsyncHandler, IRequiresSessionState
  {
    private IHttpAsyncHandler Handler { get; set; }

    internal SessionHandlerDecorator(IHttpAsyncHandler handler)
    {
      Handler = handler;
    }

    public bool IsReusable
    {
      get { return Handler.IsReusable; }
    }

    public void ProcessRequest(HttpContext context)
    {
      Handler.ProcessRequest(context);
    }

    public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
    {
      return Handler.BeginProcessRequest(context, cb, extraData);
    }

    public void EndProcessRequest(IAsyncResult result)
    {
      Handler.EndProcessRequest(result);
    }
  }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top