Use resource/language.resx in a class library to another project in ASP.NET CORE 6 - reference

I successfully managed to get Localization/Globalization setup on a project. But had resources in the main project. However, I wanted to move the resources to a class library. I moved them and have referenced the class library, changed the path in the Program.cs and set all the resx properties to "PublicResXFileCodeGenerator" but it's not working, what am I missing?
File structure:
Program.cs code:
using Microsoft.Extensions.Options;
using System.Globalization;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.Configure<RequestLocalizationOptions>(options =>
{
var cultures = new List<CultureInfo> {
new CultureInfo("en"),
new CultureInfo("es")
};
options.DefaultRequestCulture = new Microsoft.AspNetCore.Localization.RequestCulture("en");
options.SupportedCultures = cultures;
options.SupportedUICultures = cultures;
});
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources/Resources");
builder.Services.AddMvc()
.AddViewLocalization(Microsoft.AspNetCore.Mvc.Razor.LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseRequestLocalization(app.Services.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
I tried looking online for material but it's saying about linking files etc but mainly with winforms and not .NET6

Related

.NET Core API will not work on Azure App Service-The resource you are looking for has been removed,had its name changed,or is temporarily unavailable

I've deployed my API to an Azure App Service and get the error:
The resource you are looking for has been removed,had its name changed,or is temporarily unavailable.
any time I try to hit the endpoint of the only current operation in the API. All of the files have deployed correctly in the wwwroot folder and if I enter url/filename where url is the base url and filename is any of the files in the folder, I am able to download the file. The API works when run locally, hitting the operation returns the expected json result.
Running a trace gives the rather generic result:
System.NullReferenceException 2
Object reference not set to an instance of an object.
Stack Trace 1
mscorlib!System.Diagnostics.Tracing.EventSource.SendCommand
mscorlib!System.Diagnostics.Tracing.EventSource+OverideEventProvider.OnControllerCommand
mscorlib!System.Diagnostics.Tracing.EventProvider.EtwEnableCallBack
mscorlib!dynamicClass.IL_STUB_ReversePInvoke
The routes are configured correctly (in that it works locally) - the error implies that a related file is missing, however checking the folder in Kudu shows the files match the contents of the bin folder. Any ideas on what is going wrong here? Or how to determine what the missing resource is? Thanks for reading.
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddLogging(logging =>
{
logging.AddConsole();
logging.AddDebug();
});
services.AddDbContext<hidden>(options => options.UseSqlServer(Configuration.GetConnectionString("hidden")));
services.AddScoped<DbContext, hidden>();
services.AddScoped(typeof(IQuery<>), typeof(NoTrackingQuery<>));
services.AddScoped(typeof(IQuery<,>), typeof(NoTrackingQuery<,>));
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "Hidden", Version = "v1" });
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
// Expose logging where DI cannot be used
var loggerFactory = app.ApplicationServices.GetRequiredService<ILoggerFactory>();
LogManager.SetLogger(loggerFactory);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "Hidden v1"));
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
[ApiController]
[Route("[controller]")]
public class WidgetController : ControllerBase
{
private readonly IQuery<Category> _categories;
public WidgetController(IQuery<Widget> widgets)
{
_widgets = widgets;
}
[HttpGet]
public IEnumerable<Widget> Get()
{
return _widgets.QueryAll();
}
}
When you can run a solution locally, and not able to run it on Cloud, it means that you have misconfigured something.
Looking at the error message I suspect that the settings for Logging are not in place. Make sure that you put all required/consumed settings in Application Settings or Connection Strings.
Thanks singhh-msft. You were right and this was caused by using the incorrect publish task in the build pipeline. Updated to use dotnet Azure CLI publish command and the issue is resolved.

How to configure Application Insights sampling on Net Core HostBuilder?

I'm building .Net Core background service, using ApplicationInsights.WorkerService nuget package. The documentation regarding sampling configuration says to refer to this:
https://learn.microsoft.com/en-us/azure/azure-monitor/app/sampling#configure-sampling-settings
And it shows this:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, TelemetryConfiguration configuration)
{
var builder = configuration.DefaultTelemetrySink.TelemetryProcessorChainBuilder;
// For older versions of the Application Insights SDK, use the following line instead:
// var builder = configuration.TelemetryProcessorChainBuilder;
// Using adaptive sampling
builder.UseAdaptiveSampling(maxTelemetryItemsPerSecond:5);
// Alternately, the following configures adaptive sampling with 5 items per second, and also excludes DependencyTelemetry from being subject to sampling.
// builder.UseAdaptiveSampling(maxTelemetryItemsPerSecond:5, excludedTypes: "Dependency");
// If you have other telemetry processors:
builder.Use((next) => new AnotherProcessor(next));
builder.Build();
// ...
}
Now on HostBuilder I don't see any extension methods that would give me the TelemetryConfiguration, source code of the nuget doesn't have it either:
https://github.com/microsoft/ApplicationInsights-aspnetcore/blob/develop/NETCORE/src/Microsoft.ApplicationInsights.WorkerService/ApplicationInsightsExtensions.cs
So how do I get either TelemetryConfiguration or TelemetryProcessorChainBuilder on a HostBuilder? At the moment it looks like this:
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
services.AddApplicationInsightsTelemetryWorkerService();
});
You should use it as below:
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
services.Configure<TelemetryConfiguration>((config)=>
{
var builder = config.DefaultTelemetrySink.TelemetryProcessorChainBuilder;
builder.UseAdaptiveSampling(maxTelemetryItemsPerSecond: 5);
builder.Build();
}
);
// Your other code
});

MVC Core 2.1 Directory Browser some files not shown

I have an MVC core application that has some folders that allow browsing.
I have used the UseDirectoryBrowser in order to map shared folders and they do appear to be browsable, the problem is that not all files are shown (specifically the files with MSI extensions).
The files do appear when they first uploaded but then disappear after a refresh of page.
We migrated to azure recently and same code was previously used on different hosting provider where we did not ever had same problems.
Is there something i could look into ?
I cannot repro your issue, but here is what I did in my side which works well. You can compare with your code:
In Startup.cs -> ConfigureServices method, add this line of code services.AddDirectoryBrowser():
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.AddDirectoryBrowser();
}
In Startup.cs -> Configure method, add app.UseDirectoryBrowser(xxx):
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
RequestPath = "/MyImages"
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
RequestPath = "/MyImages"
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
After publish to azure, I can see all the files in images directory, even refresh many times:
It seems that the problem will only go away if PhysicalFileProvider receives an ExclusionFilters parameter equal to None. This makes the problem go away. Just in case some one else encounters it.

Setting up AAD Authentication in a Project with Autofac

I have a web API that has AAD auth (in code because it runs in IaaS not PaaS) it works well, but if I add Autofac configuration to the Startup.cs, the Authentication breaks, (if I put Autofac after Auth inizialization Autofac breaks) which makes me think that the configurations are overwriting eachother.
I have tried to find any documentation on how to use both of them together but I have not been able to find any information. One Uses HttpConfiguration and the other uses the IAppBuilder and I don't know how to combine them for them to work together.
here is my Authentication code:
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.Map("/api", inner =>
{
inner.UseWindowsAzureActiveDirectoryBearerAuthentication(new WindowsAzureActiveDirectoryBearerAuthenticationOptions()
{
Tenant = tenant,
TokenValidationParameters = new Tokens.TokenValidationParameters
{
ValidAudience = Audience
}
});
});
}
and here is the Autofac Code
public static void Register(HttpConfiguration configuration)
{
var builder = new ContainerBuilder();
Bootstrapper.Configure(builder);
var container = builder.Build();
configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
}
what are the best practices for using these two tools together?
I was not properly setting all the WebAPI autofac references to get all the dependencies I followed this Quick start and then Added my references. Bellow is the new ConfigureAutofac function (the configure auth stayed the same)
private void ConfigureAutofac(IAppBuilder app)
{
//Autofac info from https://autofaccn.readthedocs.io/en/latest/integration/webapi.html#quick-start
var builder = new ContainerBuilder();
// STANDARD WEB API SETUP:
// Get your HttpConfiguration. In OWIN, you'll create one
// rather than using GlobalConfiguration.
var config = new HttpConfiguration();
// Register your Web API controllers.
builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); //Register WebApi Controllers
builder.RegisterType<AutofacManager>().As<IAutofacManager>();
builder.RegisterSource(new AnyConcreteTypeNotAlreadyRegisteredSource());
var container = builder.Build();
config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver((IContainer)container); //Set the WebApi DependencyResolver
// and finally the standard Web API middleware.
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(config);
app.UseWebApi(config);
}

Functioning App on local server fails on Azure

I have an Angular Web app with an API that is functioning perfectly (well, as perfectly as any app under development functions) on my local server, but when I migrate it and its associated databases to an App Service on Azure every /api call fails with 500.
So thinking that the problem was with the databases I altered the connection strings on my local development server to point to the Azure databases. I found one small problem this way, I has mispelled the username in the connection string. SO I fixed that and it runs perfectly on my local server while accessing the Azure databases, but as soon as I run it on the Azure App Service using the same connection strings every call to /api fails with Internal Server Error 500.
All regular pages are served perfectly and Angular routing works just fine. Only accessing content from the DB fails. I have been at this for a few days and have no idea what to do next. Any advice welcomed.
I am using OpenIddict for authentication so I tagged that, but I can't see anyway that is relevant. Oddly though, and there is a clue here somewhere, the authentication call to "/connect/token" works and returns a valid token, but "/api/..." URLs do not.
I am using Asp Net Core 2.1 if that is relevant.
More Information
I tried the detailed logs as suggested, but they were hardly detailed. But I did note one interesting item. In the error there was the following information:
Requested URL: https://mysite.azuurewebsites.net/api/accounts/getusers
Physical Path: D:\home\site\wwwroot\api\accounts\getusers
Now this app is using MVC so there is no such Physical Path. The Controller is decorated with:
[Route("api/accounts")]
and the Action is decorated as:
[Authorize(Roles = "Somerole")]
[HttpGet("GetUsers"), Produces("application/json")]
It seems to me the route mapping is failing. But this works beautifully on my local development computer. What could be different on the Azure App Service? Is there some special setting I need to set in the portal to allow MVC? I can't imagine why the portal should care about such matters.
Even More Information
Using Postman, if I access /api/someValidUrl with a valid Bearer token I get a 500 error. If I remove the Authorization header then I get a 401 returned.
I started off by saying I didn't think it had anything to do with OpenIddict, but maybe I was wrong. My Authorization Controller simply creates the token. All the checking for validity is done by OpenIddict.
A Huge Clue
I added an ExceptionHandler and then used Postman to make an API request and that yielded the following exception:
<h1>Error: IDX20803: Unable to obtain configuration from: '[PII is hidden by default. Set the 'ShowPII' flag in IdentityModelEventSource.cs to true to reveal it.]'.</h1>
at Microsoft.IdentityModel.Protocols.ConfigurationManager`1.GetConfigurationAsync(CancellationToken cancel)
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler.HandleAuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.AuthenticateAsync()
at Microsoft.AspNetCore.Authentication.AuthenticationService.AuthenticateAsync(HttpContext context, String scheme)
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.Invoke(HttpContext context)
at Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware.Invoke(HttpContext context)
I found an explanation here but I don't fully understand this but it looks as though MS middleware on Azure is incorrectly trying to interpret it as an Azure AD request. The only thing I know for sure is I do not have a file called IdentityModelEventSource.cs in my project.
For reference https://mywebsite.azurewebsites.net/.well-known/openid-configuration returns:
{
"issuer": "https://mywebsite.azurewebsites.net/",
"token_endpoint": "https://mywebsite.azurewebsites.net/connect/token",
"jwks_uri": "https://mywebsite.azurewebsites.net/.well-known/jwks",
"grant_types_supported": [
"password"
],
"scopes_supported": [
"openid",
"email",
"profile",
"roles"
],
"claims_supported": [
"aud",
"exp",
"iat",
"iss",
"jti",
"sub"
],
"subject_types_supported": [
"public"
],
"token_endpoint_auth_methods_supported": [
"client_secret_basic",
"client_secret_post"
],
"claims_parameter_supported": false,
"request_parameter_supported": false,
"request_uri_parameter_supported": false
}
Perhaps with this information someone can point me in the right direction.
New Startup.cs
I took Pinpoint's advice and changed from JWT. The new Startup follows:
using AspNet.Security.OpenIdConnect.Primitives;
using Microsoft.AspNetCore.Builder;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using SIAngular.DBContexts;
using SIAngular.Models;
using SIAngular.Services;
using OpenIddict.Abstractions;
using Microsoft.IdentityModel.Tokens;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Identity;
using System;
using Microsoft.Extensions.Logging;
namespace SIAngular
{
public class Startup
{
private readonly IHostingEnvironment env;
public Startup(IHostingEnvironment env, IConfiguration configuration)
{
Configuration = configuration;
this.env = env;
SIDBConnectionString = Configuration.GetConnectionString("SIDB");
}
public static string SIDBConnectionString;
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
SymmetricSecurityKey _ssk = new SymmetricSecurityKey(Convert.FromBase64String(Configuration["Jwt:Key"]));
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("SqlConnection"));
options.UseOpenIddict();
});
services.AddCors();
// Register the Identity services.
services.AddIdentityCore<ApplicationUser>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
config.Password.RequireDigit = true;
config.Password.RequiredLength = 8;
config.Password.RequireLowercase = true; config.Password.RequireNonAlphanumeric = true;
config.User.RequireUniqueEmail = true;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders()
.AddRoleValidator<RoleValidator<IdentityRole>>()
.AddRoleManager<RoleManager<IdentityRole>>()
.AddSignInManager<SignInManager<ApplicationUser>>();
// Configure Identity to use the same JWT claims as OpenIddict instead
// of the legacy WS-Federation claims it uses by default (ClaimTypes),
// which saves you from doing the mapping in your authorization controller.
services.Configure<IdentityOptions>(options =>
{
options.ClaimsIdentity.UserNameClaimType = OpenIdConnectConstants.Claims.Name;
options.ClaimsIdentity.UserIdClaimType = OpenIdConnectConstants.Claims.Subject;
options.ClaimsIdentity.RoleClaimType = OpenIdConnectConstants.Claims.Role;
});
services.AddOpenIddict()
// Register the OpenIddict core services.
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and models.
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
})
// Register the OpenIddict server services.
.AddServer(options =>
{
// Register the ASP.NET Core MVC services used by OpenIddict.
// Note: if you don't call this method, you won't be able to
// bind OpenIdConnectRequest or OpenIdConnectResponse parameters.
options.UseMvc();
// Enable the token endpoint.
options.EnableTokenEndpoint("/connect/token");
options.AcceptAnonymousClients();
options.DisableScopeValidation();
// Note: the Mvc.Client sample only uses the code flow and the password flow, but you
// can enable the other flows if you need to support implicit or client credentials.
options.AllowPasswordFlow();
// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(OpenIdConnectConstants.Scopes.Email,
OpenIdConnectConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
// During development, you can disable the HTTPS requirement.
if (env.IsDevelopment())
options.DisableHttpsRequirement();
options.AddSigningKey(_ssk);
})
.AddValidation();
services.AddSingleton<IConfiguration>(Configuration);
services.AddScoped<IPasswordHasher<ApplicationUser>, SqlPasswordHasher>();
services.AddMvc();
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
app.UseCors(builder =>
builder.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
);
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
//app.UseWebpackDevMiddleware(new Microsoft.AspNetCore.SpaServices.Webpack.WebpackDevMiddlewareOptions { HotModuleReplacement = true });
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
app.MapWhen(x => !x.Request.Path.Value.StartsWith("/api"), builder =>
{
builder.UseMvc(routes =>
{
routes.MapSpaFallbackRoute(
name: "spa-fallback",
defaults: new { controller = "Home", action = "Index" });
});
});
}
}
}
Now the problem is an exception:
InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.

Resources