I might be completely off track by now, so I will just ask this here so someone can help me.
What I want to do, is to insert a value from my web.config, stored in an applicationSettings area, into my aspx markup. Specifically I want to reade a URL from config. This is the configSection setup I use
<configSections>
<sectionGroup name="applicationSettings" type="System.Configuration.ApplicationSettingsGroup, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=123456">
<section name="MyApp.Properties.Settings" type="System.Configuration.ClientSettingsSection, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=12345" requirePermission="false" />
</configSections>
Later in that file are the actual settings like so:
<applicationSettings>
<MyApp.Properties.Settings>
<setting name="ImagesUrl" serializeAs="String">
<value>http://resources/images/</value>
</setting>
Now I want to reference the above value in markup like this:
<asp:Image ID="Image1" runat="server" ImageUrl="<%$AppSettings:ImagesUrl%>/Image1.jpg
I know there's an expression available <%$ AppSettings: ImagesUrl %>, but I'm not using the appsettings part of web.config, rather the configSection.
EDIT:
I believe I can only do it with ExpressionBuilder, because I have to concatenate the string with the individual image name. I changed the example above to reflect that.
I like Bert Smith Code Solution below for accessing the config section, only I need to put it in an expression builder.
I'm stuck at overriding the GetCodeExpression method from where I would call the Configuration Manager, but I don't understand how to build an expression the parameters.
public class SettingsExpressionBuilder: ExpressionBuilder
{
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
return ??
}
EDIT
The result looks like this, and works for all kinds of files, not just images:
<asp:ScriptReference Path='<%$Code:GetAppSetting("ResourcesUrl","JS/jquery/jquery.jqplot.js")%>'
and I simply used the example from Microsoft to return any kind of code from the expression builder:
return new CodeSnippetExpression(entry.Expression);
And GetAppSetting is a method in my custom Page class.
Typically you would create a custom settings class to read these values out as this artical describes. Personally, I would just use the appSettings as suggested above as this is existing functionality and for what your doing would on the surface seem adequate.
However, not knowing your circumstances, what your attempting to do could be solved without the custom settings like so:
In the code behind I created a protected function to retrieve the setting
protected string GetCustomSetting(string Section, string Setting)
{
var config = ConfigurationManager.GetSection(Section);
if (config != null)
return ((ClientSettingsSection)config).Settings.Get(Setting).Value.ValueXml.InnerText;
return string.Empty;
}
Then in the aspx markup I call this function
<div>
<label runat="server" id="label"><%=GetCustomSetting("applicationSettings/MyApp.Properties.Settings", "ImagesUrl") %></label>
</div>
Hope this helps.
Follow Up:
The CodeExpression will look something like this:
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context)
{
var config = ConfigurationManager.GetSection("applicationSettings/MyApp.Properties.Settings");
return new CodePrimitiveExpression(((ClientSettingsSection)config).Settings.Get(entry.Expression).Value.ValueXml.InnerText);
}
In my Test, I created a class called CustomSettingsExpressionBuilder and added it to the App_Code folder. Added the configuration for the custom express to the web.config and called it from aspx like so:
<asp:Label ID="Label1" runat="server" Text="<%$CustomSettings:ImagesUrl %>"></asp:Label>
Does it has to be in markup? Why don't you set it in code-behind.
Image1.ImageUrl= //fetch your settings here.
One another way would be defining a property or static method in your code-behind and then using that in the markup.
I'm not sure about the ASP.NET bit of it, but if this was normal code you'd do MyApp.Properties.Settings.Default.ImagesUrl, so try
<asp:Image ID="Image1" runat="server"
ImageUrl="<%$MyApp.Properties.Settings.Default.ImagesUrl%>
It would definitely be easier to store this in <appSettings> though.
Related
I have a project and I am trying to register a custom server control (there is no .ascx file) on the page. I am currently using
Class Declaration
namespace MyApp.Controls{
public class CustomControl: WebControl{
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set
{
ViewState["Text"] = value;
}
}
protected override void RenderContents(HtmlTextWriter output)
{
output.Write(Text);
}
}
}
On my page,
<%# Register TagPrefix="myControls" Namespace="MyApp.Controls" %>
<myControls:CustomControl runat="server" Text="What up!" />
I receive a Parser Error, with the message "Unknown server tag 'myControls:CustomControl'."
What am I doing wrong?
Well, if this control is in another class library, or even if it's in the same one, it wouldn't be a bad idea to specify control's assembly in #Register:
<%# Register TagPrefix="myControls" Namespace="MyApp.Controls" Assembly="MyApp" %>
<myControls:CustomControl runat="server" Text="What's up!" />
Clean and rebuild your solution too in order to verify everything is compiled rightly!
If your control will be reused on several pages, you may want to register it in web.config, as one of system.web/pages/controls subelements instead of copy-pasting the same <#Register tag in all affected pages.
web.config:
<system.web>
<pages ...>
<controls>
...
<add tagPrefix="myCompany" namespace="MyCompany.Whatever.Controls" assembly="Whatever"/>
</controls>
thepage.aspx:
<myCompany:ControlClassName ID="TheStuff" runat="server" ... />
You should put your control either under the App_Code folder (in the case if the control not in assembly) or add a reference to assembly where this control is:
<%# Register TagPrefix="myControls" Namespace="MyApp.Controls"
Assembly="SomeAssembly" %>
But guessing, your control not under the App_Code folder.
Add an assembly attribute to your register tag
I have a .aspx file and would like to add some HTML to it. The problem is that it can't be modified. If I upgrade the product, this .aspx file will be overwritten and my modifications would have to be done again.
This is an open source product, so I can have a look at the codebehind. Again, I cannot modify it because that would break my upgrade path. Also, I need to add functionality that would never be included in the product, so sending in a patch is useless.
The class that's referred to is a partial class, so I tried implementing an extra Page_PreRender by creating another partial class of the same name in the same namespace. However, since this is in another assembly, .net says it doesn't know which is the correct class.
Is there any way I can do this?
So you can neither touch the .aspx of this page, nor the assembly containing its code behind? Sounds like you need to create a PageAdapter.
Say you're given this page...
<%# Page AutoEventWireup="true" ContentType="text/plain" Inherits="WebForm1" %>
SomeControl: <asp:Literal runat="server" ID="SomeControl" />
...with this code behind (in an assembly that you can only reference, not modify).
public class WebForm1 : Page {
protected void Page_Load(object sender, EventArgs e) {
var SomeControl = (Literal) FindControl("SomeControl");
SomeControl.Text = "Value set from code-behind.";
}
}
What you can do is create a PageAdapter like so (in your own assembly):
public class WebForm1Adapter : PageAdapter {
protected override void OnLoad(EventArgs e) {
base.OnLoad(e);
var SomeControl = (Literal) Page.FindControl("SomeControl");
SomeControl.Text = "Value set from control adapter.";
}
}
Then finally, you need to register your override by creating a browser definition file:
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="WebForm1" adapterType="WebForm1Adapter" />
</controlAdapters>
</browser>
</browsers>
Check the PageAdapter and ControlAdapter documentation to find out all the ways you can override the normal page behavior.
This should make updating the third party page much less painful. No matter what you do though, merging updates will be inherently brittle. That is, unless the author of the third party page is consciously presenting some form of a stable API.
You can perhaps use Reflection Emit to inject code into the code behind class in app start-up.
I've got an ASP.NET 4 site on which I want to allow people to put '<' in their password. However, .NET gets in the way by blocking (what it sees as) an attempt to put HTML in a form field. I know I can turn off input validation entirely, but I only want to turn it off for this one field. Does anyone know an easy way to do that?
This is now possible with .NET 4.5.
Update your Web.config:
<httpRuntime targetFramework="4.5" requestValidationMode="4.5" />
Then set ValidateRequestMode="Disabled" on your password controls:
<asp:YourControl id="YourControl" runat="server" ValidateRequestMode="Disabled"/>
Note - after updating web.config, you might run into the error WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for 'jquery'. See ASP.Net 2012 Unobtrusive Validation with jQuery for more info on that.
More info on RequestValidationMode 4.5: requestValidationMode 4.5 vs 2.0
You can only turn off input validation for the entire page. The only solution I can think of is to turn off the input validation, and then scrub all the other (non-password) input fields using something like Anti-XSS.
You can turn input validation off for the single MVC action using the ValidateInputAttribute. Since you're only accepting username/password (I would assume) you should be able to scrub input yourself of any invalid characters. Use the Microsoft Web Protection Library to do that.
Note in ASP.NET 4 and higher to get ValidateRequest in the #Page directive to work you need to add <httpRuntime requestValidationMode="2.0" /> to web.config. See this page for details:
http://www.asp.net/whitepapers/aspnet4/breaking-changes
But this is my preferred approach:
namespace Controls
{
public class HtmlTextBox : TextBox
{
protected override bool LoadPostData(string postDataKey, System.Collections.Specialized.NameValueCollection postCollection)
{
bool res = base.LoadPostData(postDataKey, postCollection);
Text = Text.Replace("<", "<").Replace(">", ">").Replace("&", "&");
return res;
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
ScriptManager.RegisterOnSubmitStatement(this, this.GetType(), "htmlTextBox" + UniqueID, "try { var item = document.getElementsByName('" + UniqueID + "')[0]; item.value = item.value.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>'); } catch (err) {}");
}
}
}
And then register the control in web.config:
<system.web>
<pages>
<controls>
<add tagPrefix="uc1" namespace="Controls" />
</controls>
</pages>
</system.web>
This way you can just use <uc1:HtmlTextBox runat="server" /> if you want to allow the textbox to post html, but other controls on the page will still be blocked from posting html unlike the approach of turning ValidateRequest off.
This is possible. Just add [AllowHtml] on the property that should not be validated.
see ValidateInputAttribute does not contain a definition for Exclude
I'm using Crystal Reports in a Webform inside of an MVC application. Images in the reports are not being displayed, however, on both the ASP.NET Development Server and IIS 7 (on Win7x64).
I know from a number of other questions similar to this that the CrystalImageHandler HTTP Handler is responsible for rendering the image, but I've tried all of the usual solutions to no avail.
So far, I have
Added the following to my appSettings (via http://www.mail-archive.com/bdotnet#groups.msn.com/msg26882.html)
<add key="CrystalImageCleaner-AutoStart" value="true" />
<add key="CrystalImageCleaner-Sleep" value="60000" />
<add key="CrystalImageCleaner-Age" value="120000" />
Added the following httpHandler to system.web/httpHandlers (via https://stackoverflow.com/questions/2253682/crystal-report-viewer-control-isnt-loading-the-images-inside-the-report)
<add verb="GET" path="CrystalImageHandler.aspx" type="CrystalDecisions.Web.CrystalImageHandler, CrystalDecisions.Web, Version=12.0.2000.0, Culture=neutral, PublicKeyToken=692fbea5521e1304"/>
Added the following to my Global.asax.cs (via Crystal Reports Images and ASP.Net MVC)
routes.IgnoreRoute("{resource}.aspx/{*pathInfo}");
and
routes.IgnoreRoute("CrystalImageHandler.aspx");
Any ideas as to why the images still 404?
I had similar problem. This helped me.
routes.IgnoreRoute("{*allaspx}", new { allaspx = #".*(CrystalImageHandler).*" });
I've tried the multitude of ways this can supposedly be made to work. None did. So I eventually settled on cheating:
public class CrystalImageHandlerController : Controller
{
//
// GET: /Reports/CrystalImageHandler.aspx
public ActionResult Index()
{
return Content("");
}
protected override void OnActionExecuted(ActionExecutedContext filterContext)
{
var handler = new CrystalDecisions.Web.CrystalImageHandler();
var app = (HttpApplication)filterContext.RequestContext.HttpContext.GetService(typeof(HttpApplication));
if (app == null) return;
handler.ProcessRequest(app.Context);
}
}
I added a route to this controller matching what Crystal expects (./CrystalImageHandler.aspx) and used this controller to invoke the handler when the action is executed. Not pretty, but functional.
Have you tried adding it to system.webServer/handlers? That should fix it on IIS7 but it is strange it doesn't work on the development server w/o that.
Add this in RouteConfig.cs file
routes.IgnoreRoute("Reports/{resource}.aspx/{*pathInfo}");
Note
"Reports" is the folder name which contains the aspx file of report viewer
change this folder name as per your application
I am attempting to allow my web designers to use the metadata we have about database fields in the asp.net pages they are creating. The most obvious one is as follows:
<asp:TextBox runat="server" id="txTextBox" MaxLength="<Value From Metadata here>" ... />
All the required metadata is stored in our class objects and is accessible due to its public static nature.
The benefit of this would be that they can set values which
a) might change without them being aware or caring
b) improve the user experience with very little coding effort
and all without having them need worry about what the value is or where it has come from. This will primarily be used for automatically bound controls - i.e. ones which are added with little or no developer interaction.
This question is very similar to One of my previous questions which now works wonderfully (but that was in WPF / XAML ).
The main point of this question is that I want as little developer requirement on this as possible - Ideally there would be some <%# Constant.Value %> type syntax which could be used directly within the Maxlength="" attribute of the asp:Textbox control meaning that no code needs to be added to a page/usercontrol at all.
I have a feeling it isn't possible, but I would love someone to prove me wrong.
Ta
You can use a data binding expression:
<asp:TextBox MaxLength="<%# Constant.Value %>" />
but, that requires it to be in a databound control. If it's not in a repeater or somesuch, you'll need to call Container.DataBind() at some point in the page lifecycle.
Alternatively, you could create an ExpressionBuilder which would allow syntax such as:
<asp:TextBox MaxLength="<%$ Constants:Value %>" />
Here's a sample that'll pull from a single static dictionary:
using System;
using System.Web.UI;
using System.Web.Compilation;
using System.CodeDom;
using System.Collections.Generic;
class ConstantsExpressionBuilder : ExpressionBuilder {
private static readonly Dictionary<string, object> Values =
new Dictionary<string, object>() {
{ "Value1", 12 },
{ "Value2", false },
{ "Value3", "this is a test" }
};
public override bool SupportsEvaluate { get { return true; } }
public override object EvaluateExpression(object target, BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context) {
string key = entry.Expression.Trim();
return GetValue(key);
}
public override CodeExpression GetCodeExpression(BoundPropertyEntry entry, object parsedData, ExpressionBuilderContext context) {
CodePrimitiveExpression keyExpression = new CodePrimitiveExpression(entry.Expression.Trim());
return new CodeMethodInvokeExpression(this.GetType(), "GetValue", new CodeExpression[] { keyExpression });
}
public static object GetValue(string key) {
return Values[key];
}
}
You'd register this in web.config:
<system.web>
<compilation>
<expressionBuilders>
<add expressionPrefix="Constants" type="ConstantsExpressionBuilder" />
</expressionBuilders>
</compilation>
</system.web>
And call it in an ASPX page:
<asp:Textbox runat="server" MaxLength="<%$ Constants:Value1 %>" ReadOnly="<%$ Constants:Value2 %>" Text="<%$ Constants:Value3 %>" />
Which should produce:
<input type="text" maxlength="12" readonly="false" value="this is a test" />
in the HTML output.
I think you should be able to do it with something like this
<asp:TextBox runat="server" id="txTextBox" MaxLength="<%=Constants.SomeValue%>" />
But my only concern is that this doesn't really make much sense. If the constant is stored in a .cs file in order to make a change that would cause the new constant value to be reflected in the UI you would have to recompile the site. I think it may be easier just to have a hard coded value in the .aspx page that can be changed easily without the need to recompile the entire codebase. Maybe I'm not understanding the problem though.