Does not start ASP.net service with SPA (React) - asp.net

Please help me launch the web service. I run the .exe file from the folder "\bin\Debug\net 5.0". When prompted https://localhost:5001/ gives an error.
I specified it in the spa.Options.sourcepath, but it didn't help.
the ERROR that I received is the following:
fail: Microsoft.AspNetCore.Server.Kestrel[13]
Connection id "0HMD866NK2DDC", Request id "0HMD866NK2DDC:00000011": An unhandled exception was thrown by the application.
System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request.
Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment.
This is the folder structure ClientApp Paths
My config code:
public void ConfigureServices(IServiceCollection services)
{
// получаем строку подключения из файла конфигурации
string connection = Configuration.GetConnectionString("DefaultConnection");
// добавляем контекст ApplicationContext в качестве сервиса в приложение
services.AddDbContext<ApplicationContext>(options =>
options.UseSqlServer(connection));
//чтобы кирилица нормально отображалась
services.AddWebEncoders(o =>
{
o.TextEncoderSettings = new TextEncoderSettings(UnicodeRanges.BasicLatin, UnicodeRanges.Cyrillic, UnicodeRanges.CyrillicExtendedA, UnicodeRanges.CyrillicExtendedB);
});
services.AddControllersWithViews();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/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.UseSpaStaticFiles();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}

React assets are not built by dotnet build or dotnet run not even with -c Release.
To also build the React assets you need dotnet publish.
This requirement may be masked by the presence of assets due to earlier use of dotnet publish. In that case they are potentially stale. Therefore, for any environment other than dev, you must use dotnet publish.
Why don't dotnet build and dotnet run build the React assets? In development you don't need them because you're using the dev server for hot swap. In production you're almost certainly using assets prepared by dotnet publish.
AspNetCore React can only find spa files in dev mode

Related

How do I host a WebApplication and a BackgroundService in the same application?

I have a command-line application (similar to what would be created with the dotnet new worker command) that hosts a BackgroundService implementation, like this:
var host = Host.CreateDefaultBuilder(args)
.ConfigureServices(services => {
services.AddHostedService<MyBackgroundService>();
services.AddSingleton<IMyType>(myinstance);
// and so on...
}).Build();
await host.RunAsync();
Now, I would like this application to also host a web api. Currently, I have a whole separate builder that I'm instantiating inside the MyBackgroundService class, with a separate set of services/singletons/whatever:
var builder = WebApplication.CreateBuilder();
// ... various web stuff...
var webApi = builder.Build();
// ... more web api stuff...
await webApi.StartAsync(cancellationToken);
I'd like to set this up to share a single DI container... how do I do that? My web api uses a WebApplicationBuilder, while my BackgroundService uses a DefaultBuilder (which is a IHostBuilder). Is there any way to set this up elegantly?
Edit: I found this: https://learn.microsoft.com/en-us/aspnet/core/fundamentals/host/generic-host?view=aspnetcore-6.0 which gives me the ConfigureWebHostDefaults method for the generic host, but the example isn't complete. I can put the AddControllers() and AddRouting() etc on the generic host, but once I call Build() I can't do things like UseHttpLogging() or UseSwagger() or MapControllers().
Assuming you're starting from a console app and want to add in the API portion, you can do something like:
await Host.CreateDefaultBuilder(args)
.ConfigureServices(services =>
{
services.AddHostedService<SomeBackgroundService>();
})
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder
.ConfigureServices(services =>
{
services.AddControllers();
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
})
.Configure((hostContext, app) =>
{
if (hostContext.HostingEnvironment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
​
app.UseHttpsRedirection();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
});
//can optionally use a startup file similar to what older versions of .NET used
//webBuilder.UseStartup<Startup>();
})
.Build()
.RunAsync();
}
Also, assuming you started from a console app, you may need to add:
<ItemGroup>
<FrameworkReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
to your csproj, as that will pull in the additional web options.
Edit: It appears the services specific to the web context need to be registered within the webBuilder.

Can't open Swagger UI outside of visual studio debug

I've created a very basic .net CORE WEB API, following a youtube guide.
Everything works fine when I debug from visual studio. it opens my browser and directs me to the swagger ui site.
But when I run outside visual studio, starting the exe from the build/bin folder I can't get to that swagger site.
in a command propt the exe file says it is listening on http on port 5000.
so while this is running go to this url http://localhost:5000/swagger/index.html
anyone have a hit on what I'm missing here ?
appsettings.json
{
"ConnectionStrings": {
"DefaultConnection": "server=myServerXXXX;database=myDataBaseXXXX;User ID=mydbUserXXXXX;Password=myPasswordXXX"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*"
}
program.cs
global using ShoppingList.API.Data;
global using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddDbContext<ShoppingItemDataContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
By default dotnet runs applications with the production environment and you have swagger enabled for the dev environment only. change the condition or pass the "--environment production" argument (or configure host environment: e.g. https://enlabsoftware.com/development/dotnet-core-environment-how-config-examples.html)

Asp net core and SPA (VUE): The SPA default page middleware could not return the default page '/index.html'

In asp net core and visual studio 2019 i have created a Vue 3 project from template:
https://marketplace.visualstudio.com/items?itemName=alexandredotnet.vuejsdotnetfive
In Startup.cs i have:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp";
});
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseSpaStaticFiles();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.UseSpa(spa =>
{
if (env.IsDevelopment())
spa.Options.SourcePath = "ClientApp/";
else
spa.Options.SourcePath = "dist";
if (env.IsDevelopment())
{
spa.UseVueCli(npmScript: "serve");
}
});
}
When i deploy to azure i get an internal error. So i've tried to launch in production mode on my laptop
setting:
"ASPNETCORE_ENVIRONMENT": "Production"
in launchSetting.json. It's created the "dist" folder as in the image below:
Why i have the folowing error??:
System.InvalidOperationException: The SPA default page middleware could not return the default page '/index.html' because it was not found, and no other middleware handled the request.
Your application is running in Production mode, so make sure it has been published, or that you have built your SPA manually. Alternatively you may wish to switch to the Development environment.
at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__1(HttpContext context, Func`1 next)
at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass0_1.<Use>b__1(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.TryServeStaticFile(HttpContext context, String contentType, PathString subPath)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass0_2.<Use>b__2()
at Microsoft.AspNetCore.SpaServices.SpaDefaultPageMiddleware.<>c__DisplayClass0_0.<Attach>b__0(HttpContext context, Func`1 next)
at Microsoft.AspNetCore.Builder.UseExtensions.<>c__DisplayClass0_1.<Use>b__1(HttpContext context)
at Microsoft.AspNetCore.Routing.EndpointMiddleware.Invoke(HttpContext httpContext)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Server.IIS.Core.IISHttpContextOfT`1.ProcessRequestAsync()
Il thread 0x30e8 è terminato con il codice 0 (0x0).
I experienced the same issue. Here is my resolution:
var spaStaticFileOptions = new StaticFileOptions
{
FileProvider = new Microsoft.Extensions.FileProviders.PhysicalFileProvider(System.IO.Path.Combine(env.ContentRootPath, "ClientApp/dist"))
};
app.UseSpaStaticFiles(spaStaticFileOptions);
app.UseSpa(spa =>
{
if (IsDevelopment(env))
spa.Options.SourcePath = "ClientApp/";
else
{
spa.Options.DefaultPageStaticFileOptions = spaStaticFileOptions;
//spa.Options.SourcePath = "dist";
}
if (IsDevelopment(env))
{
spa.UseVueCli(npmScript: "serve");
}
});
bool IsDevelopment(IWebHostEnvironment env)
{
return !IsProduction(env);
}
bool IsProduction(IWebHostEnvironment env)
{
return prodEnvironments.Contains(env.EnvironmentName);
}
I got this error when I was running my development website in a local IIS environment because IIS Express was unreliable and regularly went into a timeout. For the local IIS development application pool I used a custom local user account with what appeared to be insufficient access rights. I placed this account in the 'local admin group' and then after issuing the IISRESET cmd the error went away.
I know it is generally (very) bad practice to put application pool accounts in the local admin group but I only had to do this for the Development environment. I will update this answer when I get it to work with only 'Users' level access rights.

Error with IdentityServer when deploying asp.net Core REACT app to AWS Beanstalk

I have an asp.net core app with a React front-end that uses IdentityServer. It was created using the scaffold templates in Visual Studio 2019. The app works great locally, but fails when I deploy to an AWS beanstalk. The line of code it fails on is in the Configure method of my Startup.cs. app.UseIdentityServer().
Somewhere within UseIdentityServer() there is a null reference exception that is not visible to me, and I cannot reproduce when testing locally on my development machine.
Here is my Configure() method in Startup.cs:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
//app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSpaStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
//spa.UseReactDevelopmentServer(npmScript: "start"); // Starts CRA automatically
spa.UseProxyToSpaDevelopmentServer("http://localhost:3000"); // Must manually start CRA (yarn start)
}
});
}
}
There error I get when checking the AWS beanstalk logs looks like this:
Jan 1 00:36:57 ip-172-30-2-135 web: #033[41m#033[30mfail#033[39m#033[22m#033[49m: Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware[1]
Jan 1 00:36:57 ip-172-30-2-135 web: An unhandled exception has occurred while executing the request.
Jan 1 00:36:57 ip-172-30-2-135 web: System.NullReferenceException: Object reference not set to an instance of an object.
Jan 1 00:36:57 ip-172-30-2-135 web: at Microsoft.Extensions.DependencyInjection.IdentityServerBuilderConfigurationExtensions.<>c.b__10_2(IServiceProvider sp)
Jan 1 00:36:57 ip-172-30-2-135 web: at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context)
Jan 1 00:36:57 ip-172-30-2-135 web: at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor`2.VisitCallSiteMain(ServiceCallSite callSite, TArgument argument)
Has anybody run into this before? This is something that is specific to deploying to an AWS beanstalk. If I remove the UseIdentityServer() call, the app publishes and runs fine in AWS Beanstalk. I am publishing to a Linux beanstalk if that makes a difference. There must be something that needs to be configured differently with IdentityServer when deployed to Linux, or maybe something specific with AWS Beanstalk.
When running locally on my development machine, it is on Windows 10 in case that helps.
Edit: Adding ConfigureServices() method
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<BarristerContext>(options =>
options.UseNpgsql(
Configuration["Data:DefaultConnection:ConnectionString"]));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<BarristerContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Latest)
.AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeAreaFolder("Identity", "/Account/Manage");
options.Conventions.AuthorizeAreaPage("Identity", "/Account/Logout");
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = $"/Identity/Account/Login";
options.LogoutPath = $"/Identity/Account/Logout";
options.AccessDeniedPath = $"/Identity/Account/AccessDenied";
});
// using Microsoft.AspNetCore.Identity.UI.Services;
services.AddSingleton<IEmailSender, EmailSender>();
services.AddIdentityServer(options =>
{
options.UserInteraction = new UserInteractionOptions()
{
LogoutUrl = "/Identity/account/logout",
LoginUrl = "/Identity/account/login",
LoginReturnUrlParameter = "returnUrl"
};
}).AddApiAuthorization<ApplicationUser, BarristerContext>();
services.AddAuthentication().AddIdentityServerJwt();
services.AddControllersWithViews();
services.AddRazorPages();
// In production, the React files will be served from this directory
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "ClientApp/build";
});
//services.AddDatabaseDeveloperPageExceptionFilter();
}
I will also note, I am targeting .Net 5 on this deployment, which according to AWS, should work fine as long as I select "Build self contained deployment bundle" when I publish via the AWS Toolkit for Visual Studio.
https://aws.amazon.com/blogs/developer/aws-elastic-beanstalk-adds-net-core-on-linux-platform/
The difference between my local host and the AWS Beanstalk that was causing the error on the Beanstalk, was the Nginx proxy. I had to account for this by adding the following middleware in my ConfigureServices() method of my Startup.cs.
services.Configure<ForwardedHeadersOptions>(options =>
{
options.ForwardedHeaders =
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
});
This is due to:
When HTTPS requests are proxied over HTTP, the original scheme (HTTPS) is lost and must be forwarded in a header.
Because an app receives a request from the proxy and not its true source on the Internet or corporate network, the originating client IP address must also be forwarded in a header.
The following article gives more details: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/proxy-load-balancer?view=aspnetcore-5.0

Can't read swagger JSON file on ASP.NET Core 1.2 Application after hosting into local IIS

After hosting my asp.net core 1.2 application, I am getting an error as:
swagger is unable to find the swagger.json file.
I have tried to solve the problem by giving a virtual path name app.UseSwaggerUI() but it's not working.
Edit to clarify question based on comments:
After hosting Asp.net core application in IIS, the swagger.json file is generating on localhost:<random_port>/swagger/v1/swagger.json path.
How do I serve the swagger.json file on a custom route like:
localhost:<random_port>/virtualpathname/swagger/v1/swagger.json
I have tried to set a virtual path in app.UseSwaggerUI() like {virtualpathname}/swagger/v2/swagger.json but still it is not working
Could be a few reasons for this - one being that .Net Core doesnt serve static files by default (although looking at online examples this doesnt seem to be an issue).
If you havent already, try installing the package Microsoft.AspNetCore.StaticFiles and adding UseStaticFiles() in your Configure() method in Startup.cs with the following configuration. I dont think that the order is important, but this is the order I have mine running in a working app.
public void Configure(...)
{
// Enable middleware to serve static files (like .json)
app.UseStaticFiles();
//Enable middleware for your API
app.UseMvc();
// Enable middleware to serve generated Swagger as a JSON endpoint
app.UseSwagger();
// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "YourApp API V1");
});
}
You will also need SwaggerGen middleware configured in your ConfigureServices() method.
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new Info { Title = "api_name", Version = "1.0"});
});
Edit Based on comment - to serve swagger json on a custom route:
// Enable middleware to serve generated Swagger as a JSON endpoint on a custom endpoint
app.UseSwagger(c => c.RouteTemplate = "custom/swagger/{documentName}/swagger.json");
// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
// Using custom endpoint defined above
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/custom/swagger/v1/swagger.json", "YourApp API V1");
});
If you need to serve SwaggerUI on a custom route as well, then:
// Enable middleware to serve swagger-ui assets (HTML, JS, CSS etc.)
// Using custom endpoint defined above
// And serving UI on a custom route
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/custom/swagger/v1/swagger.json", "YourApp API V1");
c.RoutePrefix = "custom"; // serves UI on http://{domain}:{port}/custom/
});
I suggest you to perform the two next steps.
First, open your project web.config and enable stdoutLogEnabled. (Remember to create the folder logs on your application folder and give it proper permissions)
Second, make sure you're doing the right configuration. (https://learn.microsoft.com/en-us/aspnet/core/tutorials/web-api-help-pages-using-swagger)
Note: The first step is going to give you more details about the error you're facing.
In my case the issue was the virtual directory which I fixed by adding a relative path(../). In any case make sure you setup ConfigureServices first, then when Configure make sure everything is in order, UseSwagger should be before UseMvc and at the end UseSwaggerUI
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddSwaggerGen(c => {
c.SwaggerDoc("v1", new Swashbuckle.AspNetCore.Swagger.Info { Title = "Utility", Version = "v1" });
});
// initialize configuration
var conf = new ConfigurationHelper(Microsoft.DotNet.PlatformAbstractions.ApplicationEnvironment.ApplicationBasePath);
Configuration = conf.Configuration; // just in case
// inject the RestApiWrapperService as singleton into the services configuration
var restService = new RestApiWrapperService(conf);
services.AddSingleton<IRestApiWrapperService>(restService);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
app.UseSwagger();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
// app.UseMvc();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.UseSwaggerUI(s => {
s.RoutePrefix = "help";
s.SwaggerEndpoint("../swagger/v1/swagger.json", "Utility");
s.InjectStylesheet("../css/swagger.min.css");
});
Change the following on your startup.cs class:
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/swagger/v1/swagger.json", "MyService.API v1");
});
To
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint("/MyWebsiteName/swagger/v1/swagger.json",
"MyService.API v1");
});
[MyWebsiteName] being the name of application configured in IIS.
I happened to have a simple copy paste mistake!
see the first line in below code, the if statement env.IsDevelopment() is causing this section to not run when deployed to IIS. One option is to comment it out!
//if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger(c =>
{
c.RouteTemplate = "swagger/{documentName}/swagger.json";
});
app.UseSwaggerUI(c => {
c.RoutePrefix = "swagger";
c.SwaggerEndpoint("/swagger/v1/swagger.json", "StockOps.WebAPI v1");
});
}

Resources