I need to open both web pages and API in a single project. But I have difficulty with the route. I am not able to independently set route requests with mapwhen. First route; I route all language dependent requests to a single controller. This is for my web pages. The second is the default api route.
This My middlewareExtension
public static class WebBuilderMiddlewaresExtension
{
public static IApplicationBuilder UseWebBuilderMiddlewares(this IApplicationBuilder builder)
{
builder.MapWhen(context => context.Request.Path.StartsWithSegments("/api"), appBuilder =>
{
builder.UseRouting();
builder.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}");
});
});
builder.MapWhen(context => context.Request.RouteValues["culture"] != null || string.IsNullOrEmpty(context.Request.Path), appBuilder =>
{
builder.UseRouting();
builder.UseMiddleware<LanguageMiddleware>();
builder.UseMiddleware<RouteMiddleware>();
builder.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "culture-route",
pattern: "{culture=tr-TR}/{*default}",
defaults: new { culture = "tr-TR", controller = "Home", action = "Index" }
);
});
});
return builder;
}
This is my startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
using (var client = new WebBuilderContext())
{
client.Database.EnsureCreated();
}
}
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.AddControllersWithViews()
.AddRazorRuntimeCompilation(); ;
services.AddLocalization(opts => opts.ResourcesPath = "Resources");
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("tr-TR"),
new CultureInfo("en-US"),
};
// Dil ayarlarını ve varsayılan dil seçimini tanımlıyoruz.
var localizationOptions = new RequestLocalizationOptions
{
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
DefaultRequestCulture = new RequestCulture("tr-TR"),
};
var requestProvider = new RouteDataRequestCultureProvider();
localizationOptions.RequestCultureProviders.Insert(0, requestProvider);
services.AddScoped<UiDataService>();
services.AddDbContext<WebBuilderContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DeveloperMsSql")));
services.AddSession(options => {
options.Cookie.Name = "Language";
options.IdleTimeout = TimeSpan.FromMinutes(30); // Zamanı ayarlayabilirsiniz
});
}
// 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("/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.UseSession();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseWebBuilderMiddlewares();
For api route in .net core,you need to use Route Attribute.
Here is a sample(I add an api to .net core mvc):
[ApiController]
[Route("api/[controller]")]
public class ApiController : ControllerBase
{
[HttpGet]
[Route("Get")]
public async Task<IActionResult> Get()
{
return Ok();
}
}
result:
and change mvc route,you can change it in startup.cs:
Configure:
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
Related
I created asp.net core with React template in VS 2019, i need to authorize a controller method so I first registered my app on Azure AD and than i used this Startup.cs configurations:
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.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
services.AddControllersWithViews().AddMicrosoftIdentityUI();
// 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.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
In the controller I used AuthorizeForScopes and ITokenAcquisition as follows
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ITokenAcquisition tokenAcquisition;
public WeatherForecastController(ITokenAcquisition tokenAcquisition)
{
this.tokenAcquisition = tokenAcquisition;
}
[AuthorizeForScopes(Scopes = new[] { "https://tenantname.sharepoint.com/AllSites.FullControl" })]
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(new[] { "https://tenantname.sharepoint.com/AllSites.FullControl" });
......
......
}
}
but when i try to fetch the data i have a CORS error
Can you help me
Regarding the issue, please refer to the following steps
Register client application and server application
Use React project template with ASP.NET Core
Client application
a. Install msal
npm install msal
b. Define MsalAuthProvider.
import React, { Component } from 'react';
import { UserAgentApplication } from 'msal';
const msalConfig = {
authority: 'https://login.microsoftonline.com/common',
clientId: '232a1406-b27b-4667-b8c2-3a865c42b79c',
redirectUri: document.getElementById('root').baseURI
};
export const msalAuth = new UserAgentApplication({
auth: msalConfig
});
export function withAuth(HocComponent) {
return class extends Component {
constructor(props) {
super(props);
this.state = {
isAuthenticated: false,
user: {},
renewIframe: false,
hasError: false,
errorMessage: null
};
}
async componentWillMount() {
msalAuth.handleRedirectCallback(() => {
let userAccount = msalAuth.getAccount();
this.setState({
isAuthenticated: true,
user: userAccount
});
}, (authErr, accountState) => { // on fail
console.log(authErr);
this.setState({
hasError: true,
errorMessage: authErr.errorMessage
});
});
if (msalAuth.isCallback(window.location.hash)) {
this.setState({
auth: {
renewIframe: true
}
});
return;
}
let userAccount = msalAuth.getAccount();
if (!userAccount) {
msalAuth.loginRedirect({});
return;
} else {
this.setState({
isAuthenticated: true,
user: userAccount
});
}
}
onSignIn() {
msalAuth.loginRedirect({});
}
onSignOut() {
msalAuth.logout();
}
render() {
if (this.state.renewIframe) {
return <div>hidden renew iframe - not visible</div>;
}
if (this.state.isAuthenticated) {
return <HocComponent auth={this.state} onSignIn={() => this.onSignIn()} onSignOut={() => this.onSignOut()} {...this.props} />;
}
if (this.state.hasError) {
return <div>{this.state.errorMessage}</div>;
}
return <div>Login in progress...</div>;
}
};
}
c. Update App.js
import { withAuth } from './msal/MsalAuthProvider';
import './custom.css'
class RootApp extends Component {
static displayName ="Azure AD application";
render () {
return (
<Layout>
...
</Layout>
);
}
}
//enable auth when we access the page
const App = withAuth(RootApp)
export default App;
call the API
import { msalAuth } from '../msal/MsalAuthProvider'
async componentDidMount() {
// get token and call the api
try {
const accessTokenRequest = {
scopes: ["api://872ebcec-c24a-4399-835a-201cdaf7d68b/access_as_user"]
}
var authRes
var accessToken = null;
try {
authRes = await msalAuth.acquireTokenSilent(accessTokenRequest);
accessToken=authRes.accessToken
}
catch (error) {
console.log("AquireTokenSilent failure");
authRes = await msalAuth.acquireTokenPopup(accessTokenRequest);
accessToken = authRes.accessToken
}
console.log(accessToken)
this.populateWeatherData(accessToken);
}
catch (err) {
var error = {};
if (typeof (err) === 'string') {
var errParts = err.split('|');
error = errParts.length > 1 ?
{ message: errParts[1], debug: errParts[0] } :
{ message: err };
} else {
error = {
message: err.message,
debug: JSON.stringify(err)
};
}
this.setState({
user: {},
isLoading: false,
error: error
});
}
}
async populateWeatherData(token) {
const response = await fetch('weatherforecast', {
method: 'get',
headers: new Headers({
'Authorization': 'Bearer ' + token
})
});
const data = await response.json();
this.setState({ forecasts: data, loading: false });
}
Server code
a. Startup.cs
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.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddInMemoryTokenCaches();
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.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
});
app.UseSpa(spa =>
{
spa.Options.SourcePath = "ClientApp";
if (env.IsDevelopment())
{
spa.UseReactDevelopmentServer(npmScript: "start");
}
});
}
}
b. Controller
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
private readonly ITokenAcquisition tokenAcquisition;
public WeatherForecastController(ITokenAcquisition tokenAcquisition)
{
this.tokenAcquisition = tokenAcquisition;
}
[AuthorizeForScopes(Scopes = new[] { "<your scope>" })]
[HttpGet]
public async Task<IEnumerable<WeatherForecast>> Get()
{
string accessToken = await tokenAcquisition.GetAccessTokenForUserAsync(new[] { "<your scope>" });
......
......
}
}
For more details, please refer to here snd here.
I have a very strange issue.
Suddenly, when I start debugging on my project, I am redirected to Home/Error instead of Home/Index
without any apparent error or message.
The application is very simple because I just created it today.
This is my startup:
public Startup(IConfiguration configuration)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.SystemDefault;
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.AddSingleton<IConfiguration>(Configuration);
services.Configure<GzipCompressionProviderOptions>(options => options.Level = CompressionLevel.Optimal);
services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
options.Providers.Add<GzipCompressionProvider>();
});
// Without AddNewtonsoftJson actions that receive JSON Objects Body will return error 406
services.AddControllersWithViews().AddNewtonsoftJson();
services.AddSingleton<ITempDataProvider, CookieTempDataProvider>();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(60);
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddHttpContextAccessor();
services.AddTransient<IElasticsearchService, ElasticsearchService>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseHttpsRedirection();
// Enable compression (must be before UseStaticFiles)
app.UseResponseCompression();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
And this is (the only one for now) my controller:
public HomeController(ILogger<HomeController> logger, IHttpContextAccessor httpContextAccessor, IElasticsearchService elasticsearchService)
: base (logger, httpContextAccessor, elasticsearchService) { }
public async Task<IActionResult> Index(Dictionary<string, string> #params)
{
// some code
return View();
}
public IActionResult Privacy()
{
return View();
}
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
public IActionResult Error()
{
string errorMessage = string.Empty;
if (TempData["ErrorMessage"] != null)
{
errorMessage = TempData["ErrorMessage"].ToString();
TempData["ErrorMessage"] = null;
}
ViewBag.ErrorMessage = errorMessage;
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
I think I solved the problem on my own, maybe the issue was, that I used a RedirectToPermanent() on my Index and from then on, it always redirect me on Error.
I cleaned the cache and the temporary files and now it seems to work.
how to change domain name, controller name according to culture on a site
for asp.net core 3.0
Urls:
/tr/anasayfa/index
/en/home/index
/fr/maison/index
There will be a single controller that will be three and will respond to more
public class HomeController : Controller
{
public IActionResult Index()
{
return View();
}
}
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(opts => opts.ResourcesPath = "Resources");
services.Configure<RequestLocalizationOptions>(options =>
{
var supportedCultures = new[]{
new CultureInfo("tr"),
new CultureInfo("fr"),
new CultureInfo("en"),
};
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
});
services
.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix);
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.UseRequestLocalization();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(name: "culture-route",
pattern: "{culture=tr}/{controller=Home}/{action=Index}/{id?}");
});
}
I'm working on a ASP.Net Core 2.1 site with Razor pages, first time I've used Razor pages. But what I'd like to do is change the home or landing page. So if a user is not logged in The site should redirect to the /Account/Login page in the Areas folder, but if the user is logged in it should go to a page called DataManagement as shown below in the pages folder.
I've already got the Identity sewn in and I've tried something like below in Configure Services :
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AddAreaPageRoute("Identity", "/Account/Login", "");
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
And in the configure method :
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
To no avail.
EDIT
My StartUp.cs
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.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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("Connection")));
services.AddIdentity<ApplicationUser, ApplicationRole>(
options => options.Stores.MaxLengthForKeys = 128)
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultUI()
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc().AddRazorPagesOptions(opts =>
{
opts.Conventions.AddPageRoute("/DataManagement", "/");
opts.Conventions.AddPageRoute("/DataManagement", "home");
opts.Conventions.AddPageRoute("/DataManagement", "index");
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ApplicationDbContext context, RoleManager<ApplicationRole> roleManager, UserManager<ApplicationUser> userManager, IServiceProvider serviceProvider)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc();
}
The simplest way to do this would just to use the [Authorize] attribute on your DataManagement.cshtml.cs file.
[Authorize]
public class DataManagementModel : PageModel
{
public void OnGet()
{
}
}
Just configure your default Homepage as usual in Startup.cs:
services.AddMvc().AddRazorPagesOptions(opts =>
{
opts.Conventions.AddPageRoute("/DataManagement", "/");
opts.Conventions.AddPageRoute("/DataManagement", "home");
opts.Conventions.AddPageRoute("/DataManagement", "index");
opts.Conventions.AddAreaPageRoute("Account", "/Login", "/Account/Login");
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/Account/Login";
});
and in Configure :
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
Then remove the Index.cshtml
I think in this case you need to define custom login as above, taken from here
i have ASP.NET core project and in this project i want Implement multi-language application.
for my problem i check this question Views are localized but resources are not found but I did not find the right answer.
the question referred is about localized views and with different config .
so this is my code and couldn't find localize resources file in controller
Resource file location:
/Resources/Controllers/HomeController.fa.resx
Startup:
public class Startup
{
.....
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(o => { o.ResourcesPath = "Resources"; });
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
.....
app.UseStaticFiles();
IList<CultureInfo> supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-US"),
new CultureInfo("fa-IR"),
};
var options = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("fa-IR"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
app.UseRequestLocalization(options);
....
}
.....
}
HomeController:
public class HomeController : Controller
{
.....
private readonly IStringLocalizer<HomeController> _stringLocalizer;
public HomeController(IStringLocalizer<HomeController> stringLocalizer)
{
_stringLocalizer = stringLocalizer;
}
public IActionResult About()
{
ViewData["Message"] = _stringLocalizer["Hello"];
return View();
}
.....
}
this is my test :
Eventually After 3 Hours I was able to solve this problem, to fix this problem, the following changes are required:
startup :
public class Startup
{
......
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddLocalization(o => { o.ResourcesPath = "Resources"; });
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
app.UseRequestLocalization();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
IList<CultureInfo> supportedCultures = new List<CultureInfo>
{
new CultureInfo("en-US"),
new CultureInfo("fa-IR"),
};
var options = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture("fa-IR","fa-IR"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
};
app.UseRequestLocalization(options);
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
my resource name and path changes like this figure :
and the result of this changes :