ASP.Net Core 3.1 Aplication lost session vars after deploy - asp.net-core

There is a problem, the application uses the session, when launched on the local machine, the session lasts a long time. But when we deploy the server, session data disappears with inconsistent regularity. Sometimes it may take half an hour, sometimes already at the second transition, the application considers that there is no variable in the session. What could be the problem?
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache();
services.AddSession();
services.AddControllersWithViews().AddJsonOptions(options =>
{
options.JsonSerializerOptions.Encoder = JavaScriptEncoder.Create(UnicodeRanges.All);
});
services.Configure<WebEncoderOptions>(options =>
{
options.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.All);
});
services.AddMemoryCache();
services.AddHttpClient();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
System.Diagnostics.Debug.WriteLine("This is development env");
app.UseDeveloperExceptionPage();
// HACK
// Set worker threads as HElios sets them too low for IIS Express
// https://github.com/aspnet/Home/issues/94
int newLimits = 100 * Environment.ProcessorCount; // this is actually # cores (including hyperthreaded cores)
int existingMaxWorkerThreads;
int existingMaxIocpThreads;
System.Threading.ThreadPool.GetMaxThreads(out existingMaxWorkerThreads, out existingMaxIocpThreads);
System.Threading.ThreadPool.SetMaxThreads(Math.Max(newLimits, existingMaxWorkerThreads), Math.Max(newLimits, existingMaxIocpThreads));
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Set up session var
[HttpPost]
public async Task<JsonResult> UserCheck(string surname)
{
Boolean status = false;
String error_msg = "Что то пошло не так";
try
{
Guid? UserId = null;
if (String.IsNullOrWhiteSpace(surname))
{
error_msg = "Не указана фамилия";
}
else
{
UserId = await apm.GetUser(surname);
if (UserId != null && UserId != Guid.Empty)
{
HttpContext.Session.SetString("UserId", UserId.ToString());
status = true;
error_msg = "";
}
}
return Json(new { status, error_msg, guid = UserId });
}
catch (Exception e)
{
return Json(new { status, error_msg });
}
}
Get session vars
public IActionResult Test()
{
string strUserId = HttpContext.Session.GetString("UserId");
if (String.IsNullOrWhiteSpace(strUserId))
{
return RedirectToAction("Index", "Home");
}
else
{
return View();
}
}

Related

Error logging and handling in asp.net core mvc

Let's say you made a bug in a code (like this for example 415 Unsupported Media Type asp.net core ). And get 415 error from a web request. How do we find more information about the error? How can we log it?
Seems that .UseExceptionHandler() In Startup.cs does not catch it.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// app.UseExceptionHandler("/Home/Error");
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStatusCodePages(async context =>
{
context.HttpContext.Response.ContentType = "text/plain";
var statusCodeData = context.HttpContext.Features.Get<IStatusCodePagesFeature>();
await context.HttpContext.Response.WriteAsync(
"Status code page, status code: " +
context.HttpContext.Response.StatusCode);
});
// app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Try with Middleware. Create new class for Middleware:
public class ErrorLoggingMiddleware
{
private readonly RequestDelegate _next;
public ErrorLoggingMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext context)
{
try
{
await _next(context);
}
catch (Exception exception)
{
// Handle exception
await HandleExceptionAsync(context, exception, HttpStatusCode.InternalServerError);
}
}
private Task HandleExceptionAsync(HttpContext context, Exception exception, HttpStatusCode statusCode)
{
context.Response.StatusCode = (int)statusCode;
// TO DO: Log exceptions : Azure AppInsights or File
var message = "The requested resource was not found";
var response = new
{
ErrorDescription = $"{(int)statusCode} - {message}",
ErrorCode = message
};
string responseStringContent;
context.Response.ContentType = Application.Json;
responseStringContent =
JsonSerializer.Serialize(response, new JsonSerializerOptions() { PropertyNamingPolicy = JsonNamingPolicy.CamelCase });
return context.Response.WriteAsync(responseStringContent);
}
}
Then configure this class in Startup:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory fac)
{
...
app.UseMiddleware<ErrorLoggingMiddleware>();
...
}
Please find more details at:
https://blog.elmah.io/error-logging-middleware-in-aspnetcore/

My AspnetCore application does not receive publications from a .net core console application via SignalR

My AspnetCore application does not receive publications from a .net core console application via SignalR
I have an aspnet core 2.1 web application that contains a SignalR Hub.
I need to make a .net core 2.1 console application that send information to my hub on my web system.
I did a development here, however when I run my console app, no exception appears, but my web application does not receive the information.
See what I've done so far.
Aspnet Core 2.1
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache();
services.AddSession();
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSignalR();
services.AddMvc(
config => {
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
config.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddAuthentication(options =>
{
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.ExpireTimeSpan = TimeSpan.FromDays(1);
options.LoginPath = "/Home/Login";
options.LogoutPath = "/Usuario/Logout";
options.SlidingExpiration = true;
});
//provedor postgresql
services.AddEntityFrameworkNpgsql()
.AddDbContext<MesContext>(options =>
options.UseNpgsql(Configuration.GetConnectionString("MesContext")));
services.AddScoped<SeedingService>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, SeedingService seedingService)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
seedingService.Seed();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseAuthentication();
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseSignalR(routes =>
{
routes.MapHub<MesHub>("/MesHub");
});
}
}
View Index
//teste
// ATUALIZA LISTAGEM
connection.on("teste", function (sucesso, msg) {
if (sucesso) {
console.log(msg);
}
});
Hub
public class MesHub : Hub
{
public static ConcurrentDictionary<string, List<string>> ConnectedUsers = new ConcurrentDictionary<string, List<string>>();
public void SendAsync(string message)
{
// Call the addMessage method on all clients
Clients.All.SendAsync("teste", true, message);
}
public override Task OnConnectedAsync()
{
string name = Context.User.Identity.Name;
Groups.AddToGroupAsync(Context.ConnectionId, name);
return base.OnConnectedAsync();
}
}
Console aplication
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Teste Renan!");
var url = "https://localhost:44323/meshub";
var connection = new HubConnectionBuilder()
.WithUrl($"{url}")
.WithAutomaticReconnect() //I don't think this is totally required, but can't hurt either
.Build();
var t = connection.StartAsync();
Console.WriteLine("conected!");
//Wait for the connection to complete
t.Wait();
Console.WriteLine(connection.State);
//connection.SendAsync("SendAsync", "renan");
connection.InvokeAsync<string>("SendAsync", "HELLO World ").ContinueWith(task => {
if (task.IsFaulted)
{
Console.WriteLine("There was an error calling send: {0}",
task.Exception.GetBaseException());
}
else
{
Console.WriteLine(task.Result);
}
});
Console.WriteLine("enviado!");
}
}
In the console app I add the Microsoft.aspnetCore.SignalR.Client package
Signalr works very well within the aspnet core web system, as it is not receiving information externally.
I'm forgetting something? what am I doing wrong?
I define same hub method and do a test to invoke it from the console client, which work as expected.
Besides, I test it with my SignalR console client app, it works well too. If possible, you can test it and check if it works for you.
static void Main(string[] args)
{
Console.WriteLine("Client App Starts...");
Program p = new Program();
p.Myfunc().Wait();
Console.ReadLine();
}
public async Task Myfunc()
{
HubConnection connection = new HubConnectionBuilder()
.WithUrl("https://localhost:44323/meshub")
.Build();
connection.Closed += async (error) =>
{
await Task.Delay(new Random().Next(0, 5) * 1000);
await connection.StartAsync();
};
await connection.StartAsync();
try
{
await connection.InvokeAsync("SendAsync", "HELLO World ");
//await connection.InvokeAsync("SendMessage", "console app", "test mes");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Test Result
Updated:
in my Hub I have an OnConnectedAsync method where the name of the group is informed
You can try to update the OnConnectedAsync method as below, then check if your SignalR console client app can connect to hub and communicate with web client well.
public override async Task OnConnectedAsync()
{
string name = Context.User.Identity.Name;
if (name != null)
{
await Groups.AddToGroupAsync(Context.ConnectionId, name);
}
await base.OnConnectedAsync();
}

Aspnet core authentication cookie is ignored when the application is published online

I need my application set a cookie so that the user must not login every time. I have decided for a 365 days cookie. The cookie seems to work only in localhost and not when i publish the application online. I have checked with Chrome and the cookie is set in both cases correctly. The name of the cookie is ".AspNetCore.Identity.Application" and it is set to expire in one year, both in localhost and on the server online. The cookie remains there even when the Session is over or the application shuts down, but in localhost I remain logged-in while online not.
Here is my Startup code:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDbContext<ForumDbContext>(options =>
options.UseSqlServer(Configuration["ConnectionString"]));
services.AddIdentity<User, IdentityRole>(opts => {
opts.Password.RequireDigit = false;
opts.Password.RequiredLength = 7;
opts.Password.RequireLowercase = false;
opts.Password.RequireUppercase = false;
opts.Password.RequireNonAlphanumeric = false;
opts.SignIn.RequireConfirmedEmail = true;
}).AddDefaultTokenProviders().AddEntityFrameworkStores<ForumDbContext>();
services.ConfigureApplicationCookie(opts =>
{
opts.ExpireTimeSpan = TimeSpan.FromDays(365);
}) ;
services.AddAuthentication().AddCookie(options => {
options.LoginPath = "/account/login";
options.ExpireTimeSpan = TimeSpan.FromDays(365);
}) ;
services.AddSession(opt => opt.IdleTimeout = TimeSpan.FromMinutes(100));
services.AddSingleton<PathProvider>();
services.AddSingleton<BlackList>();
services.AddSingleton<HttpContextAccessor>(); //for the ISession
services.AddScoped<UserSession>(sp => UserSession.CreateInstanceByService(sp));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
var ci = new CultureInfo("it-IT");
ci.NumberFormat.NumberDecimalSeparator = ",";
ci.NumberFormat.CurrencyDecimalSeparator = ",";
ci.NumberFormat.CurrencySymbol = "€";
// Configure the Localization middleware
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(ci),
SupportedCultures = new List<CultureInfo>
{
ci
},
SupportedUICultures = new List<CultureInfo>
{
ci
}
});
app.UseSession();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
//Seeding the database
using (IServiceScope serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var dbContext = serviceScope.ServiceProvider.GetService<ForumDbContext>();
var roleManager = serviceScope.ServiceProvider.GetService<RoleManager<IdentityRole>>();
var userManager = serviceScope.ServiceProvider.GetService<UserManager<User>>();
DbSeeder.Seed(Configuration, dbContext, roleManager, userManager);
}
}
}
I have also checked that I pass IsPersistent = true in
await signinManager.PasswordSignInAsync(user, loginModel.Password, true, false)

Shared resource localization is not working

I am working on shared resource localization in Asp .Net Core 3.1. For that I created resource directory and created SharedResources.cs file.
Root/Resources/SharedResources.cs
Root/Resources/SharedResources.en.resx
I injected code in controller.
public AccountController(IStringLocalizer<SharedResources> sharedLocalizer)
{
_sharedLocalizer = sharedLocalizer;
}
public IActionResult Login(LoginViewModel model)
{
if(loginSuccess == true)
{
return RedirectToAction("Dashboard", "Dashboard");
}
TempData["Error"] = _sharedLocalizer["Error"];
return View(model);
In SharedResources.en.resx
Key : Error
Value : Invalid User
In SharedResources.cs
namespace RootName
public class SharedResources
{
}
It displays Error and it should display Invalid User. Where am I wrong?
For asp.net core 3.x,you need to create SharedResources.cs in your root folder and create SharedResources.en.resx in root/Resources folder like below:
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddLocalization(o =>
{
// We will put our translations in a folder called Resources
o.ResourcesPath = "Resources";
});
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]
{
new CultureInfo("en"),
new CultureInfo("de"),
};
options.DefaultRequestCulture = new RequestCulture("en");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
var localizationOptions = app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value;
app.UseRequestLocalization(localizationOptions);
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}

How to get route data from Identity Server 4 endpoints

I have a ResponseTimeMiddleware.cs responsible for getting response time metrics (I am using datadog) for every request made. Which is tagged by controller and action names. However when we hit the "connect/token" endpoint, the context.GetRouteData() is null, probably because identity server is doing it behind the scenes. Is there a way I could get this information or some other unique information where I could tag with?
here's my code:
public class ResponseTimeMiddleware
{
// other code..
public Task InvokeAsync(HttpContext context)
{
var request = context.Request;
var watch = new System.Diagnostics.Stopwatch();
watch.Start();
context.Response.OnStarting(() =>
{
watch.Stop();
var routeData = context.GetRouteData();
var responseTime = watch.ElapsedMilliseconds.ToString();
var tags = new[] { $"statusCode:{context.Response.StatusCode.ToString()}", $"controller:{routeData.Values["controller"]}", $"action:{routeData.Values["action"]}" };
context.Response.Headers[ResponseHeaderResponseTime] = responseTime;
DogStatsd.Timer("response.time", responseTime, tags: tags);
return Task.CompletedTask;
});
return nextDelegate(context);
}
}
This is my Startup:
public class Startup
{
// other code..
public static void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseMiddleware<ResponseTimeMiddleware>();
app.UseMvcWithDefaultRoute();
app.UseStaticFiles();
app.UseEndpointRouting();
app.UseCookiePolicy();
app.UseCors("CorsPolicy");
app.UseIdentityServer();
// This method gets called by the runtime. Use this method to add services to the container.
public async void ConfigureServices(IServiceCollection services)
{
services.AddDataDogStatsd(Configuration, "identity");
// other code
}
}
Use context.Request.Path conditionally if your routeData is null. It is the closest I can think of since Identity Server 4 middleware has internal routing logic for the standard OAuth protocol routes.