Alternative to 'Session_Start' in MVC 6 - asp.net-core

I'am trying to rewrite an old e-shop to MVC 6, and I'am solving a lot of problems. One of it is that I need to set up some default data when session is beginning. I found nothing usable for thins in MVC 6.
I have multiple shops implemented as one application, and I need to set for example a ShopID when session is starting. Setting is by IP address. This is not the only thing I'am setting there, but its one of the most descriptive things.
Do you have some idea how to implement this, or advice how to do it in different way ?
Sample code from old implementation in global.asax:
void Session_Start(object sender, EventArgs e)
{
string url = Request.Url.Host;
switch (url)
{
case "127.0.0.207":
(SomeSessionObject)Session["SessionData"].ShopID = 123;
break;
case "127.0.0.210":
(SomeSessionObject)Session["SessionData"].ShopID = 345;
break;
}
}
This code i would like to write down somehow in MVC 6, but have no idea where to place it, or even if it is possible.

Following is probably one way of achieving what you are trying to do...Here I am registering a middleware right after the Session middleware so that when a request comes in it would be intercepted by this middleware after Session middleware does its work. You can try it and see if it suits your scenario.
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Hosting;
using Microsoft.AspNet.Http;
using Microsoft.Framework.DependencyInjection;
namespace WebApplication43
{
public class Startup
{
// This method gets called by a runtime.
// Use this method to add services to the container
public void ConfigureServices(IServiceCollection services)
{
services.AddCaching();
services.AddSession();
services.AddMvc();
}
// Configure is called after ConfigureServices is called.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseStaticFiles();
app.UseSession();
app.Use((httpContext, nextMiddleware) =>
{
httpContext.Session.SetInt32("key1", 10);
httpContext.Session.SetString("key2", "blah");
return nextMiddleware();
});
app.UseMvc();
}
}
}
Related package dependencies in project.json:
"dependencies": {
"Microsoft.AspNet.Mvc": "6.0.0-beta7",
"Microsoft.AspNet.StaticFiles": "1.0.0-beta7",
"Microsoft.AspNet.Session": "1.0.0-beta7",
"Microsoft.Framework.Caching.Memory": "1.0.0-beta7",
"Microsoft.AspNet.Http.Extensions": "1.0.0-beta7",

Related

How to resolve Request to Long error in Asp.Net Core Azure B2C Configuraiton?

I am new to Asp.Net Core identity.
I have configured the startup as per below. When I run the code in a normal and incognito browser I get the below error.
I have cleared cookies as previous questions have suggested. What is interesting is a high number of cookies get created when loading the sign screen.
My issue is similar to those described in the below old articles. Both solutions seem outdated.
https://www.javaer101.com/en/article/18781756.html
https://blog.bitscry.com/2018/09/19/azure-ad-request-too-long/
using d365fl.DocumentGenerator.blazor_frontend.Data;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc.Authorization;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Identity.Web;
using Microsoft.IdentityModel.Logging;
namespace d365fl.DocumentGenerator.blazor_frontend
{
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.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
ConfigureIdentiy(services);
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
}
private void ConfigureIdentiy(IServiceCollection services)
{
services.AddMicrosoftIdentityWebAppAuthentication(Configuration, "AzureAdB2C");
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.Configure<OpenIdConnectOptions>(Configuration.GetSection("AzureAdB2C"));
}
// 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();
IdentityModelEventSource.ShowPII = true;
}
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.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapBlazorHub();
endpoints.MapFallbackToPage("/_Host");
});
}
}
}
EDIT 1 - HTTP Request from Developer Toolbar
EDIT 2 - Screen Shot of Cookie data from Developer Toolbar / Network Tab
As we discussed in the comment, the issue is cause by too many cookies.
Please clear your cookies and modify your code to avoid endless loops and back and forth requests.
See this answer for more details.

ASP.NET Core 2.x OnConfiguring get connectionstring string from appsettings.json

Just started messing with ASP.NET Core, pretty impressive so far. In the code generated,(see below). I want to change the hardcoded connection string to get it from the appsettings.json file.
This is apparently impossible. I haven't found a single example that works (or even builds).
What's going on??
Please help
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
#warning To protect potentially sensitive information in your connection string, you should move it out of source code. See http://go.microsoft.com/fwlink/?LinkId=723263 for guidance on storing connection strings.
optionsBuilder.UseSqlServer("Server=xxxxxxx;Database=xxxxx;Trusted_Connection=True;");
}
}
The link provided solves the problem in one area but doesn't work here in OnConfiguring. What am I doing wrong ?
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.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.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
var connection = Configuration.GetConnectionString("ConnectionName");
services.AddDbContext<SurveyContext>(options => options.UseSqlServer(connection));
}
// 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.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
In the startup class of a .NET Core project you usually register this in the ConfigureServices function.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<YourContext>(options => options.UseSqlServer(connection));
}
When you are in the startup class of a .NET Core it is no problem to read the values from appsettings.json.
You could read more at Microsoft, i.e. here: https://learn.microsoft.com/en-us/ef/core/get-started/aspnetcore/existing-db
In the place where you want to access the appsettings.json,
JToken jAppSettings = JToken.Parse(
File.ReadAllText(Path.Combine(Environment.CurrentDirectory,
"appsettings.json")));
Now since you have the object, you can access its contents.
Let me know if it works.
When you use the Scaffold-DbContext, by default it hard codes your string into the DbContext class (so it works out of the box). You will need to register your DbContext in your startup class to proceed. To set this up, you can check the instructions in this answer.
Note that the Configuration property directly connects to your appsettings.json and several other locations. You can read more about it in this documentation. While you can always use the appsettings.json file, it is generally recommended to have your secure secrets in an external json file outside your source code. The best solution for this during development is using the secret manager. The easiest way to use this is right click on your project on visual studio and select "manage user secrets". This will open a json file that is already connected to your Configuration object.
Once this is set up, you need to use dependency injection to access your db context.
public class HomeController : Controller
{
public HomeController(SurveyContext context)
{
// you can set the context you get here as a property or field
// you can use visual studio's shortcut ctrl + . when the cursor is on "context"
// you can then use the context variable inside your actions
}
}
When you use using, it creates a new connection each time. Using injection makes sure only one connection is created per request no matter how many times it is used.

Asp.net core site hangs after about 50 requests

I use asp net core 2.0 and faced very strange behavior (at least I see it locally with IIS express). I open site page then press Refresh button about 50 times and site starts hanging, processing of request takes about 40 seconds. Then after about 5 minutes of idle I refresh page again and everything works fast. Next ~50 requests and again it hangs. I'm very confused with that and don't have ideas what is the reason and how to troubleshoot it. I removed all things from code and rest only base code and it's still reproducable.
My Startup class looks so:
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)
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.AddMvc();
return services.BuildServiceProvider();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.Use(async delegate(HttpContext context, Func<Task> next)
{
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Controller actions don't do anything they just return View. In debugging I often see that it hangs on "await next.Invoke();" line (I've added this delegate only for debugging) but I'm not sure that problem is exactly in action executing.
Maybe anybody knows what can be a reason or how I can troubleshoot it?
Looks like the problem was solved in unexpected way - I updated Visual Studio and as I saw IIS was also updated together with it.

EF7 Beta 4 : AddEntityFramework dont accept argument (Configuration)

I am going through this example:
http://stephenwalther.com/archive/2015/01/17/asp-net-5-and-angularjs-part-4-using-entity-framework-7
and i am struggling with this code part:
using Microsoft.AspNet.Builder;
using Microsoft.Framework.DependencyInjection;
using Microsoft.Data.Entity;
using creaservo.com.Models;
using Microsoft.Framework.ConfigurationModel;
using Microsoft.AspNet.Hosting;
namespace creaservo.com
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
// Setup configuration sources.
Configuration = new Configuration()
.AddJsonFile("config.json")
.AddEnvironmentVariables();
}
public IConfiguration Configuration { get; set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
// Register Entity Framework
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<MoviesAppContext>();
}
public void Configure(IApplicationBuilder app)
{
app.UseMvc();
}
}
}
The Problem is with
// Register Entity Framework
services.AddEntityFramework(Configuration)
.AddSqlServer()
.AddDbContext<MoviesAppContext>();
where i get a build error:
Error CS1501 No overload for method 'AddEntityFramework' takes 1 arguments
I saw in a lot of other examples the same use of a argument for Configuration.
No idea, what's wrong....
It looks like the tutorial you're following is using an older version of the EF7 framework. EntityFramework 7 beta 4 no longer accepts any parameters to AddEntityFramework. It looks like beta 5 is still on this same track, too.
I believe what you're looking for is this:
// Register Entity Framework
services.AddEntityFramework()
.AddSqlServer()
.AddDbContext<MoviesAppContext>(options =>
{
options.UseSqlServer(Configuration.Get("Data:DefaultConnection:ConnectionString"));
});
This simplifies the structure that you need in the configuration file, because the MoviesAppContext only needs the connection string, not the EntityFramework and Data elements.

What is an analog of WebActivator in ASP.NET 5

Previously (in asp.net 4.x) there was common practice to use WebActivator class for register bootstrap logic.
I understand that now we have Startup class where everything can be configured. But with WebActivator I had more options - it was possible to drop-in an assembly into an app (add a nuget) and the assembly registered everything it needs on its own. For this an assemble had assembly level attribute with a type which should be called:
[assembly: WebActivator.PreApplicationStartMethod(typeof (ModuleBootstrapper), "Start")]
What is recommended approach for such things ("lib initialization") in the new glory asp.net 5 now?
The functionality you can get with WebActivator is not possible under ASP.NET 5 and I strongly believe that it won't ever be because one of the great things about ASP.NET 5 pipeline is that you are responsible building up your request pipeline. So, the decision should be deliberately made. As an example:
I have a middleware:
public class MonitoringMiddlware
{
private RequestDelegate _next;
public MonitoringMiddlware(RequestDelegate next)
{
_next = next;
}
public async Task Invoke(HttpContext httpContext)
{
// do some stuff on the way in
await _next(httpContext);
// do some stuff on the way out
}
}
I can package this up and publish to a NuGet feed. Consumer needs to pull this in and add this into the appropriate place inside the pipeline:
public class Startup
{
public IServiceProvider ConfigureServices(IServiceCollection services)
{
// configure services here
}
public void Configure(IApplicationBuilder app)
{
app.UseStatusCodePages();
app.UseFileServer();
// I want middleware to sit here inside the pipeline.
app.UseMiddleware<MonitoringMiddlware>();
app.UseMvc(routes =>
{
routes.MapRoute("areaRoute", "{area:exists}/{controller}/{action}");
routes.MapRoute(
"controllerRoute",
"{controller}",
new { controller = "Home" });
});
}
}
So, whenever I come into this code, I can see how the pipeline is being built without any magic. In the WebActivator case, you would need to look into a few other places to figure out your pipeline and most of all, you wouldn't be making the decision where it sits.
So, it was not a bad thing to get rid of it.