How to prevent DNN Skin AddModule Message from auto-scrolling the page? - scroll

The DNN DotNetNuke.UI.Skins.Skin.AddModuleMessage method causes the page to auto scroll on Postback. I am using DNN 9.01.01
I did try MaintainScrollPositionOnPostBack, but it seems like you can't use this in a Master page:
https://forums.asp.net/t/1038248.aspx?MaintainScrollPositionOnPostBack+true+IN+MASTER
<%# Control Language="C#" MaintainScrollPositionOnPostback="true" AutoEventWireup="true" CodeBehind="Default.aspx.cs" %>
This is the method that is causing the trouble in DNN:
private void AddModuleMessage(ModuleMessage.ModuleMessageType moduleMsgType, string Message, bool error = true)
{
if (error)
{
moduleMsgType = ModuleMessage.ModuleMessageType.RedError;
}
DotNetNuke.UI.Skins.Skin.AddModuleMessage(plcMessages, Message, moduleMsgType);
}
I have tried to disable Focus() on inputs, but it does the same.
Here are other sources I looked at https://www.dnnsoftware.com/forums/threadid/284691/scope/posts/when-page-loaded-the-browser-scrolls-down
Also, does Update Panels cause auto scrolling?

Related

Performance bottleneck Url.Action - can I workaround it?

I have an application that I recently upgraded from ASP.NET MVC1 to ASP.NET MVC4 rc1.
It uses the Webforms viewengine.
It has performance issues whenever Url.Action(action,controller) is used.
I can reproduce the issue in ASP.NET MVC3.
I need 3ms to render views that have 10 instances of the Url.Action helper in it in ASP.NET MVC1 and 40ms to render the same in ASP.NET MVC3.
I already found some ways to make it render faster:
I moved the default route to the top
I removed Url.Action and used static links
This does not feel right: the application is pretty large and I need the goodness of a decent working routing in it. I am also not confident that I found all performance bottlenecks. Routing is a central part of MVC: if there is something performing badly it will pop up in different parts of the application.
I have the impression that MVC3 introduced some routing features (like regex constraints) that even if I dont use them lead to a badly performing application.
Is there something I can do like turning of features of routing or using a different set of URL-helpers?
This code reproduces the issue:
Index action
public ActionResult Index()
{
return View();
}
index.aspx
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head >
<title></title>
<link href="../../Content/Site.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="page">
<%= Url.Action("Action1", "Controller1") %>
<%= Url.Action("Action2", "Controller2") %>
<%= Url.Action("Action3", "Controller3") %>
<%= Url.Action("Action4", "Controller4") %>
<%= Url.Action("Action5", "Controller5") %>
<%= Url.Action("Action6", "Controller6") %>
<%= Url.Action("Action7", "Controller7") %>
<%= Url.Action("Action8", "Controller8") %>
<%= Url.Action("Action9", "Controller9") %>
<%= Url.Action("Action10", "Controller10") %>
</div>
</body>
</html>
Route registration
This looks strange: but I just want to simulate my not very complicated routing. This is not the 600 routes of SO!
public static void RegisterRoutesSlow(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.IgnoreRoute("{language}/Content/{*pathInfo}");
routes.IgnoreRoute("images/{*pathinfo}");
routes.IgnoreRoute("scripts/{*pathinfo}");
routes.IgnoreRoute("content/{*pathinfo}");
routes.IgnoreRoute("{file}.gif");
routes.IgnoreRoute("{file}.jpg");
routes.IgnoreRoute("{file}.js");
routes.IgnoreRoute("{file}.css");
routes.IgnoreRoute("{file}.png");
routes.IgnoreRoute("{file}.pdf");
routes.IgnoreRoute("{file}.htm");
routes.IgnoreRoute("{file}.html");
routes.IgnoreRoute("{file}.swf");
routes.IgnoreRoute("{file}.txt");
routes.IgnoreRoute("{file}.xml");
routes.IgnoreRoute("{*favicon}", new { favicon = #"(.*/)?favicon.ico(/.*)?" });
for (int i = 0; i <= 10; i++)
{
routes.MapRoute(
// Route name
"RouteName" + i.ToString(),
// URL with parameters
"{language}/{controller}/{action}/{para1}",
// Parameter defaults
new
{
action = "Index",
language = "de",
para1 = 0
},
//Parameter constraints
new { language = "de|en", controller = "SomeNameOfAnActualController" + i.ToString() }
);
}
routes.MapRoute(
"DefaulRoute", // Route name
"{controller}/{action}", // URL with parameters
new
{
controller = "Home",
action = "Index",
}
);
routes.MapRoute("404-PageNotFound", "{*url}", new { controller = "Error", action = "PageNotFound", language = "de" });
}
EDIT
The sample code was compiled against MVC2 now. In VS2010 MVC2 can be compiled against .NET 3.5 or 4.0.
The performance with 3.5 is good and 4.0 is bad.
I guess this means that the poorly performing part is not in a MVC assembly but in a framework assembly (like System.Web.Routing.dll). The question is still the same: Can I do something about it? An accepted answer would also be: No, the code is slow because from version 3.5 to 4.0 MS changed XXX
EDIT-2
I decompiled the part of System.Web.Routing.dll that takes to long. It uses a compiled regular expression. There is a code path (constraint2.Match ) that returns without executing the regex, but I did not check yet if it internally uses a different expensive operation.
protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
{
object obj2;
IRouteConstraint constraint2 = constraint as IRouteConstraint;
if (constraint2 != null)
{
return constraint2.Match(httpContext, this, parameterName, values, routeDirection);
}
string str = constraint as string;
if (str == null)
{
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("Route_ValidationMustBeStringOrCustomConstraint"), new object[] { parameterName, this.Url }));
}
values.TryGetValue(parameterName, out obj2);
string input = Convert.ToString(obj2, CultureInfo.InvariantCulture);
string pattern = "^(" + str + ")$";
return Regex.IsMatch(input, pattern, RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.IgnoreCase);
}
There are solved problem similar to yours: First call to Url.Action on a page is slow
there are conclusion about routing constraints with regexp constraints that is very slow.
Each view is compiled and cached when it is used the first time. However, since the aspx Views were not designed specifically for Mvc each Url.Action is not compilede once for all in the final link but it is re-computed at each execution. Razor compiler has better optimization.
The only solution is computing the various linkks with Url.Action and storing them into some application level property, so it is computed just at first execution. You can put them either in the Application dictionary, or in static properties of a class.
I am not sure to the cause of what you are seeing, but it may not only be an MVC 1 vs MVC 4, IIS setup in later versions can impact the speed of view rendering. I came across a slide deck a few months ago that I thought was pretty interesting, relating to performance improvement tips in MVC 3 apps.
http://www.slideshare.net/ardalis/improving-aspnet-mvc-application-performance
Specifically, take a look at slide 28, which states:
Uninstall IIS UrlRewrite Module
If no applications on the server are using it
No effect in MVC apps before v3
Enhances speed of URL generation
I take this to mean that the UrlRewrite module will negatively impact MVC 3, but not MVC 2 or 1, which could be a source of the slowdown that you are seeing. There are some other improvements as well, but I don't believe that any of them 'directly' relate to what you are seeing.

MVC 3: Add usercontrol to Razor view

I have a DLL that contain a user control inside, in the Web Form view i can easily use it by using
<%# Register Assembly = "..." Namespace = "..." TagPrefix = "..." %>
But how to do it in Razor view?
You can't add server side controls to Razor views. In general it is very bad practice to do so anyways in an ASP.NET MVC application. Due to the heritage of WebForms view engine you could violate this rule but in Razor things have been made clearer.
This being said you could still do some pornography in Razor and include a WebForms partial which will contain the user control (totally not recommended, don't even know why I am mentioning it but anyway):
#Html.Partial("_Foo")
where in _Foo.ascx you could include server side controls:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<dynamic>" %>
<%# Register Assembly="SomeAssembly" Namespace="SomeNs" TagName="foo" %>
<foo:SomeControl runat="server" ID="fooControl" />
Also, not recommended, but you can render a control in code, like in an HTML Helper:
public static string GenerateHtmlFromYourControl(this HtmlHelper helper, string id)
{
var yourControl = new YourControl();
yourControl.ID = id;
var htmlWriter = new HtmlTextWriter(new StringWriter());
yourControl.RenderControl(htmlWriter);
return htmlWriter.InnerWriter.ToString();
}
and then you can reference it from your view:
Html.GenerateHtmlFromYourControl("YourControlId")
Just make sure you set up/reference your namespaces correctly to do this.
Caveat
FYI, I'm pretty sure there are some severe limitations regarding the Page Lifecycle here...

How do you include .html or .asp file using razor?

Is it possible to use server side include in Razor view engine to include .html or .asp file? We have an .html file and .asp files that contain website menus that are used for all of our websitse. Currently we use server side include for all of our sites so that we only need to change the mensu in one place.
I have the following code in the body of my _Layout.cshtml
<body>
<!--#include virtual="/serverside/menus/MainMenu.asp" -->
<!--#include virtual="/serverside/menus/library_menu.asp" -->
<!--#include virtual="/portfolios/serverside/menus/portfolio_buttons_head.html" -->
#RenderBody()
</body>
Instead of including the content of the file, if I do a view source, I see the literal text.
" <!--#include virtual="/serverside/menus/MainMenu.asp" -->
<!--#include virtual="/serverside/menus/library_menu.asp" -->
<!--#include virtual="/portfolios/serverside/menus/portfolio_buttons_head.html" -->"
#Html.Raw(File.ReadAllText(Server.MapPath("~/content/somefile.css")))
Try making your html page to a cshtml page and including it with:
#RenderPage("_header.cshtml")
Try implementing this HTML helper:
public static IHtmlString ServerSideInclude(this HtmlHelper helper, string serverPath)
{
var filePath = HttpContext.Current.Server.MapPath(serverPath);
// load from file
using (var streamReader = File.OpenText(filePath))
{
var markup = streamReader.ReadToEnd();
return new HtmlString(markup);
}
}
or:
public static IHtmlString ServerSideInclude(this HtmlHelper helper, string serverPath)
{
var filePath = HttpContext.Current.Server.MapPath(serverPath);
var markup = File.ReadAllText(filePath);
return new HtmlString(markup);
}
#RenderPage("PageHeader.cshtml")
<!-- your page body here -->
#RenderPage("PageFooter.cshtml")
This works just fine and can save you a lot of time.
Razor does not support server-side includes. The easiest solution would be copying the menu markup into your _Layout.cshtml page.
If you only needed to include .html files you could probably write a custom function that read the file from disk and wrote the output.
However since you also want to include .asp files (that could contain arbitrary server-side code) the above approach won't work. You would have to have a way to execute the .asp file, capture the generated output, and write it out to the response in your cshtml file.
In this case I would go with the copy+paste approach
Create a HtmlHelper extension method that gets the contents of the files:
public static class HtmlHelpers
{
public static MvcHtmlString WebPage(this HtmlHelper htmlHelper, string url)
{
return MvcHtmlString.Create(new WebClient().DownloadString(url));
}
}
Usage:
#Html.WebPage("/serverside/menus/MainMenu.asp");
Sorry guys for bit old answer but I found some way to attach asp file with razor. Of course you need to do some trick but it works! First of all I created .NET MVC 3 application.
In my _Layout.cshtml I added following line:
#Html.Partial("InsertHelper")
Then I created InsertHelper.aspx in my Shared folder with this content:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!--#include VIRTUAL="/ViewPage1.aspx"-->
ViewPage1.aspx is locaited in my root directory, and has just simple if to check whether it works:
<%
string dummy;
dummy="nz";
%>
<% if (dummy == "nz") { %>
nz indeed
<% } else { %>
not nz
<% } %>
And it works!
Razor is able to render partials with different ViewEngine, and that's why this example is working.
And one more thing: remember to not add following line in both aspx files:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
You can add it only once! Hope it helps!
I had the same issue when I tried to include an .inc file in MVC 4.
To solved this issue, I changed the suffix of the file to .cshtml and I added the following line
#RenderPage("../../Includes/global-banner_v4.cshtml")
Just do:
#Html.Partial("_SliderPartial")
while "_SliderPartial" is your "_SliderPartial.cshtml" file and your fine.
In my _Layout.cshtml I added following line:
#Html.Partial("InsertHelper")
Then I created InsertHelper.aspx in my Shared folder with this content:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage" %>
<!--#include VIRTUAL="/ViewPage1.aspx"-->
Why not include a section within your _Layout.cshtml page that will allow you to render sections based on what menu you want to use.
_Layout.cshtml
<!-- Some stuff. -->
#RenderSection("BannerContent")
<!-- Some other stuff -->
Then, in any page that uses that layout, you will have something like this:
#section BannerContent
{
#*Place your ASP.NET and HTML within this section to create/render your menus.*#
}
Html.Include(relativeVirtualPath) Extension Method
I wanted to include files like this for documentation purposes (putting the contents of a file in a <pre> tag).
To do this I added an HtmlHelperExtension with a method that takes a relative virtual path (doesn't have to be an absolute virtual path) and an optional boolean to indicate whether you wish to html encode the contents, which by default my method does since I'm using it primarily for showing code.
The real key to getting this code to work was using the VirtualPathUtility as well as the WebPageBase. Sample:
// Assume we are dealing with Razor as WebPageBase is the base page for razor.
// Making this assumption we can get the virtual path of the view currently
// executing (will return partial view virtual path or primary view virtual
// path just depending on what is executing).
var virtualDirectory = VirtualPathUtility.GetDirectory(
((WebPageBase)htmlHelper.ViewDataContainer).VirtualPath);
Full HtmlHelperExtension Code:
public static class HtmlHelperExtensions
{
private static readonly IEnumerable<string> IncludeFileSupportedExtensions = new String[]
{
".resource",
".cshtml",
".vbhtml",
};
public static IHtmlString IncludeFile(
this HtmlHelper htmlHelper,
string virtualFilePath,
bool htmlEncode = true)
{
var virtualDirectory = VirtualPathUtility.GetDirectory(
((WebPageBase)htmlHelper.ViewDataContainer).VirtualPath);
var fullVirtualPath = VirtualPathUtility.Combine(
virtualDirectory, virtualFilePath);
var filePath = htmlHelper.ViewContext.HttpContext.Server.MapPath(
fullVirtualPath);
if (File.Exists(filePath))
{
return GetHtmlString(File.ReadAllText(filePath), htmlEncode);
}
foreach (var includeFileExtension in IncludeFileSupportedExtensions)
{
var filePathWithExtension = filePath + includeFileExtension;
if (File.Exists(filePathWithExtension))
{
return GetHtmlString(File.ReadAllText(filePathWithExtension), htmlEncode);
}
}
throw new ArgumentException(string.Format(
#"Could not find path for ""{0}"".
Virtual Directory: ""{1}""
Full Virtual Path: ""{2}""
File Path: ""{3}""",
virtualFilePath, virtualDirectory, fullVirtualPath, filePath));
}
private static IHtmlString GetHtmlString(string str, bool htmlEncode)
{
return htmlEncode
? new HtmlString(HttpUtility.HtmlEncode(str))
: new HtmlString(str);
}
}
you can include server side code and aspx file in .cshtml files as below and then inlude classic asp files or html files.
Here are the steps
Index.cshtml
#Html.RenderPartial("InsertASPCodeHelper")
2.InsertASPCodeHelper.aspx
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<!--#include VIRTUAL="~/Views/Shared/Header.aspx"-->
Header.aspx
<!--#include file="/header/header.inc"-->
Using includes is not the correct way to use menus with mvc. You should be using a shared layout and/or partial views.
However if for some odd reason, you must include an html file, here is a way to do it.
Helpers/HtmlHelperExtensions.cs
using System.Web;
using System.Web.Mvc;
using System.Net;
namespace MvcHtmlHelpers
{
public static class HtmlHelperExtensions
{
public static MvcHtmlString WebPage(this HtmlHelper htmlHelper, string serverPath)
{
var filePath = HttpContext.Current.Server.MapPath(serverPath);
return MvcHtmlString.Create(new WebClient().DownloadString(filePath));
}
}
}
Add new namespace to web.config
<pages pageBaseType="System.Web.Mvc.WebViewPage">
<namespaces>
<add namespace="MvcHtmlHelpers"/>
</namespaces>
</pages>
Usage:
#Html.WebPage("/Content/pages/home.html")

Setting masterName on MVC view causes error when calling RenderAction

I have a Masterpage (site.master) that calls a View using RenderAction. At the moment the View returns "hello world".
site.master:
<%# Master Language="C#" Inherits="System.Web.Mvc.ViewMasterPage" %>
<html>
<head id="Head1" runat="server">
<title><asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server" /></title>
<asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server" />
</head>
<body>
<% Html.RenderAction("Test", "Charts"); %>
<asp:ContentPlaceHolder ID="ContentPlaceHolder3" runat="server" >
<p>site.master</p>
</asp:ContentPlaceHolder>
<asp:ContentPlaceHolder ID="ContentPlaceHolder4" runat="server" />
</body>
</html>
Test.aspx:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
hello world!
ChartsController.cs:
public ActionResult Test()
{
return View();
}
If I update the View to pass in the name of the Masterpage explicitly I get an error when I call RenderAction.
ChartsController.cs:
public ActionResult Test()
{
return View(null, "site");
}
Error:
Content controls have to be top-level controls in a content page or a nested master page that references a master page.
Stack Trace:
[HttpException (0x80004005): Content controls have to be top-level controls in a content page or a nested master page that references a master page.]
System.Web.UI.MasterPage.CreateMaster(TemplateControl owner, HttpContext context, VirtualPath masterPageFile, IDictionary contentTemplateCollection) +8857854
System.Web.UI.Page.get_Master() +54
System.Web.UI.Page.ApplyMasterPage() +15
System.Web.UI.Page.PerformPreInit() +45
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +328
How do I go about setting the master page that I want the view to use? Ultimately I will be setting the Masterpage dynamically using a custom ViewEngine (by overriding VirtualPathProviderViewEngine.FindView).
if ( String.IsNullOrEmpty(masterName) ){ masterName = "site"; }
When I set the masterName property in my ViewEngine and then call RenderAction from site.master I get the same error as when I set the masterName property in the Action.
I am using:
Visual Studio 2010
MVC 3
IIS Express
edited: added full site.master markup
Subclass ViewPage<T> and override the OnPreInit() event. In your override,
protected override void OnPreInit(EventArgs e)
{
this.MasterLocation = GetMasterLocation();
base.OnPreInit(e);
}
The GetMasterLocation() method should get the filename of the view (beginning with a "~/").
The error comes from the CreateMaster method in MasterPage, the code that throws it is:
if (masterPageFile == null)
{
if ((contentTemplateCollection != null) && (contentTemplateCollection.Count > 0))
{
throw new HttpException(SR.GetString("Content_only_allowed_in_content_page"));
}
return null;
}
So, the MasterPage doesn't exist and content template collection has templates, so the page throws an exception. Following the above instructions will programmatically set the masterpage's location (which gets processed into the virtual path which is the variable masterPageFile)
I have come up with a solution and at least a partial answer/understanding to the cause of my issue.
If I am correct the issue is that I as trying to set the Masterpage on a view that didn't have/need a Masterpage. I think that the result was that I was setting a path to a Masterpage and even though that Masterpage exists the View was not expecting it and through an error.
When I updated the View to use a Masterpage I was able to pass the name of the Masterpage directly to the View without an error.
Test.aspx:
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Charts.Master" Inherits="System.Web.Mvc.ViewPage<dynamic>" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
hello world!
</asp:Content>
The way that I resolved this in my custom ViewEngine was to check if the current View is a ChildAction.
if (String.IsNullOrEmpty(masterName) && !controllerContext.IsChildAction)
{
masterName = "site";
}

asp.net mvc 2 client side validation missing ValidationRules on custom attribute

Can't seem to get checkbox to be validate on client-side using asp.net mvc 2. Here is my code.
Model
[Serializable]
public class RegistrationModel
{
bool termsAndCondition = false;
[RequiredToBeTrue(ErrorMessage = "Need terms and service")]
public bool TermsAndConditions
{
get
{
return termsAndCondition;
}
set
{
termsAndCondition = value;
}
}
}
Custom Attribute
public class RequiredToBeTrueAttribute : RequiredAttribute
{
public override bool IsValid(object value)
{
return (value != null) && (value is bool) ? (bool)value : false;
}
}
View
<%# Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="System.Web.Mvc.ViewPage<RegistrationModel>" %>
<% Html.EnableClientValidation(); %>
<% using (Html.BeginForm("Register", "Registration", new { area="Account", id = "openid_form", inRegistration = true }))
<%=Html.ValidationSummary(false) %>
blah blah blah
<div class="checkbox"><label><%= Html.CheckBoxFor(model => model.TermsAndConditions) %>I agree to the terms and conditions of use.</label></div>
<input type="submit" id="submit" name="submit" value="Join Now" />
<%
Html.ValidateFor(m => m.TermsAndConditions);
%>
<% } %>
I am trying to call Html.ValidateFor at the end to push up all error message at top of the page. However, the property "TermsAndConditions" is not getting validated on client side (works great on server side). This leads me to look at the the window.mvcClientValidationMetData method at that mvc push out and I saw the following:
{"FieldName":"TermsAndConditions","ReplaceValidationMessageContents":false,"ValidationMessageId":null,"ValidationRules":[]}
Which you can see that "ValidationRules" are empty meaning that it is trying to validate it but the error message wasn't push out to the client for some reason.
Any ideas? Any help is appreciated.
Seems like I need to do more digging first. Was hoping the new attribute will appear magically on the client side. Instead, have to write some customer javascript to wire it up. See phil hack's post for detail.
This article from Phil Haack, ASP.NET MVC 2 Custom Validation, should help point you in the right direction.
Basically you need to create your own DataAnnotationsModelValidator<RequiredToBeTrueAttribute> and then write some client side script to get it done.
HTHs,
Charles

Resources