How to configure MVC on a Blazor WebAssembly Hosted Solution - asp.net-mvc

I have a Blazor WebAssembly Hosted solution (Client and Server) setup with IdentityServer for Authentication. I am looking to do 2 things...
I would like to set up MVC on the Server since I am more comfortable with MVC. The idea for Server Side pages would be for things like Profile Management and accessing Content that I do not want to on the Client.
The Server Startup.cs currently has
public void ConfigureServices(IServiceCollection services)
{
....Condensed
services.AddControllersWithViews();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, DataContext dataContext)
{
.....Condensed
app.UseRouting();
app.UseIdentityServer();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
With MVC setup on the backend, how can I navigate to these pages from the Client?

When you create your WebAssembly solution, be sure to check the box "ASP.Net Core Hosted".
This will create three projects: Client, Shared, and Server.
In the server project you will find a Controllers folder. Go ahead and add a controller, such as DummyController.cs
namespace BlazorWASM4.Server.Controllers
{
[ApiController]
[Route("[controller]")]
public class DummyController : Controller
{
public IActionResult Index()
{
return View();
}
}
}
Then right-click on your controller method Index and click 'Add View'. Then implement the view (Index.cshtml) like this for example:
<h1>Dummy Page</h1>
Run the project and navigate to localhost:port/Dummy
You should see your new page get displayed.

Related

.net attribute routes not matched in production

I have a asp.net v6 mvc project with an spa front end that works fine in development. (Following the new pattern where my spa dev server has a proxy configuration to forward api requests to the .net app).
When I deploy this to IIS, my api routes (all beginning "api/") are no longer recognised, and all api requests are redirected to the fallback spa home page. What's going on ?
This is my Configure method, in Startup.cs
public void Configure(IApplicationBuilder builder, IWebHostEnvironment env)
{
...
builder.UseStaticFiles();
builder.UseRouting();
builder.UseEndpoints(endpoints =>
{
// I added this line to try and fix my problem. It's not necessary in dev, but still broken in prod.
endpoints.MapControllers();
// This was all I had in dev, but all my Controller actions have AspNetCore.Mvc Route attributes.
endpoints.MapControllerRoute(
name: "default",
pattern: "api/{controller}/{action=Index}/{id?}");
// I know this method is called and used, because if I change "index.html" everything breaks and I'm no longer redirected to my spa
endpoints.MapFallbackToFile("index.html");
});
}
Here is a controller...
using Microsoft.AspNetCore.Mvc;
[ApiController]
public class AllItemsController : ControllerBase
{
[Route("api/all-items")]
public ApiResponse<List<Item>, string> Get()
{

Disable prebuilt Razor UI pages after scaffolding identity

In VS2022, I started a new Razor page project with "Individual Accounts" selected as authenization type. I found that there are no identity-related code available for customization because they are prebuilt using the Razor UI. I want to customize the pages and so I generated the pages by the method suggested as below.
https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-6.0&tabs=visual-studio&viewFallbackFrom=aspnetcore-2.1
After that, I wanted to disable the registration page after creating my admin account. I selected "Exclude from project" to Register.chtml as shown below.
Surprisingly, I found that the prebuilt Razor UI pages are automatically used when the generated pages are excluded(I can still access and use the url /Identity/Account/Register). How can I disable the prebuilt Razor UI pages?
You can add app.Map middleware like below:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseRouting();
app.Map("/Identity/Account/Register", HandleRequest);
app.Map("/Identity/Account/Login", HandleRequest);
static void HandleRequest(IApplicationBuilder app)
{
app.Run(async context =>
{
context.Response.StatusCode = StatusCodes.Status404NotFound;
await context.Response.WriteAsync("404 Not Found");
});
}
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
When you include the UI package, you opt in to using all of it. You can selectively disable pages by scaffolding them and then returning a NotFoundResult from both the OnGet and OnPost methods, but that can be laborious. You can also use Authorization to prevent access to pages or folders by specifying an authorization policy that is never applied to users, or a non-existent role, for example:
[Authorize(Roles ="Does Not Exist")]
public class RegisterModel : PageModel
{
...
Or, if you no longer need the Identity UI at all, uninstall the package from your application.

create sub domains "sub.example.com" with .net core 5

i'm trying to create a sub domain for my website, something like "sub.example.com", i've been following a tutorial on youtube but it is not working, this is what i have done.
my startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddSingleton<SubdomainRouteTransformer>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseEndpoints(endpoints =>
{
endpoints.MapDynamicControllerRoute<SubdomainRouteTransformer>(
"{controller=Home}/{action=Index}/{id?}");
});
public class SubdomainRouteTransformer: DynamicRouteValueTransformer
{
public override async ValueTask<RouteValueDictionary> TransformAsync(
HttpContext httpContext,RouteValueDictionary values)
{
var host =httpContext.Request.Host.Value;
var subdomain = httpContext.Request.Host.Value.Split(".")[0];
if(!string.IsNullOrEmpty(subdomain)){
values["controller"]= subdomain;
}
return values;
}
}
program.cs
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
webBuilder.UseUrls("https://*.localhost:5001");
});
i have also registred new subdomains on my machine hosts file
127.0.0.1 admin.localhost
127.0.0.1 bugreport.localhost
i tried to create a break point on the TransformAsync method, it is getting hit by the compiler whenever i enter the normal URL address "https://localhost:5001".
when i enter sub domain address "https://admin.localhost:5001" TransformAsync method is never getting hit .
any help is appreciated
i've figured out this by myself, it seams like the solution above is working perfectly, the issue was with Safari, somehow the solution above did not work on it but it worked perfectly on chrome.
also another small detail is that you can skip the last step of setting the host file on your machine, the solution works without it.

Is it possible to config multiple routes with ODATA

I've created a project containing both MVC and WebAPI.
There's a MVC controller named HomeController which containing only one action named Index.
Also, there's a API controller named ValuesController.
Everything works fine without OData, I can access to both http://localhost/Home/Index and http://localhost/api/Values successfully.
However, after I changed some code to support OData, I'm failed to access to http://localhost/Home/Index. Below is the related code:
//startup.cs
public void ConfigureServices(IServiceCollection services) {
services.AddDbContext<ProductsContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDb");
});
//Adding OData middleware.
services.AddOData();
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider provider){
if (env.IsDevelopment()){
app.UseDeveloperExceptionPage();
}
//Adding Model class to OData
var builder = new ODataConventionModelBuilder(provider);
builder.EntitySet<ValuesEntity>("Values");
builder.EntityType<ValuesEntity>().Filter(QueryOptionSetting.Allowed).OrderBy(QueryOptionSetting.Allowed);
//Enabling OData routing.
app.UseMvc(routebuilder =>
{
routebuilder.MapODataServiceRoute("odata", "api", builder.GetEdmModel());
routebuilder.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
As you can see, there're multiple routes, but the default route seems never get used.
I can still access to the http://localhost/api/Values, but If I access to the http://localhost/Home/Index, the page will show me the error:
An unhandled exception occurred while processing the request.
ArgumentNullException: Value cannot be null.
Parameter name: routeName
Microsoft.AspNet.OData.Extensions.HttpRequestExtensions.CreateRequestScope(HttpRequest request, string routeName)

ASP.Net Visual Studio 2017 MVC routing view not opening on Azure/server yet does on IISExpress

I am new to ASP.Net MVC. I've searched and reviewed many answers but still can't find a solution.
I have an ASP.Net MVC application which behaves differently locally to when deployed. I get 404 not found when attempting to open the 'Companies\Index' view when deployed top Azure, and to other hosting provider, but it works when run locally in Visual Studio/IIS Express.
I am using the default routing provided by the initial 'new app wizard'. Is there anything I am missing which may mean I get 404 when hitting http:\myappname\Companies\Index or http:\myname\Companies?
Action I am trying click on to open new 'Companies' view...
#{
ViewData["Title"] = "Manage";
}
<h2>Manage</h2>
<p>Choose an item below to configure settings</p>
<div class="">
<ul>
<li>#Html.ActionLink("Companies", "Index", "Companies") </li>
</ul>
</div>
Directory structure of application in Visual Studio...
directory structure
Routing...
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
// Set default erorr handler page
app.UseExceptionHandler("/Error.html");
var configuration = new ConfigurationBuilder()
.AddEnvironmentVariables()
.AddJsonFile(env.ContentRootPath+ "/config.json")
.Build();
// Set Developer Exceptions on if in development mode
if (configuration.GetValue<bool>("FeatureToggles:EnableDeveloperExceptions"))
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
Controller Index action I am trying to invoke to return the Companies\Index view...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Daylight.Data;
using Daylight.Models;
namespace Daylight.Controllers
{
public class CompaniesController : Controller
{
private readonly DaylightDataContext _context;
public CompaniesController(DaylightDataContext context)
{
_context = context;
}
// GET: Companies
public async Task<IActionResult> Index()
{
return View(await _context.Companies.ToListAsync());
}
I'd be very grateful for any pointers!!
Turns out this was down to the website not being able to access the database, and therefore not able to return data to the view hence why the view appeared blank.

Resources