Unable to use session in Pagemodel even after configuration - c#

I'm trying to use HttpContext.Session in my asp.net core web application but I'm having trouble. Accessing the session results in InvalidOperationException, with the message "Session has not been configured for this application or request".
I've search around and there some code you have to add to start up i.e adding session and uses it. (I've also added Nuget package AspNetCore.Session).
Now when I try to access Session (HttpContext.Session) in my PageModel code-behind. It throws exception with the message as specified in paragraph above. I can't find any more details aside from you gotta set up in startup code which I've done. My startup code is below:
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;
});
services.AddHttpClient();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddDistributedMemoryCache();
services.AddSession();
}
// 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.UseCookiePolicy();
app.UseSession();
app.UseMvc();
}
Page model on post is how i'm trying to access it:
public async void OnPostAsync()
{
//Some async stuff here.
//Session throws exception
HttpContext.Session.SetString("something", "something");
}

You can't seem to access the static Session via HttpContext, what you need to do is in ConfigurationServices method add services.AddHttpContextAccessor(); This will let you inject IHttpContextAccessor into your page model constructor, this will have session that you setup instead.
Makre sure you set the Session as a member variable in the constructor, as accessing it via HttpSession in the Post method would result in the same problem.

Related

What is the difference between services.Add and app.Use in startup class in ASP.NET Core?

I begin to learn ASP.NET Core, there, within the framework of the Web API template, there is a Startup class with ConfigureServices() and Configure() methods.
Can anyone tell me about how to use them? I am watching an Udemy course and I didn't understand why the instructor doing
public class Startup
{
private readonly IConfiguration config;
public Startup(IConfiguration config)
{
this.config = config;
}
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.AddApplicationServices(this.config);
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "WebAPIv5", Version = "v1" });
});
services.AddCors();
services.AddIdentityServices(this.config);
}
// 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();
// app.UseSwagger();
// app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "WebAPIv5 v1"));
//}
app.UseMiddleware<ExceptionMiddleware>();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(x => x
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(origin => true) // allow any origin
.AllowCredentials());
services.Add is to register service , app.Use is the way to use Middleware
Configure Service(): It is used to add services to the container and configure those services. basically, service is a component that is intended for common consumption in the application. There is framework service like MVC, EF core, identity so on. but there are also application services that are application-specific like send mail services.
Configure(): it is used to specify how the asp.net core application will respond to individual requests. Through this, we actually build the HTTP request pipeline
public class Startup {
// This method gets called by the runtime.
// Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services) {
// Register services here through dependency injection
}
// This method gets called by the runtime.
// Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app,
IWebHostEnvironment env) {
// Add middlware components here
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapGet("/",async Context => {
await context.Response.WriteAsync("Hello World!");
});
});
}
}
Read this example to know more.
Configure.Services and Configure are the starting points from where you can configure framework-level settings in ASP.NET Core.
Configure.Services: To add all the services i.e. the types that you created to add business, database logic to your API. e.g.: You might have created your own logging service and you need to inject in the other classes through DI. To create the objects for these Logging service you need to first register it in the IOC containter of the ASP.NET Core and Configure.Services is the place where you add those services.
Configure: To configure the request-response pipeline i.e. the types that handles the incoming request and outgoing response. e.g.: You might want to add some kind of authentication and authorization before request reaches your controller. Configure is the place where you add those middlewares.

Asp.net core login Identity template is it safe to use?

I am new is asp.net core
I am trying to create web application using asp.net core 3.1 as per the instruction on link
i created login page which is working, application login is working. so after login 1st user in application i copied the cookies of 1st user to other browser and open localhost site and i saw user got loggedin without authentication.
is this right implementation how to create safe login and authorization module in asp.net core webapp
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
// Add Distributed Redis Cache for Session
services.AddDistributedRedisCache(options =>
{
options.Configuration = "localhost";
options.InstanceName = "Session_";
});
services.AddSession(options =>
{
// 20 minutes later from last access your session will be removed.
options.IdleTimeout = TimeSpan.FromMinutes(20);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
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();
// Adds session middleware to pipeline
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
sample code from link
Let's summarize a few things here:
First of all, if your web application is configured correctly it is not possible to steal someone else's cookie. Unless you're on the same physical machine (which I assume is what you did with when you copied the cookie) of course.
So your site should always be served over HTTPS, that's configured correctly: app.UseHttpsRedirection();. And cookies should be HttpOnly (meaning not accessible by javascript): options.Cookie.HttpOnly = true; (but that's for the session cookie). The cookie that is created by the Identity template is marked as HttpOnly and Secure by default so that's also fine. So basically the answer to your question is 'Yes, the Identity template is safe to use'
As a final comment I would recommend to add app.UseHsts(); to add HSTS headers for more security.

.net core api CORS Get works but cors gets 405

I have the following middleware:
namespace TimeManagement
{
public class CorsMiddleware
{
private readonly RequestDelegate _next;
public CorsMiddleware(RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext httpContext)
{
httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
httpContext.Response.Headers.Add("Access-Control-Allow-Headers",
"Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
return _next(httpContext);
}
}
// Extension method used to add the middleware to the HTTP request pipeline.
public static class CorsMiddlewareExtensions
{
public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CorsMiddleware>();
}
}
}
And the following startup class:
namespace TimeManagement
{
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.AddDbContext<WorkTimeContext>(opt =>
opt.UseInMemoryDatabase("WorkTime"));
services.AddDbContext<TimeManagementContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("TimeManagementContext")));
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddControllers();
}
// 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();
}
app.UseHttpsRedirection();
app.UseCorsMiddleware();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
}
}
}
Then I attempt to run https://localhost:5001/api/WorkTimes GET and it returns without issues.
Now I am using an Angular frontend and from there I am trying to post. As you may know, it sends an OPTIONS first and here I get a CORS error:
You need to send status code 200 for CORS preflight request, which your middleware is not setting right now.
Why don't you just use the ASP.NET CORS middleware which handles this?
ASP.NET CORS Middleware
In here ,
https://localhost:5001/api/WorkTimes
is used by the server to return specific data set when valid credentials are sent via a GET HTTP method request.Therefore, in such a scenario, it makes no sense for the server to accept a POST request at that resource/URL, so it may respond with a 405(Method Not Allowed) status code when such a request is made.
The 405(Method Not Allowed) is an HTTP response status code indicating that the specified request HTTP method was received and recognized by the server, but the server has rejected that particular method for the requested resource.A 405 code response confirms that the requested resource is valid and exists, but the client has used an unacceptable HTTP method during the request.
This could happen in a few different circumstances:
The user agent is accidentally sending an incorrect HTTP method.
The server is expecting only a handful of valid HTTP methods for the
requested resource.
Use the ASP.NET CORS middleware as below instead of custom middleware.(Asp.Net Core v3.0 sample code)
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseCors(cor=> cor
.AllowAnyHeader()
.WithOrigins("http://localhost:4200","https://localhost:4200"));
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
Can you try putting the following in web.config:
<httpHandlers>
...
<add path="*" verb="OPTIONS" type="System.Web.DefaultHttpHandler" validate="true"/>
</httpHandlers>
chrome doesn't support this.
​Access to XMLHttpRequest at '...' from origin '...' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: It does not have HTTP ok status.
Solution 1 [Temporary Development Solution]
chrome://flags/#out-of-blink-cors
Disable the out-of-blink-cors flag by copying and pasting that address into the address bar of Chrome followed by [enter]. In the page that opens you'll see a highlighted so-called 'flag' (experiment). Disable it and restart Chrome
(Edit: previously I said to enable the flag but only disabling seems to work)
In many cases that solves the issue.
You can upvote this feature on chrome here
Solution 2 (Recommended)
Create your api under in the sub-domain
your api url will be http://localhost:4200/api/YourEndpoint
Here
Voyage is our angular application.
Under it Api where we host our API so which will be under a same domain so CORS policy is not violated.
Cors errors can be very trick. Sometimes the browser returns this erros without really call your api. So first step you need to be sure that the browser call your API. To do this I usually add a dumb inline middleware and put a breakpoint in it. You could add a logger to it too.
The dumb middleware sample:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async (context, next) =>
{
await next.Invoke();
// Do logging or other work that doesn't write to the Response.
});
// The others middlewares.
}
Now that you know if the problem is in your browser or in your app you can what can you do?
1) If the problem is in your browser, follow the instruction from #Eldho answer to enable it.
2) If the problem is in your app please read the rest of my answer.
Middlewares are executed in the same sequence you call it in Configure method.
Maybe HttpsRedirection is returning this error. (Big maybe here)
You can try declare your custom app.UseCorsMiddleware() before HttpsRedirection. But I suggest you to use Asp.net Cors Middlewares that already exists and works fine. Why reinvent the wheel?
This is a sample of Asp.Net Core v2.1 Cors Middleware
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("Any",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials();
});
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("Any");
// The others middlewares.
}
Another approach (only for development) is to use SPA Middleware to forward the requests your SPA. This way your angular app and your Asp.Net app will answer on the same port of localhost and chrome will not block any. But it just work as temporary solution. It is not recommended to use this in production.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseCors("Any");
// The others middlewares.
if (env.IsDevelopment())
{
app.UseSpa(spa =>
{
spa.UseProxyToSpaDevelopmentServer("http://localhost:4200");
});
}
}

Custom Middleware is causing Blazor Server-side page to stop working

My custom middleware appears to be causing some sort of conflict with my blazor server-side page. The sample middleware in short checks for a bool status and if true redirects to the counter page provided by the out of the box blazor template. Without the middleware inserted into the pipeline the counter page works just fine when you click the button, but once the middleware is placed in the pipeline the button no longer works, as it does not increment the count. I've placed the custom middleware right before the app.UseEndpoints middleware, though it appears it doesn't matter where it's placed, as it doesn't work no matter the order that it's in. Why is my custom middleware breaking the blazor server-side page from functioning properly?
middleware:
class CheckMaintenanceStatusMiddleware
{
private readonly RequestDelegate _next;
public CheckMaintenanceStatusMiddleware(RequestDelegate next)
{
_next = next;
}
public async Task InvokeAsync(HttpContext context)
{
var statusCheck = true;
if(statusCheck && context.Request.Path.Value != "/counter")
{
context.Response.Redirect("/counter");
}
else
{
await _next.Invoke(context);
}
}
}
public static class CheckMaintenanceStatusMiddlewareExtension
{
public static IApplicationBuilder UseCheckMaintenanceStatus(this IApplicationBuilder builder)
{
return builder.UseMiddleware<CheckMaintenanceStatusMiddleware>();
}
}
configure method in Startup file:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
var connectionString = Configuration.GetConnectionString("DefaultConnection");
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
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.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCheckMaintenanceStatus();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
With your code , the blazor negotiate url is also been redirect so negotiate won't work .
Try below codes which avoid that :
if (statusCheck && context.Request.Path.Value != "/counter"&& !context.Request.Path.Value.StartsWith("/_blazor"))
{
context.Response.Redirect("/counter");
}
else
{
await _next.Invoke(context);
}
I suspect what's happening here is
The browser goes to the app URL and attempts to negotiate a SignalR connection.
SignalR returns the protocol and token to use to successfully connect
to the Hub (using "/_blazor?id=token_value").
Unfortunately the custom middleware is redirecting every request, so it ends up stopping the application from doing the initial connection to the hub (triggering a bunch of console errors) - though I was able to successfully redirect to "/counter". But because the middleware is stopping the SignalR connection, it breaks the connection from the client to the server which is necessary for Blazor Server apps.
I would suggest moving this check from middleware. You could try creating a service that can return if the app is in maintenance mode, add a service call to the Index.razor component, and then render a "Maintenance Mode" component if necessary.
This is old post.
But I am using app_offline.htm page to stop the blazor app
I put it in the root (content root folder) and have just plain html which says "Site is under maintenance"
This page will terminate all request and all blazor hub connection.
Then, when I am done updating my app, I rename this file to app_offline2.htm
Meaning "app_offline.htm" is a special file name used my framework and Core to determine if any request can be served by application.

Add a header to all responses in ASP.NET Core MVC

I would like to know how I can add Access-Control-Allow-Origin:* to my headers.
I've tried this unsuccessfully:
app.Use((context, next) =>
{
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
return next.Invoke();
});
Using app.use(...) and mutating context.Response.Headers from within Startup.Configure is correct, but it's important to do it at the right point in the chain. ASP.NET Core middleware components can "short-circuit" (see the ASP.NET Core Middleware docs), preventing further middleware from being called, and by experimenting with it I've inferred that UseMvc() does so. In an MVC application, then, this means you have to put your app.use(...) call before app.UseMvc().
In other words, starting from the template ASP.NET Core 2.0 application that Visual Studio generates for you, you want to modify Startup.Configure in Startup.cs to look something like this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// Add header:
app.Use((context, next) =>
{
context.Response.Headers["Access-Control-Allow-Origin"] = "*";
return next.Invoke();
});
app.UseMvc();
}
I tried your code, and it worked beautifully... Placement is key: I'm pretty sure it needs to be early in the chain.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
//app.UseCors(builder => builder.AllowAnyHeader().AllowAnyMethod().AllowAnyOrigin());
app.Use((context, next) => {
context.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" });
return next.Invoke();
});
app.UseMvc();
app.UseWebSockets();
app.UseSignalR();
}
You can also try to use the in built CORS Middleware in the asp.net core framework rather than creating your own Middleware.
In Configure method of the Startup class add the following code.
// Add CORS for YourAnotherSite
app.UseCors(builder =>
builder.WithOrigins("http://YourAnotherSite.com"));
OR
Use Named Policies
In Configure method of the Startup class
options.AddPolicy("AllowMyOrigin",
builder => builder.WithOrigins("http://YourAnotherSite.com"));
and then in the ConfigureServices method of the startup class.
app.UseCors("AllowMyOrigin");
Alternatively, the Policy can be applied at each Controller or Action methods.
We've found the ApplicationBuilder methods inconsistent too - it's not clear when the handler is handing back to the chain (for instance UseStaticFiles()) and when it's not (UseMvc()).
You don't say what environment you're running under, but if you're intending on using IIS then don't give up on web.config yet! The url rewrite module works perfectly well, and allows you to set outbound rules on all request.
There's a good answer here: https://stackoverflow.com/a/26545975/548664

Categories