I am building a website which allows people to send out emails to people with a choice of different templates. When they have set-up their email and chosen a template the user can preview it. At present this loads up the corresponding aspx page to the template selected.
I currently have 3 templates but expect this to grow substantially.
The aspx pages all have the same controls, with the same names and even the codebehind(cs) page is the same. So it would be far simpler and efficient if i could somehow tie this pages together and minimise repetition, perhaps even just using one page but loading up the HTML corresponding to the selected template.
I cant think of an appropriate way to do this, or even work out if its possible. Ive probably got to the point where i cant think straight on the matter since its giving me such a headache.
So.....
Please please please give me some solutions or even just suggestions. ;-)
Thanks.
ADDITIONAL INFO
As an additional problem, i have to recreate the templates programatically when the emails are created and sent out to recipients as HTML emails. This is done via a different page and thus results in more duplication that id like to minimise.
create a Page class, let say, TemplateViewerPage
TemplateViewerPage.cs
using System;
using System.Web.UI;
public partial class TemplateViewerPage : Page
{
protected override void OnLoad(EventArgs e)
{
// load your properties
_subject = "test";
_messageBody = "body";
base.OnLoad(e);
}
// your property
private string _subject;
public string Subject
{
get { return _subject; }
set { _subject = value; }
}
private string _messageBody;
public string MessageBody
{
get { return _messageBody; }
set { _messageBody = value; }
}
}
then you can create viewer for template A :
ViewerA.aspx
<%# Page Language="C#" AutoEventWireup="false" Inherits="TemplateViewerPage" CodeFile="TemplateViewerPage.cs" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table>
<tr>
<td>Subject</td>
<td> <%= Subject %> </td>
</tr>
<tr>
<td>Message</td>
<td> <%= MessageBody %> </td>
</tr>
</table>
</div>
</form>
</body>
</html>
and ViewerB, with same code behind (codefile=TemplateViewerPage.cs)
ViewerB.aspx:
<%# Page Language="C#" AutoEventWireup="false" Inherits="TemplateViewerPage" CodeFile="TemplateViewerPage.cs" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<div class="subject">
<%= Subject %>
</div>
<div class="message">
<%= MessageBody %> </td>
</div>
</div>
</form>
</body>
</html>
How about MasterPages for the templates? The select the appropriate master page at PageLoad.
If it's content then using CSS for the formatting (you can obviously change the CSS being loaded at Pageload) also Placeholders and populating them from your data store for the mails is another option.
It think there are probably as many solutions as there are users on StackOverflow ;)
If all the controls and code behind are the same, couldn't you put all the controls into a masterpage and simply use content pages for the actual emails?
Ah I see. Although it changes is it always in a similar structure? Because you can have multiple content holders in a masterpage. So in the masterpage you would be able to have content wrapped around the controls as follows:
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
<asp:Button ID="button1" runat="server" />
<asp:ContentPlaceHolder ID="ContentPlaceHolder2" runat="server">
</asp:ContentPlaceHolder>
I haven't found that the asp.net web forms page, master pages, or mvc is a very good fit for this sort of thing. It's like using a sledgehammer to crack open a peanut.
It's very straightforward to create some custom xml tags and then merge them yourself. Save the template in the database and merge whenever you like, and without all the overhead of running asp.net. Use agile principles: create your tests first and work backwards and you'll have exactly what you need running in no time.
The most basic is straight string replacement. If you need more, which it doesn't sound like you do, you could use xslt or just walk the DOM (ie store your templates as xhtml and have your own custom tag support).
There's also an issue of deployment. It's a lot easier to update templates in a database than it is to upload files to a server. If you do go down the route of using web forms, make sure you understand the deployment scenario's before you .
Warning: html emails are tricky, and there's a lot of ugliness (from an html standpoint) to get them to render uniformly in email clients. Expect to code the html like it's 1999, and that's pretty much the state of html emails. Sad but true.
Related
I followed some examples in my ASP.NET 4.5 in C# book for Master Pages. So I made a more complex site using them, and it all works locally. But when I push it to my remote server, it is saying the file cannot be found. So I made a more basic master page in Visual Studio 2015 to check. And it works locally, but when pushed to the remote server, it still does not work. I couldn't find any answers online either. I've tried some different urls thinking I was using the wrong url too. I've used
myWebSite.com/TestFolder/MasterPage.master
myWebSite.com/TestFolder/
myWebSite.com/TestFolder/MasterPage
So I'm not sure what I'm doing wrong. Any help would be greatly appreciated.
The code for my master page looks like this:
<%# Master Language="C#" AutoEventWireup="true" CodeFile="MasterPage.master.cs" Inherits="MasterPage" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Tester</title>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<h1>This is a test of the master page.</h1>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
I fixed it. I made sure that the file path to the CodeFile in the header was "./MasterPage.master.cs" and the MasterPageFile reference in the header of the content page was "./MasterPage.master" not "~/MasterPage.master".
The url also worked just as myWebSite.com/
Thank you for the help anyways. Much appreciated.
I've been doing some really clever stuff (I think) in ASP.Net c#, so much so that the simple stuff is more difficult (if that makes sense)
I have this snippet of code in my page
<form id="form1" runat="server">
<asp:HiddenField runat="server" ID="hdnConfirm" value="Hello World" />
<asp:LinkButton runat="server" PostBackUrl="/confirm.aspx" Text="Confirm">
</asp:LinkButton>
</form>
I have this snippet of code in confirm.aspx.
if !(IsPostback)
{
lblConfirm.Text = Request.Form["hdnConfirm"]
}
I was expecting this to be nice and simple but when i click the button and go to page "confirm.aspx" the Request.Form has no values. What have I missed ?
[TESTING]
I ran a test on a brand new web forms project in VS2013. Dot.Net 4.5.1 This does not work. PreviouPage is always null. Whether surrounded by (!IsPostBack) or not. Doesn't matter if the submitting control is a Button, LinkButton or Hyperlink. Request.Form["hdn"] is also null. I have restarted my computer just in case and still no joy. I am missing something really simple I am sure of it but I can't see what
This is the first page nothing in the code behind
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication2.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LinkButton runat="server" PostBackUrl="~/WebForm2.aspx">click</asp:LinkButton>
<asp:HiddenField runat="server" ID="hdn" Value="3" />
</div>
</form>
</body>
</html>
This is the second page
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="WebApplication2.WebForm2" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
Code behind
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication2
{
public partial class WebForm2 : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
string s = ((HiddenField)this.PreviousPage.FindControl("hdn")).Value;
}
}
}
On confirm.aspx use PreviousPage.FindControl instead :
HiddenField hdnFieldName = this.PreviousPage.FindControl("hdnConfirm") as HiddenField;
string hiddenValue = string.Empty;
if (hdnFieldName != null)
{
hiddenValue = hdnFieldName.Value;
}
Here is good example to get you started.
What's going on Here:
By default with VS 2013 and Asp.Net v4.5.1 , there is a feature FriendlyUrls which is enabled.
The FriendlyUrls feature does kind of Asp.Net routing , thus changing URLs from localhost/webform1.aspx to localhost/webfrom1
PostbackUrl property will not work in combination with Asp.Net Routing. When ASP.NET routing is in use the PreviousPage URL is the final routed URL. The runtime will check for a file represented by the Routed URL now, which will be webform1 and NOT webfrom1.aspx. Since there is NO such file as webform1, so it will always set the PreviousPage to null.
Possible Solutions:
So, now you know the issue at hand.
1.) Either don't use the Routing system of Asp.Net Friendly Urls , in this case, therefore try adding the <%# PreviousPageType VirtualPath="~/WebForm1.aspx"%> to webform2.aspx page and check.
2.) OR if you keep the FriendlyURLs and hence the Routing system, make changes in your code to read the Form values using some other alternatives.
The case
I have two web forms, and some codebehind. The first webform is a formular where I enter a string. I want to send that string to the second formular using a post method, and display it.
The problem
I am getting an error message, saying the MAC Viewstate could not be validated :
Erreur du serveur dans l'application '/'. Échec de la validation MAC
Viewstate. Si cette application est hébergée par une batterie de
serveurs ou un cluster, assurez-vous que la configuration
spécifie le même validationKey et le même algorithme de validation.
AutoGenerate ne peut pas être utilisée dans un cluster.
What am I doing wrong ?
Webform1.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="WebApplication1.WebForm1" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server" action="WebForm2.aspx" method="post">
<div>
Enter your first name : <input type="text" name="FirstName"/><br />
<input type="submit" />
</div>
</form>
</body>
</html>
Webform2.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="WebApplication1.WebForm2" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
First name : <%= FirstName %>
</div>
</form>
</body>
</html>
Webform2.aspx.cs
public partial class WebForm2 : System.Web.UI.Page
{
public string FirstName { get; private set; }
protected void Page_Load(object sender, EventArgs e)
{
FirstName = Request.Form["FirstName"];
}
}
Note : I have very little experience with web technologies, and I'm trying to learn asp.net and html, so please forgive me.
EDIT 1 :
WebForm3.aspx
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm3.aspx.cs" Inherits="WebApplication1.WebForm3" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title></title>
</head>
<body>
<form id="form1" runat="server">
<%if (!IsPostBack){ %>
<div>
Enter your first name :
<input type="text" name="FirstName" /><br />
<input type="submit" />
</div>
<% } else { %>
<div>
First name : <%= FirstName %>
</div>
<% } %>
</form>
</body>
</html>
WebForm3.aspx.cs
public partial class WebForm3 : System.Web.UI.Page
{
public string FirstName { get; private set; }
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
FirstName = Request.Form["FirstName"];
}
}
}
WebForm1.aspx (revised)
<form id="form1" runat="server" method="post">
<div>
Enter your first name : <input type="text" name="FirstName"/><br />
<asp:Button PostBackUrl="~/WebForm2.aspx" Text="Validate" runat="server"/>
</div>
</form>
WebForm3.aspx is working fine, and the WebForm1 using an asp:Button is also working, thank you very much.
Additional question :
The purpose of this test was to look for other ways to send data in a "common" way (the post method, since "they" said it is the most secure way). Now, I am only left with one question : what is the best practice, using two files (WebForm1 and WebForm2 method), or a single file (WebForm3 method) ? In other words, should the same page be responsible for gathering data and treating them, or should those responsabilities be split into two files ?
EDIT 2, and last question
When using two files, I see that the IsPostBack property is equal to false. When using a single file, I see that the IsPostBack property is equal to true, when submitting. Is that property only changing (and therefore useful) when using a single file ?
Webform1.aspx
<form id="form1" runat="server" action="WebForm2.aspx" method="post">
Assuming I understood what you're trying to accomplish - if you want to override the PostBack mechanism of WebForms, an easy way is to use PostBackUrl with a Button control.
It's how ASP.Net WebForms work (postback to same page). There are other ways of POSTing to another WebForms Page, but try the PostBackUrl first and see if that's all you really need (least amount of resistance).
You can look into ASP.Net MVC or WebPages too, if you want to use more "standardized" way of doing things (like simply wanting to POST to a resource of your choosing) as what I think you want to accomplish.
Hth...
Update
Well, you won't like my answer because "it depends" -
the "common way" in ASP.net WebForms is really same page - the default PostBack mechanism, and then you'd handle display much like you did above - but through controls (e.g. Placeholder or user controls).
you can also look into things like Wizard controls -> useful for those cases where you need to guide a user through Steps - e.g. perhaps an application form that is lengthy and you want to cut it up into more manageable steps - to cobble this up on your own in a single Page using the Postback mechanism, or even multiple Pages (cross-page Posting) while doable, is probably an exercise in self-punishment :)
there are other ways, but I don't want to confuse and stay on topic (e.g. AJAX).
I'll hold off on "security" because you'll need to be more specific about that - and maybe deserves a separate question. In general the operative rule is "don't trust the client" (meaning validate all data any/all clients provide your application), server-side - not just client-side validation (they should work hand in hand, not mutually exclusive).
Hth...
Update 3
When using two files, I see that the IsPostBack property is equal to false. When using a single file, I see that the IsPostBack property is equal to true, when submitting. Is that property only changing (and therefore useful) when using a single file ?
IsPostBack means "Did this POST request come from myself"?
Page1.aspx -> Button.PostBackUrl -> Page2.aspx = IsPostBack is false
Page1.aspx -> Any button/control that triggers a postback = IsPostBack is true
Having said that, "only useful" - in this simple example perhaps. But you can use that check for other things - you mentioned security earlier, so you can check whether or not your page can/will/should accept a POST request coming from anywhere.
In your sample case, the target page of the POST (when using 2 pages and PostBackUrl) should check/validate the POST data it is receiving - because anyone can do the same thing you just did (POST to it).
here at home I have different projects and libraries for which I've created an helpfile with Sandcastle.
Now Sandcastle provides also the possibility to create a website.
What I would like to do is to create an aspx-page where I can dynamically create a menu and where the existing helpfile-websites can be sollicited. All in one place.
Is it possible to accomplish this? Maybe some control that I can use to view an entire webpage?
Thank you.
EDIT:
Seems I can't get it to work in an ASP-page for whatever reason, but probably because of the way Sandcastle creates the help-pages.
I've now tried it with a WinForm-application with a webbrowser-control and this approach works, so I guess this will be the way I have to go here.
But I do need to say thanks to Alison (and Leon) for their help regarding this issue.
Their solution works for "normal" html-pages, but (unfortunately) not for the ones I have.
For that reason, I've accepted the answer so others could benefit from it.
Updated
Take a look at jQuery load. You can have a div on your page and load the html from an external page into it. The load function can grab individual pieces of HTML from a different page.
On your main page, add this html:
<div id="myexternalpage"></div>
On the different page, add a div tag with an id around the content you want to grab like:
<div id="myexternalcontent">Test</div>
The add the following to your head tag:
<script type="text/javascript">
$(document).ready(function() {
$('#myexternalpage').load('myexternalpage.html #content');
})
</script>
Notice the addition of the "#content" selector to the end of the load function? This will have jQuery load the different page and return only the content in the div with id="content".
Using jQuery load will let you load the content once the page loads and you won't need to use any iFrames. You can use CSS to handle the height/width and handle any overflow.
I've made a quick and dirty test-page:
<%# Page Language="C#" AutoEventWireup="true" CodeBehind="Test2.aspx.cs" Inherits="Test2" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.0/jquery.min.js " ></script>
<script type="text/javascript">
$(document).ready(function () { $('#myexternalpage').load('WebHelp/KoenHoefman/ExhangeRateWebService/Index.html'); })
</script>
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div id="myexternalpage">
</div>
</form>
</body>
</html>
But I get an error on the script line.
Microsoft JScript runtime error: Object expected
Do I have to replace document with something (probably a stupid question but I'm not used to use javascript)?
Update:
Added Leon's code and now it shows something. But when I want to use the page I really want to show (which is located in a subfolder) I get only the items on the index.html. The page that should be loaded into the IFrame of that page isn't shown. Also the pictures that are located in the same folder are not shown.
Error: HTTP 404
Requested URL:
/html/aea04102-3d0d-cf0d-f5f4-5634f5f06aed.htm
Can someone tell me how to get the name of the child page being called in a Master page scenario. For example, if I have the following masterpage:
<%# Master Language="VB" CodeFile="MasterPage.master.vb" Inherits="MasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
</head>
<body>
<asp:ContentPlaceHolder ID="cphMainContent" runat="server">
</asp:ContentPlaceHolder>
</body>
</html>
And I create a page called Test.aspx which inherits this masterpage, how can I, from the masterpage, know that Test.aspx has been requested (since this masterpage can be inherited by more then 1 aspx page)?
Going with your comments, I see a couple of options:
1) In your login page, on a non-postback, check the Referrer - this will be the page that sent you to the login page (Request.UrlReferrer), store that in session for the postback of their login details, and then send the user back.
2) Use the standard features of ASP.NET to handle login/redirections (which basically use the same system as 1).
This is a similar question to what you're asking, but I would pay attention to the accepted answer, trying to figure out the child page from the master page is probably not a good design idea.
I would notify in the other direction. Add properties to your master page then set them from the content pages.
In your master:
public partial class PortalMaster : System.Web.UI.MasterPage
{
public string PageSection { get; set; }
}
In your .aspx add this directive:
<%# MasterType VirtualPath="PortalMaster.master" %>
Then in your .aspx.cs set the property value like so:
Master.PageSection = "about";
Just use the "Page" member of the masterpage
From the codebehind in the MasterPage, the Page.AppRelativeVirtualPath property will tell you the path.