Im using ASP Net Core Web App with Razor Pages. Im struggling with index.html Swagger as main/default page. When App Starts -> automatically forwards to Swagger. Im also hosting my app on Azure - same problem in that hosting env, Swagger is main page. This is problem for accessing site from Internet when u are forwarded from main url to swagger. Fresh example project from .NET is not accessing index.html.
I need to change default page and root "/" from Swagger to page i choose.
Below sample of my Program.cs and result of accessing my page.
Program.cs
`using System.Reflection;
using Microsoft.EntityFrameworkCore;
using Microsoft.OpenApi.Models;
using SwimmingSchool.Repositories;
using SwimmingSchool.Repositories.Interfaces;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Identity.Web;
using Microsoft.Identity.Web.UI;
using Microsoft.AspNetCore.Mvc.Authorization;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var config = builder.Configuration;
// Frontend services
services.AddRazorPages().AddMicrosoftIdentityUI();
services.AddMvc().AddRazorPagesOptions(opt => {
opt.RootDirectory = "/Frontend";
});
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
// Authentication services
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(config.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(Environment.GetEnvironmentVariable("DownstreamApi:Scopes")?.Split(' '))
.AddMicrosoftGraph(config.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
//Database services
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDbContext<SwimmingSchoolDbContext>(options => options.UseSqlServer(Environment.GetEnvironmentVariable("SwimmingSchoolDb")));
//Scoped services
services.AddScoped<ICustomersRespository, CustomersRepository>();
//Swagger services
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "v1",
Title = "SwimmingcSchool",
Description = "Company application for manage swimming school",
TermsOfService = new Uri("http://SwimmingSchool.pl"),
Contact = new OpenApiContact
{
Name = "Biuro",
Email = "biuro#SwimmingSchool.pl",
Url = new Uri($"http://swimmingschool.pl"),
}
});
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
//c.IncludeXmlComments(xmlPath);
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "SwimmingSchool");
c.RoutePrefix = string.Empty;
}
);
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();`
Here what is happening when i try to access main url :
I tried add:
options.Conventions.AddPageRoute("/Index.html", "");
Also tried to remove Swagger and nothings helped :(
You could try to Set a default page which provides visitors a starting point on a site with this middleware:app.UseDefaultFiles(),
you could check this document for more details
And if you don't want going forward Swagger automaticlly when you debug,you could modify your launchSettings.json :
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
//modify launchUrl to "" , you could modify it when you debug with Kestrel as well
"launchUrl": "swagger",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
and try to remove c.RoutePrefix = string.Empty; in
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "SwimmingSchool");
c.RoutePrefix = string.Empty;
}
I tried as below(index.html was not under wwwroot) in my case:
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Swagger v1");
//c.RoutePrefix = String.Empty;
});
}
app.UseHttpsRedirection();
var provider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "StaticFile"));
var options = new DefaultFilesOptions() { FileProvider=provider};
options.DefaultFileNames.Add("Index.html");
app.UseDefaultFiles(options);
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = provider,
RequestPath = ""
});
Result:
Actually worked for me move files to new-created project without installing Swashbuckle Swagger. For me Swagger isn't nesesery and solves all problem with routing.
Related
I have a netcore app with RazorPages and API Controllers.
After I log in I have a Principal on a Razor page with IsAuthenticated = true. When that Razor page calls an API the Principal on the API controller IsAuthenticated = false
Start up
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(a =>
{
a.AddPolicy("Authenticated", p => p.RequireAuthenticatedUser());
});
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.LoginPath = new PathString("/auth/login");
options.AccessDeniedPath = new PathString("/auth/denied");
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseDeveloperExceptionPage();
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.UseAuthentication();
//app.MapDefaultControllerRoute();
app.MapRazorPages();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
});
app.Run();
API Call
//Method that makes the API call
protected async Task PostUser(PortalUserModel model, string url)
{
using (var client = new HttpClient())
{
//Helper to get currentServer URL
var server = new HttpServerHelper(this.Request);
client.BaseAddress = server.Url;
var responseTask = await client.PostAsJsonAsync(url, model, new CancellationToken());
if (responseTask.IsSuccessStatusCode)
{
var json = await responseTask.Content.ReadAsStringAsync();
this.PortalUserModel = JsonConvert.DeserializeObject<PortalUserModel>(json);
}
else
{
this.PortalUserModel = model;
var ex = new Exception("Save failed. Reason: " + responseTask.ReasonPhrase);
this.PortalUserModel.ExceptionInfo = ex.GetExceptionInfo(this.User.Identity.Name);
}
this.WriteValidationErrors();
}
}
So my question is, how do you get the API Controller to use the same IPrincipal as the Razor page?
I'm using Microsoft Visual Studio Community 2019 Version 16.10.2. I created an ASP.net core 5 project from their template "ASP.net core with Angular" with Authentication checked. But Every time I request an API Method marked with the attribute [Authorize] I get 401.
Their template was supposed to work with no problem but I got some trouble logging in. I fixed them but, the only problem I can't figure out how to fix is the 401 code returned ASP.
I read the doc several times but I could not find any useful information.
The thing is: I can create accounts and login with no problem. When I login, the server returns the token. From the Angular app it shows the name of the logged-in user. But when to access an [Authorize] controller it returns 404.
Here is the link of the project I pushed to github for better debugging.
Here is the startup code:
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDatabaseDeveloperPageExceptionFilter();
services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>(op =>
{
// I added these lines because I was getting the error "Error: Client Angular_identity_test is not allowed access to scope Angular."
op.Clients[0].AllowedScopes = new List<string> { "Angular", "identity", "testAPI" };
op.ApiScopes = new Microsoft.AspNetCore.ApiAuthorization.IdentityServer.ApiScopeCollection(new List<ApiScope> { new ApiScope("Angular"), new ApiScope("identity"), new ApiScope("testAPI") });
op.ApiResources.AddApiResource("Angular", conf => conf.WithScopes(new string[] { "Angular", "identity", "testAPI" }));
op.ApiResources.AddApiResource("identity", conf => conf.WithScopes(new string[] { "Angular", "identity", "testAPI" }));
op.ApiResources.AddApiResource("testAPI", conf => conf.WithScopes(new string[] { "Angular", "identity", "testAPI" }));
});
services.AddAuthentication()
.AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
}
// In public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
app.UseHttpsRedirection();
app.UseStaticFiles();
if (!env.IsDevelopment())
{
app.UseSpaStaticFiles();
}
app.UseRouting();
// I added this line because some people say that fixed their problems.
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
}
});
In the appsettings.json there is:
"IdentityServer": {
"Clients": {
"Angular_identity_test": {
"Profile": "IdentityServerSPA"
}
}
}
And the controller that keeps return 401:
[Authorize()]
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
var rng = new Random();
return Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
So you say, But when to access a [Authorize] controller it returns 404. use this below code, instead of [Authorize].
[Authorize(AuthenticationSchemes = "Bearer")]
It will resolve your issue.
UPDATE
Use this below code and i assume that your Token is place of appsettings.development.json file. like "TokenKey":"super secret key",
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options => {
options.TokenValidationParameters=new TokenValidationParameters
{
ValidateIssuerSigningKey=true,
IssuerSigningKey=new SymmetricSecurityKey( Encoding.UTF8.GetBytes(config["TokenKey"]) ),
ValidateIssuer=false,
ValidateAudience=false
};
});
Hope it will resolve your issue.
This will be a proxy issue. In your CLIENTAPP go to the proxy.conf.js and add your controllers route into the PROXY_CONFIG->context array (like "/weatherforecast" is). Then restart your application. You don't need to change .NET Core middleware or services.
UPDATE
I added this DI BASE_URL into my service constructor and it works fine now.
constructor(private http: HttpClient, #Inject('BASE_URL') private bUrl: string) {
this.baseUrl = bUrl + "api/v1/items"; // my endpoint
}
Can you please assist, I have a .NET 5 Web API and Ionic 5.5 app. I have deployed the API and the Ionic app to Azure Web Services. The API is serving the Ionic app, so they are on the same domain - I can say same origin because the scheme, and domain are the same.
The issue is that, the Ionic app is failing to call the API because it seems like CORS is blocking it.
In my API, I have allowed any origin, any header and credentials but it's still not working. I have attached my Startup.cs file for the .NET 5 API.
Startup.cs code
using AutoMapper;
using EventManager.Business.Repositories;
using EventManager.Database;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Versioning;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.OpenApi.Models;
using System;
using System.IO;
using System.Reflection;
namespace EventManager.Api
{
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.AddCors(options =>
{
options.AddDefaultPolicy(
builder =>
{
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
});
//options.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod());
});
services.AddControllers();
services.AddApiVersioning(x =>
{
x.DefaultApiVersion = new ApiVersion(2, 1);
x.AssumeDefaultVersionWhenUnspecified = true;
x.ReportApiVersions = true;
// Supporting multiple versioning scheme
x.ApiVersionReader = new UrlSegmentApiVersionReader();
});
services.AddVersionedApiExplorer(options =>
{
options.GroupNameFormat = "'v'VVV";
options.SubstituteApiVersionInUrl = false;
});
var mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new Business.MappingProfile());
});
var mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Title = "Event Manager API Documentation",
Version = "v1",
Contact = new OpenApiContact
{
Email = "eric#xxxxx.com",
Name = "Eric Smith",
Url = new Uri("https://www.xxxxx.org/")
},
Description = #"Used for as a self-service for event attendees.
To capture attendee details and print out attendee badges",
License = new OpenApiLicense
{
Name = "Use under LICX",
Url = new Uri("https://www.xxxxx.org/api/license"),
}
});
//Set the comments path for the Swagger JSON and UI.
var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
services.AddDbContext<AppDbContext>(x => x.UseSqlServer(Configuration.GetConnectionString("MSSqlConnection"),
b => b.MigrationsAssembly("EventManager.Database")));
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddScoped<EventRepository>();
services.AddScoped<AttendeeRepository>();
services.AddScoped<DesignationRepository>();
services.AddScoped<EntryQuestionRepository>();
services.AddScoped<EntryQuestionSectionRepository>();
//Sart: To serve angular app
services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp"; });
//End: To serve angular app
}
// 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", "EventManager.Api v1"));
}
app.UseRouting();
app.UseCors(builder =>
{
builder
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials();
});
app.UseAuthorization();
//Start: To serve angular app
app.UseDefaultFiles();
app.UseSpaStaticFiles();
//End: To serve angular app
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
//Start: To serve angular app
app.UseSpa(spa => { spa.Options.SourcePath = "ClientApp"; });
//End: To serve angular app
}
}
}
My API call from the Ionic app
headers = new HttpHeaders({
"Authorization": "Bearer " + "XXXXXXX",
"Content-Type": "application/json"
});
//environment.api = 'https://myazureappname.azurewebsites.net/api/'
get(cellNumber?: string): Observable<AttendeeGetModel[]> {
return this._http.get<AttendeeGetModel[]>(`${environment.api}v1/attendees?cellNumber=${cellNumber}`, { headers: this.headers });
}
**Error message from Firefox browser attached**
[![enter image description here][1]][1]
The error ERR_NAME_NOT RESOLVED typically means: Chrome cannot resolve the domain name which in most cases means you're using the wrong domain name or have a typo.
In your case it looks like your're using the wrong top level domain in your app. Postman = ".net", Your app = ".com".
I have several .NET core API and I use IdentityServer 4 as a seperate service for authentication.
The problem is that in "debug" I also wish to run my API without authentication (without launching the IdentityServer).
So, I try to bypass it... I have try several solutions, but none work:
- With a AuthorizationHandler: Bypass Authorize Attribute in .Net Core for Release Version
- With a Middleware : Simple token based authentication/authorization in asp.net core for Mongodb datastore
- With a filter : ASP.NET Core with optional authentication/authorization
- With AllowAnonymousFilter : Bypass Authorize Attribute in .Net Core for Release Version
But no way, none of theses solutions work, I still got a "401 Undocumented Error: Unauthorized" !
Here is some parts of my code:
public void ConfigureServices(IServiceCollection services)
{
// JSON - setup serialization
services.AddControllers().
AddJsonOptions(options =>
{
options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(new TargetSpot.Core.Json.SnakeCaseNamingStrategy()));
options.JsonSerializerOptions.IgnoreNullValues = true;
});
// Force lowercase naming
services.AddRouting(options => options.LowercaseUrls = true);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
// Setup the connection to the IdentityServer to request a token to access our API
services.AddAuthentication(IdentityServer4.AccessTokenValidation.IdentityServerAuthenticationDefaults.AuthenticationScheme)
.AddIdentityServerAuthentication(options =>
{
options.Authority = Configuration.GetSection("APISettings")["AuthorityURL"];
options.RequireHttpsMetadata = false;
options.ApiName = Configuration.GetSection("APISettings")["APIName"];
});
// Add swagger
services.AddSwaggerGen(options =>
{
//options.DescribeAllEnumsAsStrings();
options.SwaggerDoc("v1", new Microsoft.OpenApi.Models.OpenApiInfo
{
Title = "HTTP API",
Version = "v1",
Description = "The Service HTTP API",
TermsOfService = new Uri("http://www.myurl.com/tos")
});
// XML Documentation
var xmlFile = $"{System.Reflection.Assembly.GetExecutingAssembly().GetName().Name}.xml";
var xmlPath = System.IO.Path.Combine(AppContext.BaseDirectory, xmlFile);
options.IncludeXmlComments(xmlPath);
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// 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.UseRouting();
app.UseAuthorization();
app.UseAuthentication();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSwagger().UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "Winamp API v1");
});
}
I had similar problem.
AllowAnonymousFilter works in ASP.NET Core 2.2 but not in ASP.NET Core 3.x.
After day of investigation I have found out that switching from UseEndpoints to UseMvc solved it and I can now disable authentication without commenting out [Authorize] attributes.
It seems that UseEndpoints does not use filter when registered by AddMvc but how to correctly register it when using UseEndpoints I do not know.
My solution
Startup.ConfigureServices:
services.AddMvc(o =>
{
o.EnableEndpointRouting = false;
o.Filters.Add(new AllowAnonymousFilter());
});
Startup.Configure:
// anonymous filter works with UseMvc but not with UseEndpoints
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
//app.UseEndpoints(endpoints =>
//{
// endpoints.MapControllerRoute(
// name: "default",
// pattern: "{controller=Home}/{action=Index}/{id?}");
//});
I found the solution in this link: https://docs.identityserver.io/_/downloads/en/latest/pdf/. Obviously I had to remove the Authorize attributes I added manually in my controllers.
app.UseEndpoints(endpoints =>
{
// Allowing Anonymous access to all controllers but only in Local environment
if (env.IsEnvironment(Constants.ApplicationConstants.LocalEnvironment))
endpoints.MapControllers();
else
endpoints.MapControllers().RequireAuthorization();
});
I have an asp.net core Angular 6 application that works fine locally in visual studio or if i run this command on the iis server: dotnet .\CTI_Admin.dll
When I try to connect via the IIS webserver all of my css and js files receive this error on an IIS 8 server.
Failed to load resource: the server responded with a status of 404 (Not Found).
Statup.cs
using AspNet.Security.OpenIdConnect.Primitives;
using AutoMapper;
using CTI_Admin.Authorization;
using CTI_Admin.Helpers;
using CTI_Admin.ViewModels;
using DAL;
using DAL.Core;
using DAL.Core.Interfaces;
using DAL.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.SpaServices.AngularCli;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using OpenIddict.Abstractions;
using Swashbuckle.AspNetCore.Swagger;
using System;
using System.IO;
using AppPermissions = DAL.Core.ApplicationPermissions;
namespace CTI_Admin
{
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration["ConnectionStrings:DefaultConnection"], b => b.MigrationsAssembly("CTI_Admin"));
options.UseOpenIddict();
});
// add identity
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
// Configure Identity options and password complexity here
services.Configure<IdentityOptions>(options =>
{
// User settings
options.User.RequireUniqueEmail = true;
// //// Password settings
// //options.Password.RequireDigit = true;
// //options.Password.RequiredLength = 8;
// //options.Password.RequireNonAlphanumeric = false;
// //options.Password.RequireUppercase = true;
// //options.Password.RequireLowercase = false;
// //// Lockout settings
// //options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30);
// //options.Lockout.MaxFailedAccessAttempts = 10;
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
// Register the OpenIddict services.
services.AddOpenIddict()
.AddCore(options =>
{
options.UseEntityFrameworkCore().UseDbContext<ApplicationDbContext>();
})
.AddServer(options =>
{
options.UseMvc();
options.EnableTokenEndpoint("/connect/token");
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
options.AcceptAnonymousClients();
options.DisableHttpsRequirement(); // Note: Comment this out in production
options.RegisterScopes(
OpenIdConnectConstants.Scopes.OpenId,
OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Phone,
OpenIdConnectConstants.Scopes.Profile,
OpenIdConnectConstants.Scopes.OfflineAccess,
OpenIddictConstants.Scopes.Roles);
// options.UseRollingTokens(); //Uncomment to renew refresh tokens on every refreshToken request
// Note: to use JWT access tokens instead of the default encrypted format, the following lines are required:
// options.UseJsonWebTokens();
})
.AddValidation(); //Only compatible with the default token format. For JWT tokens, use the Microsoft JWT bearer handler.
// Add cors
services.AddCors();
// Add framework services.
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
// In production, the Angular files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/dist";
});
//Todo: ***Using DataAnnotations for validation until Swashbuckle supports FluentValidation***
//services.AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining<Startup>());
//.AddJsonOptions(opts =>
//{
// opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
//});
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "CTI_Admin API", Version = "v1" });
c.OperationFilter<AuthorizeCheckOperationFilter>();
c.AddSecurityDefinition("oauth2", new OAuth2Scheme
{
Type = "oauth2",
Flow = "password",
TokenUrl = "/connect/token",
Description = "Note: Leave client_id and client_secret blank"
});
});
services.AddAuthorization(options =>
{
options.AddPolicy(Authorization.Policies.ViewAllUsersPolicy, policy => policy.RequireClaim(CustomClaimTypes.Permission, AppPermissions.ViewUsers));
options.AddPolicy(Authorization.Policies.ManageAllUsersPolicy, policy => policy.RequireClaim(CustomClaimTypes.Permission, AppPermissions.ManageUsers));
options.AddPolicy(Authorization.Policies.ViewAllRolesPolicy, policy => policy.RequireClaim(CustomClaimTypes.Permission, AppPermissions.ViewRoles));
options.AddPolicy(Authorization.Policies.ViewRoleByRoleNamePolicy, policy => policy.Requirements.Add(new ViewRoleAuthorizationRequirement()));
options.AddPolicy(Authorization.Policies.ManageAllRolesPolicy, policy => policy.RequireClaim(CustomClaimTypes.Permission, AppPermissions.ManageRoles));
options.AddPolicy(Authorization.Policies.AssignAllowedRolesPolicy, policy => policy.Requirements.Add(new AssignRolesAuthorizationRequirement()));
});
Mapper.Initialize(cfg =>
{
cfg.AddProfile<AutoMapperProfile>();
});
// Configurations
services.Configure<SmtpConfig>(Configuration.GetSection("SmtpConfig"));
// Business Services
services.AddScoped<IEmailSender, EmailSender>();
// Repositories
services.AddScoped<IUnitOfWork, HttpUnitOfWork>();
services.AddScoped<IAccountManager, AccountManager>();
// Auth Handlers
services.AddSingleton<IAuthorizationHandler, ViewUserAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, ManageUserAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, ViewRoleAuthorizationHandler>();
services.AddSingleton<IAuthorizationHandler, AssignRolesAuthorizationHandler>();
// DB Creation and Seeding
services.AddTransient<IDatabaseInitializer, DatabaseInitializer>();
}
// 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(LogLevel.Warning);
loggerFactory.AddFile(Configuration.GetSection("Logging"));
Utilities.ConfigureLogger(loggerFactory);
EmailTemplates.Initialize(env);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
//Configure Cors
app.UseCors(builder => builder
.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod());
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseAuthentication();
app.UseSwagger();
app.UseSwaggerUI(c =>
{
c.DocumentTitle = "Swagger UI - Quick Application";
c.SwaggerEndpoint("/swagger/v1/swagger.json", "CTI_Admin API V1");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
// To learn more about options for serving an Angular SPA from ASP.NET Core,
// see https://go.microsoft.com/fwlink/?linkid=864501
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "start");
spa.Options.StartupTimeout = TimeSpan.FromSeconds(60); // Increase the timeout if angular app is taking longer to startup
//spa.UseProxyToSpaDevelopmentServer("http://localhost:4200"); // Use this instead to use the angular cli server
}
});
}
}
}
You need to follow the steps:
Bundle your Angular application using ng build --prod
Ensure your IIS Hosting bundle is installed https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/?view=aspnetcore-2.1
Finally publish the website in a folder and the deploy to hosting server
For detailed instructions: https://code-maze.com/net-core-web-development-part16/#windowsserver
The way i resolved this was by adding --base-href to
ng build --extract-css --base-href /CTI_Admin/ClientApp/dist
However, my JS files are not loading even though i get a status code 200. The new error I receive is
scripts.c070f8cfd43553c493e4.js:1 Uncaught SyntaxError: Unexpected token <
Its basically returning the index.html code.
UPDATE:
This is the proper build script when you application is setup under site in IIS
ng build --prod --extract-css --base-href /CTI_Admin/