Link to html page not working in live server/Blazor Wasm App but is working locally in debug? - c#

I am developing a Blazor WASM application and need to add some external links to e.g. a cookies page which I am putting in a seperate tab using:
<a href="/Legal/Cookies.html" class="b-bar-link" target="_blank">
Cookies
</a>
Obviously with a Web assembly blazor app, most of it is loaded on to the client, but I don't think I have quite got my head around objects that still live on the client vs the server.
Images etc. stay on the server in the wwwroot folder. So I thought I should be able to create a /Legal folder in wwwroot and put the files there. These docs might change often so I figured better there.
So my folders look like most wasm template projects:
When I use the link to get to the cookies page, it works fine in VS under debug, but in the live server is heading to the 'Page not found'.
I am using an Azure AppService, and initially thought that maybe the problem may be due to a publishing/build issue. So I checked and the file properties all have 'copy always' as their
content action. Also, I checked the server published files and they are there.
I realise that the VS debug environment is using a cut down IIS and is different to the main Azure one, so I wondered if it could be permissions related. Suggestions please.?
EDIT
I think this is as someone suggested a routing issue. But does anyone know how to have Blazor Wasm mixed with the occasional file on the server? I mean, the default Identity stuff that MS provides does that very thing, though it is hard to figure out... any pointers to a doc? Thanks.

You should look at this for hosting: https://learn.microsoft.com/en-us/aspnet/core/blazor/host-and-deploy/?view=aspnetcore-7.0&tabs=visual-studio#app-base-path
In many hosting scenarios, the relative URL path to the app is the root of the app. In these default cases, the app's relative URL base path is the following:
Blazor WebAssembly: / configured as <base href="/" />.
Blazor Server: ~/ configured as <base href="~/" />.
In other hosting scenarios, such as GitHub Pages and IIS sub-apps, the app base path must be set to the server's relative URL path of the app.
See the rest of the article for how to adapt to your scenario. In short, you can include your path in launchSettings.json and have different configurations based on your dev/production environments.
Also take a look at the following article for absolute url handling inside your app if required: https://swimburger.net/blog/dotnet/how-to-generate-absolute-urls-in-aspdotnet-core

I am answering my own question here in case anyone else falls into this particular set of traps..
I was guided to some extent by a sort of similar question:
blazor-listing-and-linking-local-html-files-from-blazor-page
It wasn't a routing problem as such, more a mis-understanding on my part of how a Blazor app is structured, and that it can't easily switch in an out of being a Single Page App...
Anyway, I am using Blazorise to help with my UI so I constructed a 'Popup' page to handle this sort of thing, like this:
<Modal #ref="modalRef">
<ModalContent IsCentered="true" Size="ModalSize.ExtraLarge">
<ModalHeader>
<CloseButton Clicked="#HideModal" />
</ModalHeader>
<ModalBody Style="min-height: 50vh">
#htmlContent
</ModalBody>
</ModalContent>
</Modal>
This with the code page to activate the popup and get the data as follows:
[Inject] FileService _fileService { get; set; }
Modal? modalRef = new Modal();
[Parameter]
public string urlPath {get; set;}
private MarkupString htmlContent= new MarkupString();
private async Task GetContent()
{
htmlContent = (MarkupString) await _fileService.GetServerFileString(urlPath);
}
public async Task ShowModal(string? url = null)
{
if (!string.IsNullOrEmpty(url))
{
urlPath = url;
}
await GetContent();
modalRef.Show();
}
public void HideModal()
{
modalRef.Hide();
}
The _fileService function being:
public async Task<string> GetServerFileString(string serverURL)
{
string content = await HttpPublic.GetStringAsync(serverURL);
return content;
}
Then to use it in a page, (I am actually referencing straight from the MainLayout) it is as easy as:
<Button #onclick='() => ShowPopup("/Legal/Privacy.html")'>Privacy</Button>
or
<Button #onclick='() => ShowPopup("/Legal/Cookies.html")'>Cookies</Button>
With the code function being:
protected async void ShowPopup(string url)
{
await htmlPopup.ShowModal(url);
}
I did it that way because I am using the component several times in the same page... Given the Parameter function, you could also do it by just referencing the component and passing the param.
Hope this helps someone else. Cheers

Related

Is there a way in a Razor Pages app to change the default starting route to an Area?

When you create an ASP.Net Core Web App with Individual Accounts it adds an Identity Area along with the regular Pages folder.
Since I don't want to be working between the Pages folder along with the Area folder, I want to create a Home Area that my app's default route "/" will route to.
I was able to accomplish this for the Index page by adding this to Program.cs:
builder.Services.AddRazorPages(options =>
{
options.Conventions.AddAreaPageRoute("Home", "/Index", "");
});
Obviously, this just takes care of the single Index page, but if I wanted to have an About or Privacy page, I would have to add AreaPageRoutes for them as well. I tried a couple different things with AddAreaFolderRouteModelConvention that I am too embarrassed to show here, but was ultimately unable to find out how to make it work.
Is it possible and secondly, is it bad practice, to map the default routing of Pages to a specific Area?
You can use a PageRouteModelConvention to change the attribute route for pages in an area:
public class CustomPageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
foreach (var selector in model.Selectors.ToList())
{
selector.AttributeRouteModel.Template = selector.AttributeRouteModel.Template.Replace("Home/", "");
}
}
}
Generally, my advice regarding areas in Razor Page applications is don't use them. They add additional complexity for no real gain at all. You have already found yourself fighting against the framework as soon as you introduced your own area. QED.
The only place areas serve a real purpose is within Razor class libraries, so you have to live with an area when using the Identity UI. But you don't have to use the Identity UI. You can take code inspiration from it and implement your own version in your existing Pages folder.

Route to generic Razor page only if physical resource doesn't exist

I am a front-end dev and don't know a lot about C#. I have been dabbling in Razor views so I can sort-of make my way around it. I am developing a project that might require some C# routing and I can't get it working (I think this is due to my limited understanding).
We built a website that contains a mix of static resources (physical .cshtml pages) and then also content that is stored in a database. All the links to these content pieces are generated via handlebars templates so I cannot use Razor within my templates (that I know of). The database content needs to use page.cshtml, which should then also be routed to remove page from the URL.
So in essence, when you hit http://www.example.com/my-page it should check if my-page.cshtml exists, else use http://www.example.com/page/my-page rewritten as http://www.example.com/my-page.
I'm trying to use this but it isn't working:
using System.Web.Routing;
public class Routes
{
void RegisterRoutes(RouteCollection routes)
{
routes.MapPageRoute("Deals",
"/{page}", "~/page.cshtml");
}
}
Is this possible using only Razor? I have tried routing via C# RouteConfig but the project is using V4 of .NET so attribute routing doesn't work. I also can't use a catchall route as there are some pages that are within directories.
Or is my only option to explicitly state a link to /page/ in the DB and do IIS rewrites?
My other option is to always hit page.cshtml and if it can't find the content in my DB, it loads in my-page.cshtml as a partial. But then what happens if someone types http://www.example.com/my-page into the address bar?
You can check if your my-page.cshtml file exist in your controller
string myFile = Server.MapPath("path to my-page.cshtml");
if(File.Exists(myFile))
{
return View("path to my-page.cshtml");
}
else
{
//from db
}
ps: you need to use System.IO in your controller

URL routing turning /pages/test.aspx into /test

I made a folder called 'pages' in my asp web forms project. In this folder I have a lot of pages:
test.aspx
hello.aspx
When I open these pages in a browser I get:
www.domain.com/pages/test.aspx
www.domain.com/pages/hello.aspx
This is normal, I know. But what if I want to delete the /pages in the url and just show (without .aspx):
www.domain.com/test*.aspx*
www.domain.com/hello*.aspx*
I can do this by manually adding a new route (in RegisterRoutes() method) for each page but is there a way to do this dynamicly?
I found this question but I don't know if I can use it for this problem.
WebForms custom / dynamic routing
Try something like this, not sure if that will do it. But you could always just put your pages in the root directory. I think this would work.
Source Link: http://msdn.microsoft.com/en-us/library/vstudio/cc668177(v=vs.100).aspx
routes.MapPageRoute("PageRoute","{page}", "~/pages/{page}.aspx");
Not sure if that's what you were looking for, this way you can just do something like:
Response.RedirectToRoute("PageRoute", new { page = "test" });

MVC3 deploy to a directory, url issue

I have a mvc3 web application which will be delopyed to an directory of a website. the address of the application seems like http://wwww.xx.com/aopo/. aopo is the name of the directory. After the deployement I find that the url in js file does not work any more. because I had write the js code with hard code url, just like
$.ajax({url:"/employee/getemployee"})
In that case the request will be sent to http://wwww.xx.com/employee/getemployee instead of http://wwww.xx.com/aopo/employee/getemployee, and 404 is returned.
There is lots of code in js like that. I don't want to modify the js. Is there any simple approach to make it work? Can I rewrite the request in global.asax.cs?
I believe you'll need to change your url references to this:
$.ajax({url:"#Url.Action("getemplotee","employee")"})
If this is a script file you can write the correct URL into an element on the page and read that:
<div id='Main' data-url='#Url.Action("getemplotee","employee")' />
Then in your script:
$.ajax({url:$('#Main').data('url')})
Rgarding:
There is lots of code in js like that. I don't want to modify the js
I understand, but you need to use the proper helper methods to account for running under virtual directories, so I would recommending biting the bullet and just fixing it the right way.
One not so clean solution might be,
Setting a url prefix in the layout(in a common place), like
<script type="text/javascript">
#{
string root = Url.Content("~/");
if (root.EndsWith("/", StringComparison.Ordinal))
{
root = root.Substring(0, root.Length - 1);
}
}
window.URL_PREFIX = '#root';
</script>
then use the prefix in the ajaxSend hook and change the url.
$(document).ajaxSend(function (event, jqxhr, settings) {
if (window.URL_PREFIX && settings.url.indexOf(window.URL_PREFIX)) {
settings.url = window.URL_PREFIX + settings.url;
}
});
note: If $.ajax() or $.ajaxSetup() is called with the global option set to false, the .ajaxSend() method will not fire.
its not an ideal solution, but might be helpful in a tight situation.
hope this helps.
No, that's not possible. Since the request doesn't arrive in your application you can't access it and thus you can't rewrite it.
If you have control over the root site, you could use the IIS rewrite module to rewrite the URL to your website.

Why Request.Url.Authority is returning the internal path and not my domain

I'm working through the final issues of an application set to go live this week. I need help to either modify my code or explain to our hosters what they need to fix in the IIS/DNS configurations to make this code work as expected.
Here is the code:
public string BaseSiteUrl
{
get
{
var c = this.ControllerContext.RequestContext.HttpContext;
string baseUrl = c.Request.Url.Scheme + "://" + c.Request.Url.Authority
+ c.Request.ApplicationPath.TrimEnd('/') + '/';
return baseUrl;
}
}
I make a call to this in my Controller, to generate a url that gets persisted to a database.
It works fine when I run on my local machine. However, it does not work when it is run on the beta server.
Expected results on beta. On the beta server this is an application named dr405
https://beta.sc-pa.com/dr405/
The actual result on beta. (I changed the server/domain names to what you see in CAPS for security's sake)
http://SERVERNAME1.GROUP1.SUBGROUP.local/dr405/
I don't think you need the method you wrote. There is a UrlHelper class that adds extension methods. To get the base URL for your site you should be using the Content() method like this:
var baseUrl = Url.Content("~/");
In your example, it looks like the http://SERVERNAME1.GROUP1.SUBGROUP.local/dr405/ result is an internal host name. On your development machine the internal host matches your public facing one. Your hosting provider is unlikely to be able to modify this for you, especially if it's a shared hosting solution.
If you're behind a load balancer or similar, it might be worth checking server variables. In our case we do something like this:
string hostName = Request.Headers["x-forwarded-host"];
hostName = string.IsNullOrEmpty(hostName) ? Request.Url.Host : hostName;
This question I asked a while ago might be of interest:
Asp.net mvc 301 redirect from www.domain.com to domain.com
Due to time constraints, and the need to get this project out the door, I had to resort to hardcoding the main part of the url into the application. After I made the change I felt stupid for trying to make it dynamic in the first place. I mean how often should our domain name change?

Categories

Resources