Reputation: 4068
I'm having problems with routing, it looks like it thinks query parameters are view names, for some reason.
Config:
public static IServiceCollection AddAssetsSites(this IServiceCollection services, IConfiguration configuration, Action<MvcOptions> mvcOptions = default, params IAppFeatureBase[] features)
{
Identity ident = features.Exists(feat => feat.Type == AppFeatures.Identity) ? (Identity)features.Single(feat => feat.Type == AppFeatures.Identity) : new Identity(default, default);
if (configuration.GetSection(AssetsStatics.ConfigSectionName).Exists())
{
IAssetsConfig cnf = new AssetsConfig(configuration);
configuration.Bind(AssetsStatics.ConfigSectionName, cnf);
services
.AddOptions()
.Configure<IConfiguration>(configuration)
.AddTransient<IAssetsConfigAccessor, AssetsConfigAccessor>()
.AddSingleton(cnf);
}
else
{
throw new ConfigSectionNotFoundException();
}
services
.AddDbContext<AssetsDBContext>(opt => opt.UseSqlServer(AssetsStatics.ConnectionString))
.AddTransient<IAssetsDBContext, AssetsDBContext>()
.AddDbContext<AssetsIdentityDBContext>(opt => opt.UseSqlServer(AssetsStatics.ConnectionString))
.AddTransient<IAssetsIdentityDBContext, AssetsIdentityDBContext>()
.AddTransient<IAssetsDBContextAccessor, AssetsDBContextAccessor>()
.AddHttpContextAccessor()
.AddTransient<IActionContextAccessor, ActionContextAccessor>();
services
.AddTransient<IRepoFactory, RepoFactory>()
.AddTransient<IServiceAccessFactory, ServiceAccessFactory>()
.AddTransient<IQueryableExpressionFactory, QueryableExpressionFactory>()
.AddTransient<IQueriesFactory, QueriesFactory>();
services
.AddIdentity<User, Role>(ident.IdentOptions)
.AddUserManager<UserManager<User>>()
.AddRoleManager<RoleManager<Role>>()
.AddSignInManager<SignInManager<User>>()
.AddEntityFrameworkStores<AssetsIdentityDBContext>()
.AddDefaultTokenProviders().Services.ConfigureApplicationCookie(ident.CookieOptions)
.AddTransient<IIdentityRepo, IdentityRepo>();
if (features.Exists(feat => feat.Type == AppFeatures.SSL))
{
SSL ssl = (SSL)features.Single(feat => feat.Type == AppFeatures.SSL);
services
.AddHttpsRedirection(conf =>
{
conf.HttpsPort = ssl.Port;
});
}
services
.AddAssetsRepos()
.AddTransient<ITagHelperRepo, TagHelperRepo>()
.AddTransient<ISitesHelper, SitesHelper>()
.Configure<CookiePolicyOptions>(opt =>
{
opt.CheckConsentNeeded = context => true;
opt.MinimumSameSitePolicy = SameSiteMode.Unspecified;
})
.AddSession(opt =>
{
opt.IdleTimeout = TimeSpan.FromMinutes(180);
});
if (features.Exists(cnf => cnf.Type == AppFeatures.Localization))
{
Localization local = (Localization)features.Single(cnf => cnf.Type == AppFeatures.Localization);
services
.AddControllersWithViews(mvcOptions)
.AddDataAnnotationsLocalization()
.AddViewLocalization(opt =>
{
opt.ResourcesPath = local.ResourcePath;
})
.SetCompatibilityVersion(CoreStatics.DefaultCompatibilityVersion);
}
else
{
services
.AddControllersWithViews(mvcOptions)
.SetCompatibilityVersion(CoreStatics.DefaultCompatibilityVersion);
}
return services;
}
public static IApplicationBuilder UseAssetsSites(this IApplicationBuilder app, IConfiguration configuration, params IAppFeatureBase[] features)
{
if (features.Exists(feat => feat.Type == AppFeatures.Debug))
{
Debug dg = (Debug)features.Single(feat => feat.Type == AppFeatures.Debug);
if (dg.Environment.IsDevelopment() || dg.IgnoreEnvironment)
{
app.UseDeveloperExceptionPage();
}
}
if (features.Exists(feat => feat.Type == AppFeatures.SSL))
{
app.UseHttpsRedirection();
}
app
.UseStaticFiles()
.UseRouting()
.UseSession()
.UseCookiePolicy(new CookiePolicyOptions
{
CheckConsentNeeded = context => true,
MinimumSameSitePolicy = SameSiteMode.None
});
if (features.Exists(feat => feat.Type == AppFeatures.Localization))
{
Localization local = (Localization)features.Single(feat => feat.Type == AppFeatures.Localization);
app.UseRequestLocalization(opt =>
{
opt.DefaultRequestCulture = local.DefaultCulture;
opt.SupportedCultures = local.SupportedCultures.ToList();
opt.SupportedUICultures = local.SupportedCultures.ToList();
});
}
if (features.Exists(feat => feat.Type == AppFeatures.DefaultRoute))
{
DefaultRoute route = (DefaultRoute)features.Single(feat => feat.Type == AppFeatures.DefaultRoute);
app.UseEndpoints(opt =>
{
opt.MapControllerRoute("default", route.Route);
});
}
else
{
app.UseEndpoints(opt => opt.MapDefaultControllerRoute());
}
return app;
}
}
Controller:
public async Task<IActionResult> Index()
{
return View();
}
[Route("[controller]/[action]/{err?}")]
public async Task<IActionResult> Error([FromRoute(Name = "err")] string err)
{
return View(err);
}
Link:
url = Url.Action("Error", new { err = "missing" });
which generates: /Home/Error/creds
when the Error views loads I get:
InvalidOperationException: The view 'creds' was not found. The following locations were searched: /Views/Home/creds.en-US.cshtml /Views/Home/creds.en.cshtml /Views/Home/creds.cshtml /Views/Shared/creds.en-US.cshtml /Views/Shared/creds.en.cshtml /Views/Shared/creds.cshtml
Folder structure:
Views
-Assets
* Index.cshtml
-Home
* Error.cshtml
* Index.cshtml
-Shared
* _Layout.cshtml
-System
* Index.cshtml
* _ViewImports.cshtml
* _ViewStart.cshtml
Upvotes: 0
Views: 508
Reputation: 533
As suspected. Returning View(string viewname)
searches your Views
Folder with the pattern Views/ControllerName/ViewName.cshtml
.
By adding the string parameter err
You are telling it to find the creds.cshtml file in Views/Home/creds.cshtml
(Assuming your Controllername is Home) (Hence the error message that states it doesnt exist).
If you wish to display the Error.cshtml a simple return View();
is enough because by default it will search for the *.cshtml file which matches the name of the action (i.e. Error.cshtml)
Some documentation: https://learn.microsoft.com/de-de/aspnet/core/mvc/views/overview?view=aspnetcore-3.1
EDIT
For passing the route parameter to the Error View you can either pass it via a model.
[Route("[controller]/[action]/{err?}")]
public async Task<IActionResult> Error([FromRoute(Name = "err")] string err)
{
var errorModel = new ErrorModel(errorMessage: err);
return View(errorModel);
}
Or a without a Model using the dynamic ViewBag
[Route("[controller]/[action]/{err?}")]
public async Task<IActionResult> Error([FromRoute(Name = "err")] string err)
{
ViewBag.ErrorMessage = err;
return View();
}
On the Error.cshtml you can then access the ViewBag.ErrorMessage and show it in div or something
Upvotes: 1