// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); // In production, the React files will be served from this directory services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/build"; }); var mvcBuilder = services.AddMvc(); services.AddControllers().AddNewtonsoftJson(opt => { // Set Breeze defaults for entity serialization var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); if (ss.ContractResolver is DefaultContractResolver resolver) { resolver.NamingStrategy = null; // remove json camelCasing; names are converted on the client. } ss.Formatting = Newtonsoft.Json.Formatting.Indented; // format JSON for debugging }); // Add Breeze exception filter to send errors back to the client mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); // Add DbContext using connection string var connectionString = Configuration.GetConnectionString("LineOfCredit"); services.AddDbContext <LineOfCreditContext>(options => options.UseSqlite(connectionString)); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var mvcBuilder = services.AddMvc(); mvcBuilder.AddJsonOptions(opt => { var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } }); mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); //var tmp = Configuration.GetConnectionString("NorthwindIB_CF"); //services.AddScoped<NorthwindIBContext_CF>(_ => { // return new NorthwindIBContext_CF(tmp); //}); var tmp = Configuration.GetConnectionString("NorthwindIB_CF"); services.AddDbContext <NorthwindIBContext_CF>(options => options.UseSqlServer(tmp)); // services.AddCors(options => options.AddPolicy("AllowAll", p => p.AllowAnyOrigin())); }
// This method gets called by the runtime. Use this method to add services to the container public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddApplicationInsightsTelemetry(Configuration); var mvcBuilder = services.AddMvc(); mvcBuilder.AddJsonOptions(opt => { var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } }); mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); var northwindIBConnStr = Configuration.GetConnectionString("NorthwindIB_CF"); var produceTPHConnStr = Configuration.GetConnectionString("ProduceTPH"); services.AddScoped <NorthwindIBContext_CF>(_ => { return(new NorthwindIBContext_CF(northwindIBConnStr)); }); services.AddScoped <ProduceTPHContext>(_ => { return(new ProduceTPHContext(produceTPHConnStr)); }); }
/// <summary> /// Replaces the response.Content with the query results, wrapped in a QueryResult object if necessary. /// </summary> /// <param name="request"></param> /// <param name="response"></param> /// <param name="responseObject"></param> /// <param name="queryable"></param> public virtual void WrapResult(HttpRequest request, ActionExecutedContext actionExecutedContext, IQueryable queryResult) { var inlineCount = request.ODataFeature().TotalCount; // if a select or expand was encountered we need to // execute the DbQueries here, so that any exceptions thrown can be properly returned. // if we wait to have the query executed within the serializer, some exceptions will not // serialize properly. var listQueryResult = Enumerable.ToList((dynamic)queryResult); var elementType = queryResult.ElementType; if (elementType.Name.StartsWith("SelectAllAndExpand")) { var prop = elementType.GetProperties().FirstOrDefault(pi => pi.Name == "Instance"); var mi = prop.GetGetMethod(); var lqr = (List <Object>)listQueryResult; listQueryResult = (dynamic)lqr.Select(item => { var instance = mi.Invoke(item, null); return((Object)instance); }).ToList(); } // HierarchyNodeExpressionVisitor listQueryResult = PostExecuteQuery((IEnumerable)listQueryResult); if (listQueryResult != null || inlineCount.HasValue) { Object result = listQueryResult; if (inlineCount.HasValue) { result = new QueryResult() { Results = listQueryResult, InlineCount = inlineCount }; } var objResult = actionExecutedContext.Result as ObjectResult; if (objResult != null && objResult.Value != null) { var resultType = objResult.Value.GetType(); if (resultType.Name != "String") { var ss = new JsonSerializerSettings(); ss = JsonSerializationFns.UpdateWithDefaults(ss); ss.NullValueHandling = NullValueHandling.Ignore; //ss.TypeNameHandling = TypeNameHandling.None; //ss.PreserveReferencesHandling = PreserveReferencesHandling.None; //var finalJsonIndented = JsonConvert.SerializeObject(result, Formatting.Indented, ss); var jsonResult = new JsonResult(result, ss); actionExecutedContext.Result = jsonResult; //var oc = new ObjectContent(result.GetType(), result, formatter); //var oc = new ObjectResult(result.GetType(), result); //response.Content = oc; //actionExecutedContext.Result = //actionExecutedContext.HttpContext.Response.con } } } }
public BreezeJsonProfileFormatter(MvcOptions mvcOptions) : base( new JsonSerializerSettings { ContractResolver = new DefaultContractResolver() }, ArrayPool <char> .Shared, mvcOptions) { SupportedMediaTypes.Clear(); var ss = JsonSerializationFns.UpdateWithDefaults(this.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } ; SupportedMediaTypes.Add(MediaTypeHeaderValue.Parse("breeze/json")); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var mvcBuilder = services.AddMvc(); mvcBuilder.AddJsonOptions(opt => { var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } }); mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); var connection = @"Data Source=.;Initial Catalog=dnc;User Id=sa;Password=asdfASDF!"; services.AddDbContext <dncContext>(options => options.UseSqlServer(connection)); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { var mvcBuilder = services.AddMvc(); mvcBuilder.AddJsonOptions(opt => { var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } }); mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); var connection = @"Data Source=.\SQLEXPRESS;Database=AspNetCoreBreeze;Integrated Security=True;MultipleActiveResultSets=true"; services.AddDbContext <DatabaseContext>(options => options.UseSqlServer(connection)); }
// 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) { var mvcBuilder = services.AddMvc(); mvcBuilder.AddJsonOptions(opt => { // Set Breeze defaults for entity serialization var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); if (ss.ContractResolver is DefaultContractResolver resolver) { resolver.NamingStrategy = null; // remove json camelCasing; names are converted on the client. } }); // Add Breeze exception filter to send errors back to the client mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); // Add DbContext using connection string var connectionString = configuration.GetConnectionString("NorthwindCore"); services.AddDbContext <NorthwindCoreContext>(options => options.UseSqlServer(connectionString)); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { // Add framework services. var mvcBuilder = services.AddMvc(); mvcBuilder.AddJsonOptions(opt => { var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } }); mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); var connString = Configuration.GetConnectionString("SchoolContext"); services.AddScoped <SchoolContext>(_ => new SchoolContext(connString)); }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddDbContext <UnoTestDbContext>(cfg => { cfg.UseInMemoryDatabase("UnoTest"); //cfg.UseSqlServer(configuration.GetConnectionString("UnoTestConnectionString")); }); services.AddCors(); services.AddTransient <UnoTestDbSeeder>(); var mvcBuilder = services.AddMvc(); //services.AddSignalR(o => o.EnableDetailedErrors = true); services.AddSignalR(); services.AddHostedService <PeriodicServerNotifier>(); #region Breeze mvcBuilder.AddJsonOptions(opt => { var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } }); mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); #endregion //var connection = @"Data Source=.\SQLEXPRESS;Initial Catalog=UnoTest;Trusted_Connection=True"; //services.AddDbContext<UnoTestDbContext>(options => options.UseSqlServer(connection)); }
public void ConfigureServices(IServiceCollection services) { services.AddSingleton <ILocalizationProvider, StorageLocalizationProvider>(); services.AddTextLocalization(options => { options.ReturnOnlyKeyIfNotFound = !_environment.IsDevelopment(); options.FallBackNeutralCulture = !_environment.IsDevelopment(); }).Configure <RequestLocalizationOptions>(options => { options.DefaultRequestCulture = new RequestCulture(Settings.SupportedCultures[0]); options.AddSupportedCultures(Settings.SupportedCultures); options.AddSupportedUICultures(Settings.SupportedCultures); }); services.AddScoped <LazyAssemblyLoader>(); var dataProtectionBuilder = services.AddDataProtection().SetApplicationName(projectName); services.RegisterStorage(Configuration); services.Configure <ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; }); services.AddIdentity <ApplicationUser, ApplicationRole>() .AddRoles <ApplicationRole>() .AddEntityFrameworkStores <ApplicationDbContext>() .AddDefaultTokenProviders() .AddErrorDescriber <LocalizedIdentityErrorDescriber>(); services.AddScoped <IUserClaimsPrincipalFactory <ApplicationUser>, AdditionalUserClaimsPrincipalFactory>(); var authAuthority = Configuration[$"{projectName}:IS4ApplicationUrl"].TrimEnd('/'); // Adds IdentityServer https://identityserver4.readthedocs.io/en/latest/reference/options.html var identityServerBuilder = services.AddIdentityServer(options => { options.IssuerUri = authAuthority; options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; options.UserInteraction.ErrorUrl = "/identityserver/error"; }) .AddIdentityServerStores(Configuration) .AddAspNetIdentity <ApplicationUser>(); //https://identityserver4.readthedocs.io/en/latest/reference/aspnet_identity.html X509Certificate2 cert = null; var keysLocalFolder = Path.Combine(_environment.ContentRootPath, "Keys"); if (_environment.IsDevelopment()) { // The AddDeveloperSigningCredential extension creates temporary key material tempkey.jwk for signing tokens. // This might be useful to get started, but needs to be replaced by some persistent key material for production scenarios. // See http://docs.identityserver.io/en/release/topics/crypto.html#refcrypto for more information. // https://stackoverflow.com/questions/42351274/identityserver4-hosting-in-iis identityServerBuilder.AddDeveloperSigningCredential(); dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysLocalFolder)); } else { // Running on Azure Web App service - read the setup doc at blazor-boilerplate.readthedocs.io // appsettings.json parameters used: // "RunsOnAzure": true, // "RunningAsAppService": true, // "RunningAsDocker": false, // not implemented yet // "AzureKeyVault": { // "UsingKeyVault": true, // "UseManagedAppIdentity": true, // "AppKey": "", // not implemented yet. // "AppSecret": "", // "KeyVaultURI": "https://YOURVAULTNAMEHERE.vault.azure.net/", // "CertificateIdentifier": "https://YOURVAULTNAMEHERE.vault.azure.net/certificates/BBAUTH/<HEX_VERSION_STRING_HERE>", // "CertificateName": "BBAUTH", // "StorageAccountBlobBaseUrl": "https://<YOUR_STORAGE_ACCOUNT_NAME_HERE>.blob.core.windows.net", // "ContainerName": "blazor-boilerplate-keys", // "KeysBlobName": "keys.xml" if (Convert.ToBoolean(Configuration["HostingOnAzure:RunsOnAzure"]) == true) { if (Convert.ToBoolean(Configuration["HostingOnAzure:AzureKeyVault:UsingKeyVault"]) == true) { if (Convert.ToBoolean(Configuration["HostingOnAzure:AzurekeyVault:UseManagedAppIdentity"]) == true) { //https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview // In production environment we have already configured Managed Identity (blazor-boilerplate) using Azure Portal for our app to access Key Vault and Blob Storage. // Set up TokenCredential options for production and development environments bool isDeployed = !_environment.IsDevelopment(); var credentialOptions = new DefaultAzureCredentialOptions { ExcludeEnvironmentCredential = isDeployed, ExcludeManagedIdentityCredential = false, // we only use this one in production ExcludeSharedTokenCacheCredential = isDeployed, ExcludeVisualStudioCredential = isDeployed, ExcludeVisualStudioCodeCredential = isDeployed, ExcludeAzureCliCredential = isDeployed, ExcludeInteractiveBrowserCredential = isDeployed, }; // In development environment DefaultAzureCredential() will use the shared token credential from the IDE. In Visual Studio this is under Options - Azure Service Authentication. if (_environment.IsDevelopment()) { // credentialOptions.SharedTokenCacheUsername = "******"; // specify user name to use if more than one Azure username is configured in IDE. // var defaultTenantId = "?????-????-????-????-????????"; // specify AAD tenant to authenticate against (from Azure Portal - AAD - Tenant ID) // credentialOptions.SharedTokenCacheTenantId = defaultTenantId; // credentialOptions.VisualStudioCodeTenantId = defaultTenantId; // credentialOptions.VisualStudioTenantId = defaultTenantId; } TokenCredential tokenCredential = new DefaultAzureCredential(credentialOptions); // The Azure Storage Container (blazor-boilerplate-keys) Access Control must grant blazor-boilerplate the following roles: // - Storage Blob Data Contributor var blobServiceClient = new BlobServiceClient( new Uri(Configuration["HostingOnAzure:AzureKeyVault:StorageAccountBlobBaseUrl"]), tokenCredential); BlobContainerClient blobContainerClient = blobServiceClient.GetBlobContainerClient(Configuration["HostingOnAzure:AzureKeyVault:ContainerName"]); BlobClient blobClient = blobContainerClient.GetBlobClient(Configuration["HostingOnAzure:AzureKeyVault:KeysBlobName"]); var certificateIdentifier = Configuration["HostingOnAzure:AzureKeyVault:CertificateIdentifier"]; dataProtectionBuilder.PersistKeysToAzureBlobStorage(blobClient); // 1. Remove the call to ProtectKeysWithAzureKeyVault below for the first run to create the keys.xml blob in place. // 2. Add the call to ProtectKeysWithAzureKeyVault for subsequent runs.so that keys.xml gets created - see the setup doc for more information dataProtectionBuilder.ProtectKeysWithAzureKeyVault(new Uri(certificateIdentifier), tokenCredential); // Azure Key Vault Access Policy must grant the following permissions to the blazor-boilerplate app: // - Secret Permissions: Get // - Certificate Permissions: Get // Retrieve the certificate and extract the secret so that we can build the new X509 certificate for later use by Identity Server var certificateClient = new CertificateClient(vaultUri: new Uri(Configuration["HostingOnAzure:AzureKeyVault:KeyVaultUri"]), credential: new DefaultAzureCredential()); var secretClient = new SecretClient(vaultUri: new Uri(Configuration["HostingOnAzure:AzureKeyVault:KeyVaultUri"]), credential: new DefaultAzureCredential()); KeyVaultCertificateWithPolicy certificateWithPolicy = certificateClient.GetCertificateAsync(Configuration["HostingOnAzure:AzureKeyVault:CertificateName"]).GetAwaiter().GetResult(); // retrieves latest version of certificate KeyVaultSecretIdentifier secretIdentifier = new KeyVaultSecretIdentifier(certificateWithPolicy.SecretId); KeyVaultSecret secret = secretClient.GetSecretAsync(secretIdentifier.Name, secretIdentifier.Version).GetAwaiter().GetResult(); byte[] privateKeyBytes = Convert.FromBase64String(secret.Value); cert = new X509Certificate2(privateKeyBytes, (string)null, X509KeyStorageFlags.MachineKeySet); } } else // if app id and app secret are used { throw new NotImplementedException(); } } else { dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysLocalFolder)); } //TODO this implementation does not consider certificate expiration if (Convert.ToBoolean(Configuration[$"{projectName}:UseLocalCertStore"]) == true) { var certificateThumbprint = Configuration[$"{projectName}:CertificateThumbprint"]; var storeLocation = StoreLocation.LocalMachine; dynamic storeName = "WebHosting"; if (OperatingSystem.IsLinux()) { storeLocation = StoreLocation.CurrentUser; storeName = StoreName.My; } using X509Store store = new(storeName, storeLocation); store.Open(OpenFlags.ReadOnly); var certs = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false); if (certs.Count > 0) { cert = certs[0]; } else { var certPath = Path.Combine(_environment.ContentRootPath, "AuthSample.pfx"); if (File.Exists(certPath)) { string certificatePassword = Configuration[$"{projectName}:CertificatePassword"] ?? "Admin123"; cert = new X509Certificate2(certPath, certificatePassword, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); } } store.Close(); } // pass the resulting certificate to Identity Server if (cert != null) { identityServerBuilder.AddSigningCredential(cert); Log.Logger.Information($"Added certificate {cert.Subject} to Identity Server"); } else if (OperatingSystem.IsWindows()) { Log.Logger.Debug("Trying to use WebHosting Certificate for Identity Server"); identityServerBuilder.AddWebHostingCertificate(); } else { throw new Exception("Missing Certificate for Identity Server"); } } var authBuilder = services.AddAuthentication(options => { options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; }) .AddIdentityServerAuthentication(options => { options.Authority = authAuthority; options.SupportedTokens = SupportedTokens.Jwt; options.RequireHttpsMetadata = _environment.IsProduction(); options.ApiName = IdentityServerConfig.LocalApiName; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; // If the request is for our hub... var path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/chathub"))) { // Read the token out of the query string context.Token = accessToken; } return(Task.CompletedTask); } }; }); #region ExternalAuthProviders //https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/samples/SocialSample/Startup.cs //https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Google:Enabled"] ?? "false")) { authBuilder.AddGoogle(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = Configuration["ExternalAuthProviders:Google:ClientId"]; options.ClientSecret = Configuration["ExternalAuthProviders:Google:ClientSecret"]; options.AuthorizationEndpoint += "?prompt=consent"; // Hack so we always get a refresh token, it only comes on the first authorization response options.AccessType = "offline"; options.SaveTokens = true; options.Events = new OAuthEvents() { OnRemoteFailure = HandleOnRemoteFailure }; options.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url"); options.ClaimActions.Remove(ClaimTypes.GivenName); }); } if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Facebook:Enabled"] ?? "false")) { // You must first create an app with Facebook and add its ID and Secret to your user-secrets. // https://developers.facebook.com/apps/ // https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login authBuilder.AddFacebook(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.AppId = Configuration["ExternalAuthProviders:Facebook:AppId"]; options.AppSecret = Configuration["ExternalAuthProviders:Facebook:AppSecret"]; options.Scope.Add("email"); options.Fields.Add("name"); options.Fields.Add("email"); options.SaveTokens = true; options.Events = new OAuthEvents() { OnRemoteFailure = HandleOnRemoteFailure }; }); } if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Twitter:Enabled"] ?? "false")) { // You must first create an app with Twitter and add its key and Secret to your user-secrets. // https://apps.twitter.com/ // https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token authBuilder.AddTwitter(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ConsumerKey = Configuration["ExternalAuthProviders:Twitter:ConsumerKey"]; options.ConsumerSecret = Configuration["ExternalAuthProviders:Twitter:ConsumerSecret"]; // http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370 // http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1 options.RetrieveUserDetails = true; options.SaveTokens = true; options.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri); options.Events = new TwitterEvents() { OnRemoteFailure = HandleOnRemoteFailure }; }); } //https://github.com/xamarin/Essentials/blob/master/Samples/Sample.Server.WebAuthenticator/Startup.cs if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Apple:Enabled"] ?? "false")) { authBuilder.AddApple(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = Configuration["ExternalAuthProviders:Apple:ClientId"]; options.KeyId = Configuration["ExternalAuthProviders:Apple:KeyId"]; options.TeamId = Configuration["ExternalAuthProviders:Apple:TeamId"]; options.UsePrivateKey(keyId => _environment.ContentRootFileProvider.GetFileInfo($"AuthKey_{keyId}.p8")); options.SaveTokens = true; }); } // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets. // https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Microsoft:Enabled"] ?? "false")) { authBuilder.AddMicrosoftAccount(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = Configuration["ExternalAuthProviders:Microsoft:ClientId"]; options.ClientSecret = Configuration["ExternalAuthProviders:Microsoft:ClientSecret"]; options.SaveTokens = true; options.Scope.Add("offline_access"); options.Events = new OAuthEvents() { OnRemoteFailure = HandleOnRemoteFailure }; }); } #endregion #region Authorization //Add Policies / Claims / Authorization - https://identityserver4.readthedocs.io/en/latest/topics/add_apis.html#advanced services.AddScoped <EntityPermissions>(); services.AddSingleton <IAuthorizationPolicyProvider, AuthorizationPolicyProvider>(); services.AddTransient <IAuthorizationHandler, DomainRequirementHandler>(); services.AddTransient <IAuthorizationHandler, PermissionRequirementHandler>(); #endregion services.Configure <IdentityOptions>(options => { // Password settings options.Password.RequireDigit = RequireDigit; options.Password.RequiredLength = RequiredLength; options.Password.RequireNonAlphanumeric = RequireNonAlphanumeric; options.Password.RequireUppercase = RequireUppercase; options.Password.RequireLowercase = RequireLowercase; //options.Password.RequiredUniqueChars = 6; // Lockout settings options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); options.Lockout.MaxFailedAccessAttempts = 10; options.Lockout.AllowedForNewUsers = true; // Require Confirmed Email User settings if (Convert.ToBoolean(Configuration[$"{projectName}:RequireConfirmedEmail"] ?? "false")) { options.User.RequireUniqueEmail = true; options.SignIn.RequireConfirmedEmail = true; } }); #region Cookies // cookie policy to deal with temporary browser incompatibilities services.AddSameSiteCookiePolicy(); //https://docs.microsoft.com/en-us/aspnet/core/security/gdpr services.Configure <CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential // cookies is needed for a given request. options.CheckConsentNeeded = context => false; //consent not required // requires using Microsoft.AspNetCore.Http; //options.MinimumSameSitePolicy = SameSiteMode.None; }); //services.ConfigureExternalCookie(options => // { // macOS login fix //options.Cookie.SameSite = SameSiteMode.None; //}); services.ConfigureApplicationCookie(options => { options.Cookie.IsEssential = true; options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; options.ExpireTimeSpan = TimeSpan.FromDays(Convert.ToDouble(Configuration[$"{projectName}:CookieExpireTimeSpanDays"] ?? "30")); options.LoginPath = Constants.Settings.LoginPath; //options.AccessDeniedPath = "/Identity/Account/AccessDenied"; // ReturnUrlParameter requires //using Microsoft.AspNetCore.Authentication.Cookies; options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter; options.SlidingExpiration = true; // Suppress redirect on API URLs in ASP.NET Core -> https://stackoverflow.com/a/56384729/54159 options.Events = new CookieAuthenticationEvents() { OnRedirectToAccessDenied = context => { if (context.Request.Path.StartsWithSegments("/api")) { context.Response.StatusCode = Status403Forbidden; } return(Task.CompletedTask); }, OnRedirectToLogin = context => { context.Response.StatusCode = Status401Unauthorized; return(Task.CompletedTask); } }; }); #endregion services.AddMvc().AddNewtonsoftJson(opt => { // Set Breeze defaults for entity serialization var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); if (ss.ContractResolver is DefaultContractResolver resolver) { resolver.NamingStrategy = null; // remove json camelCasing; names are converted on the client. } if (_environment.IsDevelopment()) { ss.Formatting = Newtonsoft.Json.Formatting.Indented; // format JSON for debugging } }) // Add Breeze exception filter to send errors back to the client .AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }) .AddViewLocalization().AddDataAnnotationsLocalization(options => { options.DataAnnotationLocalizerProvider = (type, factory) => { return(factory.Create(typeof(Global))); }; }).AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining <LocalizationRecordValidator>()); services.AddServerSideBlazor().AddCircuitOptions(o => { if (_environment.IsDevelopment()) { o.DetailedErrors = true; } }).AddHubOptions(o => { o.MaximumReceiveMessageSize = 131072; }); services.AddSignalR(); if (_enableAPIDoc) { services.AddOpenApiDocument(document => { document.Title = "BlazorBoilerplate API"; document.Version = typeof(Startup).GetTypeInfo().Assembly.GetName().Version.ToString(); document.AddSecurity("bearer", Enumerable.Empty <string>(), new OpenApiSecurityScheme { Type = OpenApiSecuritySchemeType.OAuth2, Description = "Local Identity Server", OpenIdConnectUrl = $"{authAuthority}/.well-known/openid-configuration", //not working Flow = OpenApiOAuth2Flow.AccessCode, Flows = new OpenApiOAuthFlows() { AuthorizationCode = new OpenApiOAuthFlow() { Scopes = new Dictionary <string, string> { { LocalApi.ScopeName, IdentityServerConfig.LocalApiName } }, AuthorizationUrl = $"{authAuthority}/connect/authorize", TokenUrl = $"{authAuthority}/connect/token" }, } });; document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer")); // new OperationSecurityScopeProcessor("bearer")); }); } services.AddScoped <IUserSession, UserSession>(); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.Add(ServiceDescriptor.Scoped(typeof(ITenantSettings <>), typeof(TenantSettingsManager <>))); services.AddTransient <IEmailFactory, EmailFactory>(); services.AddTransient <IAccountManager, AccountManager>(); services.AddTransient <IAdminManager, AdminManager>(); services.AddTransient <IEmailManager, EmailManager>(); services.AddTransient <IExternalAuthManager, ExternalAuthManager>(); #region Automapper //Automapper to map DTO to Models https://www.c-sharpcorner.com/UploadFile/1492b1/crud-operations-using-automapper-in-mvc-application/ var automapperConfig = new MapperConfiguration(configuration => { configuration.AddProfile(new MappingProfile()); }); var autoMapper = automapperConfig.CreateMapper(); services.AddSingleton(autoMapper); #endregion /* ServerSideBlazor */ services.AddScoped <IAccountApiClient, AccountApiClient>(); services.AddScoped <AppState>(); // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) // if (!services.Any(x => x.ServiceType == typeof(HttpClient))) // { services.AddScoped(s => { // creating the URI helper needs to wait until the JS Runtime is initialized, so defer it. var navigationManager = s.GetRequiredService <NavigationManager>(); var httpContextAccessor = s.GetRequiredService <IHttpContextAccessor>(); var cookies = httpContextAccessor.HttpContext.Request.Cookies; var httpClientHandler = new HttpClientHandler() { UseCookies = false }; if (_environment.IsDevelopment()) { // Return 'true' to allow certificates that are untrusted/invalid httpClientHandler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => { return(true); }; } var client = new HttpClient(httpClientHandler); if (cookies.Any()) { var cks = new List <string>(); foreach (var cookie in cookies) { cks.Add($"{cookie.Key}={cookie.Value}"); } client.DefaultRequestHeaders.Add("Cookie", string.Join(';', cks)); } client.BaseAddress = new Uri(navigationManager.BaseUri); return(client); }); // } services.AddScoped <ILocalizationApiClient, LocalizationApiClient>(); services.AddScoped <IApiClient, ApiClient>(); // Authentication providers Log.Logger.Debug("Removing AuthenticationStateProvider..."); var serviceDescriptor = services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(AuthenticationStateProvider)); if (serviceDescriptor != null) { services.Remove(serviceDescriptor); } Log.Logger.Debug("Adding AuthenticationStateProvider..."); services.AddScoped <AuthenticationStateProvider, IdentityAuthenticationStateProvider>(); /**********************/ services.AddModules(); if (Log.Logger.IsEnabled(Serilog.Events.LogEventLevel.Debug)) { Log.Logger.Debug($"Total Services Registered: {services.Count}"); foreach (var service in services) { Log.Logger.Debug($"\n\tService: {service.ServiceType.FullName}\n\tLifetime: {service.Lifetime}\n\tInstance: {service.ImplementationType?.FullName}"); } } }
// 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.AddSqlLocalization(options => options.ReturnOnlyKeyIfNotFound = !_environment.IsDevelopment()) .Configure <RequestLocalizationOptions>(options => { options.DefaultRequestCulture = new RequestCulture(Settings.SupportedCultures[0]); options.AddSupportedCultures(Settings.SupportedCultures); options.AddSupportedUICultures(Settings.SupportedCultures); }); var dataProtectionBuilder = services.AddDataProtection().SetApplicationName(projectName); services.RegisterStorage(Configuration); services.Configure <ApiBehaviorOptions>(options => { options.SuppressModelStateInvalidFilter = true; }); services.AddIdentity <ApplicationUser, ApplicationRole>() .AddRoles <ApplicationRole>() .AddEntityFrameworkStores <ApplicationDbContext>() .AddDefaultTokenProviders() .AddErrorDescriber <LocalizedIdentityErrorDescriber>(); services.AddScoped <IUserClaimsPrincipalFactory <ApplicationUser>, AdditionalUserClaimsPrincipalFactory>(); var authAuthority = Configuration[$"{projectName}:IS4ApplicationUrl"].TrimEnd('/'); // Adds IdentityServer https://identityserver4.readthedocs.io/en/latest/reference/options.html var identityServerBuilder = services.AddIdentityServer(options => { options.IssuerUri = authAuthority; options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; options.UserInteraction.ErrorUrl = "/identityserver/error"; }) .AddIdentityServerStores(Configuration) .AddAspNetIdentity <ApplicationUser>(); //https://identityserver4.readthedocs.io/en/latest/reference/aspnet_identity.html X509Certificate2 cert = null; var keysFolder = Path.Combine(_environment.ContentRootPath, "Keys"); if (_environment.IsDevelopment()) { // The AddDeveloperSigningCredential extension creates temporary key material tempkey.jwk for signing tokens. // This might be useful to get started, but needs to be replaced by some persistent key material for production scenarios. // See http://docs.identityserver.io/en/release/topics/crypto.html#refcrypto for more information. // https://stackoverflow.com/questions/42351274/identityserver4-hosting-in-iis identityServerBuilder.AddDeveloperSigningCredential(); dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysFolder)); } else { // running on azure // please make sure to replace your vault URI and your certificate name in appsettings.json! if (Convert.ToBoolean(Configuration["HostingOnAzure:RunsOnAzure"]) == true) { // if we use a key vault if (Convert.ToBoolean(Configuration["HostingOnAzure:AzurekeyVault:UsingKeyVault"]) == true) { //https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview dataProtectionBuilder.PersistKeysToAzureBlobStorage(new Uri("<blobUriWithSasToken>")) .ProtectKeysWithAzureKeyVault("<keyIdentifier>", "<clientId>", "<clientSecret>"); // if managed app identity is used if (Convert.ToBoolean(Configuration["HostingOnAzure:AzurekeyVault:UseManagedAppIdentity"]) == true) { try { AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider(); var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback)); var certificateBundle = keyVaultClient.GetSecretAsync(Configuration["HostingOnAzure:AzureKeyVault:VaultURI"], Configuration["HostingOnAzure:AzurekeyVault:CertificateName"]).GetAwaiter().GetResult(); var certificate = Convert.FromBase64String(certificateBundle.Value); cert = new X509Certificate2(certificate, (string)null, X509KeyStorageFlags.MachineKeySet); } catch (Exception ex) { throw ex; } } } else // if app id and app secret are used { throw new NotImplementedException(); } } else { dataProtectionBuilder.PersistKeysToFileSystem(new DirectoryInfo(keysFolder)); } //TODO this implementation does not consider certificate expiration if (Convert.ToBoolean(Configuration[$"{projectName}:UseLocalCertStore"]) == true) { var certificateThumbprint = Configuration[$"{projectName}:CertificateThumbprint"]; using (X509Store store = new X509Store("WebHosting", StoreLocation.LocalMachine)) { store.Open(OpenFlags.ReadOnly); var certs = store.Certificates.Find(X509FindType.FindByThumbprint, certificateThumbprint, false); if (certs.Count > 0) { cert = certs[0]; } else { var certPath = Path.Combine(_environment.ContentRootPath, "AuthSample.pfx"); if (File.Exists(certPath)) { cert = new X509Certificate2(certPath, "Admin123", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable); } } store.Close(); } } // pass the resulting certificate to Identity Server if (cert != null) { identityServerBuilder.AddSigningCredential(cert); Log.Logger.Information($"Added certificate {cert.Subject} to Identity Server"); } else { Log.Logger.Debug("Trying to use WebHosting Certificate for Identity Server"); identityServerBuilder.AddWebHostingCertificate(); } } var authBuilder = services.AddAuthentication(options => { options.DefaultScheme = IdentityServerAuthenticationDefaults.AuthenticationScheme; }) .AddIdentityServerAuthentication(options => { options.Authority = authAuthority; options.SupportedTokens = SupportedTokens.Jwt; options.RequireHttpsMetadata = _environment.IsProduction() ? true : false; options.ApiName = IdentityServerConfig.LocalApiName; options.Events = new JwtBearerEvents { OnMessageReceived = context => { var accessToken = context.Request.Query["access_token"]; // If the request is for our hub... var path = context.HttpContext.Request.Path; if (!string.IsNullOrEmpty(accessToken) && (path.StartsWithSegments("/chathub"))) { // Read the token out of the query string context.Token = accessToken; } return(Task.CompletedTask); } }; }); #region ExternalAuthProviders //https://github.com/dotnet/aspnetcore/blob/master/src/Security/Authentication/samples/SocialSample/Startup.cs //https://docs.microsoft.com/en-us/aspnet/core/security/authentication/social/google-logins if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Google:Enabled"] ?? "false")) { authBuilder.AddGoogle(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = Configuration["ExternalAuthProviders:Google:ClientId"]; options.ClientSecret = Configuration["ExternalAuthProviders:Google:ClientSecret"]; options.AuthorizationEndpoint += "?prompt=consent"; // Hack so we always get a refresh token, it only comes on the first authorization response options.AccessType = "offline"; options.SaveTokens = true; options.Events = new OAuthEvents() { OnRemoteFailure = HandleOnRemoteFailure }; options.ClaimActions.MapJsonSubKey("urn:google:image", "image", "url"); options.ClaimActions.Remove(ClaimTypes.GivenName); }); } if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Facebook:Enabled"] ?? "false")) { // You must first create an app with Facebook and add its ID and Secret to your user-secrets. // https://developers.facebook.com/apps/ // https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#login authBuilder.AddFacebook(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.AppId = Configuration["ExternalAuthProviders:Facebook:AppId"]; options.AppSecret = Configuration["ExternalAuthProviders:Facebook:AppSecret"]; options.Scope.Add("email"); options.Fields.Add("name"); options.Fields.Add("email"); options.SaveTokens = true; options.Events = new OAuthEvents() { OnRemoteFailure = HandleOnRemoteFailure }; }); } if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Twitter:Enabled"] ?? "false")) { // You must first create an app with Twitter and add its key and Secret to your user-secrets. // https://apps.twitter.com/ // https://developer.twitter.com/en/docs/basics/authentication/api-reference/access_token authBuilder.AddTwitter(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ConsumerKey = Configuration["ExternalAuthProviders:Twitter:ConsumerKey"]; options.ConsumerSecret = Configuration["ExternalAuthProviders:Twitter:ConsumerSecret"]; // http://stackoverflow.com/questions/22627083/can-we-get-email-id-from-twitter-oauth-api/32852370#32852370 // http://stackoverflow.com/questions/36330675/get-users-email-from-twitter-api-for-external-login-authentication-asp-net-mvc?lq=1 options.RetrieveUserDetails = true; options.SaveTokens = true; options.ClaimActions.MapJsonKey("urn:twitter:profilepicture", "profile_image_url", ClaimTypes.Uri); options.Events = new TwitterEvents() { OnRemoteFailure = HandleOnRemoteFailure }; }); } //https://github.com/xamarin/Essentials/blob/master/Samples/Sample.Server.WebAuthenticator/Startup.cs if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Apple:Enabled"] ?? "false")) { authBuilder.AddApple(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = Configuration["ExternalAuthProviders:Apple:ClientId"]; options.KeyId = Configuration["ExternalAuthProviders:Apple:KeyId"]; options.TeamId = Configuration["ExternalAuthProviders:Apple:TeamId"]; options.UsePrivateKey(keyId => _environment.ContentRootFileProvider.GetFileInfo($"AuthKey_{keyId}.p8")); options.SaveTokens = true; }); } // You must first create an app with Microsoft Account and add its ID and Secret to your user-secrets. // https://docs.microsoft.com/en-us/azure/active-directory/develop/quickstart-register-app if (Convert.ToBoolean(Configuration["ExternalAuthProviders:Microsoft:Enabled"] ?? "false")) { authBuilder.AddMicrosoftAccount(options => { options.SignInScheme = IdentityServerConstants.ExternalCookieAuthenticationScheme; options.ClientId = Configuration["ExternalAuthProviders:Microsoft:ClientId"]; options.ClientSecret = Configuration["ExternalAuthProviders:Microsoft:ClientSecret"]; options.SaveTokens = true; options.Scope.Add("offline_access"); options.Events = new OAuthEvents() { OnRemoteFailure = HandleOnRemoteFailure }; }); } #endregion #region Authorization //Add Policies / Claims / Authorization - https://identityserver4.readthedocs.io/en/latest/topics/add_apis.html#advanced services.AddAuthorization(options => { options.AddPolicy(Policies.IsAdmin, Policies.IsAdminPolicy()); options.AddPolicy(Policies.IsUser, Policies.IsUserPolicy()); options.AddPolicy(Policies.IsReadOnly, Policies.IsReadOnlyPolicy()); options.AddPolicy(Policies.IsMyDomain, Policies.IsMyDomainPolicy()); // valid only on serverside operations options.AddPolicy(Policies.TwoFactorEnabled, Policies.IsTwoFactorEnabledPolicy()); }); services.AddScoped <ApplicationPermissions>(); services.AddSingleton <IAuthorizationPolicyProvider, AuthorizationPolicyProvider>(); services.AddTransient <IAuthorizationHandler, DomainRequirementHandler>(); services.AddTransient <IAuthorizationHandler, PermissionRequirementHandler>(); #endregion services.Configure <IdentityOptions>(options => { // Password settings options.Password.RequireDigit = false; options.Password.RequiredLength = 6; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequireLowercase = false; //options.Password.RequiredUniqueChars = 6; // Lockout settings options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(30); options.Lockout.MaxFailedAccessAttempts = 10; options.Lockout.AllowedForNewUsers = true; // Require Confirmed Email User settings if (Convert.ToBoolean(Configuration[$"{projectName}:RequireConfirmedEmail"] ?? "false")) { options.User.RequireUniqueEmail = true; options.SignIn.RequireConfirmedEmail = true; } }); #region Cookies // cookie policy to deal with temporary browser incompatibilities services.AddSameSiteCookiePolicy(); //https://docs.microsoft.com/en-us/aspnet/core/security/gdpr services.Configure <CookiePolicyOptions>(options => { // This lambda determines whether user consent for non-essential // cookies is needed for a given request. options.CheckConsentNeeded = context => false; //consent not required // requires using Microsoft.AspNetCore.Http; //options.MinimumSameSitePolicy = SameSiteMode.None; }); //services.ConfigureExternalCookie(options => // { // macOS login fix //options.Cookie.SameSite = SameSiteMode.None; //}); services.ConfigureApplicationCookie(options => { options.Cookie.IsEssential = true; options.Cookie.HttpOnly = true; options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest; options.ExpireTimeSpan = TimeSpan.FromMinutes(60); options.LoginPath = Shared.Settings.LoginPath; //options.AccessDeniedPath = "/Identity/Account/AccessDenied"; // ReturnUrlParameter requires //using Microsoft.AspNetCore.Authentication.Cookies; options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter; options.SlidingExpiration = true; // Suppress redirect on API URLs in ASP.NET Core -> https://stackoverflow.com/a/56384729/54159 options.Events = new CookieAuthenticationEvents() { OnRedirectToAccessDenied = context => { if (context.Request.Path.StartsWithSegments("/api")) { context.Response.StatusCode = Status403Forbidden; } return(Task.CompletedTask); }, OnRedirectToLogin = context => { context.Response.StatusCode = Status401Unauthorized; return(Task.CompletedTask); } }; }); #endregion services.AddMvc().AddNewtonsoftJson(opt => { // Set Breeze defaults for entity serialization var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); if (ss.ContractResolver is DefaultContractResolver resolver) { resolver.NamingStrategy = null; // remove json camelCasing; names are converted on the client. } if (_environment.IsDevelopment()) { ss.Formatting = Newtonsoft.Json.Formatting.Indented; // format JSON for debugging } }) // Add Breeze exception filter to send errors back to the client .AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }) .AddViewLocalization().AddDataAnnotationsLocalization(options => { options.DataAnnotationLocalizerProvider = (type, factory) => { return(factory.Create(typeof(Global))); }; }).AddFluentValidation(fv => fv.RegisterValidatorsFromAssemblyContaining <LocalizationRecordValidator>()); services.AddServerSideBlazor().AddCircuitOptions(o => { if (_environment.IsDevelopment()) { o.DetailedErrors = true; } }); services.AddSignalR(); if (_enableAPIDoc) { services.AddOpenApiDocument(document => { document.Title = "BlazorBoilerplate API"; document.Version = typeof(Startup).GetTypeInfo().Assembly.GetName().Version.ToString(); document.AddSecurity("bearer", Enumerable.Empty <string>(), new OpenApiSecurityScheme { Type = OpenApiSecuritySchemeType.OAuth2, Description = "Local Identity Server", OpenIdConnectUrl = $"{authAuthority}/.well-known/openid-configuration", //not working Flow = OpenApiOAuth2Flow.AccessCode, Flows = new OpenApiOAuthFlows() { AuthorizationCode = new OpenApiOAuthFlow() { Scopes = new Dictionary <string, string> { { LocalApi.ScopeName, IdentityServerConfig.LocalApiName } }, AuthorizationUrl = $"{authAuthority}/connect/authorize", TokenUrl = $"{authAuthority}/connect/token" }, } });; document.OperationProcessors.Add(new AspNetCoreOperationSecurityScopeProcessor("bearer")); // new OperationSecurityScopeProcessor("bearer")); }); } services.AddScoped <IUserSession, UserSession>(); services.AddSingleton <IHttpContextAccessor, HttpContextAccessor>(); services.Add(ServiceDescriptor.Scoped(typeof(ITenantSettings <>), typeof(TenantSettingsManager <>))); services.AddTransient <IAccountManager, AccountManager>(); services.AddTransient <IAdminManager, AdminManager>(); services.AddTransient <IEmailManager, EmailManager>(); services.AddTransient <IExternalAuthManager, ExternalAuthManager>(); #region Automapper //Automapper to map DTO to Models https://www.c-sharpcorner.com/UploadFile/1492b1/crud-operations-using-automapper-in-mvc-application/ var automapperConfig = new MapperConfiguration(configuration => { configuration.AddProfile(new MappingProfile()); }); var autoMapper = automapperConfig.CreateMapper(); services.AddSingleton(autoMapper); #endregion /* ServerSideBlazor */ services.AddScoped <IAccountApiClient, AccountApiClient>(); services.AddScoped <AppState>(); // setup HttpClient for server side in a client side compatible fashion ( with auth cookie ) if (!services.Any(x => x.ServiceType == typeof(HttpClient))) { services.AddScoped(s => { // creating the URI helper needs to wait until the JS Runtime is initialized, so defer it. var navigationManager = s.GetRequiredService <NavigationManager>(); var httpContextAccessor = s.GetRequiredService <IHttpContextAccessor>(); var cookies = httpContextAccessor.HttpContext.Request.Cookies; var client = new HttpClient(new HttpClientHandler { UseCookies = false }); if (cookies.Any()) { var cks = new List <string>(); foreach (var cookie in cookies) { cks.Add($"{cookie.Key}={cookie.Value}"); } client.DefaultRequestHeaders.Add("Cookie", string.Join(';', cks)); } client.BaseAddress = new Uri(navigationManager.BaseUri); return(client); }); } services.AddTransient <ILocalizationApiClient, LocalizationApiClient>(); services.AddTransient <IApiClient, ApiClient>(); // Authentication providers Log.Logger.Debug("Removing AuthenticationStateProvider..."); var serviceDescriptor = services.FirstOrDefault(descriptor => descriptor.ServiceType == typeof(AuthenticationStateProvider)); if (serviceDescriptor != null) { services.Remove(serviceDescriptor); } Log.Logger.Debug("Adding AuthenticationStateProvider..."); services.AddScoped <AuthenticationStateProvider, IdentityAuthenticationStateProvider>(); /**********************/ services.AddModules(); if (Log.Logger.IsEnabled(Serilog.Events.LogEventLevel.Debug)) { Log.Logger.Debug($"Total Services Registered: {services.Count}"); foreach (var service in services) { Log.Logger.Debug($"\n\tService: {service.ServiceType.FullName}\n\tLifetime: {service.Lifetime}\n\tInstance: {service.ImplementationType?.FullName}"); } } }
// This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { services.AddMvc(option => option.EnableEndpointRouting = false); var mvcBuilder = services.AddMvc(); services.AddControllers().AddNewtonsoftJson(); services.AddControllers().AddNewtonsoftJson(opt => { var ss = JsonSerializationFns.UpdateWithDefaults(opt.SerializerSettings); var resolver = ss.ContractResolver; if (resolver != null) { var res = resolver as DefaultContractResolver; res.NamingStrategy = null; // <<!-- this removes the camelcasing } #if NHIBERNATE // NHibernate settings var settings = opt.SerializerSettings; settings.ContractResolver = NHibernateContractResolver.Instance; settings.Error = delegate(object sender, Newtonsoft.Json.Serialization.ErrorEventArgs args) { // When the NHibernate session is closed, NH proxies throw LazyInitializationException when // the serializer tries to access them. We want to ignore those exceptions. var error = args.ErrorContext.Error; if (error is NHibernate.LazyInitializationException || error is System.ObjectDisposedException) { args.ErrorContext.Handled = true; } }; if (!settings.Converters.Any(c => c is NHibernateProxyJsonConverter)) { settings.Converters.Add(new NHibernateProxyJsonConverter()); } #endif }); mvcBuilder.AddMvcOptions(o => { o.Filters.Add(new GlobalExceptionFilter()); }); var tmp = Configuration.GetConnectionString("NorthwindIB_CF"); #if EFCORE services.AddDbContext <NorthwindIBContext_CF>(options => options.UseSqlServer(tmp)); #endif #if NHIBERNATE services.AddSingleton <NHibernate.ISessionFactory>(factory => { var cfg = new NHibernate.Cfg.Configuration(); cfg.DataBaseIntegration(db => { db.ConnectionString = tmp; db.Dialect <MsSql2008Dialect>(); db.Driver <Sql2008ClientDriver>(); db.LogFormattedSql = true; db.LogSqlInConsole = true; }); cfg.Properties.Add(Environment.DefaultBatchFetchSize, "32"); cfg.CurrentSessionContext <NHibernate.Context.ThreadStaticSessionContext>(); var modelAssembly = typeof(Models.NorthwindIB.NH.Customer).Assembly; cfg.AddAssembly(modelAssembly); // mapping is in this assembly var sessionFactory = cfg.BuildSessionFactory(); return(sessionFactory); }); #endif }
/// <summary> /// Override to use a specialized JsonSerializer implementation. /// </summary> protected virtual JsonSerializerSettings CreateJsonSerializerSettings() { var jsonSerializerSettings = new JsonSerializerSettings(); return(JsonSerializationFns.UpdateWithDefaults(jsonSerializerSettings)); }