Initialize Session in Masterpage: 'subpage' problem - asp.net

I'm having a hard time with the page cycles when using masterpages and contentpages.
My masterpage has two linkbuttons that are used to select a language (using resources). When these buttons are clicked I create Session["language"].
The goal I have is to 'translate' my masterpage after the buttons are clicked AND to translate the content page.
I've been trying all kinds of different methods (Page_Load etc) based on this url: http://msdn.microsoft.com/en-us/library/dct97kc3.aspx but it never works like it should. Usually the content page only gets translated after two clicks. I can't figure out the cycle problem between the masterpage and the content page combined with the click-events.
Any suggestions?
Thank you.

I used to do this by overriding InitializeCulture method in the master page. The language code is passed via query-string:
protected override void InitializeCulture()
{
if (!string.IsNullOrEmpty(base.Request["language"]))
{
System.Globalization.CultureInfo culture = System.Globalization.CultureInfo.CreateSpecificCulture(base.Request["language"]);
System.Threading.Thread.CurrentThread.CurrentCulture = culture;
System.Threading.Thread.CurrentThread.CurrentUICulture = culture;
}
}
And the link will look like the following:
Vis på Dansk
Don't forget to validate an input value first :-)

Related

Inject Html Into a View Programmatically

I have a tricky problem and I'm not sure where in the view rendering process to attempt this. I am building a simple blog/CMS in MVC and I would like to inject a some html (preferably a partial view) into the page if the user is logged in as an admin (and therefore has edit privileges).
I obviously could add render partials to master pages etc. But in my system master pages/views are the "templates" of the CMS and therefore should not contain CMS specific <% %> markup. I would like to hook in to some part of the rendering process and inject the html myself.
Does anyone have any idea how to do this in MVC? Where would be the best point, ViewPage, ViewEngine?
Thanks,
Ian
You could use Html.RenderPartial to insert an HTML fragment somewhere in the page. If you want to insert it in a place not available to the view but only on the master you could place a <asp:ContentPlaceHolder ID="Admin" runat="server" /> placeholder inside the master and in the view simply override it and insert the partial. If placing such a placeholder is not acceptable you could use AJAX like: $('#adminHolder').load('/home/admin');, but I would probably go with the previous approach as it will work in case the user has javascript disabled.
OK this took a bit of messing and the result is a little hacky. But it works and that's all that matters right....
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
if (!User.Identity.IsAuthenticated || !User.IsInRole("Admin"))
{
// If not admin continue as normal
base.Render(writer);
return;
}
// Taking a leaf out of the move viewstate to the bottom of page playbook
var stringWriter = new System.IO.StringWriter();
var htmlWriter = new HtmlTextWriter(stringWriter);
base.Render(htmlWriter);
var html = stringWriter.ToString();
var endOfBody = html.IndexOf("</body>") - 1;
if (endOfBody >= 0)
{
var adminConsole = Html.RenderPartialAsString("AdminPanel");
html = html.Insert(endOfBody, adminConsole);
}
writer.Write(html);
}
I implement my own ViewPage overriding the Render method. This checks if the user is logged in as an admin and if they are, it renders a partial at the bottom of the page. Very similar to old skool viewstate hacks in webforms.
Enjoy.

.net templates which page am I on?

I'm curious to know that using .net 2.0 with a master page if there is a way that I can pick up what page I am on so that i can use it to style a tab?
My master page has a nav bar on it, and what I wan to do is:
If the user is, say on the contact page, that the tab for the contact page would be a different color, can this be achieved. I have seen some examples that don't use master pages and of course you can use the encapsulating body tag to signify where you are but this isn't available with a masterpage.
Thanks R.
MasterPage though the name sound otherwise behaves like a child to a page that uses it.
Think of it as a UserControl to a page. You can actually access to the Page instance and it's Request property.
Here's an example on how you can use it
switch(Request.Path){
case "/page1/aspx":
//dosomething to your tabs
break:
case "/page1/aspx":
//dosomething to your tabs
break:
.
.
.
default:
//dosomething else
.
.
.
}
If you want to change the content on the masterpage from the page (i.e. change the tab color) you should:
In the masterpage, publicly expose a property or method that will change the color of the tab.
i.e.:
public void changecolor(string PageName, string Color){
switch(PageName){
case "home":
this.TabHome.Color=Color;
}
}
Then put a directive at the top of the aspx page with the masterpage path. Like such:
<%# MasterType VirtualPath="~/Site.master" %>
Once this is done, from the codebehind, you can access the masterpage and see its exposed method, then just call this and you're done.
protected void Page_Init(object sender, EventArgs e){
Master.changecolor("home", "red");
}
this way, you won't have to parse pagenames and deal with the maintenance that comes when you try to change the name of the page etc. you will also limit your case statement to the number of tabs, and not the number of pages in your site.
Create the following method in your masterpage (or helper class) and then add a reference to it in your Page_Load method in the masterpage:
public string GetCurrentPageName()
{
Uri uri = Request.Url;
string[] uriSegments = uri.Segments;
string pageName = "";
if( 0 < uriSegments.Length )
{
pageName = uriSegments.Last();
}
return pageName;
}
}
That should give you the current filename - you might want to strip out the ".aspx" part of the filename also. I haven't tested this with a QueryString yet so not sure if Last() still returns the filename in that case.
If your tabs are asp.net controls, you can use FindControl() to find the tab - you'll need to match your tab ids with your page names of course. Once you have the control you can add a "selected" style in code-behind.

Loading of controls outside of Page_Load is a no-no?

My apologies in advance for posting such a lengthy question. Believe it or not, what you see here actually represents a fairly condensed version of the problem/code at hand. And while I would appreciate any pointers on a better or different approach, I would also very much like to get the bottom of this so that I can sleep at night :)
I came across a requirement to pass confirmation messages between distinct aspx pages. I opted against using a query string variable since query string values "are" sticky (i.e. they persist on all subsequent postbacks) and I didn't want to deal with adding a bunch of conditional logic around this.
Anyway, I came up with a very simple class that uses Session to associate notifications with specific URLs. I then hooked my master page Page_Load event to query this class for any notifications that should be displayed for the current URL. If it finds any, it dynamically loads a NotificationMessage user control and displays the message content.
Everything works as expected when trying to pass Notifications between different aspx pages. Predictably, things don't work when a content page attempts to add a notification to itself (i.e. "The data you entered is not valid, try again"). The reason is pretty clear: by the time a content page adds a Notification for itself, the Page_Load event of the master page has already fired, so it's too late in the page lifecycle to do any good. The relevant code is pasted below.
public class MyMasterPage:MasterPage{
protected void Page_Load(object sender, EventArgs e)
{
LoadNotifications(this.Request.Url.ToString());
}
private void LoadNotifications(string url)
{
//look for a notification
Notification? notification = NotificationManager.Instance.RetrieveNotification(url);
//there are no notifications, nothing to see here
if (!notification.HasValue)
{
return;
}
//there is a Notification for this url, so load it into a user control
NotificationMessage notificationMessageControl = (NotificationMessage)LoadControl("~/App_UserControls/NotificationMessage.ascx");
notificationMessageControl.ID = "notificationMessage";
notificationMessageControl.Notification = notification;
notificationMessageControl.Visible = true;
//find the placeholder on the master page
PlaceHolder placeHolder = (PlaceHolder)PageUtils.FindControlRecursive(this, "NotificationPlaceholder");
if (placeHolder == null)
{
throw new ApplicationException("NotificationPlaceholder control not found.");
}
//insert into control
placeHolder.Controls.Add(notificationMessageControl);
placeHolder.Visible = true;
//remove the notification so it doesn't show up next time
NotificationManager.Instance.RemoveNotification(url);
}
}
Given the lifecycles issued alluded to above, I modified the NotificationManager class so that it raises an event whenever a notification has been added for the current page. The master page intercepts that event, and if the Page_Load has already fired, it kicks off the LoadNotifications method all over again.
//bind the event on the page constructor
public MyMasterPage()
{
NotificationManager.Instance.NotificationAdded += this.NotificationAdded;
}
private void NotificationAdded(string forUrl)
{
if (_pageLoaded){
LoadNotifications(forUrl);
}
}
Unfortunately, this doesn't work. I have stepped through this code numerous times, and despite the fact that the master page loads the NotificationMessage UserControl and adds it to the appropriate placeholder without incident, the final aspx HTML never includes the markup for that UserControl. I've put breakpoints inside the Page_Load of the UserControl and verified that they are indeed being hit during execution.
If I dynamically load the UserControl from inside the content page and bypass the Master page altogether, it renders without a hitch:
public partial class MyContentPage:Page
{
public void DoSomethingCool(object sender, EventArgs e)
{
if (MyServiceLayer.Save(foo)==false){
Notification notification = new Notification(NotificationType.Error, "We’re sorry, your document was not saved.");
NotificationMessage notificationMessage = (NotificationMessage)LoadControl("~/App_UserControls/NotificationMessage.ascx");
notificationMessage.Notification = notification;
notificationMessage.Visible = true;
PlaceHolder holder = (PlaceHolder)PageUtils.FindControlRecursive(this, "NotificationPlaceholder");
holder.Controls.Add(notificationMessage);
}
}
}
For the record, I stripped out the dynamic loading of the UserControl, opting instead for a a static declaration in the master page markup and a code based toggle of the control's Visible property; still no dice!
If someone could shed some light on this conundrum, I would be much obliged.
I've tried this sort of thing before and I was never fully comfortable with it. What I did instead, was put my ASCX on every page (or on the masterpage), and let the ASCX control its state rather than letting the ASPX control my ASCX.
I'm not sure this will help for your situation, though.
It seems like you want your information to show up after your control events fire. You might consider letting those messages aggregate until all control events have fired and then pull out all of the messages from your NotificationManager in OnPreRender, rather than Page_Load. That way you can get rid of the events (like NotificationAdded), etc that are probably complicating matters.
Not 100% what the problem is, though. It sometimes helps to know that the MasterPage is actually a control on the Page, rather than the other way around like you would think. It is going to be subject to the limitations any control would have on a Page.
HTH, Anderson

Get MasterPage Hiddenfield Value From a User Class

Is there a way to get a value I am storing in a Master Page hidden field from a User Class which I created and placed in the App_Code folder of my ASP.Net 2.0 Application?
Some examples would preferably in VB.Net is highly appreciated.
Thanks.
To give further details, assume the following:
MasterPage.Master
MasterPage.Master.vb
MyPage.aspx
Mypage.aspx.vb
IN the app_code folder, add a new class, say TESTClass.
I have placed some logic in master page. MyPage.aspx uses the Masterpage.master as its master page. In the master page, the logic which I did stores a value into a hidden field.
in my TestClass, how do I access the master page hidden field?
Please take note that TestClass is NOT a user control but a user defined class, which contains some Business-Specific logic which is accessed by myPage.aspx.vb.
I tried ScarletGarden's suggestion but it did not seem to get the Masterpage Hiddenfield which I need to get the value.
Would something like this work?
((HiddenField)this.Page.Master.FindControl("[hidden control id]")).Text
You can get it by these :
hiddenControlValue = HttpContext.Current.Request["hiddenControlId"]
or you can pass your page to your method that belongs to your class under App_Config, and reach it as :
public static string GetHiddenValue(Page currentPage)
{
return currentPage.Request["hiddenValue"];
}
or you can get it over context :
public static string GetHiddenValue()
{
return HttpContext.Current.Request["hiddenValue"];
}
hope this helps.
EDIT: I re-read the question after answering, and realize my answer was probably not quite what you were after. :/
Jared's code might work, but you can also try the following.
In your MasterPage, make the HiddenField a public property, and store the content in the ViewState to make keep it during post backs.
Something like so:
public HiddenField theHiddenField
{
get
{
if (ViewState["HiddenField"] == null)
return null; //or something that makes you handle an unset ViewState
else
return ViewState["HiddenField"].ToString();
}
set
{
ViewState["HiddenField"] = value;
}
}
You then have to add the following to your ASCX-file:
<%# Reference Control="~/Masterpages/Communication.Master" %>
You then access it thusly.
Page mypage = (Page) this.Page; // Or instead of Page, use the page you're actually working with, like MyWebsite.Pages.PageWithUserControl
MasterPage mp = (MasterPage) mypage.Master;
HiddenField hf = mp.theHiddenField;
Sorry if the answer got a bit messy. This is, of course, how to do it in C#, if you want to use VB have a look at this link for the same idea.

How do I get a custom IHttpHandler to Be Capable of Handling Postbacks?

I am writing a custom HTTP handler to provide an edit form for a grid using existing user controls. Basically, my handler creates the page, form, header, and other controls necessary to be able to render the existing user controls properly and at the end of ProcessRequest, I use Server.Execute to execute the page that was dynamically created. I am doing this because the solution where this resides is a user controls project and there are no pages, nor can we add any. This needs to be reusable for several projects.
This works great up until the point where the user controls added to this "page" require the usage of the postback mechanism. In the user control Page.IsPostBack is always false and control events (like a button click) are not handled. It is obvious that I am missing some critical piece from how a typical ASP.NET page works. The Page class is just an implementation of an IHttpHandler, but there is a lot of code that I don't think should be necessary to get the basic functionality to work here.
Any ideas?
Here's the basic code from my base HTTP handler. I have other classes that inherit from this base handler to add the actual user controls to the form of the page.
public void ProcessRequest(HttpContext context) {
context.Response.ContentType = "text/html";
HtmlGenericControl htmlPage = GetHtml();
AddTitle();
htmlPage.Controls.Add(_head);
HtmlGenericControl htmlBody = GetBody();
_form.Action = context.Request.Url.ToString();
_form.Method = "POST";
htmlBody.Controls.Add(_form);
htmlPage.Controls.Add(htmlBody);
AddAjaxManager();
AddScriptManager();
_page.Controls.Add(htmlPage);
//_page.ProcessRequest(context);
context.Response.CacheControl = "No-Cache";
context.Server.Execute(_page, context.Response.Output, true);
}
public bool IsReusable { get { return false; } }
To make this work, I inherited from Page instead of implementing IHttpHandler. You do still need to build out the entire HTML of the page, but you get all the wonderfulness (or not) of the ASP.NET WebForms page lifecycle when you do this.

Resources