I have an MVC web app, which inherits and is part of a Webform framework. Part of the webform framework outputs several ASHX handlers. Which, I cannot remove with routes.clear(), because that will remove them all together. I still need to use them.
Here is where my problem comes in, I have, <link href="#Url.Action("Index", "Styles")" rel="stylesheet" type="text/css" /> This points to a controller which generates dynamic CSS Style Attributes.
When the page renders the Url.Action looks like this -
<link href="/MyLayout/Handlers/LoginStyleHandler.ashx?
action=Index&controller=Styles" rel="stylesheet" type="text/css">
As far as trying to ignore this route here is what I have tried. None of these work. What gives? What can I do to keep the ASHX path out of my Url.Action HTML Helper.
routes.IgnoreRoute("{Handlers}.ashx");
routes.IgnoreRoute("{Handlers}/{resource}.ashx/{*pathInfo}");
routes.IgnoreRoute("TMW_LayoutPrototype/Handlers/LoginStyleHandler.ashx");
routes.IgnoreRoute("{*allaspx}", new { allaspx = #".*\.aspx(/.*)?" });
routes.IgnoreRoute("Handlers/LoginStyleHandler.ashx");
routes.IgnoreRoute("{*allashx}", new { allashx = #".*\.ashx(/.*)?" });
Update
Using the Regex tester at http://regexpal.com/ let me know that my Regex pattern #".*\.ashx(/.*)?" is valid. However it does not remove the handler from the MVC side of the web application.
Conclusion
The root of my problem stemmed from the web forms side of the application. Low-and-behold, inside the framework the MVC app inherited from laid a routing engine. So, my routes in MVC were getting placed at the bottom of the stack and the Webform routes were at the top.
The ignore routes did not work, because the routes were being created on the application_start event. Ignoring nor placing my MVC routes at the top of the stack did not work, because then I would lose Session, as well as, forms auth.
The solution was writing a constraint in the Webform routing code to stay out of my MVC application. After that all was fine in the MVC kingdom.
try routes.Ignore instead of routes.IgnoreRoutes
Some of my handlers mapped to sub directories, so I went with the regex which has to be a full match instead of a partial
routes.Ignore("{*legecy}", new { legecy = #".*\.(aspx|ashx|asmx|axd|svc)([/\?].*)?" });
Related
I have an area in my ASP.NET MVC application that needs to make use of partial views stored in the main application.
The code in question is being migrated from the main application into an area for organization, so I need to update the helper tags for the partial views.
Currently my tags look like this:
#await Html.PartialAsync("../Shared/Partials/_details.cshtml")
Of course, this fails in an area, since this helper only begins searching at the Areas/MyArea/ folder. I've tried adding additional ../ to the beginning of the address, but that doesn't change anything. How can I reconnect my partial views to this area?
You need to reference the app root.
The following example references a partial view from the app root. Paths that start with a tilde-slash (~/) or a slash (/) refer to the app root:
Partial Tag Helper:
<partial name="~/Pages/Folder/_PartialName.cshtml" />
<partial name="/Pages/Folder/_PartialName.cshtml" />
Asynchronous HTML Helper:
#await Html.PartialAsync("~/Pages/Folder/_PartialName.cshtml")
#await Html.PartialAsync("/Pages/Folder/_PartialName.cshtml")
https://learn.microsoft.com/en-us/aspnet/core/mvc/views/partial?view=aspnetcore-6.0
See also: significance of tilde sign
i'm using the MVC Sitemap Provider 4 and want to show always the canonical tag, not only when a second link is existing. Is there somebody who can help me?
The best way to do this is to edit (or create another) template to build the canonical tag. If you installed using the NuGet package, in your /Views/Shared/DisplayTemplates folder you will have a CanonicalHelperModel.cshtml file (or with a .ascx extension if you are using webforms instead of razor). The default looks like this:
#model MvcSiteMapProvider.Web.Html.Models.CanonicalHelperModel
#using System.Web.Mvc.Html
#using MvcSiteMapProvider.Web.Html.Models
#if (!String.IsNullOrEmpty(Model.CurrentNode.CanonicalUrl)) {
<link rel="canonical" href="#Model.CurrentNode.CanonicalUrl" />
}
You can change it so it uses the URL property if no canonical URL was resolved by adding an else block.
#model MvcSiteMapProvider.Web.Html.Models.CanonicalHelperModel
#using System.Web.Mvc.Html
#using MvcSiteMapProvider.Web.Html.Models
#if (!String.IsNullOrEmpty(Model.CurrentNode.CanonicalUrl)) {
<link rel="canonical" href="#Model.CurrentNode.CanonicalUrl" />
} else {
<link rel="canonical" href="#string.Format("http://www.mysite.com{0}, Model.CurrentNode.Url)" />
}
You may need to devise a better way to get the base URL (domain name and http/https) and reliably concatenate it with the URL property, as the canonical tag requires an absolute URL. You could just grab the current Request.RawUrl instead of Model.CurrentNode.Url, but you will need to ensure it is properly sanitized (and HTML encoded) before displaying it on the page to prevent XSS attacks. However, if you use the Request.RawUrl just to get the base URL (by loading it into a Uri object and then using the base URL parts), you should be fine.
This will only work for pages that have a matching node defined in the SiteMap. If reading the nodes from an external source such as a database, you should ensure that each record in the database has a node in the SiteMap so there is a one-to-one correlation (at least for the pages you want indexed in search engines). You should not be using preservedRouteParameters in this case. For more information on that subject see How to Make MvcSiteMapProvider Remember a User's Position.
On a side note, there really is no need to do what you are asking because the only pages that require canonical tags are the duplicates.
We have an editor template that contains approx 40 lines of jquery. I tried dropping this script into a <asp:Content> block to keep all of the javascript in one location within the page. However, I get the following error message content controls have to be top-level controls in a content page.
Is there any way to get this working so we don't have script dotted around our final output pages or could someone recommend the best practice for storing javascript used within ASP.NET MVC templates? At the moment I'm thinking of pulling the code into a separate file and referencing it within the master page but this means it gets pulled into every page which isn't really ideal.
Thanks in advance.
It would be easier for later maintenance, if you keep the javascript into a separate file and reference it where ever it is needed. Also, if you feel that placing all script into a single file will increase unnecessary loading of scripts, where not needed, then break the scripts into separate files based on functionality/modules in which it is useful etc. strategy and then reference them instead.
Also, it was said that always, keep/reference the scripts at the bottom of the page so that page loading will be faster.
as siva says, bottom of the page is the 'ideal'. however, as for seperate files. this is only going to be practical as long as you don't reference asp.net elements from the page - ie:
<asp:Content ContentPlaceHolderID="jsCode" ID="jsCode1" runat="server">
<script type="text/javascript">
$(document).ready(function() {
getPoundsData();
});
function getPoundsData() {
var id = $("#ID").val();
var URL = '<%=Url.Action("GetPounds", "FundShareholder")%>';
var params = { id: id };
if (id != null)
SendAjaxCache("#" + $("#ShareholderID option:selected").text() + " RSP#", URL, params, null, ListDataShareholderPounds);
}
function ListDataShareholderPounds(data) {
if (data.length != 0) {
$('#shareholderPounds').html("");
$('#shareholderPounds').show();
$('#shareholderPounds').html(data);
}
};
</script>
</asp:Content>
notice the:
var URL = '<%=Url.Action("GetPounds", "FundShareholder")%>';
part in the js. what 'we' do is to add a content section to the master page at the very bottom to hold our js stuff. however, this only works inside the ViewPage (aspx) object. the ascx pages are 'ignorant' of any master page content sections.
We are currently working on systemizing the process whereby we save 'partial' js files with asp.net references inside them and then inject them into the page-flow via a filterattribute. we're at an early stage with this but the nice thing about this approach is that the partial js is treated as a file and is therefore cached for future visits to that page.
anyway, that's our current approach, would be interested to discover if peeps are using any similar mechanisms to inject js that contains asp.net object references.
cheers...
[edit] - here's a heads up on the approach i'm talking about (this wasn't our original inspiration, but is quite similar, tho is webforms, rather than mvc) - http://www.west-wind.com/WebLog/posts/252178.aspx or this one which IS mvc: http://poundingcode.blogspot.com/2009/12/injecting-javasript-into-aspnetmvc-with.html.
Finally found the article that inspired our 'search' in this: ASP.NET MVC routing and paths is js files plus http://codepaste.net/p2s3po
I created a simple extension method for the ASP.NET MVC UrlHelper. It takes no arguments as its job is to look up the name of a stylesheet file from the configuration and return a url to the stylesheet. The extension method looks roughly like this:
public static string SiteStylesheet(this UrlHelper urlHelper)
{
var scriptFilename = UserInterfaceConfiguration.GetSection()
.Mvc.SiteStylesheet;
return urlHelper.Content(string.Format("~/Assets/Scripts/{0}",
scriptFilename));
}
And I use it like this:
<link href="<%= Url.SiteStylesheet() %>" rel="Stylesheet" type="text/css" />
The method does not get executed, however, and the following is rendered:
href="../Views/Shared/%3C%25=%20Url.SiteStylesheet()%20%25%3E"
As you can see the extension method is not executed, rather the entire thing is just encoded. If I change the method signature to accept a parameter:
public static string SiteStylesheet(this UrlHelper urlHelper, string dummy)
then the extension method is executed and the output is as expected:
href="/Assets/Stylesheets/FluidCMS.css"
So my question then is this by design or is this a bug in the ASP.NET MVC Web Form view engine?
This issue has come up a number of times. The root of the issue is that the <head> tag has runat="server", which causes the parser to treat tags as server tags.
The simplest workaround is to just remove runat="server" from the head tag. What you lose is the logic that makes the link URL's relative to the current page, but since you're using your helper anyway, you have no need for this.
When I had this problem, it was because my extension methods were in a namespace that wasn't specified in the web.config.
<add namespace="Your.Extension.Method.Namespace"/>
It goes under configuration\system.web\pages\namespaces
I think you found a bug!
I tried it and found this only happens in the head section of a Master Page and only in the <link> tags (<script> tags render fine).
The problem obviously is the text inside de href attribute is not correctly interpreted as a code nugget.
This goes beyond ASP.NET MVC. I tried it in a Master Page in a classic Web Form ASP.NET site and the problem persists. It seems to be a bug in the Web Form rendering engine or something like that.
I've got an issue with MVC routing(or at least I think it's w/routing :) )...
Just upgraded to MVC RC1, but I'm not sure that it's related as this is my first attempt at setting a MapRoute and corresponding RouteLink.
here's the route:
routes.MapRoute("Test1",
"Forecast/CurrentLineItems/{propertyID}/{forecastYear}/{forecastMonth}",
new { controller = "Forecast", action = "CurrentLineItems", propertyID = "", forecastYear = "", forecastMonth = "" }
);
here's the RouteLink...in the view it's wrapped in a table cell:
Html.RouteLink(Html.Encode(myProperty.Description),"Test1", new { controller = "Forecast", action = "CurrentLineItems", propertyID = myProperty.PropertyID.ToString(), forecastYear = "2008", forecastMonth = "10" })
here's a snippet from the controller:
namespace AnApplication.Controllers
{
[HandleError]
[Authorize]
public class ForecastController : Controller
{
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult CurrentLineItems(string propertyID, string forecastYear, string forecastMonth)
{
//Some code
}
Now for the strange behavior, when I click the link specified by the RouteLink, the app enters the CurrentLineItems method and all the method arguments are correct...
then it enters the CurrentLineItems method again!
with, for instance, these arguments:
propertyID = "scripts"
forecastYear = "jquery-1.2.6.js"
forecastMonth = ""
It then repeats this several times as it seems to run through all the scripts on this view and the Site.Master and then the last one is the .css file for this page!
What is going on!
The Call Stack is of no help as it lists the above-mentioned CurrentLineItems method and then below that is the dreaded [External Code]
When I profile the page/view in FireFox/FireBug all I see are the jQuery calls
Here's the html from the Site.Master re the scripts
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title><%= Html.Encode(ViewData["Title"]) %></title>
<script type="text/javascript" src="../../scripts/jquery-1.2.6.js"></script>
<script type="text/javascript" src="../../scripts/calculations.js"></script>
<script type="text/javascript" src="../../scripts/common.js"></script>
<style media="all" type="text/css">#import "../../Content/all.css";</style>
<!--[if IE]><link rel="stylesheet" type="text/css" href="../../Content/ie.css"media="screen"/><![endif]-->
<!--<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />-->
</head>
here's a snippet from the view re the scripts
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"AutoEventWireup="true" CodeBehind="CurrentLineItems.aspx.cs" Inherits="AnApplication.Views.Forecast.CurrentLineItems" %>
<asp:Content ID="lineItemsContent" ContentPlaceHolderID="MainContent" runat="server">
<!--<script type="text/javascript" src="../../scripts/MicrosoftAjax.debug.js"></script>-->
<script type="text/javascript" src="../../scripts/lineItems.js"></script>
<script type="text/javascript" src="../../Scripts/jquery.formatCurrency.js"></script>
<!--<script type="text/javascript" src="../../scripts/jquery-1.2.6.min.js"></script>-->
Note that this ActionLink works fine(It's basically just a menu item used for testing and the three arguments are set in the code inside the controller...):
<%= Html.ActionLink("Line Items", "CurrentLineItems", "Forecast")%>
Any help in solving this issue is greatly appreciated.
Thanks,
Greg
There were in fact two subtle, yet annoying bugs in the recently release ASP.NET MVC Release Candidate. These were the two bugs:
We changed all our URL-rendering methods to render relative URLs instead of absolute URLs. While we feel this might be the right decision in general, we found that it breaks an awful lot of scenarios. AJAX scenarios were especially affected since the URLs for retrieving data asynchronously are often different from the original URL as seen in the browser's address bar.
Html.RouteLink specifically (and not Html.ActionLink) had a bug in it (so it is not in fact a red herring - at least not necessarily). Html.RouteLink would erroneously take the "current" controller and action and pass those values into the routing system. Only Html.ActionLink is supposed to do that. Html.RouteLink is not supposed to do any processing at all. It's supposed to just take the values you give it and pass it along to the ASP.NET Routing system.
Since these two bugs were both pretty bad, we decided to roll back the change that caused #1 and to fix the issue that caused #2 and release an updated ASP.NET MVC Release Candidate Refresh.
You'll see some posts on ScottGu's blog, Phil Haack's blog, and the ASP.NET MVC Forums detailing the refresh.
Thanks,
Eilon
It could be caused by the usage of relative paths to include the scripts.
When you click on the link the URL of the new page will be something like http://[server]/Forecast/CurrentLineItems/xxx/2009/1
Now check the html code in the browser: If the URLs are in the form of '../../scripts/jquery-1.2.6.js', this will cause the browser to load it from http://[server]/Forecast/CurrentLineItems/scripts/jquery-1.2.6.js - and so your controller gets called again.
If that is the case you could either use absolute paths ('/scripts/jquery-1.2.6.js') or use a path relative to the application root ('~/scripts/jquery-1.2.6.js') and resolve it on the server side with Page.ResolveClientUrl().
Maybe there has been a change from Beta to RC1, so that the URLs in the head, even with runat="server", don't get remapped.
RouteLink versus ActionLink is a red herring here. The only thing that matters is the rendered a href="[something]". You would get exactly the same results if you wrote the a href manually instead of generating it via RouteLink.
So, yes, now we're down to routing. Inside your controller action, inspect RouteData in the debugger, and see which route name was matched. Chances are very likely it's the wrong one, and that is causing other things to misbehave. Either change the order of your reps, or add constraints to prevent the wrong one from being matched.
RouteLink works very well to prevent finding the wrong route when you're generating a URL. But when your application is consuming a URL, you still need to have your routes in order in global.asax.