Web API
61 TopicsSolutions for Blazor problems
Hi, I've significantly reduced render times, section rendering and configuration, API exposure, ... And I am starting thinking of sharing. I've never done this before, so I am wondering how to offer my Blazor framework API. Feacures I've implemented: Defer rendering (on standard component level - as naturalrendering pipeline) Custom sections (with custom state proagation and optimization minimizing render requests - my sections allow for full generic settings usable in section definition component with any amount of RenderFragment or other parameters): <YourSection Param1="StateWatchedParam1" Param2="StateWatchedParam2"> <RenderFragment1> StateWatchedContent with single render on whole section outlet </RenderFragment1> <RenderFragment2> StateWatchedContent with single render on whole section outlet </RenderFragment2> </YourSection> Unit of Work system with unltimited dependency tree of steps described by FluentAPI and accessed only by input model from client side - thus limiting any API exposure. You would have to know descriptor, rights and then guess allowed steps and stil only can fill model with input data - nothing more ... LinQ projector pattern with lego building FluentAPI system - where any business logic can be break into named step in specific named projector, so you are out of ordinary expression tree completely. That projector pattern is correctly written to check for Queryable Provider and to work with the same expression tree also for Enumerable. (Thus the same lego pieces can work for client.) Blazor component messagging done on direct Task API system - so without any queue or backlog. You can directly pass any data between any Blazor component and you are doing it in direct way without any delay or data transfer. Here I have SignalR also in the same system - allowing server to communicate with any component needed. And whole system is communicating with ToastLogger, thus any issue/unhandled exception can be (and it is) instantly logged and toasted to user. Background runner - thus any Task in Blazor can be called to just RunInBackground and it is immediately handled in Task lock mechanism, Exception mechanism and with correct Blazor stae update pipeline thus allowing for partial renders and mid render switch to background process finishing later and rendering from that deferred background.38Views0likes0Comments[ASP.NET CORE] Exchange Web Services Throw HTTP 401 When Called from IIS
Hi, Currently, I can't get Microsoft.Exchange.WebServices to work with Exchange 2019 On-Premise. Send Email feature is working OK on Development but as soon I deployed it to IIS, it stopped working with following error: Microsoft.Exchange.WebServices.Data.ServiceRequestException: The request failed. The remote server returned an error: (401) Unauthorized. ---> System.Net.WebException: The remote server returned an error: (401) Unauthorized. at System.Net.HttpWebRequest.GetResponse() at Microsoft.Exchange.WebServices.Data.EwsHttpWebRequest.Microsoft.Exchange.WebServices.Data.IEwsHttpWebRequest.GetResponse() at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request) --- End of inner exception stack trace --- at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.GetEwsHttpWebResponse(IEwsHttpWebRequest request) at Microsoft.Exchange.WebServices.Data.ServiceRequestBase.ValidateAndEmitRequest(IEwsHttpWebRequest& request) at Microsoft.Exchange.WebServices.Data.SimpleServiceRequestBase.InternalExecute() at Microsoft.Exchange.WebServices.Data.MultiResponseServiceRequest`1.Execute() at Microsoft.Exchange.WebServices.Data.ExchangeService.InternalCreateItems(IEnumerable`1 items, FolderId parentFolderId, Nullable`1 messageDisposition, Nullable`1 sendInvitationsMode, ServiceErrorHandling errorHandling) at Microsoft.Exchange.WebServices.Data.ExchangeService.CreateItem(Item item, FolderId parentFolderId, Nullable`1 messageDisposition, Nullable`1 sendInvitationsMode) at Microsoft.Exchange.WebServices.Data.Item.InternalCreate(FolderId parentFolderId, Nullable`1 messageDisposition, Nullable`1 sendInvitationsMode) at Microsoft.Exchange.WebServices.Data.EmailMessage.InternalSend(FolderId parentFolderId, MessageDisposition messageDisposition) I'm using same Exchange Settings (URL, Credentials, etc.) for both instance but it is only worked on Development. My Site is using App Pool User which is registered on Exchange Mailbox Users. How to fix this issue? Thanks in advance. Best Regards, Henoch86Views0likes0CommentsI want to use VS code instead of Visual Studio for .Net Framework 3.5 or .Net Framework 4.8 project
I’m transitioning from Visual Studio to Visual Studio Code for .NET Framework 3.5 and 4.8 projects but facing difficulties with: Debugging: Setting up a debugger for seamless support. Resource Files (.resx): Editing/viewing with auto-generation of designer files. DBML Files: Managing these and their designer files effectively. How to execute the Unit tests? Are there any extensions, workflows, or best practices in VS Code to handle these issues?73Views0likes0CommentsReact website with ASP.NET and IIS : API not working
Hi, I have found a lot of similar issues on the web but none was working for me, and I am so desperate after days so I am posting here and hope someone can help. I have an ASP.NET server that serves a React website, and also works as an API for the website itself. The server runs on a Windows 11 PC with IIS, in C:/MyWebSite. This folder contains the ASP.NET server (.exe, .dll, etc), the IIS configuration (web.config) and the build React website (index.html, favicon.ico and assets folder). The server succeed to show my main page, but it fails doing an API request. The API request fails as well when I call it from Postman, and gives me the error "HTTP 404.0 - Not Found" with these details : Module IIS Web Core Notification : MapRequestHandler Handler : StaticFile Error code : 0x80070002 FYI, the request is GET http://localhost:5058/api/configuration/settings Concerning ASP.NET, here is my Program.cs : using Microsoft.AspNetCore.Authentication.JwtBearer; using Microsoft.IdentityModel.Tokens; using System.Text; // Create the web application builder var builder = WebApplication.CreateBuilder(args); // JWT authentication builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }) .AddJwtBearer(options => { string? tKey = builder.Configuration["Jwt:Key"]; options.TokenValidationParameters = new TokenValidationParameters { ValidateIssuer = true, ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = builder.Configuration["Jwt:Issuer"], ValidAudience = builder.Configuration["Jwt:Audience"], IssuerSigningKey = tKey != null ? new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tKey)) : null }; }); // Add the controllers to the application (for input http requests) builder.Services.AddControllers(); // Configure CORS policy builder.Services.AddCors(options => { options.AddPolicy("AllowAllOrigins", builder => { builder.AllowAnyOrigin() .AllowAnyHeader() .AllowAnyMethod(); }); }); // Create the App var app = builder.Build(); // Applies the CORS policy app.UseCors("AllowAllOrigins"); // Serving the static files app.UseDefaultFiles(); app.UseStaticFiles(); app.UseRouting(); // Map the routes to the controllers app.MapControllers(); // Undefined route will lead to index.html app.MapFallbackToFile("index.html"); // Run the App app.Run(); Of course, I have created some controllers, here is ConfigurationController.cs for example : using Microsoft.AspNetCore.Mvc; namespace AspReact.Server.Controllers { [ApiController] [Route("api/configuration")] public class GeneralController : ControllerBase { [HttpGet("settings")] public ActionResult GetSettings() { return Ok(new { language = 'fr', theme = 0 }); } [HttpPost("settings")] public ActionResult SetSettings([FromQuery] string language, [FromQuery] string theme) { m_tLanguage = language; m_tTheme = theme; return Ok(); } } } Here is my IIS configuration : <?xml version="1.0"?> <configuration> <system.webServer> <rewrite> <rules> <rule name="React Routes" stopProcessing="true"> <match url=".*" /> <conditions logicalGrouping="MatchAll"> <add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /> <add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /> <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" /> </conditions> <action type="Rewrite" url="/" /> </rule> </rules> </rewrite> </system.webServer> </configuration> NB : At first I was not doing : <add input="{REQUEST_URI}" pattern="^/(api)" negate="true" /> And the API request was returning the content of index.html... If it can help. Please note that all this is working during development with the server running in a debug console. I would be grateful for any help! Thanks.Solved208Views0likes2CommentsMultiple ASP.NET Core Web API instances runs only once
I have an ASP.NET Core 8.0 Web API hosted on two IIS applications (app-1 and app-2) under the Default Web Site on a Windows 11 OS. Both IIS applications point to the same physical path (inetpub\wwwroot\myapp) and each application has its own dedicated application pool (app1 and app2). The application pools have unique identities (app1svc and app2svc), both of which are members of the Administrators group. In the Web API, I have an AppEvents class implementing IHostedService, with StartAsync and StopAsync methods to handle application start and stop events. In the Program.cs, I register it using builder.Services.AddHostedService<AppEvents>(). When accessing http://localhost/app-1, the StartAsync method is triggered as expected. However, when accessing http://localhost/app-2, the StartAsync method does not execute. It seems that the application starts only once, despite both IIS apps pointing to the same physical directory. I've tried changing the AspNetHostingModel from InProcess to OutOfProcess, but the behavior remains the same. Is there a way to deploy multiple instances of the same web app, each running separately but pointing to the same physical directory, so that each instance correctly triggers its own StartAsync?58Views0likes0CommentsIs it possible to run a asp.net core site within testing?
Hi! I'm trying to write tests for a small minimal API based on asp.net core. I don't want to test over the internet, but start the app within the tests and call the endpoints on the running site. Is this possible? And how? Should I use TestServer for this? I'm new to writing tests, so maybe it's an easy issue to code. Thanks! :)17Views0likes0CommentsMacos dotnet wacth https not working.
Hello; I wanted to start Asp.net core Angular training. I am a Macos M1 user. I installed the necessary plugins with Vscode and created a webapi. But the api does not work with the dotnet watch command. It says the reason is https certificate problem. launchSettings.json : { "$schema": "http://json.schemastore.org/launchsettings.json", "profiles": { "http": { "commandName": "Project", "dotnetRunMessages": true, "launchBrowser": false, "applicationUrl": "http://localhost:5000;https://localhost:5001", "environmentVariables": { "ASPNETCORE_ENVIRONMENT": "Development" } } } } applicationUrl also only works when it is http. In the error command: Microsoft.Extensions.Hosting.Internal.Host[11] Hosting failed to start System.InvalidOperationException: Unable to configure HTTPS endpoint. No server certificate was specified, and the default developer certificate could not be found or is out of date. To generate a developer certificate run 'dotnet dev-certs https'. To trust the certificate (Windows and macOS only) run 'dotnet dev-certs https --trust'. There is a long error like this. I enter the following commands in the terminal, in order: 1- dotnet dev-certs https 2- dotnet dev-certs https --trust I approve the certificate. When I say 3-dotnet dev-certs https --check, I get the error: No valid certificate found. I found the localhost certificates in Keychain Access and selected the always trust option. But I couldn't find a solution. Also: dotnet dev-certs https --trust Trusting the HTTPS development certificate was requested. If the certificate is not already trusted we will run the following command: 'security add-trusted-cert -p basic -p ssl -k <<login-keychain>> <<certificate>>' This command might prompt you for your password to install the certificate on the keychain. There is an addition process like To undo these changes: 'security remove-trusted-cert <<certificate>>' I didn't know how to do it. Can you help me with this?195Views0likes0Comments.NET Web API CancellationToken don't work with Angular .unsuscribe()?
In Angular, I make API calls by subscribing to observables. When a user cancels a request, the application unsubscribes to the subscription which cancels the request (I can see this in the network tab of the Chrome browser). However, it does not trigger the endpoint and so the cancellation token param in our endpoint is of no use. Is there a way around this? I need the cancellation token to cancel all database request.393Views0likes2CommentsIssue with Authentication
If anyone can give me a clue as to where I am going wrong. I have slowly been upgrading my code base from .NET 6 to .NET 8. With my authorization controller, in the authorize method with .NET 6 this line of code var results = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme) would return null or not succeed. I would then hit the Login Razor Page and Sign In, the same result would then be an actual `AuthenticateResult`. With the upgrade to .NET 8, it always returns null even after I sign in. I have looked with the Dev Tools open and I can see that the sign in does generate a cookie. I am testing this from Postman using the authorization tab in there and using all the correct parameters. Here is what is not changed from .NET 6 to .NET 8: Authorize method: [HttpGet(Name = nameof(Authorize))] [HttpPost(Name = nameof(Authorize))] [IgnoreAntiforgeryToken] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status400BadRequest)] public async Task<IActionResult> Authorize() { var request = HttpContext.GetOpenIddictServerRequest() ?? throw new InvalidOperationException("The OpenID Connect request cannot be retrieved."); // Retrieve the user principal stored in the authentication cookie. // If it can't be extracted, redirect the user to the login page. var result = await HttpContext.AuthenticateAsync(IdentityConstants.ApplicationScheme); if (result == null || !result.Succeeded) { if (request.HasPrompt(Prompts.None)) { return Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary<string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in." })); } return Challenge( authenticationSchemes: IdentityConstants.ApplicationScheme, properties: new AuthenticationProperties { RedirectUri = Request.PathBase + Request.Path + QueryString.Create( Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList()) }); } if (request.HasPrompt(Prompts.Login)) { var prompt = string.Join(" ", request.GetPrompts().Remove(Prompts.Login)); var parameters = Request.HasFormContentType ? Request.Form.Where(parameter => parameter.Key != Parameters.Prompt).ToList() : Request.Query.Where(parameter => parameter.Key != Parameters.Prompt).ToList(); parameters.Add(KeyValuePair.Create(Parameters.Prompt, new StringValues(prompt))); return Challenge( authenticationSchemes: IdentityConstants.ApplicationScheme, properties: new AuthenticationProperties { RedirectUri = Request.PathBase + Request.Path + QueryString.Create(parameters) }); } if (request.MaxAge != null && result.Properties.IssuedUtc != null && DateTimeOffset.UtcNow - result.Properties.IssuedUtc > TimeSpan.FromSeconds(request.MaxAge.Value)) { if (request.HasPrompt(Prompts.None)) { return Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary<string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.LoginRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The user is not logged in." })); } return Challenge( authenticationSchemes: IdentityConstants.ApplicationScheme, properties: new AuthenticationProperties { RedirectUri = Request.PathBase + Request.Path + QueryString.Create( Request.HasFormContentType ? Request.Form.ToList() : Request.Query.ToList()) }); } var user = await _userManager.GetUserAsync(result.Principal) ?? throw new InvalidOperationException("The user details cannot be retrieved"); var application = await _applicationManager.FindByClientIdAsync(request.ClientId) ?? throw new InvalidOperationException("Details concerning the calling client application cannot be found"); var permissionsArray = await _applicationManager.GetPermissionsAsync(application); var scopes = permissionsArray.Where(a => a.StartsWith("scp:")).Select(a => a[4..]).ToList().ToImmutableArray(); var authorizations = await _authorizationManager.FindAsync( subject: await _userManager.GetUserIdAsync(user), client: await _applicationManager.GetIdAsync(application), status: Statuses.Valid, type: AuthorizationTypes.Permanent, scopes: scopes).ToListAsync(); switch (await _applicationManager.GetConsentTypeAsync(application)) { case ConsentTypes.External when !authorizations.Any(): return Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary<string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "The logged in user is not allowed to access this client." })); case ConsentTypes.Implicit: case ConsentTypes.External when authorizations.Any(): case ConsentTypes.Explicit when authorizations.Any() && !request.HasPrompt(Prompts.Consent): var principal = await _signInManager.CreateUserPrincipalAsync(user); principal.SetScopes(scopes); principal.SetResources(await _scopeManager.ListResourcesAsync(principal.GetScopes()).ToListAsync()); var authorization = authorizations.LastOrDefault(); if (authorization == null) { authorization = await _authorizationManager.CreateAsync( principal: principal, subject: await _userManager.GetUserIdAsync(user), client: await _applicationManager.GetIdAsync(application), type: AuthorizationTypes.Permanent, scopes: principal.GetScopes()); } principal.SetAuthorizationId(await _authorizationManager.GetIdAsync(authorization)); foreach (var claim in principal.Claims) { claim.SetDestinations(GetDestinations(claim, principal)); } return SignIn(principal, OpenIddictServerAspNetCoreDefaults.AuthenticationScheme); case ConsentTypes.Explicit when request.HasPrompt(Prompts.None): case ConsentTypes.Systematic when request.HasPrompt(Prompts.None): return Forbid( authenticationSchemes: OpenIddictServerAspNetCoreDefaults.AuthenticationScheme, properties: new AuthenticationProperties(new Dictionary<string, string> { [OpenIddictServerAspNetCoreConstants.Properties.Error] = Errors.ConsentRequired, [OpenIddictServerAspNetCoreConstants.Properties.ErrorDescription] = "Interactive user consent is required." })); default: return View(new AuthorizeViewModel { ApplicationName = await _applicationManager.GetDisplayNameAsync(application), Scope = string.Join(" ", scopes) }); } } Login page: [AllowAnonymous] public class LoginModel : PageModel { private readonly ApplicationUserManager _userManager; private readonly SignInManager<ApplicationUsers> _signInManager; private readonly ILogger<LoginModel> _logger; public LoginModel(SignInManager<ApplicationUsers> signInManager, ILogger<LoginModel> logger, ApplicationUserManager userManager) { _userManager = userManager; _signInManager = signInManager; _logger = logger; } [BindProperty] public InputModel Input { get; set; } public IList<AuthenticationScheme> ExternalLogins { get; set; } public string ReturnUrl { get; set; } [TempData] public string ErrorMessage { get; set; } public class InputModel { //Snipped fro brevity } public async Task OnGetAsync(string returnUrl = null) { if (!string.IsNullOrEmpty(ErrorMessage)) { ModelState.AddModelError(string.Empty, ErrorMessage); } returnUrl ??= Url.Content("~/"); // Clear the existing external cookie to ensure a clean login process await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme); ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync()).ToList(); ReturnUrl = returnUrl; } public async Task<IActionResult> OnPostAsync(string returnUrl = null) { returnUrl ??= Url.Content("~/"); if (ModelState.IsValid) { var user = await _userManager.FindByNameAsync(Input.Email); if (user != null) { if (!await _signInManager.CanSignInAsync(user) || (_userManager.SupportsUserLockout && await _userManager.IsLockedOutAsync(user))) { _logger.LogInformation("Login was unsuccessful through controller"); } if (!await _userManager.CheckPasswordAsync(user, Input.Password)) { _logger.LogInformation("Login was unsuccessful through controller"); await _userManager.AccessFailedAsync(user); } if (_userManager.SupportsUserLockout) { await _userManager.ResetAccessFailedCountAsync(user); } var result = await _signInManager.PasswordSignInAsync(Input.Email, Input.Password, Input.RememberMe, lockoutOnFailure: true); if (result.Succeeded) { _logger.LogInformation("User logged in."); return LocalRedirect(returnUrl); } if (result.RequiresTwoFactor) { return RedirectToPage("./LoginWith2fa", new { ReturnUrl = returnUrl, Input.RememberMe }); } if (result.IsLockedOut) { _logger.LogWarning("User account locked out."); return RedirectToPage("./Lockout"); } else { ModelState.AddModelError(string.Empty, "Invalid login attempt."); return Page(); } } else { ModelState.AddModelError(string.Empty, "Invalid login attempt."); return Page(); } } return Page(); } } Here is what I have changed in the .NET 6 to .NET 8 basically a move from `startup.cs` to `program.cs`: .NET 6 `startup.cs`: public void ConfigureServices(IServiceCollection services) { services.AddCors(options => { options.AddPolicy("Policy", builder => { builder.WithOrigins(Configuration.GetSection("Cors:Origins").GetChildren().Select(c => c.Value).ToArray()) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); services.AddControllers(); services.AddRazorPages(); services.AddDbContext<IdentDbContext>(options => { options.UseSqlServer( Configuration.GetConnectionString("IdentityDB")); options.UseOpenIddict(); }); services.AddDataProtection() .PersistKeysToDbContext<IdentDbContext>() .SetDefaultKeyLifetime(TimeSpan.FromDays(7)) .SetApplicationName("Applications"); services.AddIdentity<ApplicationUsers, ApplicationRoles>() .AddEntityFrameworkStores<IdentDbContext>() .AddUserStore<ApplicationUserStore>() .AddRoleStore<ApplicationRoleStore>() .AddRoleManager<ApplicationRoleManager>() .AddUserManager<ApplicationUserManager>() .AddErrorDescriber<ApplicationIdentityErrorDescriber>() .AddDefaultTokenProviders() .AddDefaultUI(); services.Configure<IdentityOptions>(options => { options.ClaimsIdentity.UserNameClaimType = Claims.Name; options.ClaimsIdentity.UserIdClaimType = Claims.Subject; options.ClaimsIdentity.RoleClaimType = Claims.Role; // Configure the options for the Identity Account options.SignIn.RequireConfirmedEmail = true; options.SignIn.RequireConfirmedAccount = true; options.User.RequireUniqueEmail = true; options.Lockout.MaxFailedAccessAttempts = 3; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); }); services.Configure<SecurityStampValidatorOptions>(options => { options.ValidationInterval = TimeSpan.FromSeconds(1); }); services.AddQuartz(options => { options.UseMicrosoftDependencyInjectionJobFactory(); options.UseSimpleTypeLoader(); options.UseInMemoryStore(); }); services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true); services.AddOpenIddict() // Register the OpenIddict core components. .AddCore(options => { options.UseEntityFrameworkCore() .UseDbContext<IdentDbContext>(); options.UseQuartz(); }) // Register the OpenIddict server components. .AddServer(options => { options.SetAuthorizationEndpointUris("/api/Authorization/Authorize") .SetTokenEndpointUris("/Token") .SetIntrospectionEndpointUris("/Introspect") .SetUserinfoEndpointUris("/api/Userinfo/Userinfo") .SetVerificationEndpointUris("/Verify"); options.RegisterScopes(Scopes.OpenId, Scopes.Email, Scopes.Profile, Scopes.Roles); options.UseReferenceAccessTokens() .UseReferenceRefreshTokens() .UseDataProtection(); options.AllowClientCredentialsFlow() .AllowAuthorizationCodeFlow() .RequireProofKeyForCodeExchange() .AllowRefreshTokenFlow(); if (_env.IsDevelopment()) { options.AddDevelopmentEncryptionCertificate() .AddDevelopmentSigningCertificate(); } else if (_env.IsProduction() || _env.IsStaging()) { options.AddSigningCertificate(Configuration.GetSection("CertifcateThumbprints:SigningCertificate").Value) .AddEncryptionCertificate(Configuration.GetSection("CertifcateThumbprints:EncryptionCertificate").Value); } options.UseAspNetCore() .EnableAuthorizationEndpointPassthrough() .EnableTokenEndpointPassthrough() .EnableStatusCodePagesIntegration() .EnableUserinfoEndpointPassthrough() .EnableVerificationEndpointPassthrough(); }) // Register the OpenIddict validation components. .AddValidation(options => { options.UseLocalServer(); options.UseDataProtection(); options.UseSystemNetHttp(); options.UseAspNetCore(); }); services.AddSwaggerGen(swagger => { swagger.OperationFilter<SwaggerDefaultValues>(); swagger.OperationFilter<AuthenticationRequirementOperationFilter>(); swagger.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); // Set the comments path for the Swagger JSON and UI. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); swagger.IncludeXmlComments(xmlPath); }); services.AddApiVersioning(); services.AddVersionedApiExplorer(options => { options.GroupNameFormat = "'v'VVVV"; options.DefaultApiVersion = ApiVersion.Parse("0.10.alpha"); options.AssumeDefaultVersionWhenUnspecified = true; }); services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>(); if (_env.IsDevelopment()) { services.AddHostedService<TestData>(); } else if (_env.IsStaging() || _env.IsProduction()) { services.AddHostedService<ProdStageSeed>(); } } public void Configure(IApplicationBuilder app, IApiVersionDescriptionProvider provider) { if (_env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseStatusCodePagesWithReExecute("/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.UseCors("Policy"); app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseSwagger(); // Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.), // specifying the Swagger JSON endpoint. app.UseSwaggerUI(c => { c.DisplayOperationId(); var versionDescription = provider.ApiVersionDescriptions; foreach (var description in provider.ApiVersionDescriptions.OrderByDescending(_ => _.ApiVersion)) { c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", $"API {description.GroupName}"); } }); app.UseSerilogRequestLogging(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); endpoints.MapControllers(); }); } .NET 8 `program.cs`: builder.Services.AddCors(options => { options.AddPolicy("Policy", opt => { opt.WithOrigins(builder.Configuration.GetSection("Cors:Origins").GetChildren().Select(c => c.Value).ToArray()!) .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials(); }); }); builder.Services.AddControllersWithViews() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new EntityIdJsonConverterFactory()); }); builder.Services.AddRazorPages(); builder.Services.AddDbContext<IdentDbContext>(options => { options.UseSqlServer( builder.Configuration.GetConnectionString("IdentityDB")); options.UseOpenIddict(); }); builder.Services.AddDataProtection() .PersistKeysToDbContext<IdentDbContext>() .SetDefaultKeyLifetime(TimeSpan.FromDays(7)) .SetApplicationName("Applications"); builder.Services.AddIdentity<ApplicationUsers, ApplicationRoles>() .AddEntityFrameworkStores<IdentDbContext>() .AddUserStore<ApplicationUserStore>() .AddRoleStore<ApplicationRoleStore>() .AddRoleManager<ApplicationRoleManager>() .AddUserManager<ApplicationUserManager>() .AddErrorDescriber<ApplicationIdentityErrorDescriber>() .AddDefaultTokenProviders() .AddDefaultUI(); builder.Services.Configure<IdentityOptions>(options => { options.ClaimsIdentity.UserNameClaimType = Claims.Name; options.ClaimsIdentity.UserIdClaimType = Claims.Subject; options.ClaimsIdentity.RoleClaimType = Claims.Role; options.SignIn.RequireConfirmedEmail = true; options.SignIn.RequireConfirmedAccount = true; options.User.RequireUniqueEmail = true; options.Lockout.MaxFailedAccessAttempts = 3; options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(10); }); builder.Services.Configure<SecurityStampValidatorOptions>(options => { options.ValidationInterval = TimeSpan.FromSeconds(1); }); builder.Services.AddQuartz(options => { options.UseSimpleTypeLoader(); options.UseInMemoryStore(); }); builder.Services.AddQuartzHostedService(options => options.WaitForJobsToComplete = true); builder.Services.AddOpenIddict() // Register the OpenIddict core components. .AddCore(options => { options.UseEntityFrameworkCore() .UseDbContext<IdentDbContext>(); options.UseQuartz(); }) // Register the OpenIddict server components. .AddServer(options => { options.SetAuthorizationEndpointUris("api/Authorization/Authorize") .SetTokenEndpointUris("Token") .SetIntrospectionEndpointUris("Introspect") .SetUserinfoEndpointUris("api/Userinfo/Userinfo") .SetVerificationEndpointUris("Verify"); options.RegisterScopes(Scopes.OpenId, Scopes.Email, Scopes.Profile, Scopes.Roles); options.UseReferenceAccessTokens() .UseReferenceRefreshTokens() .UseDataProtection(); options.AllowClientCredentialsFlow() .AllowAuthorizationCodeFlow() .RequireProofKeyForCodeExchange() .AllowRefreshTokenFlow(); if (builder.Environment.IsDevelopment()) { options.AddDevelopmentEncryptionCertificate() .AddDevelopmentSigningCertificate(); } else if (builder.Environment.IsProduction() || builder.Environment.IsStaging()) { options.AddSigningCertificate(builder.Configuration.GetSection("CertifcateThumbprints:SigningCertificate").Value!) .AddEncryptionCertificate(builder.Configuration.GetSection("CertifcateThumbprints:EncryptionCertificate").Value!); } options.UseAspNetCore() .EnableAuthorizationEndpointPassthrough() .EnableTokenEndpointPassthrough() .EnableStatusCodePagesIntegration() .EnableUserinfoEndpointPassthrough() .EnableVerificationEndpointPassthrough(); }) // Register the OpenIddict validation components. .AddValidation(options => { options.UseLocalServer(); options.UseDataProtection(); options.UseSystemNetHttp(); options.UseAspNetCore(); }); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(swagger => { swagger.OperationFilter<SwaggerDefaultValues>(); swagger.OperationFilter<AuthenticationRequirementOperationFilter>(); swagger.ResolveConflictingActions(apiDescriptions => apiDescriptions.First()); // Set the comments path for the Swagger JSON and UI. var xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml"; var xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile); swagger.IncludeXmlComments(xmlPath); }); builder.Services.AddApiVersioning(options => { options.DefaultApiVersion = new ApiVersion(0, 10, "alpha"); options.AssumeDefaultVersionWhenUnspecified = true; options.ReportApiVersions = true; }).AddMvc() .AddApiExplorer(options => { options.GroupNameFormat = "'v'VVVV"; options.SubstituteApiVersionInUrl = false; }); builder.Services.AddApplication() .AddInfrastructure(builder.Configuration) .AddDataLibrary(); builder.Services.AddHttpClient("Login", sp => { sp.BaseAddress = new Uri(builder.Configuration.GetSection("BaseAddresses:Api").Value!); }); builder.Services.AddTransient<IConfigureOptions<SwaggerGenOptions>, ConfigureSwaggerOptions>(); if (builder.Environment.IsDevelopment()) { builder.Services.AddHostedService<TestData>(); builder.Services.AddHostedService<ProdStageSeed>(); } else if (builder.Environment.IsStaging() || builder.Environment.IsProduction()) { builder.Services.AddHostedService<ProdStageSeed>(); } builder.Host.UseWolverine(opts => { opts.PersistMessagesWithSqlServer(builder.Configuration.GetConnectionString("IdentityDB")!); opts.UseEntityFrameworkCoreTransactions(); opts.Policies.AutoApplyTransactions(); opts.Policies.UseDurableLocalQueues(); opts.Discovery.IncludeAssembly(Assembly.Load("IdentityApplication")); opts.UseFluentValidation(); opts.Services.AddResourceSetupOnStartup(); opts.OnException<SqlException>().MoveToErrorQueue(); }); builder.Services.AddTransient<ExceptionMiddleware>(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment() || app.Environment.IsStaging()) { app.UseDeveloperExceptionPage(); app.UseSwagger(); var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>(); app.UseSwaggerUI(c => { c.DisplayOperationId(); var versionDescription = provider.ApiVersionDescriptions; foreach (var description in provider.ApiVersionDescriptions.OrderByDescending(_ => _.ApiVersion)) { c.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json", $"API {description.GroupName}"); } }); } else { app.UseStatusCodePagesWithReExecute("/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.UseCors("Policy"); app.UseSerilogRequestLogging(); app.UseStaticFiles(); app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseMiddleware<ExceptionMiddleware>(); app.MapRazorPages(); app.MapControllers(); app.Run(); So with the minimal change I made I cannot figure out why the result is always returning null. A cookie is generated by the Login Page and does show up in program and Postman. I understand that the AuthenticateAsync changed in .NET 7 but I cannot find any good documentation as to what might be affected in my code. Not sure what the cause is, but I have been stuck on this for over a coupe of weeks.187Views0likes0CommentsCustomer portal application using .NET, Microsoft 365 and Microsoft Graph
Hello, I want to develop an customer portal application using .NET, Microsoft 365 and Microsoft Graph. I want to retrieve information from SharePoint lists where there's the information I want to show customers (bookings, invoices, etc.). Customers don't have Microsoft 365 account so my idea is to use my credentials for retrieving the information from M365 and use Identity Framework for identify them filter queries. I am not sure this is possible, specially the fact of using my credentials for connecting to Microsoft 365. I really appreciate any suggestion or previous experience that you share. Thanks, Regards612Views0likes4Comments