Add Session storage to ASP.NET Core 3.0 - asp.net-core

We are currently migrating an existing ASP.NET Core 2.2 web application to 3.0 So far we've got most things working, except session storage.
We had this fully working in v2.2 as we used it to hold the current logged in user's details. Now that we've upgraded to v3.0 it no longer works.
Here's the middleware code.
public void ConfigureServices(IServiceCollection services)
{
// configure Razor pages, MVC, authentication here
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
//prevent session storage from being accessed from client script
//i.e. only server side code (added security)
options.Cookie.HttpOnly = true;
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSession();
}
N.B. I've removed the rest of the middleware code for clarity.
I've tried moving the app.SetSession() line to the top of the method in case the order of execution was the problem but this has made no difference.
When I hover over the HttpContent.Session property in the debugger I get the following error:
HttpContext.Session threw an exception of type System.InvalidOperationException
How do I enable Session storage in ASP.NET Core 3.0?

I've just tried adding the app.UseSession() to the top of the method and it's working now. It definitely didn't work before but it's working now and that's the main thing.

Related

How to bypass .NET Core 2.2 and 3.1 error handling and display standard IIS status code pages?

In Asp.NET Core 2.2 and 3.1 there is a method called Configure() in the Startup class where you declare what exception handling method you want to use. For example, if you want to send a custom response when an exception occurs, you can do the following:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHttpContextAccessor accessor, IRazorViewEngine razorViewEngine, ITempDataProvider tempDataProvider, IServiceProvider serviceProvider)
{
app.UseExceptionHandler(delegate (IApplicationBuilder errorApp)
{
errorApp.Run(async delegate (HttpContext Context)
{
Context.Response.StatusCode = 500;
Context.Response.ContentType = "text/plain";
await Context.Response.WriteAsync("An error occurred.");
});
});
//var x = ((string)null).Length; <--if this is uncommented, the custom handler won't catch it
//other configuration settings go here
}
Asp.Net Core will default to a standard developer exception page and show all the details of the exception if you don't define a custom handler.
My question is, how do I disable both the .Net Core developer exception page and the custom exception handler, and just have the errors bubble up to IIS so the old-fashioned error pages display?
The reason for wanting to do this is because custom handlers defined in the Configure() method only take effect after the Configure() method has completed. This means any exception that occurs in the Configure() method (see the commented-out line in the example) will send the user a full-blown developer error page, and there is (as far as I've researched) no way to disable this detailed developer page.
Obviously, I don't want these error details to appear on a production site. I figure disabling the Asp.NET Core error handling mechanism altogether will allow for 100% control of exceptions using the standard IIS error pages.
If you don't change any configuration and keep it as default, I assume you run .NET Core with IIS in in-process mode. You can try to disableStartUpErrorPage in this guideline.
Remember, In-Process means your .NET Core process is running on the same process with IIS so whenever you got startup exception, it will be fallback into Program.Main, not in your ExceptionHandler delegate. That is the reason why user can see full stack trace.

.NET Core Controller API call to Azure SQL Database works in localhost but not in deployed Azure Web App

Summary:
I have a .NET Core project that uses the React web app template for the front end. This app uses Entity Framework Core to connect to an Azure SQL Database. I used the Db-Scaffold command to generate my models (just one table at the moment), and created a controller to return this table. Locally, this works fine and the table (JSON) is returned at localhost/api/Users. However when I deploy the website to Azure (CD pipeline is VS 2017 - > GitHub -> DockerHub -> Azure Web App), navigating to mysite.azurewebsites.net/api/Users just renders the login page (React) of my app.
Attempts:
I have tried:
Adding a connection string as a shared value in Azure (named DefaultConnection)
Adding all the outbound IP's of the Azure Web App to the Azure SQL Whitelist
Running the following in the consoles of the web app
fetch('api/users')
This just returns:
Failed to load resource: the server responded with a status of 500 (Internal Server Error)
I have also tried changing database values and refreshing the local version to make sure it was not just a cached page and sure enough the changes were reflected locally.
I also set ASPNETCORE_ENVIRONMENT in the Web App settings in Azure to Production. Although when I go to the error message, page (through the console) I get this:
<h1 class="text-danger">Error.</h1>
<h2 class="text-danger">An error occurred while processing your request.</h2>
<p>
<strong>Request ID:</strong> <code>0HLK3RLI8HD9Q:00000001</code>
</p>
<h3>Development Mode</h3>
<p>
Swapping to the <strong>Development</strong> environment displays detailed information about the error that occurred.
</p>
<p>
<strong>The Development environment shouldn't be enabled for deployed applications.</strong>
It can result in displaying sensitive information from exceptions to end users.
For local debugging, enable the <strong>Development</strong> environment by setting the <strong>ASPNETCORE_ENVIRONMENT</strong> environment variable to <strong>Development</strong>
and restarting the app.
</p>
Code
UsersController.cs
[Route("api/[controller]")]
public class UsersController : Controller
{
private readonly AccrubalanceDbContext _context;
public UsersController(AccrubalanceDbContext context)
{
_context = context;
}
// GET: api/values
[HttpGet]
public async Task<IEnumerable<Users>> Get()
{
return await _context.Users.ToListAsync();
}
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection":<MyConnectionStringGoesHere>
},
index.js (just in case React might be the routing problem)
const baseUrl = document.getElementsByTagName('base')
[0].getAttribute('href');
const rootElement = document.getElementById('root');
ReactDOM.render(
<BrowserRouter basename={baseUrl}>
<App />
</BrowserRouter>,
rootElement);
registerServiceWorker();
Startup.cs (could be potentially problem with HTTP routing in Prod?)
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.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
services.AddDbContext<AccrubalanceDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
}
// 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("/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.UseSpaStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
Conclusion
In conclusion, I need this API call to work within the hosted Azure Web App like it does on my local machine. I know I am close since I got it to work locally, but I am missing something along the way to Azure. Any help or pointers you can provide would be great :)
I am still new to SO and took my time to do my best to format this correctly. I am open to constructive formatting critiques and suggestions to help me improve.
Edit:
As I mentioned before, I am using docker for CD/CI. So I ran my docker container locally and the api does not work there either. Docker throws this warning in the command window when I navigate to the apps home page.
warn: Microsoft.AspNetCore.HttpsPolicy.HttpsRedirectionMiddleware[3]
Failed to determine the https port for redirect.
Edit 1 Determination
I also found this article which points to react routing being an issue. I have looked in Kudo in my Azure app and I do not have a web.config. Could potentially try adding on but I do not have the regular Windows UI since my app is a Linux server.
The container build acts like the Azure App does, may not be an Azure issue. Still unsure why docker is acting differently than running in VS.
Solution:
There is obviously some problem with Docker. Since it was becoming more of a headache then a help, I removed it from the deployment pipeline and just followed the instructions here. Once I did this deployment method, all the API's worked. Only downside is I had to make a new app in Azure.

ASP.Net Core SignalR simple host - 404 error

I am wanting to have 1 simple console app host that is solely for self-hosting the SignalR component.
I have created an "Empty Web Application" using the template. I have created a very simple StartUp file that does not contain anything like MVC etc as it is not needed. However I am getting a 404 not found error from the browser when attempting to negotiate.
The Startup file is as follows:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors();
services.AddSignalR();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors(builder => builder.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
app.UseSignalR(routes =>
{
routes.MapHub<Masterhub>("masterhub");
});
}
}
As you can see, it is very basic, but as I don't want any MVC/Web API functionality, I didn't include all of that setup. There is setup for CORS and SignalR, that is all.
Is what I am attempting to do possible?
It turns out that the JavaScript file I was using from the web client to connect to the self-hosted SignalR Console Application, was the old full .Net version, and not the new version you can get from NPM.

AspNet Core Identity - cookie not getting set in production

I have a .NET Core 2 web app and I want to use ASP.NET Identity to authenticate my users. On .NET Core 1.x, my code was working fine.
I migrated to .NET Core 2, and authentication works when running locally in Visual Studio. But when I deploy to a live environment, authentication stops working: the authentication cookie isn't being set in production.
My Startup.cs code looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<AppUser, RavenDB.IdentityRole>()
.AddDefaultTokenProviders();
...
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseAuthentication();
}
To sign in, my code looks like this:
public async Task<ActionResult> SignIn(...)
{
var user = ...; // Load the User from the database.
await this.signInManager.SignInAsync(user, isPersistent: true);
...
}
This code works locally: the ASP.NET Identity auth cookie is set. However, when I deploy this to production enviro in Azure, the cookie never gets set.
What am I missing?
I solved the problem. It boiled down to HTTPS: it appears that signInManager.SignInAsync(...) sets a cookie that is HTTPS-only. I was publishing to a non-HTTPS site initially for testing.
Once I published to an HTTPS site, the cookie started working again.
The reason it was working locally was that I was running in HTTPS locally.
Had same problem with Chrome 60+. Cookie did not want to set on HTTP site or even HTTPS and Cordova.
options.Cookie.SameSite = SameSiteMode.None;
https://github.com/aspnet/Docs/blob/master/aspnetcore/security/authentication/cookie.md
Changing from default value (Lax) to None fixed it for me.
I had similar issue. In the startup.cs file, I had to change
app.UseCookiePolicy(new CookiePolicyOptions
{
Secure = CookieSecurePolicy.Always
});
to
app.UseCookiePolicy(new CookiePolicyOptions
{
Secure = CookieSecurePolicy.SameAsRequest
});
This allowed cookie authentication to work on both http and https.

Asp.net Core API with CORS on Service Fabric 100% CPU bottleneck

I have an ASP.net Core on .Net Framework 4.5.2 hosted on Service Fabric as STATELESS Service.
The API is a vanilla API, empty
[Route("Test")]
public class TestController : Controller
{
[HttpGet]
public IActionResult Get()
{
return Ok("Done");
}
}
This is my Startup Code
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfigurationRoot Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddResponseCompression();
services.AddMvc().AddJsonOptions(opts =>
{
// Force Camel Case to JSON
opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors("CorsPolicy");
app.UseResponseCompression();
app.UseMvc();
}
}
This is the OpenAsync method:
Task<string> ICommunicationListener.OpenAsync(CancellationToken cancellationToken)
{
var endpoint = FabricRuntime.GetActivationContext().GetEndpoint(_endpointName);
string serverUrl = $"{endpoint.Protocol}://{FabricRuntime.GetNodeContext().IPAddressOrFQDN}:{endpoint.Port}";
//.UseWebListener()
_webHost = new WebHostBuilder().UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseStartup<Startup>()
.UseUrls(serverUrl)
.Build();
_webHost.Start();
return Task.FromResult(serverUrl);
}
Everything plain and simple, no customizations.
The CORS call works, everything is perfect.
I did a test using Visual Studio Team Services with 15K users load, and it all worked like a charm, with 14K RPS. I think the Load test from VS do not use the CORS middleware by the way.
Now the problem is that when I put this exactly empty API in production, receiving calls from around just 100 simultaneous users, the CPU jump to 100% in 3 minutes. The calls are answered until the CPU reach 100% and then start sending errors back.
Seems that with 15000 users and NO CORS it all WORKS, and with 100 users + CORS DOES NOT WORK, CPU goes to 100% and remain like that until I reboot the VM Scale set.
If I stop sending calls, the CPU of the 5 nodes remains stable at 99% without receiving any single call.
How is this possible?
I tried everything, the project is plain and simple, the VS load test works, it's only when I put this on real CORS calls from different sites and different IP addresses that this happens.
I did a performance Trace in the server before sending traffic to it, again with a load test from Visual studio using EXACTLY the CORS headers everything is blazing fast.
With Real world calls this is what I see in the profiler:
There is nothing in it but the CORS middleware and the usual Kestrel processes.
The Stateless service eat up 99% of the CPU, and keep it even if I STOP the Traffic.
This is another 30 seconds trace with no traffic coming but CPU at 90%
I don't know what else to do, there is something wrong with CORS, I'm sure of it, even if it works, somehow something goes wrong.
This is a CORS call, correctly served.
Is there a bug in the Asp.net Core CORS middleware?
UPDATE:
I tried many combinations to isolate the problem:
New cluster, same Asp.net Core vanilla service=> Problem still there
Same cluster new project same Asp.net Core vanilla service=> Problem still there
Same Cluster WebAPI OWIN service, same code => Problem VANISHED!
The problem occurs with Asp.Net Core on Service Fabric using CORS with more than 50 concurrent requests.
This is the CPU (0.85%) with a Asp.Net Stateless service using Visual Studio template, OWIN and CORS, with around 100 concurrent connections and the same empty web API above
At this point I need help from a Microsoft official source to address the problem.
I'm almost sure this is a Asp.net Core CORS bug, that happens when you host it on Service Fabric as a stateless service and send it some minimum traffic (not just a couple of refresh in the browser).