C# 能够存储在IHttpContextAccessor.HttpContext.Session中-检索为空

C# 能够存储在IHttpContextAccessor.HttpContext.Session中-检索为空,c#,session,asp.net-core,C#,Session,Asp.net Core,我正在使用一个API,并使用.NETCore2.1中的会话功能和标准依赖项注入来存储和检索会话存储中的值。我的问题是,我能够设置字符串值并将其存储到Session.store中,但是当我尝试在另一个方法中检索这些值时,存储是空的 下面是我的Startup.cs为DI设置IHttpContextAccessor并启用会话存储 public void ConfigureServices(IServiceCollection services) { services.Confi

我正在使用一个API,并使用.NETCore2.1中的会话功能和标准依赖项注入来存储和检索会话存储中的值。我的问题是,我能够设置字符串值并将其存储到Session.store中,但是当我尝试在另一个方法中检索这些值时,存储是空的

下面是我的Startup.cs为DI设置IHttpContextAccessor并启用会话存储

public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-                // essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        // Configure app settings to inject in other classes.
        services.AddOptions();
        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));

        // Services to be injected.
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        services.AddSingleton<IAuthenticationService, AuthenticationService>();
        services.AddSingleton<IConstituentsService, ConstituentsService>();
        services.AddSingleton<ISessionService, SessionService>();

        // Add MVC.
        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

        // Configure session.
        services.AddMemoryCache();
        services.AddDistributedMemoryCache();
        services.AddSession(options => {
            options.IdleTimeout = TimeSpan.FromMinutes(10);
            options.Cookie.Name = ".AuthCodeFlowTutorial.Session";
        });
    }

    // This method gets called by the runtime. Use this method to configure     the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            app.UseHsts();
        }

        app.UseSession();
        app.UseHttpsRedirection();
        app.UseStaticFiles();
        app.UseCookiePolicy();

        app.UseMvc(routes =>
        {
            routes.MapRoute(
                name: "default",
                template: "{controller=Home}/{action=Index}/{id?}");
        });
    }

您在哪里以及如何使用ISessionService?您的意思是什么?我在上面的类中使用它,这是接口中列出的四个方法的实现。我的意思是在哪里注入
ISessionService
并调用
GetAccessToken
SetTokens
。你可能会在没有HTTP上下文的时候调用它
SetTokens()
AuthenticationService
调用,该服务也在
Startup.cs
中设置,并在
AuthenticationController
中用于加载初始页面。所以HTTP上下文应该在那个时候就已经完全设置好了
TryGetString()
SessionService
中调用,而不是在其他地方调用。因此,如果我能够在调用
TrGetString()
之前成功地将值存储在
SessionService
中,那么值应该在那里。您在哪里调用
GetAccessToken
using System;
using System.Collections.Generic;
using System.Net.Http;
using Microsoft.AspNetCore.Http;
using Newtonsoft.Json;

namespace CHS.SkyApiAuthCodeFlow
{

/// <summary>
/// Sets, gets, and destroys session variables.
/// </summary>
public class SessionService : ISessionService
{
    private const string ACCESS_TOKEN_NAME = "token";
    private const string REFRESH_TOKEN_NAME = "refreshToken";
    private readonly IHttpContextAccessor _httpContextAccessor;

    public SessionService(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }


    /// <summary>
    /// Destroys access and refresh tokens from the session.
    /// </summary>
    public void ClearTokens()
    {
        try 
        {
            _httpContextAccessor.HttpContext.Session.Remove(ACCESS_TOKEN_NAME);
            _httpContextAccessor.HttpContext.Session.Remove(REFRESH_TOKEN_NAME);
        }
        catch (Exception error)
        {
            Console.WriteLine("LOGOUT ERROR: " + error.Message);
        }
    }


    /// <summary>
    /// Return access token, if saved, or an empty string.
    /// </summary>
    public string GetAccessToken()
    {
        return TryGetString(ACCESS_TOKEN_NAME);
    }


    /// <summary>
    /// Return refresh token, if saved, or an empty string.
    /// </summary>
    public string GetRefreshToken()
    {
        return TryGetString(REFRESH_TOKEN_NAME);
    }


    /// <summary>
    /// Sets the access and refresh tokens based on an HTTP response.
    /// </summary>
    public void SetTokens(HttpResponseMessage response)
    {
        if (response.IsSuccessStatusCode)
        {
            string jsonString = response.Content.ReadAsStringAsync().Result;
            Dictionary<string, string> attrs = JsonConvert.DeserializeObject<Dictionary<string, string>>(jsonString);
            _httpContextAccessor.HttpContext.Session.SetString(ACCESS_TOKEN_NAME, attrs["access_token"]);
            _httpContextAccessor.HttpContext.Session.SetString(REFRESH_TOKEN_NAME, attrs["refresh_token"]);
        }
    }


    /// <summary>
    /// Return session value as a string (if it exists), or an empty string.
    /// </summary>
    private string TryGetString(string name)
    {
        byte[] valueBytes = new Byte[700];
        bool valueOkay = _httpContextAccessor.HttpContext.Session.TryGetValue(name, out valueBytes);
        if (valueOkay)
        {
            return System.Text.Encoding.UTF8.GetString(valueBytes);
        }
        return null;
    }
}
}
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.Extensions.Options;

namespace CHS.SkyApiAuthCodeFlow
{

/// <summary>
/// Contains business logic and helper methods that interact with the authentication provider.
/// </summary>
public class AuthenticationService : IAuthenticationService
{   

    private readonly IOptions<AppSettings> _appSettings;
    private ISessionService _sessionService;

    public AuthenticationService(IOptions<AppSettings> appSettings, ISessionService sessionService)
    {
        _appSettings = appSettings;
        _sessionService = sessionService;
    }


    /// <summary>
    /// Fetches access/refresh tokens from the provider.
    /// <param name="requestBody">Key-value attributes to be sent with the request.</param>
    /// <returns>The response from the provider.</returns>
    /// </summary>
    private HttpResponseMessage FetchTokens(Dictionary<string, string> requestBody) 
    {
        using (HttpClient client = new HttpClient()) 
        {   
            // Build token endpoint URL.
            string url = new Uri(new Uri(_appSettings.Value.AuthBaseUri), "token").ToString();

            // Set request headers.
            client.DefaultRequestHeaders.Accept.Clear();
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-www-form-urlencoded"));
            client.DefaultRequestHeaders.TryAddWithoutValidation(
                "Authorization", "Basic " + Base64Encode(_appSettings.Value.AuthClientId + ":" + _appSettings.Value.AuthClientSecret));

            // Fetch tokens from auth server.
            HttpResponseMessage response = client.PostAsync(url, new FormUrlEncodedContent(requestBody)).Result;

            // Save the access/refresh tokens in the Session.
            _sessionService.SetTokens(response);

            return response;
        }
    }


    /// <summary>
    /// Fetches a new set of access/refresh tokens (from an authorization code).
    /// <param name="code">The authorization code contained within the provider's authorization response.</param>
    /// </summary>
    public HttpResponseMessage ExchangeCodeForAccessToken(string code)
    {
        return FetchTokens(new Dictionary<string, string>(){
            { "code", code },
            { "grant_type", "authorization_code" },
            { "redirect_uri", _appSettings.Value.AuthRedirectUri }
        });
    }


    /// <summary>
    /// Refreshes the expired access token (from the refresh token stored in the session).
    /// </summary>
    public HttpResponseMessage RefreshAccessToken()
    {
        return FetchTokens(new Dictionary<string, string>(){
            { "grant_type", "refresh_token" },
            { "refresh_token", _sessionService.GetRefreshToken() }
        });
    }


    /// <summary>
    /// Builds and returns a string representative of the provider's authorization URI.
    /// </summary>
    public Uri GetAuthorizationUri()
    {
        return new Uri(
            new Uri(_appSettings.Value.AuthBaseUri), "authorization" +
            "?client_id=" + _appSettings.Value.AuthClientId +
            "&response_type=code" + 
            "&redirect_uri=" + _appSettings.Value.AuthRedirectUri
        );
    }


    /// <summary>
    /// Determines if the session contains an access token.
    /// </summary>
    public bool IsAuthenticated()
    {
        return (_sessionService.GetAccessToken() != null);
    }


    /// <summary>
    /// Destroys the access/refresh tokens stored in the session.
    /// </summary>
    public void LogOut()
    {
        _sessionService.ClearTokens();
    }


    /// <summary>
    /// Encodes a string as Base64.
    /// </summary>
    private static string Base64Encode(string plainText) 
    {
        byte[] bytes = System.Text.Encoding.UTF8.GetBytes(plainText);
        return System.Convert.ToBase64String(bytes);
    }
}
}