URL rewriting in MVC 3 - asp.net-mvc-3

I want to access a article with User friendly URL http://localhost/Content/Article/{id}/{title}, which internally process this url like http://localhost/Content/Article/{i}. I have created an Url routing rule for these url which is
routes.MapRoute(
"Article",
"{controller}/{action}/{id}/{title}",
new { controller = "content", action = "article", id = UrlParameter.Optional, title = UrlParameter.Optional }
);
However it is processing the request but, html respons is messing up. It is changing all image, anchor, css, javascript url. Replacing root url with /Content/Article and my html is being displayed messed up. All css formating gone. I have tried IIS7.0 rewriting module and Asp.nET routing, both giving me this issue.

Make sure that all references to external files are relative to the root of your website.
This isn't an issue with ASP.NET routing, it's an issue with how you're referencing your external files.

If you explicitly type the correct url into your browser do you get the correct page?
I have come across that problem a lot, especially when I have Areas. I have found that using T4MVC (NuGet Package) for all #Html.ActionLinks, etc, solves the problem. For example, using T4MVC, instead of:
<li>#Html.ActionLink("Home Page", "Index", "Home")</li>
...you can write:
<li>#Html.ActionLink("Home Page", MVC.Home.Index())</li>
Note the MVC.Home.Index(). This is how T4MVC allows you to do away with the magic strings (actionName and controllerName). In other words, T4MVC allows you to use the following overload of HtmlHelper.ActionLink:
HtmlHelper.ActionLink(string linkText, ActionResult result)
Instead of:
HtmlHelper.ActionLink(string linkText, string actionName, string controllerName)
For reasons that escape me right now (I have forgotten why!), this gets round the issue I think you are having.
Just check and see if typing the desired Url into the address bar works. If so, then it is the links that are going bad, not the routing.
If you still have a problem, then this isn't the answer...

Related

ASP.NET Core MVC : Razor pages routing, incorrectly re-using previous route data

I'm working on a dotnet 6 mvc application using RazorPages, and I'm having a problem with strange routing behavior.
I have a RazorPage /Pages/News.cshtml
This page is accessible using the default route /news
When called without any parameters this page will display an index of news articles.
I also want this page to be able to display a specific news article, via a path like this...
/news/1234-my-news-article
To achieve this, I've added a config like so...
builder.Services.AddRazorPages(options =>
{
options.Conventions.AddPageRoute("/News", "News/{id:regex(^\\d+\\-.*)?}");
});
In my templates, I can then use links like this...
<a asp-page="/News" asp-all-route-data="#(new Dictionary<string, string> { { "id", "1234-my-news-article" } })">My News Article</a>
or
<a asp-page="/News">All Articles</a>
However, once I've navigated to a specific article, the index link doesn't render correctly, and will instead link again to the same article. It appears to be re-using the current routing parameters.
Is there some way to avoid this?
update:
I've found a work-around, if I use this tag instead...
<a asp-page="/News" asp-route-id="">All Articles</a>
then it will link correctly to "/news".
It seems a bit counter-intuitive to have to explicitly set this to blank. I would have assumed it would default to unset, unless explicitly set otherwise.
This is known as ambient route values (https://www.learnrazorpages.com/razor-pages/tag-helpers/anchor-tag-helper#ambient-route-values), where the current route values are automatically added to outbound links which are generated by the anchor tag helper if the destination page is the same as the current page. In older versions of Razor Pages, this was the default behaviour for all pages.
As you have discovered, you can override this by setting the route value to an empty string, or as suggested elsewhere, to use a plain anchor tag for your link.
asp-page tag helper will add id value to the route by default.It is by design.If you don't want to add it,you can try to use href to replace asp-page:
All Articles

ASP.NET MVC3 Html.Raw changing absolute URLs?

I'm using ASP.NET MVC 3 and the helper #Html.Raw in my view.
I'm passing it some HTML markup that I have stored in a database. The markup contains some URLs that point to other places on my site. For example http://www.foo.fom/events. These data are forum posts, so the page they're displayed on has the form http://www.foo.com/forums/thread/42/slug.
However, when the page is rendered, the saved URLs are rendered in modified form as:
http://www.foo.com/forums/thread/42/events/
This only happens for URLs on my site. If the URL points to some external site, it is unchanged.
I have verified that what I'm passing into #Html.Raw is the correct URL (http://www.foo.com/events). Why is it getting changed as the page is rendered? Is there an easy way to disable this "feature"?
Here's my code for displaying the markup:
<div>
#Html.Raw(post.Body)
</div>
and here's the controller code that genrates the page data:
var post = _forumRepository.GetPostById(id)
var model = new ForumPostView()
{
Body = post.Body,
PostDate = post.DatePosted,
PostedBy = post.Author,
PostId = post.Id
};
return View(model);
I have verified via debugger that the exact URL in the post.Body before being passed back to the View is of the form "http://www.foo.com/events" (no trailing slash). I have also verified via debugger that the value is unchanged before it is passed into #Html.Raw.
It sounds like the urls that are pointing to other pages on your site are non-absolute. Are you certain they start with a / or http? If not, it's behaving exactly as it's supposed and treating them like relative urls -- and thus appending them to the current url.
(Html.Raw will not manipulate the string, so it's not at fault here)
Also, it wouldn't hurt to show us your code.
No, in fact I am an idiot. The URLs were indeed stored in relative form without a leading /, which is why they ended up being relative to the current page. The text displayed was absolute, which is what I saw when I looked at the db. That's what I get for debugging on a few hours' sleep ;)

CSS and image files not found after routing in ASP.NET MVC

In my ASP.NET MVC (3) application, I have setup the following route in global.asax.cs:
routes.MapRoute(
"UniqueId",
"{uniqueId}",
new { controller = "Book", action = "DownloadBook" },
new { uniqueId = "[0-9a-zA-Z]{5}" }
);
The DownloadFile action method is:
public ActionResult DownloadBook(string uniqueId)
{
string path = Server.MapPath(String.Format("~/App_Data/Books/{0}/index.htm", uniqueId));
if (System.IO.File.Exists(path))
{
return File(path, "text/html");
}
return new EmptyResult();
}
The method correctly serves the index.htm file from the subdirectory in the /App_Data/Books directory with the name that corresponds to the uniqueId that is defined in the route. However, the CSS and image files in the index.htm file cannot be found, since the browser tries to find them in the original URL location (e.g. http://localhost/3Yru3/).
Is there anything I can do about this? I am probably overlooking something?
EDIT (also see my comments in the answers to my question):
The books are stored as HTML files (and not as MVC Views, which would make referring to the CSS and images less of a problem) because:
1. They will be uploaded as such by users.
2. I want to store the index.htm file and the resources it uses in an HTML5 appcache, to be available offline.
EDIT 2 I have found a solution to my own question and would like to know what you think of it. See my own answer in the answers below.
This must be happening because you are referencing your files in a wrong way (relatively), meaning that it will be served according to the root of your current page.
Ex:
<link rel="Stylesheet" href="/Styles/site.css" />
or
<link rel="Stylesheet" href="../../Styles/site.css" />
Instead of this way, use the following sytax to link you CSS files and your images
<link rel="Stylesheet" href="<%=Url.Content("~/Styles/site.css")%>" />
This should work fine and be evaluated correctly from any page regardless of it's location.
You can do something, but it's more of a hack. Put placeholders for the css link then, when serving the file, do a replace, something like this.
public ActionResult DownloadBook(string uniqueId)
{
string path = Server.MapPath(String.Format("~/App_Data/Books/{0}/index.htm", uniqueId));
if (System.IO.File.Exists(path))
{
var file=File.ReadAllText(path);
//this needs a bit more refining, it's just a proof of concept
//you can use Razor templating, there is a library for that
file=file.Replace("{CssHref}",UrlHelper.GenerateContentUrl("~/Content/site.css",HttpContext));
return Content(file);
}
return new EmptyResult();
}
I think I may have found a solution to my problem that is quite elegant, but I would like to hear from you what you think of it. I have been looking at 'classic' URL rewriting in trying to send the browser to the right location, when it attempts to GET CSS files and image files that are referred to by the index.htm file in the App_Data subfolder (that has become a long sentence, I hope it makes sense ;-).
First I have tried to use Context.RewritePath in the BeginRequest event handler of the global.asax.cs of the app. That gave some unexpected side effects. Then I created a custom route class that covers both the original route described in my question above and URL rewriting for the CSS and images files requests. The custom route uses the fact that during those requests the Request.UrlReferrer property contains the URL of the location of the index.htm file. Since this is becoming a very long story, I refer to a blog post that I have written on this subject for the technical details. I hope this information will save others some valuable time.

How can I add a URL parameter but hide others in a POST - Spring MVC

I'm trying to add a URL parameter within a Spring MVC application. It's a basic search page that shows results.
In the search page, there is a form that is set to POST. There are many hidden fields and other fields I don't want in the URL. So, I don't want to do a GET.
I do want the search query in the URL. So after clicking the search button, the resulting search results page needs to have a URL like /search?query=hello
To get it to work, I'm creating a RequestMapping method in the Spring MVC Controller and doing a redirect: tacking on the query parameter. However, I'm not sure using a redirect is the best answer, seems there could be performance concerns redirecting as well.
I looked around and noticed folks using javascript and the location object, but setting the location object obviously relaunches the URL you set it to. I also looked at the HTTPServletResponse & HTTPServletRequest objects, but couldn't find much.
Any thoughts on how I can force the search parameter to be added to the URL?
Your form will have an 'action' specified telling it where to POST to. I'd have thought you could attach an onclick event to your submit button (or an onsubmit event to your form) that updates the action url by appending "?query=" to it.
document.<form name>.action += "?query=...";
Then you just have to worry about someone posting your form without JavaScript enabled - in this case you could fall back to your redirect.
I don't know how the server technology so I can't say if it will be happy giving you both GET and POST parameters, if not you'll have to manually strip the GETs out of the URL.
But anyway, this seems like a rather odd situation to be in - is it really that big a deal to show the parameters in the URL? Anything that gets posted by an HTML form can still be inspected with the right tools, it's just ever so slightly more difficult.
I wanted to provide a more complete answer to my question with code. The previous user helped me down this path, so I'll keep it as the accepted answer. However, there is one item to note:
If you add on to the action, and you have an input text box with the same name, the page posts a duplicate value like: query=hello,hello.
So, I needed to remove the name on the input box, and use the following javascript. Note, I am using the prototype.js framework:
Event.observe(window, 'load', function(event) {
Event.observe('searchForm', 'submit', function(event) {
$('searchForm').action += "?query="+$('searchBox').value;
});

ASP.Net MVC 3: Multiple views/urls to one controller action

I'm trying to do the following with ASP.Net MVC 3:
I have a lot of "flat pages", which are basically html documents with no dot.net code attached.
I want to be able to request these pages through routed URLs, but I do not want to manually add each url to the routes.
So my question is: Is it possible to define a default route, which uses the same controller / action, but returns a view based on the URL requested ?
e.g. /home/about and /profile would use the views /home/about.cshtml and /profile.cshtml
but both would use the same controller and action, which pretty much just goes:
return View();
The reason: I'm doing all the pages of the site, which require dot.net code. However another person is doing all the "flat pages" (informative pages, etc.).
I want him to be able to add new pages, by just adding a cshtml file (like he would with webforms creating aspx files, with no code-behind)
This is necessary because I'd otherwise have to edit global.asax each and everytime he adds a page, which is quite often.
If this is not possible, I'll have to stick with webforms, which I really don't want to :-(
You can make an action that takes as a parameter the name of the View; Something like this:
public ActionResult StaticPage(string viewName)
{
return View(viewName);
}
Then define a route so the viewName isn't a parameter but instead is part of the URL:
"/Static/{viewName}"

Resources