CSHTML Views are not updated until application restart - asp.net-core

I am using browserlink to edit CSS styles and it works pretty nice. Unfortunately, if I change something in .cshtml files, my browser automatically refresh on save, but changes are not visible.
If I close my application and open again, changes are visible.
It seems like my application is caching views somehow somewhere and not reloading changes I do into my files.
This is really not a browser caching problem. The application really sends unchanged html result.
How can I disable such a caching feature in development?
I am using latest ASP NET Core MVC libraries.
EDIT:
if I change anything in _layout, the website is updated without any problem.
EDIT 2: Startup functions
public void ConfigureServices(IServiceCollection services)
{
services.AddWebSocketManager();
var env = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT");
var path = System.AppDomain.CurrentDomain.BaseDirectory;
var machineName = Environment.MachineName;
var confBuilder = new ConfigurationBuilder();
IConfigurationBuilder conf = confBuilder.SetBasePath(path);
if (env == "Development")
{
conf = conf.AddJsonFile($"appsettings.json", optional: true, reloadOnChange: true);
conf = conf.AddJsonFile($"appsettings.Development.json", optional: true, reloadOnChange: true);
conf = conf.AddJsonFile($"appsettings.{machineName}.json", optional: true, reloadOnChange: true);
conf = conf.AddJsonFile($"appsettings.External.json", optional: true, reloadOnChange: true);
}
else
{
conf = conf.AddJsonFile($"appsettings.json", optional: true, reloadOnChange: true);
conf = conf.AddJsonFile($"appsettings.Production.json", optional: true, reloadOnChange: true);
conf = conf.AddJsonFile($"appsettings.External.json", optional: true, reloadOnChange: true);
}
Configuration = conf.Build();
services.AddSingleton(provider => Configuration);
CoreStarter.OnServiceConfiguration?.Invoke(Configuration, services);
var settings = new JsonSerializerSettings();
settings.ContractResolver = new SignalRContractResolver();
var serializer = JsonSerializer.Create(settings);
services.Add(new ServiceDescriptor(typeof(JsonSerializer),provider => serializer,ServiceLifetime.Transient));
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.TryAddSingleton<IContextService, ContextService>();
services.TryAddSingleton<ICryptoService, CryptoService>();
services.TryAddSingleton<IAuthorizationHandler, AuthenticationHandler>();
services.TryAddSingleton<IHttpService, RestApiService>();
if (services.Any(x => x.ServiceType == typeof(IIdentityService)))
{
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.Events.OnRedirectToLogin = (context) =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
options.Events.OnRedirectToAccessDenied = (context) =>
{
context.Response.StatusCode = 401;
return Task.CompletedTask;
};
var sharedCookiePath = Configuration.GetJsonKey<string>("SharedCookiePath");
if (!String.IsNullOrWhiteSpace(sharedCookiePath))
{
options.DataProtectionProvider = DataProtectionProvider.Create(new DirectoryInfo(sharedCookiePath));
}
});
}
services.AddCors();
services.AddLogging(builder =>
{
builder.AddConsole().AddDebug();
});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info {Title = "CoreR API", Version = "v1"});
});
services.AddDistributedMemoryCache();
services.AddSession();
services.AddMemoryCache();
services.AddSingleton<IAssemblyLocator, BaseAssemblyLocator>();
services.AddSignalR(options =>
{
options.Hubs.EnableDetailedErrors = true;
});
var mvcBuilder = services.AddMvc(config =>
{
if (services.Any(x => x.ServiceType == typeof(IIdentityService)))
{
var policyBuilder = new AuthorizationPolicyBuilder();
policyBuilder.RequireAuthenticatedUser();
policyBuilder.AddRequirements(new AuthenticationRequirement());
var policy = policyBuilder.Build();
config.Filters.Add(new AuthorizeFilter(policy));
}
})
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
var assemblies = AppDomain.CurrentDomain.GetAssemblies().ToList();
foreach (var assembly in assemblies)
{
mvcBuilder.AddApplicationPart(assembly);
}
ServiceProvider = services.BuildServiceProvider();
}
public void Configure(IApplicationBuilder app, IServiceProvider serviceProvider, IHostingEnvironment env)
{
var embeddedProvider = new EmbeddedFileProvider(Assembly.GetExecutingAssembly());
var physicalProvider = env.ContentRootFileProvider;
var compositeProvider = new CompositeFileProvider(physicalProvider, embeddedProvider);
app.UseCors(o => o.AllowAnyOrigin().AllowCredentials().AllowAnyMethod().AllowAnyHeader());
app.UseAuthentication();
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDefaultFiles(new DefaultFilesOptions()
{
FileProvider = compositeProvider,
DefaultFileNames = new List<string>() { "default.html"},
});
app.UseStaticFiles(new StaticFileOptions {FileProvider = compositeProvider});
app.UseSession();
app.UseWebSockets();
app.UseSignalR();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "CoreR API");
});
app.UseMvc(routes =>
{
routes.MapRoute("Default", "api/{controller}/{action}/{id?}");
});
CoreStarter.OnConfiguration?.Invoke(Configuration, app, serviceProvider, env);
}

according to Razor file compilation in ASP.NET Core If you want enable run time compilation only for local development:
1.Conditionally reference the Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation package based on the active Configuration value:
<PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.0" Condition="'$(Configuration)' == 'Debug'" />
2. Update the project's Startup.cs file ConfigureServices method:
public void ConfigureServices(IServiceCollection services)
{
IMvcBuilder builder = services.AddRazorPages();
if (env.IsDevelopment())
{
builder.AddRazorRuntimeCompilation();
}
}

Related

Exception unhandled when I upgrade .NET Core 3.1 to .NET 6

I upgraded a project from .NET Core 3.1 to .NET 6 (Web API). Then I fixed errors and applied new syntax as documented by Microsoft. Also, when I start the project in debug mode, it shows this exception in Program.cs:
CreateHostBuilder(args).Build().Run();
System.InvalidOperationException: 'Can't compile a NewExpression with a constructor declared on an abstract class'
My code at Program.cs:
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Autofac.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using System.IO;
using System.Linq;
using Serilog;
using Serilog.Events;
using Microsoft.Extensions.Hosting;
namespace Portal.Api
{
public class Program
{
public static void Main(string[] args)
{
// Serilog config
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Debug()
.MinimumLevel.Override("Microsoft", LogEventLevel.Information)
.Enrich.FromLogContext()
.CreateLogger();
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.UseServiceProviderFactory(new AutofacServiceProviderFactory())
.ConfigureAppConfiguration((hostingContext, config) =>
{
config.AddEnvironmentVariables();
config.SetBasePath(Directory.GetCurrentDirectory());
config.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true);
config.AddJsonFile("appsettings.config.json", optional: true, reloadOnChange: true);
#if DEBUG
config.AddJsonFile("appsettings.Development.json", optional: false, reloadOnChange: true);
var subConfig = Directory.GetFiles(Directory.GetCurrentDirectory(), "appsettings.Dev-*.json", SearchOption.TopDirectoryOnly)
.Where(e => !e.EndsWith("appsettings.Development.json"))
.ToList();
if (subConfig.Count > 0)
{
foreach (var file in from string path in subConfig let file = Path.GetFileName(path) select file)
config.AddJsonFile(file, true, true);
}
#endif
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
}
and Startup.cs
using AspNetCoreRateLimit;
using Autofac;
using Autofac.Core;
using Autofac.Extensions.DependencyInjection;
using AutoMapper;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using Portal.Api.Common;
using Portal.Api.CoreProcess;
using Portal.Api.EvaluateProcess;
using Portal.Api.EventProcess;
using Portal.Api.Middleware;
using Portal.Api.Plugins;
using Portal.Api.Plugins.SlackLogger;
using Portal.Api.Provider;
using Portal.Common;
using Portal.Data;
using Portal.Repository;
using Portal.Services;
using Portal.Services.Impl;
using Portal.Services.Interface;
using ServiceStack;
using ServiceStack.Text;
using System;
using System.Globalization;
using System.IO;
using System.Text;
namespace Portal.Api
{
public class Startup
{
public Startup(IConfiguration configuration)
{
//var configuration = new ConfigurationBuilder()
// .SetBasePath(Directory.GetCurrentDirectory())
// .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
// //.AddJsonFile(#"App_Data\message.json", optional: false, reloadOnChange: false)// custom config file
// .Build();
Configuration = configuration;
}
public IConfiguration Configuration { get; private set; }
public ILifetimeScope AutofacContainer { get; private set; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.Cookie.HttpOnly = false;
options.Cookie.IsEssential = true;
});
services.AddControllers()
.AddNewtonsoftJson(options =>
{
options.UseMemberCasing();
});
services.AddCors();
services.AddMemoryCache();
services.RegisterPlugins();
services.AddControllers().AddNewtonsoftJson();
var defaultConnection = Configuration["DefaultConnection"];
var encyptor = Configuration.GetValue($"Encyptor:{defaultConnection}", string.Empty);
string conStr = Configuration.GetConnectionString(Configuration["DefaultConnection"]);
if (!string.IsNullOrEmpty(encyptor))
{
var enable = Configuration.GetValue("Encyptor:Enable", true);
if (enable)
{
try
{
Uri uri = new Uri(new Uri(encyptor), "GetConnection");
var base64EncodedData = uri.OriginalString.GetStringFromUrl();
if (!string.IsNullOrEmpty(base64EncodedData))
{
var base64EncodedBytes = Convert.FromBase64String(base64EncodedData);
conStr = Encoding.UTF8.GetString(base64EncodedBytes);
}
}
catch (Exception)
{
var error = new Exception("Can not connect to Encryptor");
throw error;
}
}
}
services.AddDbContext<PortalDbContext>(item => item.UseSqlServer(conStr));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "Development",
Title = "ezHR Portal Public API",
Description = "ASP.NET Core Web API"
});
c.CustomSchemaIds(type => type.ToString());
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
var SecretKey = Encoding.ASCII.GetBytes(GlobalParam.SECRET_KEY);
var ezAuthSection = Configuration.GetSection("Auth").Get<Data.Dtos.AuthSection>() ?? new Data.Dtos.AuthSection();
services.AddSingleton(ezAuthSection);
// Configure JWT Token Authentication
if (ezAuthSection.Enable && ezAuthSection.Okta)
{
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = ezAuthSection.Url,
ValidateAudience = true,
ValidAudience = ezAuthSection.Url,
ValidateIssuerSigningKey = false,
SignatureValidator = delegate (string token, TokenValidationParameters parameters)
{
var jwt = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(token);
return jwt;
},
RequireExpirationTime = false,
ValidateLifetime = true,
NameClaimType = GlobalParam.NameIdentifierClaimType
};
});
}
else if (ezAuthSection.Enable && !string.IsNullOrEmpty(ezAuthSection.NameClaimType))
{
var nameClaim = ezAuthSection.NameClaimType;
services.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
Microsoft.IdentityModel.Logging.IdentityModelEventSource.ShowPII = true;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidIssuer = ezAuthSection.Url,
ValidateAudience = false,
ValidAudience = ezAuthSection.Url,
ValidateIssuerSigningKey = false,
SignatureValidator = delegate (string token, TokenValidationParameters parameters)
{
var jwt = new System.IdentityModel.Tokens.Jwt.JwtSecurityToken(token);
return jwt;
},
RequireExpirationTime = false,
ValidateLifetime = true,
NameClaimType = nameClaim
};
});
}
else
{
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = ezAuthSection.Url;
options.RequireHttpsMetadata = false;
options.Audience = $"{ezAuthSection.Url}/resources";
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = GlobalParam.NameIdentifierClaimType
};
})
.AddJwtBearer("ezHR9", token =>
{
token.RequireHttpsMetadata = false;
token.SaveToken = true;
token.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(SecretKey),
ValidateIssuer = false,
ValidateAudience = false,
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(JwtBearerDefaults.AuthenticationScheme, "ezHR9");
defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
}
ConfigJson();
// Repository DI
services.AddScoped<IRepositoryFactory, UnitOfWork<PortalDbContext>>();
services.AddScoped<IUnitOfWork, UnitOfWork<PortalDbContext>>();
services.AddScoped<IUnitOfWork<PortalDbContext>, UnitOfWork<PortalDbContext>>();
services.AddScoped<IUserSession, UserSession>();
services.AddScoped<ITR_FinalTeacherWorkingService, TR_FinalTeacherWorkingService>();
services.AddScoped<IHR_BankService, HR_BankService>();
services.AddScoped<IHR_EmployeeAccountService, HR_EmployeeAccountService>();
services.AddSingleton<IUserSessionFactory>(provider => new UserSessionFactory(provider));
services.AddSingleton<Plugins.Locales.ILocales, Plugins.Locales.Locales>();
// Custom DI
services.RegisterProvider();
// Add services to the collection
services.AddOptions();
// Rate limit DI
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimiting"));
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
services.AddSingleton<IRateLimitConfiguration, RateLimitConfiguration>();
services.AddHttpContextAccessor();
services.AddAutoMapper(typeof(Startup));
//// Create a container-builder and register dependencies
//var builder = new ContainerBuilder();
//// Populate the service-descriptors added to `IServiceCollection`
//builder.Populate(services);
//// Register dependency directly with Autofac
//builder.RegisterWebRepository();
//builder.RegisterWebServices();
//builder.RegisterEventProcessDI();
//builder.RegisterEvaluateProcessDI();
//builder.RegisterCoreProcessDI();
//builder.RegisterType<MongoDBHelper>();
//AutofacContainer = builder.Build();
//// this will be used as the service-provider for the application!
//return new AutofacServiceProvider(AutofacContainer);
}
public void ConfigureContainer(ContainerBuilder builder)
{
// Register your own things directly with Autofac
// Populate the service-descriptors added to `IServiceCollection`
//builder.Populate(services);
// Register dependency directly with Autofac
builder.RegisterWebRepository();
builder.RegisterWebServices();
builder.RegisterEventProcessDI();
builder.RegisterEvaluateProcessDI();
builder.RegisterCoreProcessDI();
builder.RegisterType<MongoDBHelper>();
//AutofacContainer = builder.Build();
// this will be used as the service-provider for the application!
// return new AutofacServiceProvider(AutofacContainer);
//...
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (env.EnvironmentName == Environments.Development)
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
var aspNetCoreTemp = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ASPNETCORE_TEMP");
if (!Directory.Exists(aspNetCoreTemp))
{
Directory.CreateDirectory(aspNetCoreTemp);
}
Environment.SetEnvironmentVariable("ASPNETCORE_TEMP", aspNetCoreTemp ?? Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StaticFiles"));
var slackConfiguration = Configuration.GetSection("SlackConfiguration").Get<SlackConfiguration>();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.SetIsOriginAllowed(org => true)
//.AllowCredentials()
);
app.UseAuthentication();
app.UseAuthorization();
app.UseSession();
app.UseIpRateLimiting();
// use 2 custom middleware before UseMVC to handle request
app.UseMiddleware(typeof(CaptureRequestMiddleware));
app.UseMiddleware(typeof(ErrorHandlingMiddleware));
app.UseSwagger();
app.UseSwaggerUI(c => { c.SwaggerEndpoint("/swagger/v1/swagger.json", "ezHR Portal Public API"); });
//app.UseMvc();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StaticFiles")),
RequestPath = "/StaticFiles"
});
app.EnrichLog();
if (env.IsDevelopment())
{
app.UseFileServer(new FileServerOptions()
{
FileProvider = new PhysicalFileProvider(
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "StaticFiles")),
RequestPath = new PathString("/StaticFiles"),
EnableDirectoryBrowsing = true
});
}
// giả lập call 1 service để giảm thời gian request lần đầu ở client
Console.WriteLine("Starting application...");
MockResolve(app);
}
private void MockResolve(IApplicationBuilder app)
{
var serviceProvider = app.ApplicationServices;
_ = serviceProvider.GetService<EventProcess.EventHandler.Register.RegisterLeaveHandler>();
}
private void ConfigJson()
{
//JsConfig.TextCase = TextCase.PascalCase;
JsConfig.MaxDepth = 6;
JsConfig<DateTime>.SerializeFn = date => date.ToString("o", CultureInfo.InvariantCulture);
JsConfig<DateTime?>.SerializeFn = date => date.HasValue ? date.Value.ToString("o", CultureInfo.InvariantCulture) : string.Empty;
JsConfig<TimeSpan>.SerializeFn = time => (time.Ticks < 0 ? "-" : "") + time.ToString("hh':'mm':'ss'.'fffffff");
JsConfig<TimeSpan?>.SerializeFn = time => time.HasValue ? (time.Value.Ticks < 0 ? "-" : "") + time.Value.ToString("hh':'mm':'ss'.'fffffff") : null;
JsConfig<Guid>.SerializeFn = guid => guid.ToString("D");
JsConfig<Guid?>.SerializeFn = guid => null;
}
}
}
I searched and lookup many case about upgrade .NET Core 3.1 to .NET 6 but I think this case is exception
The three steps to be followed for Non-Blazor .NET core 3.1 to 6.0.
Step1: Upgrade the Target Framework. Right-click on the project file and open the property in which the target framework can be changed.
Step2: Update the package References: Edit the project file in Notepad++ or in solution explorer in VSS. Upgrade the ASP.NET core 3.1 associated packages to 6.0
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="3.1.6" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.6" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="3.1.6" />
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
To
<PackageReference Include="Microsoft.AspNetCore.JsonPatch" Version="6.0.0" />
<PackageReference Include=" Microsoft.EntityFrameworkCore.Tools" Version="6.0.0" />
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
<PackageReference Include="System.Net.Http.Json" Version="6.0.0" />
</ItemGroup>
Step3: Bin and Obj folder: Bin and Obj folder can be deleted manually or apply the below line.
dotnet nuget locals --clear all
Step 4: Rebuild/ compile the project.
Step 5: Docker Image: If application uses the docker, the below command can be used for it
docker pull mcr.microsoft.com/dotnet/aspnet:6.0

Htttp 400 Bad Request Request Header is too long

I am currently developing an application using Asp.net core 5.0 and Identity server 4.My OIDC authentication flow handled by Microsoft.AspNetCore.Authentication.OpenIdConnect. I deployed my application into IIS and I am getting my login screen. But after login I got the Http 400 Bad request error.Error. I checked my application cookie it contains many AspNetCore.OpenIdConnect.Nonce cookies. I deleted the cookies but doesn't solve my issue. What is the proper solution to handle this solution. I tried this but doesn't help me. I will share the code below
MVC Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).SetCompatibilityVersion(CompatibilityVersion.Version_3_0);
services.AddScoped<RenewToken>();
services.AddAuthorization(options =>
{
options.AddPolicy("CreatePolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RC", "UC")));
options.AddPolicy("ReadPolicy", policy => policy.RequireAssertion(context => AuthorizeAccess(context, "RR", "UR")));
});
services.AddControllersWithViews();
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "oidc";
}).AddCookie("Cookies", options =>
{
options.Cookie.Name = "Cookies";
options.ExpireTimeSpan = TimeSpan.FromMinutes(10);
options.SlidingExpiration = true;
}).AddOpenIdConnect("oidc", options =>
{
options.BackchannelHttpHandler = new HttpClientHandler { ServerCertificateCustomValidationCallback = delegate { return true; } };
options.Authority = Configuration.GetSection("API:IDS4").Value;
options.SignInScheme = "Cookies";
options.SignedOutRedirectUri = Configuration.GetSection("API:WebClient").Value + "/signout-callback-oidc";
options.RequireHttpsMetadata = true;
options.ClientId = "mvc";
options.ClientSecret = "*****";
options.ResponseType = "code";
options.UsePkce = true;
options.Scope.Add("profile");
options.Scope.Add("mcApi");
options.Scope.Add("Api1");
options.Scope.Add("Api2");
options.Scope.Add("Api3");
options.Scope.Add("Api4");
options.Scope.Add("Api5");
options.Scope.Add("Api6");
options.Scope.Add("Api7");
options.Scope.Add("offline_access");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
options.Events.OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.Prompt = "login";
return Task.CompletedTask;
};
options.Events = new OpenIdConnectEvents
{
OnRemoteFailure = (context) =>
{
context.Response.Redirect("/");
context.HandleResponse();
return Task.CompletedTask;
}
};
options.TokenValidationParameters = new TokenValidationParameters
{
RoleClaimType = JwtClaimTypes.Role
};
});
services.AddHttpClient<IAdminService, AdminService>();
services.AddSingleton<DataProtectionPurposeStrings>();
services.AddSingleton<GlobalConstants>();
}
private bool AuthorizeAccess(AuthorizationHandlerContext context, string roleClaim, string userClaim)
{
return context.User.HasClaim(claim => claim.Type == roleClaim && claim.Value == "True") &&
context.User.HasClaim(claim => claim.Type == userClaim && claim.Value == "True") ||
context.User.IsInRole("MyAdmin");
}
// 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.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Identity Server Startup.cs
public class Startup
{
public IWebHostEnvironment Environment { get; }
public IConfiguration Configuration { get; }
public Startup(IWebHostEnvironment environment, IConfiguration configuration)
{
Environment = environment;
Configuration = configuration;
}
// 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)
{
services.AddControllersWithViews();
/****Register asp.net core Identity DBConetexts***/
var idenConnectionString = Configuration["DbContextSettings:IdentityConnectionString"];
var dbPassword = Configuration["DbContextSettings:DbPassword"];
var builder = new NpgsqlConnectionStringBuilder(idenConnectionString)
{
Password = dbPassword
};
services.AddDbContext<IdentityDBContext>(opts => opts.UseNpgsql(builder.ConnectionString));
services.AddIdentity<ApplicationUser, ApplicationRole>(options =>
{
options.Password.RequiredLength = 8;
options.User.AllowedUserNameCharacters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+ ";
options.SignIn.RequireConfirmedEmail = false;
options.User.RequireUniqueEmail = false;
}).AddRoles<ApplicationRole>().AddEntityFrameworkStores<IdentityDBContext>()
.AddDefaultTokenProviders();
/****Identity Server implementation with asp.net core Identity***/
var idsServerConnectionString = Configuration["DbContextSettings:IdentityServer4ConnectionString"];
var migrationAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
var idsServerdbPassword = Configuration["DbContextSettings:DbPassword"];
var idsServerbuilder = new NpgsqlConnectionStringBuilder(idsServerConnectionString)
{
Password = dbPassword
};
var idBuilder = services.AddIdentityServer(options =>
{
options.Events.RaiseErrorEvents = true;
options.Events.RaiseInformationEvents = true;
options.Events.RaiseFailureEvents = true;
options.Events.RaiseSuccessEvents = true;
options.UserInteraction.LoginUrl = "/Account/Login";
options.UserInteraction.LogoutUrl = "/Account/Login";
options.Authentication = new AuthenticationOptions()
{
CookieLifetime = TimeSpan.FromMinutes(10),
CookieSlidingExpiration = true
};
})
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(idsServerbuilder.ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseNpgsql(idsServerbuilder.ConnectionString, sql => sql.MigrationsAssembly(migrationAssembly));
options.EnableTokenCleanup = true;
}).AddAspNetIdentity<MembershipUser>()
.AddProfileService<ProfileService>();
X509Certificate2 cert = null;
using (var certStore = new X509Store(StoreName.My, StoreLocation.LocalMachine))
{
certStore.Open(OpenFlags.ReadOnly);
var certCollection = certStore.Certificates.Find(
X509FindType.FindByThumbprint,
"thumbprint",
false);
if (certCollection.Count > 0)
{
cert = certCollection[0];
}
}
if (Environment.IsDevelopment())
{
idBuilder.AddDeveloperSigningCredential();
}
else
{
idBuilder.AddSigningCredential(cert);
}
idBuilder.Services.ConfigureExternalCookie(options =>
{
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode)(-1);
});
idBuilder.Services.ConfigureApplicationCookie(options =>
{
options.Cookie.IsEssential = true;
options.Cookie.SameSite = (SameSiteMode)(-1);
});
services.AddMediatR(typeof(Startup));
RegisterServices(services);
}
private void RegisterServices(IServiceCollection services)
{
services.AddSingleton<IEventBus, RabbitMQBus>(sp =>
{
var scopeFactory = sp.GetRequiredService<IServiceScopeFactory>();
return new RabbitMQBus(sp.GetService<IMediator>(), scopeFactory);
});
services.AddTransient<UserDBContext>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{
if (Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
// uncomment if you want to add MVC
app.UseStaticFiles();
app.UseRouting();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
}
Can I store the cookies into SessionStore using MemoryCacheTicketStore ? Kindly share your thoughts.
A potential thing could be that IIS thinks the cookie header is too long.
By default ASP.NET Core chunks up the cookie in 4Kb chunks, like this picture shows:
So either you try to reduce the size of the cookie or look at the IIS settings, if you can increase the max header length?
Alternatively, you stop saving the tokens inside the cookie, by setting:
options.SaveTokens = false;
Now you of course need top store it somewhere else, like in a tokenstore.

Authentication in .NET Core Web API not activating

Am trying to activate JWT token authentication scheme in .net core web api. Its not activating at all.
I configured Swagger to take in a token and give the consumer of the API access to all its controllers. But it just lets everyone get access rather than checking if a valid token exists.
I've tried putting the [Authorize] keyword on all the controllers but it still doesnt work.
Here i provide my startup.cs file
namespace Web.Api
{
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
}
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddOptions();
services.AddSwaggerDocumentation();
// CORS Configurations
services.AddCors(options =>
{
options.AddPolicy("AllowAllOrigins",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
});
// Authentication Configurations
services.Configure<TokenManagement>(Configuration.GetSection("Jwt"));
var token = Configuration.GetSection("Jwt").Get<TokenManagement>();
var secret = Encoding.ASCII.GetBytes(token.Key);
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ClockSkew = TimeSpan.FromMinutes(5),
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = token.Issuer,
ValidAudience = token.Audience,
IssuerSigningKey = new SymmetricSecurityKey(secret)
};
});
services.AddRouting(options => options.LowercaseUrls = true);
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
services.AddScoped<IUnitOfWork, UnitOfWork>();
services.AddScoped<IUrlHelper>(implementationFactory =>
{
var actionContext = implementationFactory.GetService<IActionContextAccessor>().ActionContext;
return new UrlHelper(actionContext);
});
services.AddVersionedApiExplorer(o => o.GroupNameFormat = "'v'VVV");
services.AddMvcCore()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddFormatterMappings()
.AddJsonFormatters();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IApiVersionDescriptionProvider provider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
app.UseAuthentication();
app.UseSwaggerDocumentation(provider);
app.UseMvc(routes =>
{
routes.MapRoute("API Default", "api/{controller}/{action}/{id?}");
routes.MapRoute("Printers Default", "api/{controller}/{action}/{vendorDriver}/{vendormodel}");
});
}
}
}
services.AddMvc() will load the Authorization service(AddAuthorization()) :
return services
.AddMvcCore()
.AddApiExplorer()
.AddAuthorization()
.AddCors()
.AddDataAnnotations()
.AddFormatterMappings();
so you can use services.AddMvc() or services.AddMvcCore().AddAuthorization()
The differences between services.AddMvc() and services.AddMvcCore() is the services that are loaded inside you application.
AddMvcCore() add only the mandatory services to run the Asp.net app, while AddMvc() load common used services.
I'm gonna show you the way I made it work in my project (I'm using ASP.NET Core 2.2)
// Inside ConfigureServices
services.AddAuthentication().AddCookie().AddJwtBearer(cfg => {
cfg.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = configuration["Tokens:Issuer"],
ValidAudience = configuration["Tokens:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration["Tokens:Key"]))
};
});
// Inside Configure
app.UseAuthentication();
// In the controllers that need Authentication
[ApiController]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class SampleController : ControllerBase {
}
Well, i just added the line
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
I dont know why the line
services.AddMvcCore().SetCompatibilityVersion(CompatibilityVersion.Version_2_2) won't
activate it

How to sign in ASP.NET Core Identity User, using OpenIdConnect Authentication?

I'm using ASP.NET Identity to authenticate my users and I want to be able to do this via Azure AD as well. All users will be in the DB beforehand, so all I need to do is sign them in and set their cookies, if the AzureAD login was successful. The problem is that when I implement the new external authentication and validate that they exist in my DB, they are not signed in.
So after successful remote login, if in my controller I check for User.Identity.IsAuthenticated it returns true, but _signInManager.IsSignedIn(User), it returns false. I have tried to follow the MS guidelines and documentation, but I assume there is something wrong with my config.
Here's the startup:
services.AddMvc(options => options.EnableEndpointRouting = false)
.SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddRouting(options =>
{
options.LowercaseQueryStrings = true;
options.LowercaseUrls = true;
});
services.Configure<CookiePolicyOptions>(options =>
{
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(Configuration.GetConnectionString("<my_db_connection_string_here>")));
services.AddDefaultIdentity<ApplicationUser>()
.AddRoles<IdentityRole>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddUserManager<UserManager<ApplicationUser>>();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
Configuration.GetSection("OpenIdConnect").Bind(options);
options.TokenValidationParameters.ValidateIssuer = false;
options.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = async ctx =>
{
var request = ctx.HttpContext.Request;
var currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
var credential = new ClientCredential(ctx.Options.ClientId, ctx.Options.ClientSecret);
var distributedCache = ctx.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
string userId = ctx.Principal.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier").Value;
var authContext = new AuthenticationContext(ctx.Options.Authority);
var result = await authContext.AcquireTokenByAuthorizationCodeAsync(
ctx.ProtocolMessage.Code, new Uri(currentUri), credential, ctx.Options.Resource);
ctx.HandleCodeRedemption(result.AccessToken, result.IdToken);
}
};
});
var builder = services.AddIdentityCore<ApplicationUser>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 6;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
options.User.RequireUniqueEmail = true;
})
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.AddLogging(options =>
{
options.AddConfiguration(Configuration.GetSection("Logging"))
.AddConsole();
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
IdentityModelEventSource.ShowPII = true;
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
And in my controller:
[AllowAnonymous]
public IActionResult AzureLogin()
{
if (User.Identity.IsAuthenticated)
{
return RedirectToAction(nameof(HandleLogin)):
}
return Challenge(new AuthenticationProperties
{
RedirectUri = Url.Action(nameof(HandleLogin))
});
}
[Authorize]
public async Task<IActionResult> HandleLogin()
{
var isAuth = User.Identity.IsAuthenticated; // true
var isSigned = _signInmanager.IsSignedIn(User); // false
return ....
}
You could try to set AutomaticAuthenticate cookie to true:
services.Configure<IdentityOptions>(options => {
// other configs
options.Cookies.ApplicationCookie.AutomaticAuthenticate = true;
});
Here's how I managed to do it:
Since I'm authorizing the user via ASP.NET Identity, I changed the default authentication method in the authentication options to options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme; and in the OpenIdConnectOptions OnAuthorizationCodeRecieved event, I validate and sign in the Identity User via the SignInManager.SignInAsync() method

No 'Access-Control-Allow-Origin' in header error

I am working with an Angular 2 app with asp.net core back end. I am trying to print a pdf (client side code below). When I run on our dev server, everything is ok; however, running on production I get
Failed to load api_url: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin url is therefore not allowed access.
Everything I have seen mentions something about CORS policy, but I don't understand how this could be working fine on one server, but not on another. Also, it appears to be retrieving fine when hitting other API endpoints.
Client-side api call:
getPDF(pickupId: string): void {
this.printingSub.next(true);
this._http.get(this._dataUrl + 'pickupsheet?pickupid=' + pickupId + '&barcode=true', { responseType: ResponseContentType.Blob })
.catch(error => this.handleError(error))
.subscribe((response: Response) => {
this.pdfBlob = new Blob([response.blob()], { type: 'application/pdf' });
const blobUrl = URL.createObjectURL(this.pdfBlob);
const iframe = document.createElement('iframe');
iframe.style.display = 'none';
iframe.src = blobUrl;
document.body.appendChild(iframe);
iframe.contentWindow.print();
this.printingSub.next(false);
});
}
Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public IConfigurationSection AppSettings { get; }
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile(#"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
AppSettings = Configuration.GetSection("appSettings");
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
ConfigureDatabase();
ConfigurePolicies(services);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddOptions();
services.Configure<AppAccessSettings>(s =>
{
s.Env = AppSettings.GetSection("env").Value;
s.EnableAuth = bool.Parse(AppSettings.GetSection("enableAuth").Value);
});
services.AddMvc().AddJsonOptions(options =>
options.SerializerSettings.ContractResolver = new Newtonsoft.Json.Serialization.DefaultContractResolver()
);
}
// 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)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
// Configure JWT authentication
Authentication.SetVarFromFile(AppSettings.GetSection("authFile").Value);
Authentication.SetAuth(ref app, AppSettings.GetSection("audience").Value);
app.UseCors("CorsPolicy");
app.UseMvc();
}
private void ConfigureDatabase()
{
string dbSource = AppSettings.GetSection("env").Value;
OracleEnv.Connection = Configuration.GetSection("connectionStrings").GetSection(dbSource).Value;
}
private void ConfigurePolicies(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddAuthorization(options =>
{
options.AddPolicy("EnableAuth",
policy => policy.Requirements.Add(new AuthRequirement(Configuration)));
});
services.AddSingleton<IAuthorizationHandler, UserAuthHandler>();
}
}
private void ConfigurePolicies(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddAuthorization(options =>
{
options.AddPolicy("EnableAuth",
policy => policy.Requirements.Add(new AuthRequirement(Configuration)));
});
services.AddSingleton<IAuthorizationHandler, UserAuthHandler>();
}
Pickup Sheet API Method
[Route("PickupSheet")]
public IActionResult GetPickupSheet(string pickupId, bool barCode)
{
PbReportGenerator rpt = new PbReportGenerator();
byte[] report = rpt.RetrievePDFReport(232, new Dictionary<string, string>
{
{ pickupId, "string" },
{ (barCode ? 1 : 0).ToString(), "int" }
});
var stream = new MemoryStream(report);
var response = File(stream, "application/pdf", String.Format("Report232_{0}.pdf", pickupId));
return response;
}
You need to set withCredentials with each request:
this._http.get(URL, { responseType: ResponseContentType.Blob, withCredentials: true })