Dostęp do sesji za pomocą interfejsu API sieci Web ASP.NET

268

Zdaję sobie sprawę, że sesja i REST nie idą w parze, ale czy nie można uzyskać dostępu do stanu sesji przy użyciu nowego interfejsu API sieci Web? HttpContext.Current.Sessionjest zawsze zerowy.

znak
źródło
4
[SessionState(SessionStateBehavior.Required)]na ApiControllerlewę (lub w .ReadOnlyrazie potrzeby).
Roman Starkov
@RomanStarkov Nie udało się tego uruchomić. Z jakiego środowiska korzystałeś? .NET Core?
Bondolin
@Bondolin nie, to nie był Core.
Roman Starkov
@RomanStarkov MVC? Mam problem ze znalezieniem tego.
Bondolin
@Bondolin SessionStateAttribute i tak, MVC.
Roman Starkov

Odpowiedzi:

336

MVC

W przypadku projektu MVC wprowadź następujące zmiany (poniżej znajdują się odpowiedzi na formularze WebForms i Dot Net Core):

WebApiConfig.cs

public static class WebApiConfig
{
    public static string UrlPrefix         { get { return "api"; } }
    public static string UrlPrefixRelative { get { return "~/api"; } }

    public static void Register(HttpConfiguration config)
    {
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
    }
}

Global.asax.cs

public class MvcApplication : System.Web.HttpApplication
{
    ...

    protected void Application_PostAuthorizeRequest()
    {
        if (IsWebApiRequest())
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

    private bool IsWebApiRequest()
    {
        return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(WebApiConfig.UrlPrefixRelative);
    }

}

To rozwiązanie ma dodatkową zaletę, że możemy pobrać podstawowy adres URL w javascript do wykonywania wywołań AJAX:

_Layout.cshtml

<body>
    @RenderBody()

    <script type="text/javascript">
        var apiBaseUrl = '@Url.Content(ProjectNameSpace.WebApiConfig.UrlPrefixRelative)';
    </script>

    @RenderSection("scripts", required: false) 

a następnie w plikach / kodzie JavaScript możemy wykonywać nasze wywołania webapi, które mogą uzyskać dostęp do sesji:

$.getJSON(apiBaseUrl + '/MyApi')
   .done(function (data) {
       alert('session data received: ' + data.whatever);
   })
);

Formularze internetowe

Wykonaj powyższe czynności, ale zmień funkcję WebApiConfig.Register, aby zamiast tego pobrać RouteCollection:

public static void Register(RouteCollection routes)
{
    routes.MapHttpRoute(
        name: "DefaultApi",
        routeTemplate: WebApiConfig.UrlPrefix + "/{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );
}

A następnie wywołaj następujące w Application_Start:

WebApiConfig.Register(RouteTable.Routes);

Dot Net Core

Dodaj pakiet NuGet Microsoft.AspNetCore.Session , a następnie wprowadź następujące zmiany kodu:

Startup.cs

Wywołaj metody AddDistributMemoryCache i AddSession w obiekcie usług w ramach funkcji ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddMvc();
    ...

    services.AddDistributedMemoryCache();
    services.AddSession();

i w funkcji Konfiguruj dodaj wywołanie do UseSession :

public void Configure(IApplicationBuilder app, IHostingEnvironment env, 
ILoggerFactory loggerFactory)
{
    app.UseSession();
    app.UseMvc();

SessionController.cs

W swoim kontrolerze dodaj instrukcję using u góry:

using Microsoft.AspNetCore.Http;

a następnie użyj obiektu HttpContext.Session w kodzie w następujący sposób:

    [HttpGet("set/{data}")]
    public IActionResult setsession(string data)
    {
        HttpContext.Session.SetString("keyname", data);
        return Ok("session data set");
    }

    [HttpGet("get")]
    public IActionResult getsessiondata()
    {
        var sessionData = HttpContext.Session.GetString("keyname");
        return Ok(sessionData);
    }

powinieneś teraz być w stanie trafić:

http://localhost:1234/api/session/set/thisissomedata

a następnie przejście do tego adresu URL spowoduje jego wyciągnięcie:

http://localhost:1234/api/session/get

Więcej informacji na temat uzyskiwania dostępu do danych sesji w ramach dot net core tutaj: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/app-state

Obawy dotyczące wydajności

Przeczytaj poniżej odpowiedź Simona Weavera dotyczącą wydajności. Jeśli uzyskujesz dostęp do danych sesji w projekcie WebApi, może to mieć bardzo poważny wpływ na wydajność - widziałem, jak ASP.NET wymusza opóźnienie 200 ms dla równoczesnych żądań. Może się to sumować i stać się katastrofalne, jeśli masz wiele równoczesnych żądań.


Obawy dotyczące bezpieczeństwa

Upewnij się, że blokujesz zasoby na użytkownika - uwierzytelniony użytkownik nie powinien mieć możliwości pobierania danych z WebApi, do których nie ma dostępu.

Przeczytaj artykuł Microsoftu na temat uwierzytelniania i autoryzacji w ASP.NET Web API - https://www.asp.net/web-api/overview/security/authentication-and-authorization-in-aspnet-web-api

Przeczytaj artykuł Microsoftu na temat unikania ataków hakerskich na żądanie krzyżowej witryny. (W skrócie, sprawdź metodę AntiForgery.Validate) - https://www.asp.net/web-api/overview/security/preventing-cross-site-request-forgery-csrf-attacks

Rocklan
źródło
7
Idealny. Prosty i działa. W przypadku wersji innej niż MVC wystarczy dodać Application_PostAuthorizeRequest () do Global.ascx.cs.
mhenry1384
1
Dzięki @JCallico, chyba większość ludzi trafiła na stronę ASP.NET, która tworzy sesję.
Rocklan
3
Musiałem zmodyfikować IsWebApiRequest (), aby zwracało true, gdzie ścieżka zaczyna się od WebApiConfig.UrlPrefix, a także WebApiConfig.UrlPrefixRelative. Poza tym działa zgodnie z oczekiwaniami.
gb2d
7
Należy wspomnieć o tej poprawce. podczas ustawiania SessionStateBehavior na Wymagane, wąskie gardło webapi, ponieważ wszystkie twoje żądania będą uruchamiane zsynchronizowane z powodu blokowania obiektu sesji. Zamiast tego możesz uruchomić go jako SessionStateBehavior.Readonly. W ten sposób nie utworzy blokad na obiekcie sesji.
Michael Kire Hansen
2
Zachowaj ostrożność, ustawiając zachowanie stanu sesji na „Wymagane”. Żądania z uprawnieniami do zapisu zablokują sesję i zapobiegną pojawieniu się wielu aplikacji Http na klienta. Powinieneś ustawić stan sesji na odpowiedni poziom dla każdej trasy. Proszę odnieść się do mojej odpowiedzi tutaj: stackoverflow.com/a/34727708/1412787
Axel Wilczek
66

Dostęp do stanu sesji można uzyskać za pomocą niestandardowego narzędzia RouteHandler.

// In global.asax
public class MvcApp : System.Web.HttpApplication
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        var route = routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional }
        );
        route.RouteHandler = new MyHttpControllerRouteHandler();
    }
}

// Create two new classes
public class MyHttpControllerHandler
    : HttpControllerHandler, IRequiresSessionState
{
    public MyHttpControllerHandler(RouteData routeData) : base(routeData)
    { }
}
public class MyHttpControllerRouteHandler : HttpControllerRouteHandler
{
    protected override IHttpHandler GetHttpHandler(
        RequestContext requestContext)
    {
        return new MyHttpControllerHandler(requestContext.RouteData);
    }
}

// Now Session is visible in your Web API
public class ValuesController : ApiController
{
    public string Get(string input)
    {
        var session = HttpContext.Current.Session;
        if (session != null)
        {
            if (session["Time"] == null)
                session["Time"] = DateTime.Now;
            return "Session Time: " + session["Time"] + input;
        }
        return "Session is not availabe" + input;
    }
}

Znalezione tutaj: http://techhasnoboundary.blogspot.com/2012/03/mvc-4-web-api-access-session.html

warrickh
źródło
14
Aktualizacja: jeśli funkcje API odczytują sesję i nie modyfikują sesji, dobrym pomysłem może być użycie IReadOnlySessionState zamiast IRequiresSessionState. Dzięki temu sesja nie jest blokowana podczas przetwarzania funkcji API.
warrickh
6
nie działa dla mnie w MVC 4 - route.RouteHandler nie jest nawet dla mnie własnością. @LachlanB wydaje się mieć to, co dla mnie zadziałało.
bkwdesign
3
Dzięki @bkwdesign za wskazanie rozwiązania MVC. Ta odpowiedź dotyczy wyłącznie interfejsu API sieci Web.
warrickh
2
To nie wydaje się wspierać atrybutów trasy. Myśli?
Tim S
Jak zauważył bkwdesign, nie jest to już obsługiwane. Istnieje jednak sposób na zdefiniowanie zachowania stanu sesji dla trasy za pomocą DataTokens: stackoverflow.com/a/34727708/1412787
Axel Wilczek
46

Dlaczego warto unikać używania sesji w WebAPI?

Wydajność, wydajność, wydajność!

Jest bardzo dobry i często pomijany powód, dla którego nie powinieneś w ogóle używać Sesji w WebAPI.

Sposób działania ASP.NET podczas korzystania z sesji polega na serializacji wszystkich żądań otrzymanych od jednego klienta . Teraz nie mówię o serializacji obiektów, ale uruchamiam je w otrzymanej kolejności i czekam na zakończenie każdego z nich przed uruchomieniem następnego. Ma to na celu uniknięcie nieprzyjemnych warunków dotyczących wątku / wyścigu, jeśli dwa żądania próbują uzyskać dostęp do sesji jednocześnie.

Współbieżne żądania i stan sesji

Dostęp do stanu sesji ASP.NET jest wyłączny dla każdej sesji, co oznacza, że ​​jeśli dwóch różnych użytkowników zgłasza współbieżne żądania, dostęp do każdej oddzielnej sesji jest przyznawany jednocześnie. Jeśli jednak dla tej samej sesji zostaną wysłane dwa jednoczesne żądania (przy użyciu tej samej wartości SessionID), pierwsze żądanie uzyska wyłączny dostęp do informacji o sesji. Drugie żądanie zostanie wykonane dopiero po zakończeniu pierwszego żądania.(Druga sesja może również uzyskać dostęp, jeśli wyłączna blokada informacji zostanie zwolniona, ponieważ pierwsze żądanie przekroczy limit czasu blokady.) Jeśli wartość EnableSessionState w dyrektywie @ Page jest ustawiona na Tylko do odczytu, żądanie tylko do odczytu informacje o sesji nie powodują wyłącznej blokady danych sesji. Jednak żądania tylko do odczytu danych sesji mogą nadal wymagać oczekiwania na ustawienie blokady przez żądanie odczytu i zapisu dla danych sesji.

Co to oznacza dla Web API? Jeśli masz aplikację obsługującą wiele żądań AJAX, tylko JEDNA będzie mogła być uruchomiona jednocześnie. Jeśli masz wolniejsze żądanie, spowoduje to zablokowanie wszystkich pozostałych klientów tego klienta, dopóki nie zostanie zrealizowane. W niektórych aplikacjach może to prowadzić do bardzo zauważalnie niskiej wydajności.

Dlatego prawdopodobnie powinieneś użyć kontrolera MVC, jeśli absolutnie potrzebujesz czegoś z sesji użytkownika i uniknąć niepotrzebnej utraty wydajności w przypadku włączenia go dla WebApi.

Możesz to łatwo sprawdzić sam, wprowadzając Thread.Sleep(5000)metodę WebAPI i włączając sesję. Wykonaj do niego 5 próśb, a ich wypełnienie zajmie 25 sekund. Bez sesji zajmie to nieco ponad 5 sekund.

(To samo rozumowanie dotyczy SignalR).

Simon_Weaver
źródło
18
Można obejść ten problem, używając [SessionState (SessionStateBehavior.ReadOnly)], jeśli metoda odczytuje tylko z sesji.
Rocklan
21

Masz rację, REST jest bezpaństwowcem. Jeśli użyjesz sesji, przetwarzanie stanie się stanowe, kolejne żądania będą mogły użyć stanu (z sesji).

Aby sesja została uwodniona, musisz podać klucz do powiązania stanu. W normalnej aplikacji asp.net klucz ten jest dostarczany za pomocą pliku cookie (sesje cookie) lub parametru adresu URL (sesje bez plików cookie).

Jeśli potrzebujesz sesji zapomnij o odpoczynku, sesje nie mają znaczenia w projektach opartych na REST. Jeśli potrzebujesz sesji do weryfikacji, użyj tokena lub autoryzuj według adresów IP.

Nickz
źródło
10
Nie jestem pewien co do tego. W przykładach Microsoftu pokazują one za pomocą atrybutu Autoryzuj. Próbowałem tego i działa z uwierzytelnianiem opartym na formularzach. Interfejs API sieci Web jest świadomy stanu uwierzytelnienia przekazywanego w domyślnym pliku cookie uwierzytelniania.
Mark
4
Oto przykład, o którym mówię, code.msdn.microsoft.com/ASPNET-Web-API-JavaScript-d0d64dd7 . Korzysta z nowego interfejsu API sieci Web opartego na REST i implementuje uwierzytelnianie formularzy.
Mark
4
Z powodzeniem korzystałem z atrybutu [Autoryzuj] bez potrzeby stanu sesji. Właśnie napisałem procedurę obsługi wiadomości uwierzytelniającej, aby ustawić tożsamość.
Antony Scott
57
Znalazłem cię w dół, ponieważ nie zaoferowałeś odpowiedzi na jego problem, a ponadto Web Api to asynchroniczny framework, który świetnie współpracuje z ciężką aplikacją internetową ajax. Nikt nie powiedział, że musisz szanować wszystkie zasady projektowania RESTful, aby czerpać korzyści z używania frameworka Web API.
Brian Ogden
3
@Znaki. ma prawo poinformować, że interfejs API sieci Web nie powinien być świadomy stanu sesji. Odpowiedź negatywna nadal pozostaje odpowiedzią. Do góry głosuj.
Antoine Meltzheim,
20

Zaznacz, jeśli sprawdzisz przykład MVC nerddinner, logika jest prawie taka sama.

Wystarczy pobrać plik cookie i ustawić go w bieżącej sesji.

Global.asax.cs

public override void Init()
{
    this.AuthenticateRequest += new EventHandler(WebApiApplication_AuthenticateRequest);
    base.Init();
}

void WebApiApplication_AuthenticateRequest(object sender, EventArgs e)
{
    HttpCookie cookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];
    FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

    SampleIdentity id = new SampleIdentity(ticket);
    GenericPrincipal prin = new GenericPrincipal(id, null); 

    HttpContext.Current.User = prin;
}

enter code here

Musisz zdefiniować klasę „SampleIdentity”, którą możesz pożyczyć z projektu nerddinner .

JSancho
źródło
Klasa tożsamości znajduje się w NerdDinner_2.0 \ NerdDinner \ Models \ NerdIdentity.cs.
mhenry1384
To nie działa dla mnie (w .NET 4). Nigdy nie mam tego pliku cookie. Czy to działa tylko wtedy, gdy masz włączone uwierzytelnianie formularzy?
mhenry1384
plik cookie faktycznie generowany jest po uwierzytelnieniu za pomocą formularza logowania. Możesz także dostosować sposób / czas utworzenia, patrz stackoverflow.com/questions/7217105 Ale nadal potrzebujesz użytkownika, aby skutecznie uwierzytelnić się na serwerze WWW
JSancho
Pytanie dotyczy HttpContext.Current.Session, a ta odpowiedź nie wyjaśnia, co należy zrobić. Zobacz odpowiedź @LachlanB.
JCallico
14

Aby rozwiązać problem:

protected void Application_PostAuthorizeRequest()
{
    System.Web.HttpContext.Current.SetSessionStateBehavior(System.Web.SessionState.SessionStateBehavior.Required);
}

w Global.asax.cs

Suresh Muttagi
źródło
4
Ostrzeżenie! Umożliwi to sesję dla WSZYSTKICH żądań. Może to naprawdę zaszkodzić wydajności, jeśli aplikacja korzysta z zasobów osadzonych.
cgatian
@cgatian alternatywnym rozwiązaniem stałe ?
Kiquenet
Myślę, że najlepsze podejście sugeruje @Treyphor. Nie włączaj go dla wszystkich żądań. Tylko trasy, które mają „/ api” lub coś w adresie URL. Ponadto, jeśli to możliwe, ustaw stan sesji na odczyt tylko dla kontrolerów API.
cgatian
10

Ostatni nie działa teraz, weź ten, działał dla mnie.

w WebApiConfig.cs w App_Start

    public static string _WebApiExecutionPath = "api";

    public static void Register(HttpConfiguration config)
    {
        var basicRouteTemplate = string.Format("{0}/{1}", _WebApiExecutionPath, "{controller}");

        // Controller Only
        // To handle routes like `/api/VTRouting`
        config.Routes.MapHttpRoute(
            name: "ControllerOnly",
            routeTemplate: basicRouteTemplate//"{0}/{controller}"
        );

        // Controller with ID
        // To handle routes like `/api/VTRouting/1`
        config.Routes.MapHttpRoute(
            name: "ControllerAndId",
            routeTemplate: string.Format ("{0}/{1}", basicRouteTemplate, "{id}"),
            defaults: null,
            constraints: new { id = @"^\d+$" } // Only integers 
        );

Global.asax

protected void Application_PostAuthorizeRequest()
{
  if (IsWebApiRequest())
  {
    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
  }
}

private static bool IsWebApiRequest()
{
  return HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith(_WebApiExecutionPath);
}

po czwarte tutaj: http://forums.asp.net/t/1773026.aspx/1

Cruiser KID
źródło
Jest to najprostsze rozwiązanie, ale zawiera kilka błędów w kodzie, więc w rzeczywistości nie działa. Opublikowałem inne rozwiązanie oparte na tym, możesz edytować swoje, aby pasowały do ​​mojego.
Rocklan
Nieznaczna korekta w linii _WebApiExecutionPath musi odczytać publiczny ciąg statyczny _WebApiExecutionPath = "~ / api";
stephen ebichondo
8

Zgodnie z odpowiedzią LachlanB, jeśli Twój ApiController nie znajduje się w określonym katalogu (jak / api), możesz zamiast tego przetestować żądanie za pomocą RouteTable.Routes.GetRouteData, na przykład:

protected void Application_PostAuthorizeRequest()
    {
        // WebApi SessionState
        var routeData = RouteTable.Routes.GetRouteData(new HttpContextWrapper(HttpContext.Current));
        if (routeData != null && routeData.RouteHandler is HttpControllerRouteHandler)
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
    }
Stumblor
źródło
8

Miałem ten sam problem w asp.net mvc, naprawiłem go, umieszczając tę ​​metodę w moim podstawowym kontrolerze interfejsu API, który dziedziczą wszystkie moje kontrolery interfejsu API:

    /// <summary>
    /// Get the session from HttpContext.Current, if that is null try to get it from the Request properties.
    /// </summary>
    /// <returns></returns>
    protected HttpContextWrapper GetHttpContextWrapper()
    {
      HttpContextWrapper httpContextWrapper = null;
      if (HttpContext.Current != null)
      {
        httpContextWrapper = new HttpContextWrapper(HttpContext.Current);
      }
      else if (Request.Properties.ContainsKey("MS_HttpContext"))
      {
        httpContextWrapper = (HttpContextWrapper)Request.Properties["MS_HttpContext"];
      }
      return httpContextWrapper;
    }

Następnie w interfejsie API, który chcesz uzyskać dostęp do sesji, po prostu wykonaj:

HttpContextWrapper httpContextWrapper = GetHttpContextWrapper();
var someVariableFromSession = httpContextWrapper.Session["SomeSessionValue"];

Mam to również w moim pliku Global.asax.cs, tak jak inne osoby, nie jestem pewien, czy nadal potrzebujesz go za pomocą powyższej metody, ale tutaj jest tak na wszelki wypadek:

/// <summary>
/// The following method makes Session available.
/// </summary>
protected void Application_PostAuthorizeRequest()
{
  if (HttpContext.Current.Request.AppRelativeCurrentExecutionFilePath.StartsWith("~/api"))
  {
    HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
  }
}

Możesz także utworzyć niestandardowy atrybut filtru, który możesz trzymać na wywołaniach interfejsu API potrzebnych do sesji, a następnie możesz użyć sesji w wywołaniu interfejsu API, tak jak zwykle za pośrednictwem HttpContext.Current.Session [„SomeValue”]:

  /// <summary>
  /// Filter that gets session context from request if HttpContext.Current is null.
  /// </summary>
  public class RequireSessionAttribute : ActionFilterAttribute
  {
    /// <summary>
    /// Runs before action
    /// </summary>
    /// <param name="actionContext"></param>
    public override void OnActionExecuting(HttpActionContext actionContext)
    {
      if (HttpContext.Current == null)
      {
        if (actionContext.Request.Properties.ContainsKey("MS_HttpContext"))
        {
          HttpContext.Current = ((HttpContextWrapper)actionContext.Request.Properties["MS_HttpContext"]).ApplicationInstance.Context;
        }
      }
    }
  }

Mam nadzieję że to pomoże.

Treyphor
źródło
6

Postępowałem zgodnie z podejściem @LachlanB i rzeczywiście sesja była dostępna, gdy plik cookie sesji był obecny na żądanie. Brakuje tego, w jaki sposób plik cookie sesji jest wysyłany do klienta po raz pierwszy?

Utworzyłem HttpModule, który nie tylko włącza dostępność HttpSessionState, ale także wysyła ciasteczko do klienta, gdy tworzona jest nowa sesja.

public class WebApiSessionModule : IHttpModule
{
    private static readonly string SessionStateCookieName = "ASP.NET_SessionId";

    public void Init(HttpApplication context)
    {
        context.PostAuthorizeRequest += this.OnPostAuthorizeRequest;
        context.PostRequestHandlerExecute += this.PostRequestHandlerExecute;
    }

    public void Dispose()
    {
    }

    protected virtual void OnPostAuthorizeRequest(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;

        if (this.IsWebApiRequest(context))
        {
            context.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

    protected virtual void PostRequestHandlerExecute(object sender, EventArgs e)
    {
        HttpContext context = HttpContext.Current;

        if (this.IsWebApiRequest(context))
        {
            this.AddSessionCookieToResponseIfNeeded(context);
        }
    }

    protected virtual void AddSessionCookieToResponseIfNeeded(HttpContext context)
    {
        HttpSessionState session = context.Session;

        if (session == null)
        {
            // session not available
            return;
        }

        if (!session.IsNewSession)
        {
            // it's safe to assume that the cookie was
            // received as part of the request so there is
            // no need to set it
            return;
        }

        string cookieName = GetSessionCookieName();
        HttpCookie cookie = context.Response.Cookies[cookieName];
        if (cookie == null || cookie.Value != session.SessionID)
        {
            context.Response.Cookies.Remove(cookieName);
            context.Response.Cookies.Add(new HttpCookie(cookieName, session.SessionID));
        }
    }

    protected virtual string GetSessionCookieName()
    {
        var sessionStateSection = (SessionStateSection)ConfigurationManager.GetSection("system.web/sessionState");

        return sessionStateSection != null && !string.IsNullOrWhiteSpace(sessionStateSection.CookieName) ? sessionStateSection.CookieName : SessionStateCookieName;
    }

    protected virtual bool IsWebApiRequest(HttpContext context)
    {
        string requestPath = context.Request.AppRelativeCurrentExecutionFilePath;

        if (requestPath == null)
        {
            return false;
        }

        return requestPath.StartsWith(WebApiConfig.UrlPrefixRelative, StringComparison.InvariantCultureIgnoreCase);
    }
}
JCallico
źródło
To działa świetnie. Dzięki temu sesja pozostaje taka sama między żądaniami, dopóki nie upłynie limit czasu. Nie jestem pewien, czy będę go jeszcze używać w prod, dopóki nie wymyślę dobrego sposobu na przełączenie stanu sesji pomiędzy wymaganym i tylko do odczytu, aby zatrzymać blokowanie żądań, ale to dało mi ścieżkę początkową, której pragnę. Dziękuję Ci!
Derreck Dean,
3

jedną rzecz należy wspomnieć w odpowiedzi @LachlanB.

protected void Application_PostAuthorizeRequest()
    {
        if (IsWebApiRequest())
        {
            HttpContext.Current.SetSessionStateBehavior(SessionStateBehavior.Required);
        }
    }

Jeśli pominiesz linię if (IsWebApiRequest())

W całej witrynie występuje problem spowolnienia ładowania strony, jeśli jest ona pomieszana ze stronami formularzy internetowych.

maxisam
źródło
0

Tak, sesja nie idzie w parze z Rest API, a także powinniśmy unikać tych praktyk. Ale zgodnie z wymaganiami musimy w jakiś sposób utrzymywać sesję, aby na każde żądanie serwer klienta mógł wymieniać lub utrzymywać stan lub dane. Tak więc najlepszym sposobem na osiągnięcie tego bez złamania protokołów REST jest komunikacja za pomocą tokena, takiego jak JWT.

https://jwt.io/

Sulabh Singla
źródło
-4

Wracając do podstaw, dlaczego nie uprościć tego i zapisać wartość sesji w ukrytej wartości HTML, aby przekazać ją do interfejsu API?

Kontroler

public ActionResult Index()
        {

            Session["Blah"] = 609;

            YourObject yourObject = new YourObject();
            yourObject.SessionValue = int.Parse(Session["Blah"].ToString());

            return View(yourObject);
        }

cshtml

@model YourObject

@{
    var sessionValue = Model.SessionValue;
}

<input type="hidden" value="@sessionValue" id="hBlah" />

JavaScript

$ (dokument) .ready (function () {

    var sessionValue = $('#hBlah').val();

    alert(sessionValue);

    /* Now call your API with the session variable */}

}

Andy A.
źródło
1
Waht, jeśli aplikacja korzysta zarówno z MVC, jak i WebAPI? Ponadto rozsądniej jest przechowywać niektóre rzeczy po stronie serwera, np. Tokeny bezpieczeństwa Sharepoint. Zamiast implementować specjalne opakowanie do przechowywania tokenów, takie jak kontener lazurowych obiektów blobowych, czasem uzasadnione jest ponowne użycie sesji dla tego typu danych. Kontekst bezpieczeństwa Sharepoint, zaimplementowany w szablonie aplikacji, używa sesji do przechowywania tych kontekstów bezpieczeństwa i tylko małe fragmenty danych są przesyłane (tag sesji) zamiast kilku kilobajtów danych. Byłoby wspaniale, gdyby kontekst ten był mniejszy ...
Konstantin Isaev