What is the ASP.NET Core convention for static, non-MVC pages? - asp.net-core

I'm converting my website from Web Forms to .NET Core. I don't want to change the directory level of various files, e.g.:
MYDOMAIN.com/FAQ.html
MYDOMAIN.com/Privacy.html
By using the UseStaticFiles() middleware, I can place these in the wwwroot folder and they will be served as is. However, I don't know how to apply a Layout page with my website theme to those files since they're outside of the MVC framework.
I'd like to leverage the Layout files and MVC framework by using .cshtml files, but I'm also trying to avoid the extra controller directory that's imposed on the URL:
MYDOMAIN.com/home/FAQ.html
MYDOMAIN.com/home/Privacy.html
Maybe this is short-sighted, but how do developers handle this?
And actually, my existing files are .aspx at the moment, not .html files so that adds another level of confusion as to what the convention is for migrating to .Net Core. Should I use any .aspx files anywhere in the project or should they all be converted to .cshtml / .html files? Or something else?

I have successfully implemented a solution, but it's kind of a hack. I add controllers for each static page, for example I created both a FAQController.cs and PrivacyController.cs.
Each controller has only Index() actions so that they can take advantage of _Layout.cshtml and _ViewStart.cshtml.
It seems like a roundabout way to go just to move the following up one level e.g.
MYDOMAIN.com/FAQ
MYDOMAIN.com/Privacy
but it works.

Related

How to host Blazon in Razor Pages application

The "standard" Blazor WASM application is hosted inside a static HTML page; e.g., index.html. Due to certain requirements, I want to host Blazor inside a Razor pages application.
What I did is starting from a "standard" Blazor WASM application, removed the static files, because I do not need them, moved the content of index.html to the Wasm.cshtml, and change endpoints.MapFallbackToFile("index.html"); to endpoints.MapFallbackToPage("/Wasm");.
Everything seemed to be working as expected; I can run the application and navigate to the different pages I have in Blazor.
However, things fall apart when I try to access a page using its URL; e.g., http://mysite/counter, where /counter is a page in Blazor, and I get the following error:
An unhandled exception occurred while processing the request.
AmbiguousMatchException: The request matched multiple endpoints. Matches:
/Wasm
/Wasm
Can someone help me identify what I am doing wrong?
P.S.:
I looked at some answer here, but all that I found is people talking about Blazor Server.
I am using .NET 3.1 and Blazor 3.2.
I want to use my Razor Pages application to host/serve Blazor WASM not mixing them in a single project. They as still 2 different projects.
I am totally aware that Blazor WASM and Razor Pages are unrelated technologies. I am not trying to integrate them. I am only trying to server Blazor WASM files from a dynamic page. If it makes you think better about what I am trying to achieve, think about Razor Pages as any server-side technology; PHP, Node, or whatever, then apply this to the routing issue that I am trying to resolve.
OK, based on what you've written so far take a look at ShaunCurtis/Blazor-Experimental on Github. It's a temporary Repo for some experimental code. Ignore BlazorTest. The startup project is Blazor-Experimental.
The default page is a normal razor page. It's a mixed Razor, Blazor Server and Blazor WASM site. All the WASM routes look like wasm/fetchdata, so we have different URLs for all the Server and WASM "Pages".
Startup differentiates URLs using multiple endpoints, so any URL that is in the "scope" of the Blazor WASM application gets set to _wasm.cshtml. Anything else that can't be mapped directly is in the "scope" of the Blazor Server Application at _host.cshtml. All plan Razor pages on the site get served as is. You don't need the Blazor Server bit at all, just fallback to the default Razor page.
endpoints.MapFallbackToPage("/wasm/{**segment}", "/_wasm");
endpoints.MapFallbackToPage("/_Host");
To summarise the answer:
Create a Blazor WASM project. You can copy the one from Blazor Hosted template.
Reference the project from the Razor Pages project.
Create the page that will host Blazor WASM; e.g., Wasm.cshtml, and make sure the page route is not set; i.e., only #page at the top of the page, so that it takes the default route /wasm.
Copy the code from index.html in the Blazor WASM project into Wasm.cshtml.
Important: If you are using your own layout, it is important to have <base href="/" /> on the page or the layout <head> section.
Remove all the static files from form the Blazor WASM project; e.g., index.html.
Remove all *.razor pages from the Blazor WASM project.
Add Wasm.razor to the Blazor WASM project and set its route to /wasm; i.e., #page "/wasm".
In Startup.cs in the Razor Pages project, add app.UseBlazorFrameworkFiles(); after app.UseStaticFiles();.
Also in the same Startup.cs, add endpoints.MapFallbackToPage("/wasm/{**segment}", "/wasm"); inside app.UseEndpoints() lambda.
Now run the application and navigate to /wasm. You should see the content of your Wasm.razor in addition to whatever layout you have set. You will get the same result when you paste the URL http://whateveryoursiteis/wasm.
You give very little information, so I'll have to make a number of guesses.
I guess you based your WASM integration on the Blazor WASM ASP.NET hosted template. That template consists of three projects: The .Client project, the .Server project and some extra project with shared models (they're probably doing clean architecture). The server project is a Razor pages project and the client a WASM project.
What you must understand is that a Blazor WASM project is not comparable with a Razor pages application. A Blazor WASM, or actually any WASM file is a different kind of binary and is fully run at the client! It is a client-side application. I.e. the output binary is totally different. You cannot have one project that generates both a server (x86/arm) binary and a client (WASM) binary. You need two separate projects.
What actually happens while compiling the WASM project, is that all page routing is also converted to WASM. Just inspect your network traffic when you change a page. Even though you browser url changes, that's fake... there is no network traffic! In fact, you stay on the same page.
Now think what happens when you enter "[..]/counter" manually in the browser. The host will actually again download the same .wasm file from the root ("/" = "/Index") and then parse the routing client-side.
Going back to your problem. For some reason you copied all the contents from the Blazer WASM project wwwroot/index.html to a Razor Page project Pages/Index.cshtml. Now you're confusing the whole routing system. When you type "[...]/counter", the WASM router will tell you that the .wasm file needs to be downloaded from "/Index". At the same time the Razor Pages router will tell you the compiled Index.cshtml is available at "/Index". That will give your "AmbiguousMatchException: The request matched multiple endpoints. Matches: /Index /Index".
Just look at the Summary of UseBlazorFrameworkFiles:
Configures the application to serve Blazor WebAssembly framework files from the root path "/".
Solution is just to keep the index.html in the WASM project as is. Just look at the default Blazor WASM ASP.Net app: it hosts Blazor WASM, Razor Pages and MVC at the same time and routing is just fine.
A different solution would be to use the overload of UseBlazorFrameworkFiles, where you can give a path prefix. E.g.
app.UseBlazorFrameworkFiles("/wasm");
You will need to fix other routing.
edit:
So let's give a case. you have:
A Blazor WASM project that serves pages /, /counter, etc.
A Razor pages project that serves pages /weatherforecast, etc.
Now:
you start the app on /. This loads the WASM from the server.
Next you click on the counter icon. this doesn't change the page!: it shows the counter page and updates the navigation url, but doensn't load a new page.
Now to go to weatherforecast. This is not found in the WASM, so a new page is actually loaded from the server. (either a razor page or controller/view)
If you would go back to counter, this is not found on the server, so the server 'falls-back' to the root (/Index) and loads the WASM again. Next is look if counter is found in the WASM.
Having a dynamic /Index will disrupt this system, so you'll have to manually solve all the routing.

How to deploy cshtml files in asp.net core

How to deploy cshtml files in asp.net core?
If I publish my asp.net core project the cshtml doesn't get published.
How to run the cshtml file directly in Chrome?
Here's some code to explain this further
My Program.cs file contains
public static void Main(string[] args)
{
//since zoho can pass only 10 parameters in one webhook we are splitting into two updates
//update1
UpdateClassBoatFromZohoModel upd = new UpdateClassBoatFromZohoModel();
upd.OnGet();
//update2
UpdateClassBoatFromZohoModel2 upd2 = new UpdateClassBoatFromZohoModel2();
upd2.OnGet();
//CreateWebHostBuilder(args).Build().Run();
}
Now each of these files UpdateClassBoatFromZoho.cshtml and UpdateClassBoatFromZoho2.cshtml are to be served in the browser with different querystring parameters. How to do that?
You can't because that's not how any of this works. The cshtml files cannot be run on their own. They are not served, for one, and they contain pre-processed code that only works in conjunction with the rest of the ASP.NET Core request pipeline. Even if you could access them directly, they wouldn't be anything but a text file (i.e. a web browser would have no idea what to do with it).
Precompilation of pages/views is the default behaviour. It is possible to skip this step and to publish the raw .cshtml files, resulting in pages/views that are updateable in a similar way to classic ASP or the ASP.NET Web Pages frameworks. In other words, you can make changes to the .cshtml files and then copy them to the web server while the application is running, and the new content will take effect immediately.
If you would like to adopt this approach, add an MvcCompileOnPublish node to your .csproj file, with the value set to false:
<PropertyGroup>
<TargetFramework>netcoreapp2.0</TargetFramework>
<MvcRazorCompileOnPublish>false</MvcRazorCompileOnPublish>
</PropertyGroup>
This will result in a Pages folder containing the content pages and a refs folder containing the libraries required for the application:

Why is app.UseMvc() added when creating a Razor Pages Project?

I'm new to ASP.NET Core and Razor and I apologize if this is insanely obvious somewhere.
After doing some research, I elected to use Razor Pages over MVC as I thought there would be more benefits and liked the idea of the code behind page models etc.. I chose ASP.NET Core Web Application -> Web Application and create a new project targeting ASP.NET Core 2.2.
The default template appears to create a "pure" RP project - eg. The Pages folder instead of MVC's Controller/Models/Views.
I'm getting really confused because there are still elements of MVC in the RP project - eg. app.useMvc() in Startup.cs, the inclusion of _ViewStart.cshtml, the use of ViewData["x"].
Realistically this is fine and one can press on but then following RP guides and supposed conventions seems to go haywire - eg. _PageStart.cshtml doesn't actually work from my testing.
Where am I going wrong - am I reading into it or caring too much? Hopefully someone can enlighten me! Thanks in advance for trying :)
razor pages, whilst they do not use controllers, are actually part of the mvc framework and require you to call app.UseMvc() in order to initilise everything it needs including routing etc.
You can also use UseMvc to do some configuration to your application:
app.AddMvc()
.AddRazorPagesOptions(options =>
{
options.Conventions.Add("options");
});
More information on this can be found at https://learn.microsoft.com/en-us/aspnet/core/razor-pages/razor-pages-conventions?view=aspnetcore-2.2

Who insert Angular scripts in ASP.NET Core Angular template project

I created a new ASP.NET Core 2.1 Angular project.
What is interesting is that there is index.html file inside ClientApp/src which is hosted as default page. I would like to know, which code triggers that index.html is served by default?
In my old application from universal template Controllers and Views are used which seems more naturally then serving index.html from client code.
When application is runned, some code magically inserts Angular scripts (inline.bundle.js, polyfills.bundle.js, vendor.bundle.js, main.bundle.js and styles.bundle.css) at the end of index.html file? Can someone share some light which code does that?
I want to understand this, because I want to serve content from RazorPage instead of static index.html, but in order to try anything I need to know a little more about magic behind this template.

How is configuration data protected in ASP .NET 5?

Rather than requiring Web.config, ASP .NET 5 provides a number of options to provide configuration data. Info on this can be found at:
Introducing ASP .NET 5 by Scott Guthrie
How can we store configuration data in new asp.net vnext? (StackOverflow)
ASP.NET vNext Moving Parts: IConfiguration by Louis DeJardin
There's an interesting question in the comments section of ScottGu's article:
The config.json file in the example, how is that protected by the webserver/http server? web.config is protected by IIS, but if any file can be used (which is great), it also comes with the burden that the webserver shouldn't serve the file out if one requests it in a URL. Or are there prefab names to choose from?
Can anyone answer this?
In previous versions of ASP.NET root of the project was also a root for the website. Some mechanisms were created to prevent access to files which should not be accessible to the outside world (like a whitelist of mime types, RequestFilteringModule).
This changed in ASP.NET 5 as a website root is no longer a project root.
Website root folder is a subfolder in your project directory (named wwwroot by default, but can be changed in project.json).
This means that everything outside a website root folder is not accessible to the outside world.
config.json file is outside of wwwroot so it won't be ever handled by any requests.